diff --git a/.cirrus.yml b/.cirrus.yml new file mode 100644 index 0000000000..e48f24b4ed --- /dev/null +++ b/.cirrus.yml @@ -0,0 +1,233 @@ +# only run for releases +only_if: $CIRRUS_TAG != '' + +env: + MACOSX_DEPLOYMENT_TARGET: "10.15" + +macosx_arm64_wheel_task: + macos_instance: + image: ghcr.io/cirruslabs/macos-monterey-base:latest + + checkout_script: + - git submodule init + - git submodule update + + install_deps_script: + - brew update + - brew install coreutils golang pyenv python + + install_various_python_script: + - pyenv install 3.8.16 + - pyenv install 3.9.16 + - pyenv install 3.10.10 + - pyenv install 3.11.2 + + install_apache_arrow_script: | + echo "Installing apache-arrow ..." + mkdir -p /tmp/install + cd /tmp/install + curl -L https://github.com/apache/arrow/archive/refs/tags/apache-arrow-8.0.1.tar.gz --output apache-arrow-8.0.1.tar.gz + tar zxf apache-arrow-8.0.1.tar.gz + cd arrow-apache-arrow-8.0.1 + mkdir -p build-dir + cd build-dir + cmake ../cpp \ + -DARROW_COMPUTE=OFF \ + -DARROW_WITH_UTF8PROC=OFF \ + -DARROW_CSV=OFF \ + -DARROW_CUDA=OFF \ + -DARROW_DATASET=OFF \ + -DARROW_FILESYSTEM=ON \ + -DARROW_FLIGHT=OFF \ + -DARROW_GANDIVA=OFF \ + -DARROW_GANDIVA_JAVA=OFF \ + -DARROW_HDFS=OFF \ + -DARROW_HIVESERVER2=OFF \ + -DARROW_JSON=OFF \ + -DARROW_ORC=OFF \ + -DARROW_PARQUET=OFF \ + -DARROW_PLASMA=OFF \ + -DARROW_PLASMA_JAVA_CLIENT=OFF \ + -DARROW_PYTHON=OFF \ + -DARROW_S3=OFF \ + -DARROW_WITH_BZ2=OFF \ + -DARROW_WITH_ZLIB=OFF \ + -DARROW_WITH_LZ4=OFF \ + -DARROW_WITH_SNAPPY=OFF \ + -DARROW_WITH_ZSTD=OFF \ + -DARROW_WITH_BROTLI=OFF \ + -DARROW_IPC=ON \ + -DARROW_BUILD_BENCHMARKS=OFF \ + -DARROW_BUILD_EXAMPLES=OFF \ + -DARROW_BUILD_INTEGRATION=OFF \ + -DARROW_BUILD_UTILITIES=OFF \ + -DARROW_BUILD_TESTS=OFF \ + -DARROW_ENABLE_TIMING_TESTS=OFF \ + -DARROW_FUZZING=OFF \ + -DARROW_USE_ASAN=OFF \ + -DARROW_USE_TSAN=OFF \ + -DARROW_USE_UBSAN=OFF \ + -DARROW_JEMALLOC=OFF \ + -DARROW_BUILD_SHARED=OFF \ + -DARROW_BUILD_STATIC=ON + sudo make install -j$(sysctl -n hw.ncpu) + cd /tmp + sudo rm -rf /tmp/install + + install_boost_script: | + echo "Installing boost ..." + mkdir -p /tmp/install + cd /tmp/install + wget -q https://boostorg.jfrog.io/artifactory/main/release/1.75.0/source/boost_1_75_0.tar.gz + tar zxf boost_1_75_0.tar.gz + cd boost_1_75_0 + ./bootstrap.sh + sudo ./b2 install -j`nproc` variant=release threading=multi \ + --with-atomic \ + --with-chrono \ + --with-date_time \ + --with-filesystem \ + --with-random \ + --with-regex \ + --with-system \ + --with-thread + cd /tmp + sudo rm -rf /tmp/install + + install_gflags_script: | + echo "Installing gflags ..." + mkdir -p /tmp/install + cd /tmp/install + curl -L https://github.com/gflags/gflags/archive/v2.2.2.tar.gz --output gflags-v2.2.2.tar.gz + tar zxf gflags-v2.2.2.tar.gz + cd gflags-2.2.2 + mkdir -p build-dir + cd build-dir + cmake .. -DBUILD_SHARED_LIBS=OFF + sudo make install -j$(sysctl -n hw.ncpu) + cd /tmp + sudo rm -rf /tmp/install + + install_glog_script: | + echo "Installing glog ..." + mkdir -p /tmp/install + cd /tmp/install + curl -L https://github.com/google/glog/archive/v0.6.0.tar.gz --output glog-v0.6.0.tar.gz + tar zxf glog-v0.6.0.tar.gz + cd glog-0.6.0 + mkdir -p build-dir + cd build-dir + cmake .. -DBUILD_SHARED_LIBS=OFF \ + -DWITH_GFLAGS=OFF \ + -DBUILD_TESTING=OFF + sudo make install -j$(sysctl -n hw.ncpu) + cd /tmp + sudo rm -rf /tmp/install + + install_protobuf_grpc_script: | + echo "Installing protobuf & grpc ..." + mkdir -p /tmp/install + cd /tmp/install + wget -q https://github.com/unsafecoerce/git-submodules-tarball/releases/download/grpc%2Fgrpc-v1.36.x/grpc-grpc-1.36.x.tar.gz + tar zxf grpc-grpc-1.36.x.tar.gz + cd grpc-grpc-1.36.x + mkdir -p cmake-build + cd cmake-build + cmake .. -DCMAKE_BUILD_TYPE=MinSizeRel \ + -DBUILD_SHARED_LIBS=OFF \ + -DgRPC_INSTALL=ON \ + -DgRPC_BUILD_TESTS=OFF \ + -DgRPC_BUILD_CSHARP_EXT=OFF \ + -DgRPC_BUILD_GRPC_CSHARP_PLUGIN=OFF \ + -DgRPC_BUILD_GRPC_NODE_PLUGIN=OFF \ + -DgRPC_BUILD_GRPC_OBJECTIVE_C_PLUGIN=OFF \ + -DgRPC_BUILD_GRPC_PHP_PLUGIN=OFF \ + -DgRPC_BUILD_GRPC_PYTHON_PLUGIN=OFF \ + -DgRPC_BUILD_GRPC_RUBY_PLUGIN=OFF \ + -DgRPC_SSL_PROVIDER=package \ + -DgRPC_ZLIB_PROVIDER=package \ + -DOPENSSL_ROOT_DIR=$(brew --prefix openssl) \ + -DgRPC_BACKWARDS_COMPATIBILITY_MODE=ON + sudo make install -j$(sysctl -n hw.ncpu) + cd /tmp + sudo rm -rf /tmp/install + + build_vineyardctl_script: + - make -C k8s vineyardctl + + vineyardctl_artifacts: + path: k8s/vineyardctl + + build_vineyardd_script: + - mkdir -p build + - cd build + - | + pyenv global 3.11.2 + cmake .. -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_CXX_STANDARD=17 \ + -DCMAKE_CXX_STANDARD_REQUIRED=TRUE \ + -DBUILD_SHARED_LIBS=OFF \ + -DBUILD_VINEYARD_SERVER=ON \ + -DBUILD_VINEYARD_CLIENT=OFF \ + -DBUILD_VINEYARD_PYTHON_BINDINGS=OFF \ + -DBUILD_VINEYARD_PYPI_PACKAGES=OFF \ + -DBUILD_VINEYARD_BASIC=OFF \ + -DBUILD_VINEYARD_GRAPH=OFF \ + -DBUILD_VINEYARD_IO=OFF \ + -DBUILD_VINEYARD_HOSSEINMOEIN_DATAFRAME=OFF \ + -DBUILD_VINEYARD_TESTS=OFF \ + -DBUILD_VINEYARD_TESTS_ALL=OFF \ + -DBUILD_VINEYARD_PROFILING=OFF + make vineyardd -j$(sysctl -n hw.ncpu) + + vineyardd_artifacts: + path: build/bin/vineyardd + + build_vineyard_bdist_script: + - pyenv global 3.11.2 + - cp k8s/vineyardctl ./python/vineyard/bdist/vineyardctl + - cp build/bin/vineyardd ./python/vineyard/bdist/vineyardd + - strip ./python/vineyard/bdist/vineyardctl + - strip ./python/vineyard/bdist/vineyardd + - python3 setup_bdist.py bdist_wheel --plat=macosx_11_0_arm64 + + build_vineyard_python_script: + - | + for py in 3.8.16 3.9.16 3.10.10 3.11.2; do + current_python=$(pyenv root)/versions/$py/bin/python + echo "Python is: $current_python, $($current_python --version)" + $current_python -m pip install delocate wheel + rm -rf build/lib* build/bdist.* python/vineyard/*.dylib python/vineyard/*.so + mkdir -p build + cd build + cmake .. -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_CXX_STANDARD=17 \ + -DCMAKE_CXX_STANDARD_REQUIRED=TRUE \ + -DBUILD_SHARED_LIBS=OFF \ + -DBUILD_VINEYARD_SERVER=OFF \ + -DBUILD_VINEYARD_CLIENT=ON \ + -DBUILD_VINEYARD_PYTHON_BINDINGS=ON \ + -DBUILD_VINEYARD_PYPI_PACKAGES=ON \ + -DPYTHON_EXECUTABLE=$current_python \ + -DBUILD_VINEYARD_BASIC=OFF \ + -DBUILD_VINEYARD_GRAPH=OFF \ + -DBUILD_VINEYARD_IO=OFF \ + -DBUILD_VINEYARD_HOSSEINMOEIN_DATAFRAME=OFF \ + -DBUILD_VINEYARD_TESTS=OFF \ + -DBUILD_VINEYARD_TESTS_ALL=OFF \ + -DBUILD_VINEYARD_PROFILING=OFF + make vineyard_client_python -j$(sysctl -n hw.ncpu) + cd .. + $current_python setup.py bdist_wheel + done + + delocate_wheel_script: + - | + $(brew --prefix python)/bin/python3 -m pip install delocate wheel + for wheel in dist/*.whl; do + delocate-wheel -w fixed_wheels -v $wheel + done + ls -la ./fixed_wheels + + macosx_arm64_wheel_artifacts: + path: fixed_wheels/*.whl diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000..6f1fa81d27 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,55 @@ +.git +**/.git + +# contents from .gitignore +build/ +build-mac/ +install/ +build-static/ +build-static-mac/ +install-static/ +build-docker/ +install-docker/ +build-docker-gsa/ +install-docker-gsa/ +*.code-workspace +.vscode +.idea +.DS_store +cmake-build-debug + +# for python packaging +dist/ +**/*.egg-info/ +**/*.so +**/*.dylib +**/*.a +**/*.pyc +**/*.bin +**/*.egg + +# generated files +*.vineyard.h + +# etcd data directory during testing +default.etcd/ + +# tmp data directory during building image +docker/dist/ + +# docs +docs/_build/ + +# go vendor +vendor/ + +# k8s +k8s/bin/ +k8s/vendor/ +k8s/examples/ +k8s/test/ +k8s/hack/ +!k8s/config/scheduler/config.yaml + +# artifacts +wheels/ diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 0000000000..8833043ae7 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,85 @@ +title = "Gitleaks for Vineyard" + +[extend] +useDefault = true + +[[rules]] +description = "Alibaba AccessKey ID" +id = "alibaba-access-key-id" +regex = '''(?i)((LTAI)[a-z0-9]+)''' +keywords = [ + "ltai", +] + +[[rules]] +description = "Alibaba AccessKey ID" +id = "alibaba-access-id-in-config" +regex = '''(?i)((access).?id\s*=\s*.+)''' +keywords = [ + "access", +] + +[[rules]] +description = "Alibaba AccessKey ID" +id = "alibaba-access-key-in-config" +regex = '''(?i)((access).?key\s*=\s*.+)''' +keywords = [ + "access", +] + +[[rules]] +description = "Alibaba AccessKey ID" +id = "alibaba-access-secret-in-config" +regex = '''(?i)((access).?secret\s*=\s*.+)''' +keywords = [ + "access", + "secret", +] + +[[rules]] +description = "Alibaba AccessKey ID" +id = "alibaba-access-key-id-in-config" +regex = '''(?i)((access).?key.?id\s*=\s*.+)''' +keywords = [ + "access", +] + +[rules.allowlist] +paths = [ + '''python/vineyard/drivers/io/tests/test_open.py''', + '''python/vineyard/drivers/io/tests/test_serialize.py''', +] + +[[rules]] +description = "Alibaba AccessKey ID" +id = "alibaba-access-key-secret-in-config" +regex = '''(?i)((access).?key.?secret\s*=\s*.+)''' +keywords = [ + "access", + "secret", +] + +[rules.allowlist] +paths = [ + '''python/vineyard/drivers/io/tests/test_open.py''', + '''python/vineyard/drivers/io/tests/test_serialize.py''', +] + +[[rules]] +description = "Alibaba AccessKey ID" +id = "alibaba-secret-access-key-in-config" +regex = '''(?i)((secret).?access.?key\s*=\s*.+)''' +keywords = [ + "access", + "secret", +] + +[allowlist] +paths = [ + '''build''', + '''docs/_build''', + '''docs/_templates/footer.html''', + '''thirdparty''', + '''modules/graph/thirdparty''', +] + diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000000..e69de29bb2 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..401a71bcee --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,8 @@ +repos: + - repo: https://github.com/zricethezav/gitleaks + rev: v8.15.0 + hooks: + - id: gitleaks + args: + - '--verbose' + diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000000..4b3b599d40 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,614 @@ +[MASTER] + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. +extension-pkg-whitelist=numpy, + vineyard + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the +# number of processors available to use. +jobs=1 + +# Control the amount of potential inferred values when inferring a single +# object. This can help the performance when dealing with large functions or +# complex, nested conditions. +limit-inference-results=100 + +# List of plugins (as comma separated values of python module names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Specify a configuration file. +#rcfile= + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages. +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=yes + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED. +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once). You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable=abstract-method, + apply-builtin, + attribute-defined-outside-init, + backtick, + bad-continuation, + bad-inline-option, + bad-option-value, + bad-python3-import, + bare-except, + basestring-builtin, + buffer-builtin, + cmp-builtin, + cmp-method, + coerce-builtin, + coerce-method, + comprehension-escape, + consider-using-f-string, + delslice-method, + deprecated-itertools-function, + deprecated-operator-function, + deprecated-pragma, + deprecated-str-translate-call, + deprecated-string-function, + deprecated-sys-function, + deprecated-types-field, + deprecated-urllib-function, + dict-items-not-iterating, + dict-iter-method, + dict-keys-not-iterating, + dict-values-not-iterating, + dict-view-method, + div-method, + duplicate-code, + eq-without-hash, + exception-escape, + exception-message-attribute, + execfile-builtin, + file-builtin, + file-ignored, + filter-builtin-not-iterating, + fixme, + getslice-method, + global-statement, + hex-method, + idiv-method, + import-star-module-level, + indexing-exception, + input-builtin, + intern-builtin, + invalid-name, + invalid-str-codec, + locally-disabled, + long-builtin, + long-suffix, + map-builtin-not-iterating, + metaclass-assignment, + missing-class-docstring, + missing-function-docstring, + missing-docstring, + missing-module-docstring, + next-method-called, + next-method-defined, + no-absolute-import, + no-else-continue, + no-else-raise, + no-else-return, + no-self-use, + non-ascii-bytes-literal, + nonzero-method, + oct-method, + old-division, + old-ne-operator, + old-octal-literal, + old-raise-syntax, + parameter-unpacking, + print-statement, + protected-access, + raising-string, + range-builtin-not-iterating, + raw-checker-failed, + raw_input-builtin, + rdiv-method, + redefined-builtin, + redefined-outer-name, + reduce-builtin, + reload-builtin, + round-builtin, + setslice-method, + standarderror-builtin, + suppressed-message, + sys-max-int, + too-few-public-methods, + too-many-ancestors, + too-many-arguments, + too-many-branches, + too-many-locals, + unichr-builtin, + unicode-builtin, + unnecessary-comprehension, + unpacking-in-except, + unrecognized-option, + unsubscriptable-object, + use-dict-literal, + use-list-literal, + use-symbolic-message-instead, + useless-else-on-loop, + useless-option-value, + useless-suppression, + using-cmp-argument, + xrange-builtin, + xreadlines-attribute, + zip-builtin-not-iterating, + django-not-configured + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable=c-extension-no-member + + +[REPORTS] + +# Python expression which should return a score less than or equal to 10. You +# have access to the variables 'error', 'warning', 'refactor', and 'convention' +# which contain the number of messages in each category, as well as 'statement' +# which is the total number of statements analyzed. This score is used by the +# global evaluation report (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details. +#msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio). You can also give a reporter class, e.g. +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages. +reports=no + +# Activate the evaluation score. +score=yes + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=sys.exit + + +[LOGGING] + +# Format style used to check logging format string. `old` means using % +# formatting, `new` is for `{}` formatting,and `fstr` is for f-strings. +logging-format-style=old + +# Logging modules to check that the string format arguments are in logging +# function parameter format. +logging-modules=logging + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes. +max-spelling-suggestions=4 + +# Spelling dictionary name. Available dictionaries: none. To make it work, +# install the python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains the private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to the private dictionary (see the +# --spelling-private-dict-file option) instead of raising a message. +spelling-store-unknown-words=no + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# Tells whether to warn about missing members when the owner of the attribute +# is inferred to be None. +ignore-none=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis). It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + +# List of decorators that change the signature of a decorated function. +signature-mutators= + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid defining new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, + _cb + +# A regular expression matching the name of dummy variables (i.e. expected to +# not be used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore. +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=128 + +# Maximum number of lines in a module. +max-module-lines=4294967296 + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma, + dict-separator + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[SIMILARITIES] + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[BASIC] + +# Naming style matching correct argument names. +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style. +#argument-rgx= + +# Naming style matching correct attribute names. +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style. +#attr-rgx= + +# Bad variable names which should always be refused, separated by a comma. +bad-names=foo, + bar, + baz, + toto, + tutu, + tata + +# Naming style matching correct class attribute names. +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style. +#class-attribute-rgx= + +# Naming style matching correct class names. +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming- +# style. +#class-rgx= + +# Naming style matching correct constant names. +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style. +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names. +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style. +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma. +good-names=i, + j, + k, + ex, + Run, + _ + +# Include a hint for the correct naming format with invalid-name. +include-naming-hint=no + +# Naming style matching correct inline iteration names. +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style. +#inlinevar-rgx= + +# Naming style matching correct method names. +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style. +#method-rgx= + +# Naming style matching correct module names. +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style. +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +# These decorators are taken in consideration only for invalid-name. +property-classes=abc.abstractproperty + +# Naming style matching correct variable names. +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style. +#variable-rgx= + + +[STRING] + +# This flag controls whether the implicit-str-concat-in-sequence should +# generate a warning on implicit string concatenation in sequences defined over +# several lines. +check-str-concat-over-line-jumps=no + + +[IMPORTS] + +# List of modules that can be imported at any level, not just the top level +# one. +allow-any-import-level= + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma. +deprecated-modules=optparse,tkinter.tix + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled). +ext-import-graph= + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled). +import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled). +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + +# Couples of modules and preferred modules, separated by a comma. +preferred-modules= + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, + _fields, + _replace, + _source, + _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=cls + + +[DESIGN] + +# Maximum number of arguments for function / method. +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in an if statement (see R0916). +max-bool-expr=5 + +# Maximum number of branch for function / method body. +max-branches=12 + +# Maximum number of locals for function / method body. +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body. +max-returns=6 + +# Maximum number of statements in function / method body. +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "BaseException, Exception". +overgeneral-exceptions=BaseException, + Exception diff --git a/.stoat/config.yaml b/.stoat/config.yaml new file mode 100644 index 0000000000..02f7dd8e6d --- /dev/null +++ b/.stoat/config.yaml @@ -0,0 +1,80 @@ +--- +version: 1 +enabled: true +plugins: + static_hosting: + e2e-tests-airflow-integration-logs: + metadata: + name: "airflow-integration-logs" + path: e2e-tests-airflow-integration-logs + file_viewer: true + e2e-tests-assembly-local-logs: + metadata: + name: "assembly-local-logs" + path: e2e-tests-assembly-local-logs + file_viewer: true + e2e-tests-assembly-distributed-logs: + metadata: + name: "assembly-distributed-logs" + path: e2e-tests-assembly-distributed-logs + file_viewer: true + e2e-tests-autogenerated-helm-chart-logs: + metadata: + name: "autogenerated-helm-chart-logs" + path: e2e-tests-autogenerated-helm-chart-logs + file_viewer: true + e2e-tests-failover-logs: + metadata: + name: "failover-logs" + path: e2e-tests-failover-logs + file_viewer: true + e2e-tests-repartition-dask-logs: + metadata: + name: "repartition-dask-logs" + path: e2e-tests-repartition-dask-logs + file_viewer: true + e2e-tests-schedule-workflow-logs: + metadata: + name: "schedule-workflow-logs" + path: e2e-tests-schedule-workflow-logs + file_viewer: true + e2e-tests-schedule-workflow-without-crd-logs: + metadata: + name: "schedule-workflow-without-crd-logs" + path: e2e-tests-schedule-workflow-without-crd-logs + file_viewer: true + e2e-tests-serialize-logs: + metadata: + name: "serialize-logs" + path: e2e-tests-serialize-logs + file_viewer: true + e2e-tests-sidecar-logs: + metadata: + name: "sidecar-logs" + path: e2e-tests-sidecar-logs + file_viewer: true + e2e-tests-spill-logs: + metadata: + name: "spill-logs" + path: e2e-tests-spill-logs + file_viewer: true + e2e-tests-workflow-logs: + metadata: + name: "workflow-logs" + path: e2e-tests-workflow-logs + file_viewer: true + e2e-tests-vineyardctl-logs: + metadata: + name: "vineyardctl-logs" + path: e2e-tests-vineyardctl-logs + file_viewer: true + e2e-tests-deploy-raw-backup-and-recover-logs: + metadata: + name: "deploy-raw-backup-and-recover-logs" + path: e2e-tests-deploy-raw-backup-and-recover-logs + file_viewer: true + e2e-tests-schedule-workload-logs: + metadata: + name: "schedule-workload-logs" + path: e2e-tests-schedule-workload-logs + file_viewer: true \ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 0000000000..f14607a400 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +v6d.io \ No newline at end of file diff --git a/_images/dask-tf.jpg b/_images/dask-tf.jpg new file mode 100644 index 0000000000..e33dddd526 Binary files /dev/null and b/_images/dask-tf.jpg differ diff --git a/_images/data_sharing_with_deployment.jpg b/_images/data_sharing_with_deployment.jpg new file mode 100644 index 0000000000..7053b4875e Binary files /dev/null and b/_images/data_sharing_with_deployment.jpg differ diff --git a/_images/data_sharing_with_sidecar.jpg b/_images/data_sharing_with_sidecar.jpg new file mode 100644 index 0000000000..99f6b909ac Binary files /dev/null and b/_images/data_sharing_with_sidecar.jpg differ diff --git a/_images/fraud-detection-job.jpg b/_images/fraud-detection-job.jpg new file mode 100644 index 0000000000..34005ee5a7 Binary files /dev/null and b/_images/fraud-detection-job.jpg differ diff --git a/_images/social_previews/summary_docs_d89dba2d.png b/_images/social_previews/summary_docs_d89dba2d.png new file mode 100644 index 0000000000..1dd0e9ed65 Binary files /dev/null and b/_images/social_previews/summary_docs_d89dba2d.png differ diff --git a/_images/social_previews/summary_notes_architecture_d259b4fa.png b/_images/social_previews/summary_notes_architecture_d259b4fa.png new file mode 100644 index 0000000000..0777f2e94d Binary files /dev/null and b/_images/social_previews/summary_notes_architecture_d259b4fa.png differ diff --git a/_images/social_previews/summary_notes_cloud-native_deploy-kubernetes_89b4ecce.png b/_images/social_previews/summary_notes_cloud-native_deploy-kubernetes_89b4ecce.png new file mode 100644 index 0000000000..5508680ee3 Binary files /dev/null and b/_images/social_previews/summary_notes_cloud-native_deploy-kubernetes_89b4ecce.png differ diff --git a/_images/social_previews/summary_notes_cloud-native_vineyard-operator_1cd8fbe9.png b/_images/social_previews/summary_notes_cloud-native_vineyard-operator_1cd8fbe9.png new file mode 100644 index 0000000000..f73436c6c4 Binary files /dev/null and b/_images/social_previews/summary_notes_cloud-native_vineyard-operator_1cd8fbe9.png differ diff --git a/_images/social_previews/summary_notes_cloud-native_vineyardctl_81b03e4a.png b/_images/social_previews/summary_notes_cloud-native_vineyardctl_81b03e4a.png new file mode 100644 index 0000000000..8f1f8d1622 Binary files /dev/null and b/_images/social_previews/summary_notes_cloud-native_vineyardctl_81b03e4a.png differ diff --git a/_images/social_previews/summary_notes_developers_build-from-source_50de0ec0.png b/_images/social_previews/summary_notes_developers_build-from-source_50de0ec0.png new file mode 100644 index 0000000000..a7a34430d5 Binary files /dev/null and b/_images/social_previews/summary_notes_developers_build-from-source_50de0ec0.png differ diff --git a/_images/social_previews/summary_notes_developers_cd3c57ef.png b/_images/social_previews/summary_notes_developers_cd3c57ef.png new file mode 100644 index 0000000000..45299bc61a Binary files /dev/null and b/_images/social_previews/summary_notes_developers_cd3c57ef.png differ diff --git a/_images/social_previews/summary_notes_developers_contributing_a859553e.png b/_images/social_previews/summary_notes_developers_contributing_a859553e.png new file mode 100644 index 0000000000..6f38f6ca4e Binary files /dev/null and b/_images/social_previews/summary_notes_developers_contributing_a859553e.png differ diff --git a/_images/social_previews/summary_notes_developers_faq_12883f8f.png b/_images/social_previews/summary_notes_developers_faq_12883f8f.png new file mode 100644 index 0000000000..0c687ba0ae Binary files /dev/null and b/_images/social_previews/summary_notes_developers_faq_12883f8f.png differ diff --git a/_images/social_previews/summary_notes_developers_roadmap_c6c72dd1.png b/_images/social_previews/summary_notes_developers_roadmap_c6c72dd1.png new file mode 100644 index 0000000000..dd2ba6840c Binary files /dev/null and b/_images/social_previews/summary_notes_developers_roadmap_c6c72dd1.png differ diff --git a/_images/social_previews/summary_notes_developers_troubleshooting_91c806be.png b/_images/social_previews/summary_notes_developers_troubleshooting_91c806be.png new file mode 100644 index 0000000000..64bd2cf7c0 Binary files /dev/null and b/_images/social_previews/summary_notes_developers_troubleshooting_91c806be.png differ diff --git a/_images/social_previews/summary_notes_getting-started_4d3ea308.png b/_images/social_previews/summary_notes_getting-started_4d3ea308.png new file mode 100644 index 0000000000..867f8f7de0 Binary files /dev/null and b/_images/social_previews/summary_notes_getting-started_4d3ea308.png differ diff --git a/_images/social_previews/summary_notes_integration-bigdata_ad1d2f83.png b/_images/social_previews/summary_notes_integration-bigdata_ad1d2f83.png new file mode 100644 index 0000000000..3e4fc9efb5 Binary files /dev/null and b/_images/social_previews/summary_notes_integration-bigdata_ad1d2f83.png differ diff --git a/_images/social_previews/summary_notes_integration-orchestration_707c71ea.png b/_images/social_previews/summary_notes_integration-orchestration_707c71ea.png new file mode 100644 index 0000000000..4388544888 Binary files /dev/null and b/_images/social_previews/summary_notes_integration-orchestration_707c71ea.png differ diff --git a/_images/social_previews/summary_notes_integration_airflow_2beddf0f.png b/_images/social_previews/summary_notes_integration_airflow_2beddf0f.png new file mode 100644 index 0000000000..7d91890408 Binary files /dev/null and b/_images/social_previews/summary_notes_integration_airflow_2beddf0f.png differ diff --git a/_images/social_previews/summary_notes_integration_dask_19c0eabb.png b/_images/social_previews/summary_notes_integration_dask_19c0eabb.png new file mode 100644 index 0000000000..912bdc83f2 Binary files /dev/null and b/_images/social_previews/summary_notes_integration_dask_19c0eabb.png differ diff --git a/_images/social_previews/summary_notes_integration_kedro_02749c30.png b/_images/social_previews/summary_notes_integration_kedro_02749c30.png new file mode 100644 index 0000000000..67e34566e3 Binary files /dev/null and b/_images/social_previews/summary_notes_integration_kedro_02749c30.png differ diff --git a/_images/social_previews/summary_notes_integration_ml_1c86f116.png b/_images/social_previews/summary_notes_integration_ml_1c86f116.png new file mode 100644 index 0000000000..f302b02de5 Binary files /dev/null and b/_images/social_previews/summary_notes_integration_ml_1c86f116.png differ diff --git a/_images/social_previews/summary_notes_integration_ray_77a3b5ab.png b/_images/social_previews/summary_notes_integration_ray_77a3b5ab.png new file mode 100644 index 0000000000..544c45e27d Binary files /dev/null and b/_images/social_previews/summary_notes_integration_ray_77a3b5ab.png differ diff --git a/_images/social_previews/summary_notes_key-concepts_c2187017.png b/_images/social_previews/summary_notes_key-concepts_c2187017.png new file mode 100644 index 0000000000..275ca275c3 Binary files /dev/null and b/_images/social_previews/summary_notes_key-concepts_c2187017.png differ diff --git a/_images/social_previews/summary_notes_key-concepts_data-accessing_08934504.png b/_images/social_previews/summary_notes_key-concepts_data-accessing_08934504.png new file mode 100644 index 0000000000..b7cf0d74cb Binary files /dev/null and b/_images/social_previews/summary_notes_key-concepts_data-accessing_08934504.png differ diff --git a/_images/social_previews/summary_notes_key-concepts_io-drivers_490518e5.png b/_images/social_previews/summary_notes_key-concepts_io-drivers_490518e5.png new file mode 100644 index 0000000000..34518f53c7 Binary files /dev/null and b/_images/social_previews/summary_notes_key-concepts_io-drivers_490518e5.png differ diff --git a/_images/social_previews/summary_notes_key-concepts_objects_2df5ca9c.png b/_images/social_previews/summary_notes_key-concepts_objects_2df5ca9c.png new file mode 100644 index 0000000000..b193536598 Binary files /dev/null and b/_images/social_previews/summary_notes_key-concepts_objects_2df5ca9c.png differ diff --git a/_images/social_previews/summary_notes_key-concepts_streams_23ce4443.png b/_images/social_previews/summary_notes_key-concepts_streams_23ce4443.png new file mode 100644 index 0000000000..9b239c3e6c Binary files /dev/null and b/_images/social_previews/summary_notes_key-concepts_streams_23ce4443.png differ diff --git a/_images/social_previews/summary_notes_key-concepts_vcdl_c450cf56.png b/_images/social_previews/summary_notes_key-concepts_vcdl_c450cf56.png new file mode 100644 index 0000000000..74d9c05feb Binary files /dev/null and b/_images/social_previews/summary_notes_key-concepts_vcdl_c450cf56.png differ diff --git a/_images/social_previews/summary_notes_references_5a7969ca.png b/_images/social_previews/summary_notes_references_5a7969ca.png new file mode 100644 index 0000000000..b97b9a0b82 Binary files /dev/null and b/_images/social_previews/summary_notes_references_5a7969ca.png differ diff --git a/_images/social_previews/summary_notes_references_cpp-api_70b4f3a8.png b/_images/social_previews/summary_notes_references_cpp-api_70b4f3a8.png new file mode 100644 index 0000000000..6d14c91fc9 Binary files /dev/null and b/_images/social_previews/summary_notes_references_cpp-api_70b4f3a8.png differ diff --git a/_images/social_previews/summary_notes_references_ctl_7a964b58.png b/_images/social_previews/summary_notes_references_ctl_7a964b58.png new file mode 100644 index 0000000000..d623fd2608 Binary files /dev/null and b/_images/social_previews/summary_notes_references_ctl_7a964b58.png differ diff --git a/_images/social_previews/summary_notes_references_python-api_5ce5770e.png b/_images/social_previews/summary_notes_references_python-api_5ce5770e.png new file mode 100644 index 0000000000..640d13e3a8 Binary files /dev/null and b/_images/social_previews/summary_notes_references_python-api_5ce5770e.png differ diff --git a/_images/social_previews/summary_tutorials_data-processing_3792c053.png b/_images/social_previews/summary_tutorials_data-processing_3792c053.png new file mode 100644 index 0000000000..dc2b0b0f0f Binary files /dev/null and b/_images/social_previews/summary_tutorials_data-processing_3792c053.png differ diff --git a/_images/social_previews/summary_tutorials_data-processing_accelerate-data-sharing-in-kedro_f87dee05.png b/_images/social_previews/summary_tutorials_data-processing_accelerate-data-sharing-in-kedro_f87dee05.png new file mode 100644 index 0000000000..d1c6517d6b Binary files /dev/null and b/_images/social_previews/summary_tutorials_data-processing_accelerate-data-sharing-in-kedro_f87dee05.png differ diff --git a/_images/social_previews/summary_tutorials_data-processing_distributed-learning_1cab632c.png b/_images/social_previews/summary_tutorials_data-processing_distributed-learning_1cab632c.png new file mode 100644 index 0000000000..ecec3f4278 Binary files /dev/null and b/_images/social_previews/summary_tutorials_data-processing_distributed-learning_1cab632c.png differ diff --git a/_images/social_previews/summary_tutorials_data-processing_python-sharedmemory_07c9bb62.png b/_images/social_previews/summary_tutorials_data-processing_python-sharedmemory_07c9bb62.png new file mode 100644 index 0000000000..731739fc0a Binary files /dev/null and b/_images/social_previews/summary_tutorials_data-processing_python-sharedmemory_07c9bb62.png differ diff --git a/_images/social_previews/summary_tutorials_data-processing_using-objects-python_e8b77cca.png b/_images/social_previews/summary_tutorials_data-processing_using-objects-python_e8b77cca.png new file mode 100644 index 0000000000..e9698d1ae7 Binary files /dev/null and b/_images/social_previews/summary_tutorials_data-processing_using-objects-python_e8b77cca.png differ diff --git a/_images/social_previews/summary_tutorials_extending_47fc873b.png b/_images/social_previews/summary_tutorials_extending_47fc873b.png new file mode 100644 index 0000000000..8cff2a9777 Binary files /dev/null and b/_images/social_previews/summary_tutorials_extending_47fc873b.png differ diff --git a/_images/social_previews/summary_tutorials_extending_define-datatypes-cpp_c059e8f9.png b/_images/social_previews/summary_tutorials_extending_define-datatypes-cpp_c059e8f9.png new file mode 100644 index 0000000000..53a9975aa2 Binary files /dev/null and b/_images/social_previews/summary_tutorials_extending_define-datatypes-cpp_c059e8f9.png differ diff --git a/_images/social_previews/summary_tutorials_extending_define-datatypes-python_a073e2d8.png b/_images/social_previews/summary_tutorials_extending_define-datatypes-python_a073e2d8.png new file mode 100644 index 0000000000..02456bc583 Binary files /dev/null and b/_images/social_previews/summary_tutorials_extending_define-datatypes-python_a073e2d8.png differ diff --git a/_images/social_previews/summary_tutorials_kubernetes_data-sharing-with-vineyard-on-kubernetes_70d4da3c.png b/_images/social_previews/summary_tutorials_kubernetes_data-sharing-with-vineyard-on-kubernetes_70d4da3c.png new file mode 100644 index 0000000000..5babd76f34 Binary files /dev/null and b/_images/social_previews/summary_tutorials_kubernetes_data-sharing-with-vineyard-on-kubernetes_70d4da3c.png differ diff --git a/_images/social_previews/summary_tutorials_kubernetes_e3fed720.png b/_images/social_previews/summary_tutorials_kubernetes_e3fed720.png new file mode 100644 index 0000000000..85e6393f8c Binary files /dev/null and b/_images/social_previews/summary_tutorials_kubernetes_e3fed720.png differ diff --git a/_images/social_previews/summary_tutorials_kubernetes_ml-pipeline-mars-pytorch_d3131a56.png b/_images/social_previews/summary_tutorials_kubernetes_ml-pipeline-mars-pytorch_d3131a56.png new file mode 100644 index 0000000000..768f971049 Binary files /dev/null and b/_images/social_previews/summary_tutorials_kubernetes_ml-pipeline-mars-pytorch_d3131a56.png differ diff --git a/_images/social_previews/summary_tutorials_kubernetes_using-vineyard-operator_e285bc93.png b/_images/social_previews/summary_tutorials_kubernetes_using-vineyard-operator_e285bc93.png new file mode 100644 index 0000000000..c66532e4ff Binary files /dev/null and b/_images/social_previews/summary_tutorials_kubernetes_using-vineyard-operator_e285bc93.png differ diff --git a/_images/social_previews/summary_tutorials_tutorials_3792c053.png b/_images/social_previews/summary_tutorials_tutorials_3792c053.png new file mode 100644 index 0000000000..dc2b0b0f0f Binary files /dev/null and b/_images/social_previews/summary_tutorials_tutorials_3792c053.png differ diff --git a/_images/vineyard-logo-rect.png b/_images/vineyard-logo-rect.png new file mode 100644 index 0000000000..2c3ca4dae7 Binary files /dev/null and b/_images/vineyard-logo-rect.png differ diff --git a/_images/vineyard_arch.jpg b/_images/vineyard_arch.jpg new file mode 100644 index 0000000000..813ab5d29e Binary files /dev/null and b/_images/vineyard_arch.jpg differ diff --git a/_images/vineyard_composable.jpg b/_images/vineyard_composable.jpg new file mode 100644 index 0000000000..f4541b655d Binary files /dev/null and b/_images/vineyard_composable.jpg differ diff --git a/_images/vineyard_distributed_tensor.jpg b/_images/vineyard_distributed_tensor.jpg new file mode 100644 index 0000000000..2b0ce68980 Binary files /dev/null and b/_images/vineyard_distributed_tensor.jpg differ diff --git a/_images/vineyard_operator_arch.png b/_images/vineyard_operator_arch.png new file mode 100644 index 0000000000..68283ed017 Binary files /dev/null and b/_images/vineyard_operator_arch.png differ diff --git a/_modules/index.html b/_modules/index.html new file mode 100644 index 0000000000..f279250e42 --- /dev/null +++ b/_modules/index.html @@ -0,0 +1,391 @@ + + + + + + + + Overview: module code - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+ +
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/_modules/vineyard.html b/_modules/vineyard.html new file mode 100644 index 0000000000..6f2ee07e6c --- /dev/null +++ b/_modules/vineyard.html @@ -0,0 +1,778 @@ + + + + + + + + vineyard - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for vineyard

+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020-2023 Alibaba Group Holding Limited.
+#
+# 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.
+#
+
+import contextlib
+import logging
+import os
+import sys
+from typing import Any
+from typing import Dict
+from typing import Generator
+from typing import Optional
+from typing import Tuple
+from typing import Union
+
+from .version import __version__
+
+__doc__ = """
+Vineyard - an in-memory immutable data manager. (Project under CNCF)
+====================================================================
+
+Vineyard (v6d) is an in-memory immutable data manager that provides
+out-of-the-box high-level abstraction and zero-copy in-memory
+sharing for distributed data in big data tasks, such as graph analytics
+(e.g., GraphScope), numerical computing (e.g., Mars), and machine learning.
+"""
+
+# pylint: disable=import-outside-toplevel,wrong-import-position
+
+logger = logging.getLogger('vineyard')
+
+
+@contextlib.contextmanager
+def envvars(
+    key: Union[str, Dict[str, str]],
+    value: Union[str, None] = None,
+    append: bool = False,
+) -> Generator[os._Environ, Any, Any]:
+    """Create a context with specified environment variables set.
+
+    It is useful for setting the :code`VINEYARD_IPC_SOCKET` environment
+    variable to obtain a proper default vineyard client.
+
+    This context macro can be used as
+
+    .. code:: python
+
+        with environment('KEY'):
+            # env :code:`KEY` will be set to None.
+
+        with environment('KEY', 'value'):
+            # env :code:`KEY` will be set as :code:`value`.
+
+        with environment({'KEY1': None, 'KEY2': 'value2'}):
+            # env :code:`KEY1` will be set as None and :code:`KEY2` will
+            # be set as :code:`value2`.
+    """
+    if isinstance(key, str):
+        if value is None:
+            items = dict()
+        else:
+            items: Dict[str, str] = {key: value}
+    else:
+        items: Dict[str, str] = key
+    original_items = dict()
+    for k, v in items.items():
+        original_items[k] = os.environ.get(k, None)
+        if append and original_items[k] is not None:
+            os.environ[k] = original_items[k] + ':' + v
+        else:
+            os.environ[k] = v
+
+    yield os.environ
+
+    for k, v in original_items.items():
+        if v is not None:
+            os.environ[k] = v
+        else:
+            del os.environ[k]
+
+
+def _init_global_context():
+    import os as _dl_flags  # pylint: disable=reimported
+
+    if sys.platform == 'linux':
+        registry = os.path.join(
+            os.path.dirname(__file__), 'libvineyard_internal_registry.so'
+        )
+    elif sys.platform == 'darwin':
+        registry = os.path.join(
+            os.path.dirname(__file__), 'libvineyard_internal_registry.dylib'
+        )
+    else:
+        raise RuntimeError("Unsupported platform: %s" % sys.platform)
+
+    ctx = {'__VINEYARD_INTERNAL_REGISTRY': registry}
+
+    if os.environ.get('VINEYARD_DEVELOP', None) is None:
+        with envvars(ctx):  # n.b., no append
+            from . import _C
+        return
+
+    if not hasattr(_dl_flags, 'RTLD_GLOBAL') or not hasattr(_dl_flags, 'RTLD_LAZY'):
+        try:
+            # next try if DLFCN exists
+            import DLFCN as _dl_flags  # noqa: N811
+        except ImportError:
+            _dl_flags = None
+
+    if _dl_flags is not None:
+        old_flags = sys.getdlopenflags()
+
+        # import the extension module
+        sys.setdlopenflags(_dl_flags.RTLD_GLOBAL | _dl_flags.RTLD_LAZY)
+        with envvars(ctx):  # n.b., no append
+            from . import _C  # noqa: F811
+        # restore
+        sys.setdlopenflags(old_flags)
+
+
+_init_global_context()
+del _init_global_context
+
+
+from . import core
+from . import data
+from . import deploy
+from . import io
+from . import launcher
+from . import shared_memory
+from ._C import ArrowErrorException
+from ._C import AssertionFailedException
+from ._C import Blob
+from ._C import BlobBuilder
+from ._C import ConnectionErrorException
+from ._C import ConnectionFailedException
+from ._C import EndOfFileException
+from ._C import EtcdErrorException
+from ._C import InstanceStatus
+from ._C import InvalidException
+from ._C import InvalidStreamStateException
+from ._C import IOErrorException
+from ._C import IPCClient
+from ._C import KeyErrorException
+from ._C import MetaTreeInvalidException
+from ._C import MetaTreeLinkInvalidException
+from ._C import MetaTreeNameInvalidException
+from ._C import MetaTreeNameNotExistsException
+from ._C import MetaTreeSubtreeNotExistsException
+from ._C import MetaTreeTypeInvalidException
+from ._C import MetaTreeTypeNotExistsException
+from ._C import NotEnoughMemoryException
+from ._C import NotImplementedException
+from ._C import Object
+from ._C import ObjectBuilder
+from ._C import ObjectExistsException
+from ._C import ObjectID
+from ._C import ObjectMeta
+from ._C import ObjectName
+from ._C import ObjectNotExistsException
+from ._C import ObjectNotSealedException
+from ._C import ObjectSealedException
+from ._C import RemoteBlob
+from ._C import RemoteBlobBuilder
+from ._C import RPCClient
+from ._C import StreamDrainedException
+from ._C import StreamFailedException
+from ._C import TypeErrorException
+from ._C import UnknownErrorException
+from ._C import UserInputErrorException
+from ._C import VineyardServerNotReadyException
+from ._C import _connect
+from ._C import memory_copy
+from .core import builder_context
+from .core import default_builder_context
+from .core import default_driver_context
+from .core import default_resolver_context
+from .core import driver_context
+from .core import resolver_context
+from .data import register_builtin_types
+from .data.graph import Graph
+from .deploy.local import get_current_socket
+from .deploy.local import shutdown
+from .deploy.local import try_init
+
+
+def _init_vineyard_modules():  # noqa: C901
+    """Resolve registered vineyard modules in the following order:
+
+    * /etc/vineyard/config.py
+    * {sys.prefix}/etc/vineyard/config.py
+    * /usr/share/vineyard/01-xxx.py
+    * /usr/local/share/vineyard/01-xxx.py
+    * {sys.prefix}/share/vineyard/02-xxxx.py
+    * $HOME/.vineyard/03-xxxxx.py
+
+    Then import packages like vineyard.drivers.*:
+
+    * vineyard.drivers.io
+    """
+
+    import glob
+    import importlib.util
+    import pkgutil
+    import site
+    import sysconfig
+
+    def _import_module_from_file(filepath):
+        filepath = os.path.expanduser(os.path.expandvars(filepath))
+        if os.path.exists(filepath):
+            try:
+                spec = importlib.util.spec_from_file_location(
+                    "vineyard._contrib", filepath
+                )
+                mod = importlib.util.module_from_spec(spec)
+                spec.loader.exec_module(mod)
+            except Exception:  # pylint: disable=broad-except
+                logger.debug("Failed to load %s", filepath, exc_info=True)
+
+    def _import_module_from_qualified_name(module):
+        try:
+            importlib.import_module(module)
+        except Exception:  # pylint: disable=broad-except
+            logger.debug('Failed to load module %s', module, exc_info=True)
+
+    _import_module_from_file('/etc/vineyard/config.py')
+    _import_module_from_file(os.path.join(sys.prefix, '/etc/vineyard/config.py'))
+    for filepath in glob.glob('/usr/share/vineyard/*-*.py'):
+        _import_module_from_file(filepath)
+    for filepath in glob.glob('/usr/local/share/vineyard/*-*.py'):
+        _import_module_from_file(filepath)
+    for filepath in glob.glob(os.path.join(sys.prefix, '/share/vineyard/*-*.py')):
+        _import_module_from_file(filepath)
+    for filepath in glob.glob(os.path.expanduser('$HOME/.vineyard/*-*.py')):
+        _import_module_from_file(filepath)
+
+    package_sites = set()
+    pkg_sites = site.getsitepackages()
+    if not isinstance(pkg_sites, (list, tuple)):
+        pkg_sites = [pkg_sites]
+    package_sites.update(pkg_sites)
+    pkg_sites = site.getusersitepackages()
+    if not isinstance(pkg_sites, (list, tuple)):
+        pkg_sites = [pkg_sites]
+    package_sites.update(pkg_sites)
+
+    paths = sysconfig.get_paths()
+    if 'purelib' in paths:
+        package_sites.add(paths['purelib'])
+    if 'platlib' in paths:
+        package_sites.add(paths['purelib'])
+
+    # add relative path
+    package_sites.add(os.path.join(os.path.dirname(__file__), '..'))
+
+    # dedup
+    deduped = set()
+    for pkg_site in package_sites:
+        deduped.add(os.path.abspath(pkg_site))
+
+    for pkg_site in deduped:
+        for _, mod, _ in pkgutil.iter_modules(
+            [os.path.join(pkg_site, 'vineyard', 'drivers')]
+        ):
+            _import_module_from_qualified_name('vineyard.drivers.%s' % mod)
+
+
+try:
+    _init_vineyard_modules()
+except Exception:  # pylint: disable=broad-except
+    pass
+del _init_vineyard_modules
+
+
+
[docs]def connect(*args, **kwargs): + """ + Connect to vineyard by specified UNIX-domain socket or TCP endpoint. + + If no arguments are provided and failed to resolve both the environment + variables :code:`VINEYARD_IPC_SOCKET` and :code:`VINEYARD_RPC_ENDPOINT`, + it will launch a standalone vineyardd server in the background and then + connect to it. + + The `connect()` method has various overloading: + + .. function:: connect(socket: str, + username: str = None, + password: str = None) -> IPCClient + :noindex: + + Connect to vineyard via UNIX domain socket for IPC service: + + .. code:: python + + client = vineyard.connect('/var/run/vineyard.sock') + + Parameters: + socket: str + UNIX domain socket path to setup an IPC connection. + username: str + Username to login, default to None. + password: str + Password to login, default to None. + + Returns: + IPCClient: The connected IPC client. + + .. function:: connect(host: str, + port: int or str, + username: str = None, + password: str = None) -> RPCClient + :noindex: + + Connect to vineyard via TCP socket. + + Parameters: + host: str + Hostname to connect to. + port: int or str + The TCP that listened by vineyard TCP service. + username: str + Username to login, default to None. + password: str + Password to login, default to None. + + Returns: + RPCClient: The connected RPC client. + + .. function:: connect(endpoint: (str, int or str), + username: str = None, + password: str = None) -> RPCClient + :noindex: + + Connect to vineyard via TCP socket. + + Parameters: + endpoint: tuple(str, int or str) + Endpoint to connect to. The parameter is a tuple, in which the first + element is the host, and the second parameter is the port (can be int + a str). + username: str + Username to login, default to None. + password: str + Password to login, default to None. + + Returns: + RPCClient: The connected RPC client. + + .. function:: connect(username: str = None, + password: str = None) -> IPCClient or RPCClient + :noindex: + + Connect to vineyard via UNIX domain socket or TCP endpoint. This method normally + usually no arguments, and will first tries to resolve IPC socket from the + environment variable `VINEYARD_IPC_SOCKET` and connect to it. If it fails to + establish a connection with vineyard server, the method will tries to resolve + RPC endpoint from the environment variable `VINEYARD_RPC_ENDPOINT`. + + If both tries are failed, this method will raise a :class:`ConnectionFailed` + exception. + + In rare cases, user may be not sure about if the IPC socket or RPC endpoint + is available, i.e., the variable might be :code:`None`. In such cases this + method can accept a `None` as arguments, and do resolution as described above. + + Parameters: + username: str + Username to login, default to None. + password: str + Password to login, default to None. + + Raises: + ConnectionFailed + """ + if ( + not args + and not kwargs + and 'VINEYARD_IPC_SOCKET' not in os.environ + and 'VINEYARD_RPC_ENDPOINT' not in os.environ + ): + logger.info( + 'No vineyard socket or endpoint is specified, ' + 'try to launch a standalone one.' + ) + try_init() + return _connect(*args, **kwargs)
+
+
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/_modules/vineyard/core/builder.html b/_modules/vineyard/core/builder.html new file mode 100644 index 0000000000..e8b2b1fcdb --- /dev/null +++ b/_modules/vineyard/core/builder.html @@ -0,0 +1,605 @@ + + + + + + + + vineyard.core.builder - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for vineyard.core.builder

+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020-2023 Alibaba Group Holding Limited.
+#
+# 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.
+#
+
+import contextlib
+import copy
+import inspect
+import threading
+import warnings
+from typing import Any
+from typing import Callable
+from typing import Dict
+from typing import Generator
+from typing import Optional
+
+from vineyard._C import IPCClient
+from vineyard._C import Object
+from vineyard._C import ObjectID
+from vineyard._C import ObjectMeta
+from vineyard._C import RPCClient
+
+
+
[docs]class BuilderContext: + def __init__(self, parent_context: Optional["BuilderContext"] = None): + self._factory = dict() + if parent_context is not None: + self._parent_context = parent_context + else: + self._parent_context = self + + def __str__(self) -> str: + return str(self._factory) + + @property + def parent_context(self) -> "BuilderContext": + return self._parent_context + +
[docs] def register(self, type_id: type, builder: Callable): + """Register a Python type to the builder context. + + Parameters + ---------- + type_id: Python type + Like `int`, or `numpy.ndarray` + + builder: callable, e.g., a method, callable object + A builder translates a python object to vineyard, it accepts a Python + value as parameter, and returns an vineyard object as result. + """ + self._factory[type_id] = builder
+ +
[docs] def run(self, client, value, **kw): + """Follows the MRO to find the proper builder for given python value. + + Here "Follows the MRO" implies: + + - If the type of python value has been found in the context, the registered + builder will be used. + + - If not, it follows the MRO chain from down to top to find a registered + Python type and used the associated builder. + + - When the traversal reaches the :code:`object` type, since there's a default + builder that serialization the python value, the parameter will be serialized + and be put into a blob. + """ + + # if the python value comes from a vineyard object, we choose to just reuse it. + + # N.B.: don't do that. + # + # we still construct meta, and optimize the duplicate copy in blob builder + # + # base = getattr(value, '__vineyard_ref', None) + # if base: + # return base.meta + + for ty in type(value).__mro__: + if ty in self._factory: + builder_func_sig = inspect.getfullargspec(self._factory[ty]) + if ( + 'builder' in builder_func_sig.args + or builder_func_sig.varkw is not None + ): + kw['builder'] = self + return self._factory[ty](client, value, **kw) + raise RuntimeError('Unknown type to build as vineyard object')
+ + def __call__(self, client, value, **kw): + return self.run(client, value, **kw) + + def extend(self, builders=None): + builder = BuilderContext(self) + builder._factory = copy.copy( # pylint: disable=unused-private-member + self._factory + ) + if builders: + builder._factory.update(builders) + return builder
+ + +default_builder_context = BuilderContext() + +_builder_context_local = threading.local() +_builder_context_local.default_builder = default_builder_context + + +
[docs]def get_current_builders() -> BuilderContext: + '''Obtain the current builder context.''' + default_builder = getattr(_builder_context_local, 'default_builder', None) + if not default_builder: + default_builder = default_builder_context.extend() + return default_builder
+ + +
[docs]@contextlib.contextmanager +def builder_context( + builders: Optional[Dict[type, Callable]] = None, + base: Optional[BuilderContext] = None, +) -> Generator[BuilderContext, Any, Any]: + """Open a new context for register builders, without populating outside global + environment. + + See Also: + resolver_context + driver_context + """ + current_builder = get_current_builders() + try: + builders = builders or dict() + base = base or current_builder + local_builder = base.extend(builders) + _builder_context_local.default_builder = local_builder + yield local_builder + finally: + _builder_context_local.default_builder = current_builder
+ + +def put( + client, + value: Any, + builder: Optional[BuilderContext] = None, + persist: bool = False, + name: Optional[str] = None, + **kwargs +): + """Put python value to vineyard. + + .. code:: python + + >>> arr = np.arange(8) + >>> arr_id = client.put(arr) + >>> arr_id + 00002ec13bc81226 + + Parameters: + client: IPCClient + The vineyard client to use. + value: + The python value that will be put to vineyard. Supported python value + types are decided by modules that registered to vineyard. By default, + python value can be put to vineyard after serialized as a bytes buffer + using pickle. + builder: optional + When putting python value to vineyard, an optional *builder* can be + specified to tell vineyard how to construct the corresponding vineyard + :class:`Object`. If not specified, the default builder context will be + used to select a proper builder. + persist: bool, optional + If true, persist the object after creation. + name: str, optional + If given, the name will be automatically associated with the resulted + object. Note that only take effect when the object is persisted. + kw: + User-specific argument that will be passed to the builder. + + Returns: + ObjectID: The result object id will be returned. + """ + if builder is not None: + return builder(client, value, **kwargs) + + meta = get_current_builders().run(client, value, **kwargs) + + # the builders is expected to return an :class:`ObjectMeta`, or an + # :class:`Object` (in the `bytes_builder` and `memoryview` builder). + if isinstance(meta, (ObjectMeta, Object)): + r = meta.id + else: + r = meta # None or ObjectID + + if isinstance(r, ObjectID): + if persist: + client.persist(r) + if name is not None: + if persist: + client.put_name(r, name) + else: + warnings.warn( + "The object is not persisted, the name won't be associated.", + UserWarning, + ) + return r + + +setattr(IPCClient, 'put', put) +setattr(RPCClient, 'put', put) + +__all__ = [ + 'default_builder_context', + 'builder_context', + 'get_current_builders', +] +
+
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/_modules/vineyard/core/driver.html b/_modules/vineyard/core/driver.html new file mode 100644 index 0000000000..467d831139 --- /dev/null +++ b/_modules/vineyard/core/driver.html @@ -0,0 +1,545 @@ + + + + + + + + vineyard.core.driver - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for vineyard.core.driver

+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020-2023 Alibaba Group Holding Limited.
+#
+# 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.
+#
+
+import contextlib
+import copy
+import functools
+import threading
+
+from sortedcontainers import SortedDict
+
+from vineyard.core.utils import find_most_precise_match
+
+
+
[docs]class DriverContext: + def __init__(self): + self._factory = SortedDict(dict) + + def __str__(self) -> str: + return str(self._factory) + + def register(self, typename_prefix, meth, func): + if typename_prefix not in self._factory: + self._factory[typename_prefix] = dict() + self._factory[typename_prefix][meth] = func + + def resolve(self, obj, typename): + prefix, methods = find_most_precise_match(typename, self._factory) + if prefix: + for meth, func in methods.items(): + # if shouldn't failed, since it has already been wrapped in during + # resolving + setattr(obj, meth, functools.partial(func, obj)) + return obj + + def __call__(self, obj, typename): + return self.resolve(obj, typename) + + def extend(self, drivers=None): + driver = DriverContext() + driver._factory.update(((k, copy.copy(v)) for k, v in self._factory.items())) + if drivers: + for ty, methods in drivers.items(): + if ty not in self._factory: + driver._factory[ty] = dict() + driver._factory[ty].update(methods) + return driver
+ + +default_driver_context = DriverContext() + +_driver_context_local = threading.local() +_driver_context_local.default_driver = default_driver_context + + +
[docs]def get_current_drivers(): + '''Obtain current driver context.''' + default_driver = getattr(_driver_context_local, 'default_driver', None) + if not default_driver: + default_driver = default_driver_context.extend() + return default_driver
+ + +
[docs]@contextlib.contextmanager +def driver_context(drivers=None, base=None): + """Open a new context for register drivers, without populting outside global + environment. + + See Also: + builder_context + resolver_context + """ + current_driver = get_current_drivers() + try: + drivers = drivers or dict() + base = base or current_driver + local_driver = base.extend(drivers) + _driver_context_local.default_driver = local_driver + yield local_driver + finally: + _driver_context_local.default_driver = current_driver
+ + +def register_builtin_drivers(ctx): + assert isinstance(ctx, DriverContext) + + # TODO + # there's no builtin drivers yet. + + +def registerize(func): + """Registerize a method, add a `_factory` attribute and a `register` + interface to a method. + + multiple-level register is automatically supported, users can + + >>> open.register(local_io_adaptor) + >>> open.register(oss_io_adaptor) + + OR + + >>> open.register('file', local_io_adaptor) + >>> open.register('odps', odps_io_adaptor) + + OR + + >>> open.register('file', 'csv', local_csv_reader) + >>> open.register('file', 'tsv', local_tsv_reader) + """ + + @functools.wraps(func) + def wrap(*args, **kwargs): + return func(*args, **kwargs) + + setattr(wrap, '_factory', None) + + def register(*args): + if len(args) == 1: + if wrap._factory is None: + wrap._factory = [] + if not isinstance(wrap._factory, list): + raise RuntimeError( + 'Invalid arguments: inconsistent with existing registerations' + ) + wrap._factory.append(args[0]) + else: + if wrap._factory is None: + wrap._factory = {} + if not isinstance(wrap._factory, dict): + raise RuntimeError( + 'Invalid arguments: inconsistent with existing registerations' + ) + root = wrap._factory + for arg in args[:-2]: + if arg not in root: + root[arg] = dict() + root = root[arg] + if args[-2] not in root: + root[args[-2]] = list() + root[args[-2]].append(args[-1]) + + setattr(wrap, 'register', register) + + return wrap + + +__all__ = [ + 'default_driver_context', + 'register_builtin_drivers', + 'driver_context', + 'get_current_drivers', + 'registerize', +] +
+
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/_modules/vineyard/core/resolver.html b/_modules/vineyard/core/resolver.html new file mode 100644 index 0000000000..694a215e01 --- /dev/null +++ b/_modules/vineyard/core/resolver.html @@ -0,0 +1,629 @@ + + + + + + + + vineyard.core.resolver - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for vineyard.core.resolver

+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020-2023 Alibaba Group Holding Limited.
+#
+# 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.
+#
+
+import contextlib
+import inspect
+import threading
+from typing import Any
+from typing import Callable
+from typing import Dict
+from typing import Generator
+from typing import Optional
+
+from sortedcontainers import SortedDict
+
+from vineyard._C import IPCClient
+from vineyard._C import Object
+from vineyard._C import ObjectID
+from vineyard._C import RPCClient
+from vineyard.core.utils import find_most_precise_match
+
+
+
[docs]class ResolverContext: + def __init__(self, parent_context: Optional["ResolverContext"] = None): + self._factory = SortedDict() + if parent_context is not None: + self._parent_context = parent_context + else: + self._parent_context = self + + def __str__(self) -> str: + return str(self._factory) + + @property + def parent_context(self) -> "ResolverContext": + return self._parent_context + + def register(self, typename_prefix: str, resolver: Callable): + self._factory[typename_prefix] = resolver + + def run(self, obj: Any, **kw): + typename = obj.meta.typename + prefix, resolver = find_most_precise_match(typename, self._factory) + vineyard_client = kw.pop('__vineyard_client', None) + if prefix: + resolver_func_sig = inspect.getfullargspec(resolver) + if resolver_func_sig.varkw is not None: + value = resolver(obj, resolver=self, **kw) + else: + try: + # don't pass the `**kw`. + if 'resolver' in resolver_func_sig.args: + value = resolver(obj, resolver=self) + else: + value = resolver(obj) + except Exception as e: + raise RuntimeError( # pylint: disable=raise-missing-from + 'Unable to construct the object using resolver: ' + 'typename is %s, resolver is %s' % (obj.meta.typename, resolver) + ) from e + if value is None: + # if the obj has been resolved by pybind types, and there's no proper + # resolver, it shouldn't be an error + if type(obj) is not Object: # pylint: disable=unidiomatic-typecheck + return obj + + # we might `client.put(None)` + return None + + # associate a reference to the base C++ object + try: + setattr(value, '__vineyard_ref', obj) + setattr(value, '__vineyard_client', vineyard_client) + + # register methods + from vineyard.core.driver import get_current_drivers + + get_current_drivers().resolve(value, obj.typename) + except AttributeError: + pass + + return value + # keep it as it is + return obj + + def __call__(self, obj, **kw): + return self.run(obj, **kw) + + def extend(self, resolvers=None): + resolver = ResolverContext(self) + resolver._factory = ( # pylint: disable=unused-private-member + self._factory.copy() + ) + if resolvers: + resolver._factory.update(resolvers) + return resolver
+ + +default_resolver_context = ResolverContext() + +_resolver_context_local = threading.local() +_resolver_context_local.default_resolver = default_resolver_context + + +
[docs]def get_current_resolvers() -> ResolverContext: + '''Obtain current resolver context.''' + default_resolver = getattr(_resolver_context_local, 'default_resolver', None) + if not default_resolver: + default_resolver = default_resolver_context.extend() + return default_resolver
+ + +
[docs]@contextlib.contextmanager +def resolver_context( + resolvers: Optional[Dict[str, Callable]] = None, + base: Optional[ResolverContext] = None, +) -> Generator[ResolverContext, Any, Any]: + """Open a new context for register resolvers, without populating outside + the global environment. + + The :code:`resolver_context` can be useful when users have more than + more resolver for a certain type, e.g., the :code:`vineyard::Tensor` + object can be resolved as :code:`numpy.ndarray` or :code:`xgboost::DMatrix`. + + We could have + + .. code:: python + + def numpy_resolver(obj): + ... + + default_resolver_context.register('vineyard::Tensor', numpy_resolver) + + and + + .. code:: python + + def xgboost_resolver(obj): + ... + + default_resolver_context.register('vineyard::Tensor', xgboost_resolver) + + Obviously there's a conflict, and the stackable :code:`resolver_context` could + help there, + + .. code:: python + + with resolver_context({'vineyard::Tensor', xgboost_resolver}): + ... + + Assuming the default context resolves :code:`vineyard::Tensor` to + :code:`numpy.ndarray`, inside the :code:`with resolver_context` the + :code:`vineyard::Tensor` will be resolved to :code:`xgboost::DMatrix`, + and after exiting the context the global environment will be restored + back as default. + + The :code:`with resolver_context` is nestable as well. + + See Also: + builder_context + driver_context + """ + current_resolver = get_current_resolvers() + try: + resolvers = resolvers or dict() + base = base or current_resolver + local_resolver = base.extend(resolvers) + _resolver_context_local.default_resolver = local_resolver + yield local_resolver + finally: + _resolver_context_local.default_resolver = current_resolver
+ + +def get( + client, + object_id: Optional[ObjectID] = None, + name: Optional[str] = None, + resolver: Optional[ResolverContext] = None, + fetch: bool = False, + **kw +): + """Get vineyard object as python value. + + .. code:: python + + >>> arr_id = vineyard.ObjectID('00002ec13bc81226') + >>> arr = client.get(arr_id) + >>> arr + array([0, 1, 2, 3, 4, 5, 6, 7]) + + Parameters: + client: IPCClient or RPCClient + The vineyard client to use. + object_id: ObjectID + The object id that will be obtained from vineyard. + name: ObjectID + The object name that will be obtained from vineyard, ignored if + ``object_id`` is not None. + resolver: + When retrieving vineyard object, an optional *resolver* can be specified. + If no resolver given, the default resolver context will be used. + fetch: + Whether to trigger a migration when the target object is located on + remote instances. + kw: + User-specific argument that will be passed to the builder. + + Returns: + A python object that return by the resolver, by resolving an vineyard object. + """ + # wrap object_id + if object_id is not None: + if isinstance(object_id, (int, str)): + object_id = ObjectID(object_id) + elif name is not None: + object_id = client.get_name(name) + + # run resolver + obj = client.get_object(object_id, fetch=fetch) + meta = obj.meta + if not meta.islocal and not meta.isglobal: + raise ValueError( + "Not a local object: for remote object, you can only get its metadata" + ) + if resolver is None: + resolver = get_current_resolvers() + return resolver(obj, __vineyard_client=client, **kw) + + +setattr(IPCClient, 'get', get) +setattr(RPCClient, 'get', get) + +__all__ = [ + 'default_resolver_context', + 'resolver_context', + 'get_current_resolvers', +] +
+
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/_modules/vineyard/deploy/distributed.html b/_modules/vineyard/deploy/distributed.html new file mode 100644 index 0000000000..39eba0e4d0 --- /dev/null +++ b/_modules/vineyard/deploy/distributed.html @@ -0,0 +1,519 @@ + + + + + + + + vineyard.deploy.distributed - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for vineyard.deploy.distributed

+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020-2023 Alibaba Group Holding Limited.
+#
+# 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.
+#
+
+import contextlib
+import logging
+import subprocess
+import sys
+import textwrap
+import time
+
+import pkg_resources
+
+from vineyard.deploy.utils import ssh_base_cmd
+from vineyard.deploy.utils import start_etcd
+
+logger = logging.getLogger('vineyard')
+
+
+
[docs]@contextlib.contextmanager +def start_vineyardd( + hosts=None, + etcd_endpoints=None, + vineyardd_path=None, + size='', + socket='/var/run/vineyard.sock', + rpc_socket_port=9600, + debug=False, +): + """Launch a local vineyard cluster in a distributed fashion. + + Parameters: + hosts: list of str + A list of machines to launch vineyard server. + etcd_endpoint: str + Launching vineyard using specified etcd endpoints. If not specified, + vineyard will launch its own etcd instance. + vineyardd_path: str + Location of vineyard server program. If not specified, vineyard will + use its own bundled vineyardd binary. + size: int + The memory size limit for vineyard's shared memory. The memory size + can be a plain integer or as a fixed-point number using one of these + suffixes: + + .. code:: + + E, P, T, G, M, K. + + You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. + Defaults to "", means not limited. + + For example, the following represent roughly the same value: + + .. code:: + + 128974848, 129k, 129M, 123Mi, 1G, 10Gi, ... + socket: str + The UNIX domain socket socket path that vineyard server will listen on. + rpc_socket_port: int + The port that vineyard will use to privode RPC service. + debug: bool + Whether print debug logs. + """ + if vineyardd_path is None: + vineyardd_path = pkg_resources.resource_filename('vineyard', 'vineyardd') + + if hosts is None: + hosts = ['localhost'] + + if etcd_endpoints is None: + etcd_ctx = start_etcd(host=hosts[0]) + _etcd_proc, etcd_endpoints = etcd_ctx.__enter__() # pylint: disable=no-member + else: + etcd_ctx = None + + env = dict() + if debug: + env['GLOG_v'] = 11 + + command = [ + vineyardd_path, + '--deployment', + 'distributed', + '--size', + str(size), + '--socket', + socket, + '--rpc_socket_port', + str(rpc_socket_port), + '--etcd_endpoint', + etcd_endpoints, + ] + + procs = [] + try: + for host in hosts: + proc = subprocess.Popen( + ssh_base_cmd(host) + command, + env=env, + stdout=subprocess.PIPE, + stderr=sys.__stderr__, + universal_newlines=True, + encoding='utf-8', + ) + procs.append(proc) + time.sleep(1) + for proc in procs: + rc = proc.poll() + if rc is not None: + err = textwrap.indent(proc.stdout.read(), ' ' * 4) + raise RuntimeError( + 'vineyardd exited unexpectedly with ' + 'code %d: error is:\n%s' % (rc, err) + ) + yield procs, socket, etcd_endpoints + finally: + logger.info('Distributed vineyardd being killed') + for proc in procs: + if proc.poll() is None: + logger.info('killing the vineyardd') + proc.kill() + if etcd_ctx is not None: + etcd_ctx.__exit__(None, None, None) # pylint: disable=no-member
+ + +__all__ = ['start_vineyardd'] +
+
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/_modules/vineyard/deploy/kubernetes.html b/_modules/vineyard/deploy/kubernetes.html new file mode 100644 index 0000000000..4c3d592147 --- /dev/null +++ b/_modules/vineyard/deploy/kubernetes.html @@ -0,0 +1,663 @@ + + + + + + + + vineyard.deploy.kubernetes - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for vineyard.deploy.kubernetes

+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020-2023 Alibaba Group Holding Limited.
+#
+# 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.
+#
+
+import logging
+import os
+import re
+import tempfile
+import time
+
+try:
+    import kubernetes
+except ImportError:
+    kubernetes = None
+
+from vineyard.deploy.etcd import start_etcd_k8s
+from vineyard.deploy.utils import ensure_kubernetes_namespace
+
+logger = logging.getLogger('vineyard')
+
+
+
[docs]def start_vineyardd( + namespace='vineyard', + size='512Mi', + socket='/var/run/vineyard.sock', + rpc_socket_port=9600, + vineyard_image='vineyardcloudnative/vineyardd:latest', + vineyard_image_pull_policy='IfNotPresent', + vineyard_image_pull_secrets=None, + k8s_client=None, +): + """Launch a vineyard cluster on kubernetes. + + Parameters: + namespace: str + namespace in kubernetes + size: int + The memory size limit for vineyard's shared memory. The memory size + can be a plain integer or as a fixed-point number using one of these + suffixes: + + .. code:: + + E, P, T, G, M, K. + + You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. + + For example, the following represent roughly the same value: + + .. code:: + + 128974848, 129k, 129M, 123Mi, 1G, 10Gi, ... + socket: str + The UNIX domain socket socket path that vineyard server will listen on. + rpc_socket_port: int + The port that vineyard will use to provide RPC service. + k8s_client: kubernetes.client.api.ApiClient + A kubernetes client. If not specified, vineyard will try to resolve the + kubernetes configuration from current context. + vineyard_image: str + The docker image of vineyardd to launch the daemonset. + vineyard_image_pull_policy: str + The docker image pull policy of vineyardd. + vineyard_image_pull_secrets: str + The docker image pull secrets of vineyardd. + + Returns: + A list of created kubernetes resources during the deploying process. The + resources can be later release using :meth:`delete_kubernetes_objects`. + + See Also: + vineyard.deploy.kubernetes.delete_kubernetes_objects + """ + if kubernetes is None: + raise RuntimeError('Please install the package python "kubernetes" first') + + if k8s_client is None: + kubernetes.config.load_kube_config() + k8s_client = kubernetes.client.ApiClient() + + created_objects = [] + ensure_kubernetes_namespace(namespace, k8s_client=k8s_client) + created_objects.extend(start_etcd_k8s(namespace, k8s_client=k8s_client)) + + with open( + os.path.join(os.path.dirname(__file__), "vineyard.yaml.tpl"), + 'r', + encoding='utf-8', + ) as fp: + formatter = { + 'Namespace': namespace, + 'Size': size, + 'Socket': socket, + 'Port': rpc_socket_port, + 'Image': vineyard_image, + 'ImagePullPolicy': vineyard_image_pull_policy, + 'ImagePullSecrets': vineyard_image_pull_secrets + if vineyard_image_pull_secrets + else 'none', + } + definitions = fp.read().format(**formatter) + + with tempfile.NamedTemporaryFile( + mode='w', encoding='utf-8', delete=False + ) as rendered: + rendered.write(definitions) + rendered.flush() + rendered.close() + + with open(rendered.name, 'r', encoding='utf-8') as fp: + logger.debug(fp.read()) + + created_objects.extend( + kubernetes.utils.create_from_yaml( + k8s_client, rendered.name, namespace=namespace + ) + ) + return created_objects
+ + +def recursive_flatten(targets): + """Flatten the given maybe nested list as a 1-level list.""" + + def _recursive_flatten_impl(destination, targets): + if isinstance(targets, (list, tuple)): + for target in targets: + _recursive_flatten_impl(destination, target) + else: + destination.append(targets) + + destination = [] + _recursive_flatten_impl(destination, targets) + return destination + + +
[docs]def delete_kubernetes_objects( + targets, k8s_client=None, verbose=False, wait=False, timeout_seconds=60, **kwargs +): + """Delete the given kubernetes resources. + + Parameters: + target: List + List of Kubernetes objects + k8s_client: + The kubernetes client. If not specified, vineyard will try to resolve + the kubernetes configuration from current context. + verbose: bool + Whether to print the deletion logs. + wait: bool + Whether to wait for the deletion to complete. + timeout_seconds: int + The timeout in seconds for waiting for the deletion to complete. + + See Also: + vineyard.deploy.kubernetes.start_vineyardd + vineyard.deploy.kubernetes.delete_kubernetes_object + """ + for target in recursive_flatten(targets): + delete_kubernetes_object( + target, + k8s_client, + verbose=verbose, + wait=wait, + timeout_seconds=timeout_seconds, + **kwargs + )
+ + +def delete_kubernetes_object( + target, k8s_client=None, verbose=False, wait=False, timeout_seconds=60, **kwargs +): + """Delete the given kubernetes resource. + + Parameters: + target: object + The Kubernetes objects that will be deleted. + k8s_client: + The kubernetes client. If not specified, vineyard will try to resolve + the kubernetes configuration from current context. + verbose: bool + If True, print confirmation from the delete action. Defaults to False. + wait: bool + Whether to wait for the deletion to complete. Defaults to False. + timeout_seconds: int + The timeout in seconds for waiting for the deletion to complete. Defaults + to 60. + + Returns: + Status: Return status for calls kubernetes delete method. + + See Also: + vineyard.deploy.kubernetes.start_vineyardd + vineyard.deploy.kubernetes.delete_kubernetes_objects + """ + if isinstance(target, (list, tuple)): + return delete_kubernetes_objects( + target, k8s_client, verbose=verbose, wait=wait, **kwargs + ) + + if kubernetes is None: + raise RuntimeError('Please install the package python "kubernetes" first') + + if k8s_client is None: + kubernetes.config.load_kube_config() + k8s_client = kubernetes.client.ApiClient() + + group, _, version = target.api_version.partition("/") + if version == "": + version = group + group = "core" + # Take care for the case e.g. api_type is "apiextensions.k8s.io" + # Only replace the last instance + group = "".join(group.rsplit(".k8s.io", 1)) + # convert group name from DNS subdomain format to + # python class name convention + group = "".join(word.capitalize() for word in group.split(".")) + fcn_to_call = "{0}{1}Api".format(group, version.capitalize()) + k8s_api = getattr(kubernetes.client, fcn_to_call)( + k8s_client + ) # pylint: disable=not-callable + + kind = target.kind + kind = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", kind) + kind = re.sub("([a-z0-9])([A-Z])", r"\1_\2", kind).lower() + + try: + # Expect the user to create namespaced objects more often + kwargs["name"] = target.metadata.name + if hasattr(k8s_api, "delete_namespaced_{0}".format(kind)): + # Decide which namespace we are going to put the object in, if any + kwargs["namespace"] = target.metadata.namespace + resp = getattr(k8s_api, "delete_namespaced_{0}".format(kind))(**kwargs) + else: + kwargs.pop("namespace", None) + resp = getattr(k8s_api, "delete_{0}".format(kind))(**kwargs) + except kubernetes.client.rest.ApiException: + # Object already deleted. + return None + else: + # Waiting for delete + if wait: + start_time = time.time() + if hasattr(k8s_api, "read_namespaced_{0}".format(kind)): + while True: + try: + getattr(k8s_api, "read_namespaced_{0}".format(kind))(**kwargs) + except kubernetes.client.rest.ApiException as ex: + if ex.status != 404: + logger.exception( + "Deleting %s %s failed", kind, target.metadata.name + ) + break + else: + time.sleep(1) + if time.time() - start_time > timeout_seconds: + logger.info( + "Deleting %s/%s timeout", kind, target.metadata.name + ) + if verbose: + msg = "{0}/{1} deleted.".format(kind, target.metadata.name) + if hasattr(resp, "status"): + msg += " status='{0}'".format(str(resp.status)) + logger.info(msg) + return resp + + +__all__ = [ + 'start_vineyardd', + 'delete_kubernetes_object', + 'delete_kubernetes_objects', +] +
+
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/_modules/vineyard/deploy/local.html b/_modules/vineyard/deploy/local.html new file mode 100644 index 0000000000..78d71b7516 --- /dev/null +++ b/_modules/vineyard/deploy/local.html @@ -0,0 +1,644 @@ + + + + + + + + vineyard.deploy.local - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for vineyard.deploy.local

+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020-2023 Alibaba Group Holding Limited.
+#
+# 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.
+#
+
+import atexit
+import contextlib
+import logging
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+import textwrap
+import time
+from typing import Generator
+from typing import Optional
+from typing import Tuple
+
+from vineyard.deploy.etcd import start_etcd
+from vineyard.deploy.utils import check_socket
+from vineyard.deploy.utils import find_vineyardd_path
+
+logger = logging.getLogger('vineyard')
+
+
+
[docs]@contextlib.contextmanager +def start_vineyardd( + meta: Optional[str] = 'etcd', + etcd_endpoints: Optional[str] = None, + etcd_prefix: Optional[str] = None, + vineyardd_path: Optional[str] = None, + size: Optional[str] = '', + socket: Optional[str] = None, + rpc: Optional[str] = True, + rpc_socket_port: Optional[str] = 9600, + debug=False, +) -> Generator[Tuple[subprocess.Popen, str, str], None, None]: + """Launch a local vineyard cluster. + + Parameters: + meta: str, optional. + Metadata backend, can be "etcd", "redis" and "local". Defaults to + "etcd". + etcd_endpoint: str + Launching vineyard using specified etcd endpoints. If not specified, + vineyard will launch its own etcd instance. + etcd_prefix: str + Specify a common prefix to establish a local vineyard cluster. + vineyardd_path: str + Location of vineyard server program. If not specified, vineyard will + use its own bundled vineyardd binary. + size: int + The memory size limit for vineyard's shared memory. The memory size + can be a plain integer or as a fixed-point number using one of these + suffixes: + + .. code:: + + E, P, T, G, M, K. + + You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. + Defaults to "", means not limited. + + For example, the following represent roughly the same value: + + .. code:: + + 128974848, 129k, 129M, 123Mi, 1G, 10Gi, ... + socket: str + The UNIX domain socket socket path that vineyard server will listen on. + Default is None. + + When the socket parameter is None, a random path under temporary directory + will be generated and used. + rpc_socket_port: int + The port that vineyard will use to provided RPC service. + debug: bool + Whether print debug logs. + + Returns: + (proc, socket): + Yields a tuple with the subprocess as the first element and the UNIX-domain + IPC socket as the second element. + """ + + if not vineyardd_path: + vineyardd_path = find_vineyardd_path() + + if not vineyardd_path: + raise RuntimeError('Unable to find the "vineyardd" executable') + + if socket is None: + socketfp = tempfile.NamedTemporaryFile( + delete=True, prefix='vineyard-', suffix='.sock' + ) + socket = socketfp.name + socketfp.close() + + command = [ + vineyardd_path, + '--deployment', + 'local', + '--size', + str(size), + '--socket', + socket, + '--rpc' if rpc else '--norpc', + '--rpc_socket_port', + str(rpc_socket_port), + '--meta', + meta, + ] + + if meta == 'etcd': + if etcd_endpoints is None: + etcd_ctx = start_etcd() + ( + _etcd_proc, + etcd_endpoints, + ) = etcd_ctx.__enter__() # pylint: disable=no-member + else: + etcd_ctx = None + command.extend(('--etcd_endpoint', etcd_endpoints)) + if etcd_prefix is not None: + command.extend(('--etcd_prefix', etcd_prefix)) + else: + etcd_ctx = None + + env = os.environ.copy() + if debug: + env['GLOG_v'] = '11' + + proc = None + try: + proc = subprocess.Popen( + command, + env=env, + stdout=subprocess.PIPE, + stderr=sys.__stderr__, + universal_newlines=True, + encoding='utf-8', + ) + # wait for vineyardd ready: check the rpc port and ipc sockets + rc = proc.poll() + while rc is None: + if check_socket(socket) and ( + (not rpc) or check_socket(('0.0.0.0', rpc_socket_port)) + ): + break + time.sleep(1) + rc = proc.poll() + + if rc is not None: + err = textwrap.indent(proc.stdout.read(), ' ' * 4) + raise RuntimeError( + 'vineyardd exited unexpectedly ' + 'with code %d, error is:\n%s' % (rc, err) + ) + + logger.debug('vineyardd is ready.............') + yield proc, socket, etcd_endpoints + finally: + logger.debug('Local vineyardd being killed') + if proc is not None and proc.poll() is None: + proc.terminate() + proc.wait() + try: + shutil.rmtree(socket) + except Exception: # pylint: disable=broad-except + pass + if etcd_ctx is not None: + etcd_ctx.__exit__(None, None, None) # pylint: disable=no-member
+ + +__default_instance_contexts = {} + + +def try_init() -> str: + """ + Launching a local vineyardd instance and get a client as easy as possible. + + In a clean environment, simply use: + + .. code:: python + + vineyard.try_init() + + It will launch a local vineyardd and return a connected client to the + vineyardd. + + It will also setup the environment variable :code:`VINEYARD_IPC_SOCKET`. + + The init method can only be called once in a process, to get the established + sockets or clients later in the process, use :code:`get_current_socket` or + :code:`connect()` respectively. + """ + assert not __default_instance_contexts + + if 'VINEYARD_IPC_SOCKET' in os.environ: + raise ValueError( + "VINEYARD_IPC_SOCKET has already been set: %s, which " + "means there might be a vineyard daemon already running " + "locally" % os.environ['VINEYARD_IPC_SOCKET'] + ) + + ctx = start_vineyardd(meta='local', rpc=False) + _, ipc_socket, etcd_endpoints = ctx.__enter__() # pylint: disable=no-member + __default_instance_contexts[ipc_socket] = ctx + + # populate the environment variable + os.environ['VINEYARD_IPC_SOCKET'] = ipc_socket + return get_current_socket() + + +
[docs]def get_current_socket() -> str: + """ + Get current vineyard UNIX-domain socket established by :code:`vineyard.try_init()`. + + Raises: + ValueError if vineyard is not initialized. + """ + if not __default_instance_contexts: + raise ValueError( + 'Vineyard has not been initialized, ' + 'use vineyard.try_init() to launch vineyard instances' + ) + sockets = list(__default_instance_contexts.keys()) + if sockets: + return sockets[0] + raise RuntimeError("Vineyard has not been initialized")
+ + +def shutdown(): + """ + Shutdown the vineyardd instances launched by previous :code:`vineyard.try_init()`. + """ + global __default_instance_contexts + if __default_instance_contexts: + for ipc_socket in reversed(__default_instance_contexts.keys()): + __default_instance_contexts[ipc_socket].__exit__(None, None, None) + # NB. don't pop pre-existing env if we not launch + os.environ.pop('VINEYARD_IPC_SOCKET', None) + __default_instance_contexts = {} + + +@atexit.register +def __shutdown_handler(): + with contextlib.suppress(Exception): + shutdown() + + +__all__ = ['start_vineyardd', 'try_init', 'shutdown'] +
+
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/_modules/vineyard/io/byte.html b/_modules/vineyard/io/byte.html new file mode 100644 index 0000000000..73b971073b --- /dev/null +++ b/_modules/vineyard/io/byte.html @@ -0,0 +1,553 @@ + + + + + + + + vineyard.io.byte - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for vineyard.io.byte

+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020-2023 Alibaba Group Holding Limited.
+#
+# 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.
+#
+
+''' This module exposes support for ByteStream, that use can used like:
+
+.. code:: python
+
+    # create a builder, then seal it as stream
+    >>> stream = ByteStream.new(client)
+    >>> stream
+    ByteStream <o0001e09ddd98fd70>
+
+    # use write to put chunks
+    >>> writer = stream.open_writer(client)
+    >>> chunk = reader.next(1024)
+    >>> chunk
+    <memory at 0x136ca2ac0>
+    >>> len(chunk)
+    1024
+    >>> chunk.readonly
+    False
+    >>> vineyard.memory_copy(chunk, offset=0, src=b'abcde')
+
+    # mark the stream as finished
+    >>> writer.finish()
+
+    # open a reader
+    >>> reader = stream.open_reader(client)
+    >>> chunk = reader.next()
+    >>> chunk
+    <memory at 0x136d207c0>
+    >>> len(chunk)
+    1234
+    >>> chunk.readonly
+    True
+    >>> bytes(chunk[:10])
+    b'abcde\x00\x00\x00\x00\x00'
+
+    # the reader reaches the end of the stream
+    >>> chunk = reader.next()
+    ---------------------------------------------------------------------------
+    StreamDrainedException                    Traceback (most recent call last)
+    ~/libvineyard/python/vineyard/io/byte.py in next(self)
+        108
+    --> 109         def next(self) -> memoryview:
+        110             try:
+
+    StreamDrainedException: Stream drain: Stream drained: no more chunks
+
+    The above exception was the direct cause of the following exception:
+
+    StopIteration                             Traceback (most recent call last)
+    <ipython-input-11-d8809de11870> in <module>
+    ----> 1 chunk = reader.next()
+
+    ~/libvineyard/python/vineyard/io/byte.py in next(self)
+        109         def next(self) -> memoryview:
+        110             try:
+    --> 111                 return self._client.next_buffer_chunk(self._stream)
+        112             except StreamDrainedException as e:
+        113                 raise StopIteration('No more chunks') from e
+
+    StopIteration: No more chunks
+'''
+
+import json
+from io import BytesIO
+from typing import Dict
+
+from vineyard._C import ObjectID
+from vineyard._C import ObjectMeta
+from vineyard._C import StreamDrainedException
+from vineyard._C import memory_copy
+from vineyard.io.stream import BaseStream
+
+
+
[docs]class ByteStream(BaseStream): + def __init__(self, meta: ObjectMeta, params: Dict = None): + super().__init__(meta) + self._params = params + + @property + def params(self): + return self._params + + @staticmethod + def new(client, params: Dict = None, meta: ObjectMeta = None) -> "ByteStream": + if meta is None: + meta = ObjectMeta() + meta['typename'] = 'vineyard::ByteStream' + if params is None: + params = dict() + meta['params_'] = params + meta = client.create_metadata(meta) + client.create_stream(meta.id) + return ByteStream(meta, params) + + class Reader(BaseStream.Reader): + def __init__(self, client, stream: ObjectID): + super().__init__(client, stream) + + def next(self) -> memoryview: + try: + return self._client.next_buffer_chunk(self._stream) + except StreamDrainedException as e: + raise StopIteration('No more chunks') from e + + class Writer(BaseStream.Writer): + def __init__(self, client, stream: ObjectID): + super().__init__(client, stream) + + self._buffer_size_limit = 1024 * 1024 * 256 + self._buffer = BytesIO() + + @property + def buffer_size_limit(self): + return self._buffer_size_limit + + @buffer_size_limit.setter + def buffer_size_limit(self, value: int): + self._buffer_size_limit = value + + def next(self, size: int) -> memoryview: + return self._client.new_buffer_chunk(self._stream, size) + + def write(self, data: bytes): + self._buffer.write(data) + self._try_flush_buffer() + + def _try_flush_buffer(self, force=False): + view = self._buffer.getbuffer() + if len(view) >= self._buffer_size_limit or (force and len(view) > 0): + if len(view) > 0: + chunk = self.next(len(view)) + memory_copy(chunk, 0, view) + self._buffer = BytesIO() + + def finish(self): + self._try_flush_buffer(True) + return self._client.stop_stream(self._stream, False) + + def _open_new_reader(self, client): + return ByteStream.Reader(client, self.id) + + def _open_new_writer(self, client): + return ByteStream.Writer(client, self.id)
+ + +def byte_stream_resolver(obj): + meta = obj.meta + if 'params_' in meta: + params = json.loads(meta['params_']) + else: + params = dict + return ByteStream(obj.meta, params) + + +def register_byte_stream_types(_builder_ctx, resolver_ctx): + if resolver_ctx is not None: + resolver_ctx.register('vineyard::ByteStream', byte_stream_resolver) +
+
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/_modules/vineyard/io/dataframe.html b/_modules/vineyard/io/dataframe.html new file mode 100644 index 0000000000..6658e35953 --- /dev/null +++ b/_modules/vineyard/io/dataframe.html @@ -0,0 +1,551 @@ + + + + + + + + vineyard.io.dataframe - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for vineyard.io.dataframe

+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020-2023 Alibaba Group Holding Limited.
+#
+# 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.
+#
+
+''' This module exposes support for DataframeStream, that use can used like:
+
+.. code:: python
+
+    # create a builder, then seal it as stream
+    >>> stream = DataframeStream.new(client)
+    >>> stream = builder.seal(client)
+    >>> stream
+    DataframeStream <o0001e09ddd98fd70>
+
+    # use write to put chunks
+    >>> writer = stream.open_writer(client)
+    >>> writer.write_table(
+            pa.Table.from_pandas(
+                pd.DataFrame({"x": [1,2,3], "y": [4,5,6]})))
+
+    # mark the stream as finished
+    >>> writer.finish()
+
+    # open a reader
+    >>> reader = stream.open_reader(client)
+    >>> batch = reader.next()
+    >>> batch
+    pyarrow.RecordBatch
+    x: int64
+    y: int64
+
+    # the reader reaches the end of the stream
+    >>> batch = reader.next()
+    ---------------------------------------------------------------------------
+    StreamDrainedException                    Traceback (most recent call last)
+    ~/libvineyard/python/vineyard/io/dataframe.py in next(self)
+        97             try:
+    ---> 98                 buffer = self._client.next_buffer_chunk(self._stream)
+        99                 with pa.ipc.open_stream(buffer) as reader:
+
+    StreamDrainedException: Stream drain: Stream drained: no more chunks
+
+    The above exception was the direct cause of the following exception:
+
+    StopIteration                             Traceback (most recent call last)
+    <ipython-input-11-10f09bf65f8a> in <module>
+    ----> 1 batch = reader.next()
+
+    ~/libvineyard/python/vineyard/io/dataframe.py in next(self)
+        100                     return reader.read_next_batch()
+        101             except StreamDrainedException as e:
+    --> 102                 raise StopIteration('No more chunks') from e
+        103
+        104         def __str__(self) -> str:
+
+    StopIteration: No more chunks
+'''
+
+import contextlib
+import json
+from io import BytesIO
+from typing import Dict
+
+import pyarrow as pa
+import pyarrow.ipc  # pylint: disable=unused-import
+
+from vineyard._C import ObjectID
+from vineyard._C import ObjectMeta
+from vineyard._C import StreamDrainedException
+from vineyard._C import memory_copy
+from vineyard.io.stream import BaseStream
+
+
+
[docs]class DataframeStream(BaseStream): + def __init__(self, meta: ObjectMeta, params: Dict = None): + super().__init__(meta) + self._params = params + + @property + def params(self): + return self._params + + @staticmethod + def new(client, params: Dict = None, meta: ObjectMeta = None) -> "DataframeStream": + if meta is None: + meta = ObjectMeta() + meta['typename'] = 'vineyard::DataframeStream' + if params is None: + params = dict() + meta['params_'] = params + meta = client.create_metadata(meta) + client.create_stream(meta.id) + return DataframeStream(meta, params) + + class Reader(BaseStream.Reader): + def __init__(self, client, stream: ObjectID): + super().__init__(client, stream) + + def next(self) -> pa.RecordBatch: + try: + buffer = self._client.next_buffer_chunk(self._stream) + with pa.ipc.open_stream(buffer) as reader: + return reader.read_next_batch() + except StreamDrainedException as e: + raise StopIteration('No more chunks') from e + + def read_table(self) -> pa.Table: + batches = [] + while True: + try: + batches.append(self.next()) + except StopIteration: + break + return pa.Table.from_batches(batches) + + class Writer(BaseStream.Writer): + def __init__(self, client, stream: ObjectID): + super().__init__(client, stream) + + self._buffer = BytesIO() + + def next(self, size: int) -> memoryview: + return self._client.new_buffer_chunk(self._stream, size) + + def write(self, batch: pa.RecordBatch): + sink = BytesIO() + with pa.ipc.new_stream(sink, batch.schema) as writer: + writer.write(batch) + view = sink.getbuffer() + if len(view) > 0: + buffer = self.next(len(view)) + memory_copy(buffer, 0, view) + + def write_table(self, table: pa.Table): + for batch in table.to_batches(): + self.write(batch) + + def finish(self): + return self._client.stop_stream(self._stream, False) + + def _open_new_reader(self, client): + return DataframeStream.Reader(client, self.id) + + def _open_new_writer(self, client): + return DataframeStream.Writer(client, self.id)
+ + +def dataframe_stream_resolver(obj): + meta = obj.meta + if 'params_' in meta: + params = json.loads(meta['params_']) + else: + params = dict + return DataframeStream(obj.meta, params) + + +def register_dataframe_stream_types(_builder_ctx, resolver_ctx): + if resolver_ctx is not None: + resolver_ctx.register('vineyard::DataframeStream', dataframe_stream_resolver) +
+
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/_modules/vineyard/io/recordbatch.html b/_modules/vineyard/io/recordbatch.html new file mode 100644 index 0000000000..1d63959dbf --- /dev/null +++ b/_modules/vineyard/io/recordbatch.html @@ -0,0 +1,457 @@ + + + + + + + + vineyard.io.recordbatch - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for vineyard.io.recordbatch

+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020-2023 Alibaba Group Holding Limited.
+#
+# 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.
+#
+
+''' This module exposes support for RecordBatchStream.
+'''
+
+import contextlib
+import json
+from typing import Any
+from typing import Dict
+from typing import Optional
+
+from vineyard._C import ObjectMeta
+from vineyard.core import context
+from vineyard.io.stream import BaseStream
+
+
+
[docs]class RecordBatchStream(BaseStream): + def __init__(self, meta: ObjectMeta, params: Optional[Dict[str, Any]] = None): + super().__init__(meta) + self._params = params + + @property + def params(self): + return self._params + + @staticmethod + def new( + client, + params: Optional[Dict[str, Any]] = None, + meta: Optional[ObjectMeta] = None, + ) -> "RecordBatchStream": + if meta is None: + meta = ObjectMeta() + meta['typename'] = 'vineyard::RecordBatchStream' + if params is None: + params = dict() + meta['params_'] = params + meta = client.create_metadata(meta) + client.create_stream(meta.id) + return RecordBatchStream(meta, params)
+ + +def recordbatch_stream_resolver(obj, resolver): # pylint: disable=unused-argument + meta = obj.meta + if 'params_' in meta: + params = json.loads(meta['params_']) + else: + params = dict + return RecordBatchStream(meta, params) + + +def register_recordbatch_stream_types(_builder_ctx, resolver_ctx): + if resolver_ctx is not None: + resolver_ctx.register( + 'vineyard::RecordBatchStream', recordbatch_stream_resolver + ) + + +@contextlib.contextmanager +def recordbatch_stream_context(): + with context() as (builder_ctx, resolver_ctx): + register_recordbatch_stream_types(builder_ctx, resolver_ctx) + yield builder_ctx, resolver_ctx +
+
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/_modules/vineyard/io/stream.html b/_modules/vineyard/io/stream.html new file mode 100644 index 0000000000..c3fd139cbc --- /dev/null +++ b/_modules/vineyard/io/stream.html @@ -0,0 +1,834 @@ + + + + + + + + vineyard.io.stream - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for vineyard.io.stream

+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020-2023 Alibaba Group Holding Limited.
+#
+# 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.
+#
+
+import json
+import logging
+import traceback
+from typing import Callable
+from typing import Dict
+from typing import List
+from typing import Optional
+from urllib.parse import urlparse
+
+from vineyard._C import ObjectID
+from vineyard._C import ObjectMeta
+from vineyard._C import StreamDrainedException
+from vineyard.core.driver import registerize
+from vineyard.core.resolver import resolver_context
+
+logger = logging.getLogger('vineyard')
+
+
+
[docs]@registerize +def read( + path, + *args, + handlers=None, + accumulate=False, + chunk_hook: Optional[Callable] = None, + **kwargs +): + """Open a path and read it as a single stream. + + Parameters + ---------- + path: str + Path to read, the last reader registered for the scheme of + the path will be used. + handlers: list, optional + If handlers is not None, launched worker processes will be + emplaced into the list for further customized job lifecycle + management. Default is None. + accumulate: bool, optional + If :code:`accumulate` is True, it will return a data frame, + rather than dataframe stream. Default is False. + chunk_hook: callable, optional + If the read/write target is a global dataframe (e.g., csv, + orc, parquet, etc.), the hook will be called for each chunk + to be read or write (usually a :code:`pyarrow.RecordBatch`). + The hook should return a :code:`pyarrow.RecordBatch` object + and should be stateless as the invoke order is not guaranteed. + E.g., + + .. code:: python + + def exchange_column(batch): + import pyarrow as pa + + columns = batch.columns + first = columns[0] + second = columns[1] + columns = [second, first] + columns[2:] + return pa.RecordBatch.from_arrays(columns, schema=batch.schema) + + vineyard_ipc_socket: str + The local or remote vineyard's IPC socket location that the + remote readers will use to establish connections with the + vineyard server. + vineyard_endpoint: str, optional + An optional address of vineyard's RPC socket, which will be + used for retrieving server's information on the client side. + If not provided, the `vineyard_ipc_socket` will be used, or + it will tries to discovery vineyard's IPC or RPC endpoints + from environment variables. + """ + parsed = urlparse(path) + if read._factory and read._factory.get(parsed.scheme): + errors = [] + for reader in read._factory[parsed.scheme][::-1]: + try: + proc_kwargs = kwargs.copy() + r = reader( + path, + proc_kwargs.pop('vineyard_ipc_socket'), + *args, + handlers=handlers, + accumulate=accumulate, + chunk_hook=chunk_hook, + **proc_kwargs + ) + if r is not None: + return r + except Exception: # pylint: disable=broad-except + errors.append('%s: %s' % (reader.__name__, traceback.format_exc())) + raise RuntimeError( + 'Unable to find a proper IO driver for %s, potential causes are:\n %s' + % (path, '\n'.join(errors)) + ) + else: + raise ValueError("No IO driver registered for %s" % path)
+ + +
[docs]@registerize +def write( + path, stream, *args, handlers=None, chunk_hook: Optional[Callable] = None, **kwargs +): + """Write the stream to a given path. + + Parameters + ---------- + path: str + Path to write, the last writer registered for the scheme of the path + will be used. + stream: vineyard stream + Stream that produces the data to write. + handlers: list, optional + If handlers is not None, launched worker processes will be + emplaced into the list for further customized job lifecycle + management. Default is None. + chunk_hook: callable, optional + If the read/write target is a global dataframe (e.g., csv, + orc, parquet, etc.), the hook will be called for each chunk + to be read or write (usually a :code:`pyarrow.RecordBatch`). + The hook should return a :code:`pyarrow.RecordBatch` object + and should be stateless as the invoke order is not guaranteed. + E.g., + + .. code:: python + + def exchange_column(batch): + import pyarrow as pa + + columns = batch.columns + first = columns[0] + second = columns[1] + columns = [second, first] + columns[2:] + return pa.RecordBatch.from_arrays(columns, schema=batch.schema) + + vineyard_ipc_socket: str + The local or remote vineyard's IPC socket location that the remote + readers will use to establish connections with the vineyard server. + vineyard_endpoint: str, optional + An optional address of vineyard's RPC socket, which will be used for + retrieving server's information on the client side. If not provided, + the `vineyard_ipc_socket` will be used, or it will tries to discovery + vineyard's IPC or RPC endpoints from environment variables. + """ + parsed = urlparse(path) + if write._factory and write._factory.get(parsed.scheme): + errors = [] + for writer in write._factory[parsed.scheme][::-1]: + try: + proc_kwargs = kwargs.copy() + writer( + path, + stream, + proc_kwargs.pop('vineyard_ipc_socket'), + *args, + handlers=handlers, + chunk_hook=chunk_hook, + **proc_kwargs + ) + except Exception: # pylint: disable=broad-except + exc = traceback.format_exc() + errors.append('%s: %s' % (writer.__name__, exc)) + if 'StreamFailedException: Stream failed' in exc: + # if the source stream has already failed, we should + # fail immediately and don't try other drivers. + break + continue + else: + return + raise RuntimeError( + 'Unable to find a proper IO driver for %s, potential causes are:\n %s' + % (path, '\n'.join(errors)) + ) + else: + raise ValueError("No IO driver registered for %s" % path)
+ + +
[docs]def open( + path, + *args, + mode='r', + handlers=None, + chunk_hook: Optional[Callable] = None, + **kwargs +): + """Open a path as a reader or writer, depends on the parameter :code:`mode`. + If :code:`mode` is :code:`r`, it will open a stream for read, and open a + stream for write when :code:`mode` is :code:`w`. + + Parameters + ---------- + path: str + Path to open. + mode: char + Mode about how to open the path, :code:`r` is for read and :code:`w` for write. + handlers: + A dict that will be filled with a :code:`handler` that contains the process + handler of the underlying read/write process that can be joined using + :code:`join` to capture the possible errors during the I/O proceeding. + chunk_hook: callable, optional + If the read/write target is a global dataframe (e.g., csv, + orc, parquet, etc.), the hook will be called for each chunk + to be read or write (usually a :code:`pyarrow.RecordBatch`). + The hook should return a :code:`pyarrow.RecordBatch` object + and should be stateless as the invoke order is not guaranteed. + E.g., + + .. code:: python + + def exchange_column(batch): + import pyarrow as pa + + columns = batch.columns + first = columns[0] + second = columns[1] + columns = [second, first] + columns[2:] + return pa.RecordBatch.from_arrays(columns, schema=batch.schema) + + vineyard_ipc_socket: str + Vineyard's IPC socket location. + vineyard_endpoint: str + Vineyard's RPC socket address. + + See Also + -------- + vineyard.io.read + vineyard.io.write + """ + parsed = urlparse(path) + if not parsed.scheme: + path = 'file://' + path + + if mode == 'r': + return read(path, *args, handlers=handlers, chunk_hook=chunk_hook, **kwargs) + + if mode == 'w': + return write(path, *args, handlers=handlers, chunk_hook=chunk_hook, **kwargs) + + raise RuntimeError('Opening %s with mode %s is not supported' % (path, mode))
+ + +class BaseStream: + class Reader: + def __init__(self, client, stream: ObjectID, resolver=None): + self._client = client + self._stream = stream + self._resolver = resolver + self._client.open_stream(stream, 'r') + + def next(self) -> object: + try: + chunk = self._client.next_chunk(self._stream) + except StreamDrainedException as e: + raise StopIteration('No more chunks') from e + + if self._resolver is not None: + return self._resolver(chunk) + else: + with resolver_context() as ctx: + return ctx.run(chunk) + + def next_metadata(self) -> ObjectMeta: + try: + return self._client.next_chunk_meta(self._stream) + except StreamDrainedException as e: + raise StopIteration('No more chunks') from e + + def __str__(self) -> str: + return repr(self) + + def __repr__(self) -> str: + return '%s of Stream <%r>' % (self.__class__, self._stream) + + class Writer: + def __init__(self, client, stream: ObjectID): + self._client = client + self._stream = stream + self._client.open_stream(stream, 'w') + + def next(self, size: int) -> memoryview: + return self._client.new_buffer_chunk(self._stream, size) + + def append(self, chunk: ObjectID): + return self._client.push_chunk(self._stream, chunk) + + def fail(self): + return self._client.stop_stream(self._stream, True) + + def finish(self): + return self._client.stop_stream(self._stream, False) + + def __str__(self) -> str: + return repr(self) + + def __repr__(self) -> str: + return '%s of Stream <%r>' % (self.__class__, self._stream) + + def __init__(self, meta: ObjectMeta, resolver=None): + self._meta = meta + self._stream = meta.id + self._resolver = resolver + + self._reader = None + self._writer = None + + @property + def id(self) -> ObjectID: + return self._stream + + @property + def meta(self) -> ObjectMeta: + return self._meta + + @property + def reader(self) -> "BaseStream.Reader": + return self.open_reader() + + def __str__(self) -> str: + return repr(self) + + def __repr__(self) -> str: + return '%s <%r>' % (self.__class__.__name__, self._stream) + + def _open_new_reader(self, client) -> "BaseStream.Reader": + '''Always open a new reader.''' + return BaseStream.Reader(client, self.id, self._resolver) + + def open_reader(self, client=None) -> "BaseStream.Reader": + if self._reader is None: + if client is None: + client = self._meta._client + self._reader = self._open_new_reader(client) + return self._reader + + @property + def writer(self) -> "BaseStream.Writer": + return self.open_writer() + + def _open_new_writer(self, client) -> "BaseStream.Writer": + return BaseStream.Writer(client, self.id) + + def open_writer(self, client=None) -> "BaseStream.Writer": + if self._writer is None: + if client is None: + client = self._meta._client + self._writer = self._open_new_writer(client) + return self._writer + + def drop(self, client=None): + if client is None: + client = self._meta._client + if hasattr(client, 'drop_stream'): + client.drop_stream(self.id) + + +class StreamCollection: + """A stream collection is a set of stream, where each element is a stream, or, + another stream collection. + """ + + KEY_OF_STREAMS = '__streams' + KEY_OF_PATH = '__path' + KEY_OF_GLOBAL = '__global' + KEY_OF_OPTIONS = '__options' + + def __init__(self, meta: ObjectMeta, streams: List[ObjectID]): + self._meta = meta + self._streams = streams + if StreamCollection.KEY_OF_GLOBAL in self._meta: + self._global = self._meta[StreamCollection.KEY_OF_GLOBAL] + else: + self._global = False + + @staticmethod + def new( + client, metadata: Dict, streams: List[ObjectID], meta: ObjectMeta = None + ) -> "StreamCollection": + if meta is None: + meta = ObjectMeta() + meta['typename'] = 'vineyard::StreamCollection' + for k, v in metadata.items(): + if k not in [ + 'id', + 'signature', + 'instance_id', + 'transient', + 'global', + 'typename', + ]: + meta[k] = v + meta[StreamCollection.KEY_OF_STREAMS] = [int(s) for s in streams] + meta = client.create_metadata(meta) + return StreamCollection(meta, streams) + + @property + def id(self): + return self.meta.id + + @property + def meta(self): + return self._meta + + @property + def isglobal(self): + return self._global + + @property + def streams(self): + return self._streams + + def __repr__(self) -> str: + return "StreamCollection: %s [%s]" % ( + repr(self.id), + [repr(s) for s in self.streams], + ) + + def __str__(self) -> str: + return repr(self) + + +def stream_collection_resolver(obj): + meta = obj.meta + streams = json.loads(meta[StreamCollection.KEY_OF_STREAMS]) + return StreamCollection(meta, [ObjectID(s) for s in streams]) + + +def register_stream_collection_types(_builder_ctx, resolver_ctx): + if resolver_ctx is not None: + resolver_ctx.register('vineyard::StreamCollection', stream_collection_resolver) + + +__all__ = [ + 'open', + 'read', + 'write', + 'BaseStream', + 'StreamCollection', + 'register_stream_collection_types', +] +
+
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/_modules/vineyard/shared_memory/shared_memory.html b/_modules/vineyard/shared_memory/shared_memory.html new file mode 100644 index 0000000000..5dbf843af7 --- /dev/null +++ b/_modules/vineyard/shared_memory/shared_memory.html @@ -0,0 +1,751 @@ + + + + + + + + vineyard.shared_memory.shared_memory - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+

Source code for vineyard.shared_memory.shared_memory

+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020-2023 Alibaba Group Holding Limited.
+#
+# 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.
+#
+
+'''
+The shared_memory module provides similar interface like multiprocessing.shared_memory
+for direct access shared memory backed by vineyard across processes.
+
+The API is kept consistent with multiprocessing.shared_memory but the semantics is
+slightly different. For vineyard, to make the shared memory visible for other process,
+a explicitly ``seal`` or ``close`` operation is needed.
+
+Refer to the documentation of multiprocessing.shared_memory for details.
+'''
+
+# pylint: skip-file
+
+try:
+    import multiprocessing.shared_memory as shm
+except ImportError:
+    # multiprocessing.shared_memory is available since Python 3.8, we use the slim
+    # library for earlier version of Python.
+    #
+    # see also github #327.
+    import shared_memory as shm
+
+import struct
+import warnings
+
+from vineyard._C import ObjectID
+
+
+
[docs]class SharedMemory: + def __init__(self, vineyard_client, name=None, create=False, size=0): + """Create or obtain a shared memory block that backed by vineyard. + + Parameters + ---------- + vineyard_client: + The vineyard IPC or RPC client. + name: + The vineyard ObjectID, could be vineyard.ObjectID, int or stringified + ObjectID. + create: + Whether to create a new shared memory block or just obtain existing one. + size: + Size of the shared memory block. + + See Also + -------- + multiprocessing.shared_memory.SharedMemory + """ + if not size >= 0: + raise ValueError("'size' must be a positive integer") + if create: + if size == 0: + raise ValueError( + "'size' must be a positive number " "different from zero" + ) + if name is not None: + raise ValueError("'name' can only be None if create=True") + else: + if size != 0: + warnings.warn( + "'size' will take no effect if create=False", + ) + if name is None: + raise ValueError("'name' cannot be None if create=False") + + self._name = None + self._size = None + self._buf = None + self._blob, self._blob_builder = None, None + self._vineyard_client = vineyard_client + + if create: + self._blob_builder = vineyard_client.create_blob(size) + self._name = self._blob_builder.id + self._size = size + self._buf = memoryview(self._blob_builder) + else: + self._blob = vineyard_client.get_object(ObjectID(name)) + self._name = self._blob.id + self._size = self._blob.size + self._buf = memoryview(self._blob) + + def __del__(self): + try: + self.close() + except Exception: + pass + + def __reduce__(self): + return ( + self.__class__, + ( + self.name, + False, + self.size, + ), + ) + + def __repr__(self): + return f'{self.__class__.__name__}({self.name!r}, size={self.size})' + + @property + def buf(self): + "A memoryview of contents of the shared memory block." + return self._buf + + @property + def name(self): + "Unique name that identifies the shared memory block." + return repr(self._name) + + @property + def size(self): + "Size in bytes." + return self._size + +
[docs] def freeze(self): + "Seal the shared memory to make it visible for other processes." + if self._blob_builder: + self._blob = self._blob_builder.seal(self._vineyard_client) + self._blob_builder = None + return self
+ + def close(self): + self.freeze() + +
+ + +_encoding = "utf8" + + +
[docs]class ShareableList(shm.ShareableList): + """ + Pattern for a mutable list-like object shareable via a shared + memory block. It differs from the built-in list type in that these + lists can not change their overall length (i.e. no append, insert, + etc.) + + Because values are packed into a memoryview as bytes, the struct + packing format for any storable value must require no more than 8 + characters to describe its format. + + The ShareableList in vineyard differs slightly with its equivalent + in the multiprocessing.shared_memory.ShareableList, as it becomes + immutable after obtaining from the vineyard backend. + + See Also + -------- + multiprocessing.shared_memory.ShareableList + """ + + # note that the implementation of ``__init__`` entirely comes from + # multiprocessing.shared_memory. + # + # and note that + # + # https://github.com/python/cpython/commit/c8f1715283ec51822fb37a702bf253cbac1af276 + # + # has made a set of changes to the ``ShareableList`` code. + # + def __init__(self, vineyard_client, sequence=None, *, name=None): + if name is None or sequence is not None: + if name is not None: + warnings.warn( + "'name' will take no effect as we are going to " + "create a ShareableList", + ) + + sequence = sequence or () + _formats = [ + self._types_mapping[type(item)] + if not isinstance(item, (str, bytes)) # noqa: E131 + else self._types_mapping[type(item)] + % (self._alignment * (len(item) // self._alignment + 1),) # noqa: E131 + for item in sequence + ] + self._list_len = len(_formats) + assert sum(len(fmt) <= 8 for fmt in _formats) == self._list_len + offset = 0 + # The offsets of each list element into the shared memory's + # data area (0 meaning the start of the data area, not the start + # of the shared memory area). + self._allocated_offsets = [0] + for fmt in _formats: + offset += self._alignment if fmt[-1] != "s" else int(fmt[:-1]) + self._allocated_offsets.append(offset) + _recreation_codes = [ + self._extract_recreation_code(item) for item in sequence + ] + requested_size = struct.calcsize( + "q" + + self._format_size_metainfo + + "".join(_formats) + + self._format_packing_metainfo + + self._format_back_transform_codes + ) + + self.shm = SharedMemory(vineyard_client, create=True, size=requested_size) + else: + self.shm = SharedMemory(vineyard_client, name) + + if sequence is not None: + _enc = _encoding + struct.pack_into( + "q" + self._format_size_metainfo, + self.shm.buf, + 0, + self._list_len, + *(self._allocated_offsets), + ) + struct.pack_into( + "".join(_formats), + self.shm.buf, + self._offset_data_start, + *(v.encode(_enc) if isinstance(v, str) else v for v in sequence), + ) + struct.pack_into( + self._format_packing_metainfo, + self.shm.buf, + self._offset_packing_formats, + *(v.encode(_enc) for v in _formats), + ) + struct.pack_into( + self._format_back_transform_codes, + self.shm.buf, + self._offset_back_transform_codes, + *(_recreation_codes), + ) + + else: + self._list_len = len(self) # Obtains size from offset 0 in buffer. + self._allocated_offsets = list( + struct.unpack_from(self._format_size_metainfo, self.shm.buf, 1 * 8) + ) + + def _get_back_transform(self, position): + "Gets the back transformation function for a single value." + + if (position >= self._list_len) or (self._list_len < 0): + raise IndexError("Requested position out of range.") + + transform_code = struct.unpack_from( + "b", self.shm.buf, self._offset_back_transform_codes + position + )[0] + transform_function = self._back_transforms_mapping[transform_code] + + return transform_function + + def _set_packing_format_and_transform(self, position, fmt_as_str, value): + """Sets the packing format and back transformation code for a + single value in the list at the specified position.""" + + if (position >= self._list_len) or (self._list_len < 0): + raise IndexError("Requested position out of range.") + + struct.pack_into( + "8s", + self.shm.buf, + self._offset_packing_formats + position * 8, + fmt_as_str.encode(_encoding), + ) + + transform_code = self._extract_recreation_code(value) + struct.pack_into( + "b", + self.shm.buf, + self._offset_back_transform_codes + position, + transform_code, + ) + + def __getitem__(self, position): + position = position if position >= 0 else position + self._list_len + try: + offset = self._offset_data_start + self._allocated_offsets[position] + (v,) = struct.unpack_from( + self._get_packing_format(position), self.shm.buf, offset + ) + except IndexError: + raise IndexError("index out of range") + + back_transform = self._get_back_transform(position) + v = back_transform(v) + + return v + + def __setitem__(self, position, value): + position = position if position >= 0 else position + self._list_len + try: + item_offset = self._allocated_offsets[position] + offset = self._offset_data_start + item_offset + current_format = self._get_packing_format(position) + except IndexError: + raise IndexError("assignment index out of range") + + if not isinstance(value, (str, bytes)): + new_format = self._types_mapping[type(value)] + encoded_value = value + else: + allocated_length = self._allocated_offsets[position + 1] - item_offset + + encoded_value = value.encode(_encoding) if isinstance(value, str) else value + if len(encoded_value) > allocated_length: + raise ValueError("bytes/str item exceeds available storage") + if current_format[-1] == "s": + new_format = current_format + else: + new_format = self._types_mapping[str] % (allocated_length,) + + self._set_packing_format_and_transform(position, new_format, value) + struct.pack_into(new_format, self.shm.buf, offset, encoded_value) + + @property + def _format_size_metainfo(self): + "The struct packing format used for the items' storage offsets." + return "q" * (self._list_len + 1) + + @property + def _format_packing_metainfo(self): + "The struct packing format used for the items' packing formats." + return "8s" * self._list_len + + @property + def _format_back_transform_codes(self): + "The struct packing format used for the items' back transforms." + return "b" * self._list_len + + @property + def _offset_data_start(self): + # - 8 bytes for the list length + # - (N + 1) * 8 bytes for the element offsets + return (self._list_len + 2) * 8 + + @property + def _offset_packing_formats(self): + return self._offset_data_start + self._allocated_offsets[-1] + + @property + def _offset_back_transform_codes(self): + return self._offset_packing_formats + self._list_len * 8 + +
[docs] def freeze(self): + '''Make the shareable list immutable and visible for other vineyard clients.''' + self.shm.freeze()
+ + +__all__ = ['SharedMemory', 'ShareableList'] +
+
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/_panels_static/panels-bootstrap.5fd3999ee7762ccc51105388f4a9d115.css b/_panels_static/panels-bootstrap.5fd3999ee7762ccc51105388f4a9d115.css new file mode 100644 index 0000000000..1b057df2f2 --- /dev/null +++ b/_panels_static/panels-bootstrap.5fd3999ee7762ccc51105388f4a9d115.css @@ -0,0 +1 @@ +.badge{border-radius:.25rem;display:inline-block;font-size:75%;font-weight:700;line-height:1;padding:.25em .4em;text-align:center;vertical-align:baseline;white-space:nowrap}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{border-radius:10rem;padding-left:.6em;padding-right:.6em}.badge-primary{background-color:#007bff;color:#fff}.badge-primary[href]:focus,.badge-primary[href]:hover{background-color:#0062cc;color:#fff;text-decoration:none}.badge-secondary{background-color:#6c757d;color:#fff}.badge-secondary[href]:focus,.badge-secondary[href]:hover{background-color:#545b62;color:#fff;text-decoration:none}.badge-success{background-color:#28a745;color:#fff}.badge-success[href]:focus,.badge-success[href]:hover{background-color:#1e7e34;color:#fff;text-decoration:none}.badge-info{background-color:#17a2b8;color:#fff}.badge-info[href]:focus,.badge-info[href]:hover{background-color:#117a8b;color:#fff;text-decoration:none}.badge-warning{background-color:#ffc107;color:#212529}.badge-warning[href]:focus,.badge-warning[href]:hover{background-color:#d39e00;color:#212529;text-decoration:none}.badge-danger{background-color:#dc3545;color:#fff}.badge-danger[href]:focus,.badge-danger[href]:hover{background-color:#bd2130;color:#fff;text-decoration:none}.badge-light{background-color:#f8f9fa;color:#212529}.badge-light[href]:focus,.badge-light[href]:hover{background-color:#dae0e5;color:#212529;text-decoration:none}.badge-dark{background-color:#343a40;color:#fff}.badge-dark[href]:focus,.badge-dark[href]:hover{background-color:#1d2124;color:#fff;text-decoration:none}.border-0{border:0 !important}.border-top-0{border-top:0 !important}.border-right-0{border-right:0 !important}.border-bottom-0{border-bottom:0 !important}.border-left-0{border-left:0 !important}.p-0{padding:0 !important}.pt-0,.py-0{padding-top:0 !important}.pr-0,.px-0{padding-right:0 !important}.pb-0,.py-0{padding-bottom:0 !important}.pl-0,.px-0{padding-left:0 !important}.p-1{padding:.25rem !important}.pt-1,.py-1{padding-top:.25rem !important}.pr-1,.px-1{padding-right:.25rem !important}.pb-1,.py-1{padding-bottom:.25rem !important}.pl-1,.px-1{padding-left:.25rem !important}.p-2{padding:.5rem !important}.pt-2,.py-2{padding-top:.5rem !important}.pr-2,.px-2{padding-right:.5rem !important}.pb-2,.py-2{padding-bottom:.5rem !important}.pl-2,.px-2{padding-left:.5rem !important}.p-3{padding:1rem !important}.pt-3,.py-3{padding-top:1rem !important}.pr-3,.px-3{padding-right:1rem !important}.pb-3,.py-3{padding-bottom:1rem !important}.pl-3,.px-3{padding-left:1rem !important}.p-4{padding:1.5rem !important}.pt-4,.py-4{padding-top:1.5rem !important}.pr-4,.px-4{padding-right:1.5rem !important}.pb-4,.py-4{padding-bottom:1.5rem !important}.pl-4,.px-4{padding-left:1.5rem !important}.p-5{padding:3rem !important}.pt-5,.py-5{padding-top:3rem !important}.pr-5,.px-5{padding-right:3rem !important}.pb-5,.py-5{padding-bottom:3rem !important}.pl-5,.px-5{padding-left:3rem !important}.m-0{margin:0 !important}.mt-0,.my-0{margin-top:0 !important}.mr-0,.mx-0{margin-right:0 !important}.mb-0,.my-0{margin-bottom:0 !important}.ml-0,.mx-0{margin-left:0 !important}.m-1{margin:.25rem !important}.mt-1,.my-1{margin-top:.25rem !important}.mr-1,.mx-1{margin-right:.25rem !important}.mb-1,.my-1{margin-bottom:.25rem !important}.ml-1,.mx-1{margin-left:.25rem !important}.m-2{margin:.5rem !important}.mt-2,.my-2{margin-top:.5rem !important}.mr-2,.mx-2{margin-right:.5rem !important}.mb-2,.my-2{margin-bottom:.5rem !important}.ml-2,.mx-2{margin-left:.5rem !important}.m-3{margin:1rem !important}.mt-3,.my-3{margin-top:1rem !important}.mr-3,.mx-3{margin-right:1rem !important}.mb-3,.my-3{margin-bottom:1rem !important}.ml-3,.mx-3{margin-left:1rem !important}.m-4{margin:1.5rem !important}.mt-4,.my-4{margin-top:1.5rem !important}.mr-4,.mx-4{margin-right:1.5rem !important}.mb-4,.my-4{margin-bottom:1.5rem !important}.ml-4,.mx-4{margin-left:1.5rem !important}.m-5{margin:3rem !important}.mt-5,.my-5{margin-top:3rem !important}.mr-5,.mx-5{margin-right:3rem !important}.mb-5,.my-5{margin-bottom:3rem !important}.ml-5,.mx-5{margin-left:3rem !important}.btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;color:#212529;cursor:pointer;display:inline-block;font-size:1rem;font-weight:400;line-height:1.5;padding:.375rem .75rem;text-align:center;transition:color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none;vertical-align:middle}.btn:hover{color:#212529;text-decoration:none}.btn:visited{color:#212529}.btn.focus,.btn:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.25);outline:0}.btn.disabled,.btn:disabled{opacity:.65}@media (prefers-reduced-motion: reduce){.btn{transition:none}}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{background-color:#007bff;border-color:#007bff;color:#fff}.btn-primary:visited{color:#fff}.btn-primary:hover{background-color:#0069d9;border-color:#0062cc;color:#fff}.btn-primary.focus,.btn-primary:focus{background-color:#0069d9;border-color:#0062cc;box-shadow:0 0 0 .2rem rgba(0,123,255,0.5);color:#fff}.btn-primary.disabled,.btn-primary:disabled{background-color:#007bff;border-color:#007bff;color:#fff}.btn-primary.active:not(:disabled):not(.disabled),.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{background-color:#0062cc;border-color:#005cbf;color:#fff}.btn-primary.active:not(:disabled):not(.disabled):focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.5)}.btn-secondary{background-color:#6c757d;border-color:#6c757d;color:#fff}.btn-secondary:visited{color:#fff}.btn-secondary:hover{background-color:#5a6268;border-color:#545b62;color:#fff}.btn-secondary.focus,.btn-secondary:focus{background-color:#5a6268;border-color:#545b62;box-shadow:0 0 0 .2rem rgba(108,117,125,0.5);color:#fff}.btn-secondary.disabled,.btn-secondary:disabled{background-color:#6c757d;border-color:#6c757d;color:#fff}.btn-secondary.active:not(:disabled):not(.disabled),.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{background-color:#545b62;border-color:#4e555b;color:#fff}.btn-secondary.active:not(:disabled):not(.disabled):focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.btn-success{background-color:#28a745;border-color:#28a745;color:#fff}.btn-success:visited{color:#fff}.btn-success:hover{background-color:#218838;border-color:#1e7e34;color:#fff}.btn-success.focus,.btn-success:focus{background-color:#218838;border-color:#1e7e34;box-shadow:0 0 0 .2rem rgba(40,167,69,0.5);color:#fff}.btn-success.disabled,.btn-success:disabled{background-color:#28a745;border-color:#28a745;color:#fff}.btn-success.active:not(:disabled):not(.disabled),.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{background-color:#1e7e34;border-color:#1c7430;color:#fff}.btn-success.active:not(:disabled):not(.disabled):focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.btn-info{background-color:#17a2b8;border-color:#17a2b8;color:#fff}.btn-info:visited{color:#fff}.btn-info:hover{background-color:#138496;border-color:#117a8b;color:#fff}.btn-info.focus,.btn-info:focus{background-color:#138496;border-color:#117a8b;box-shadow:0 0 0 .2rem rgba(23,162,184,0.5);color:#fff}.btn-info.disabled,.btn-info:disabled{background-color:#17a2b8;border-color:#17a2b8;color:#fff}.btn-info.active:not(:disabled):not(.disabled),.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{background-color:#117a8b;border-color:#10707f;color:#fff}.btn-info.active:not(:disabled):not(.disabled):focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,0.5)}.btn-warning{background-color:#ffc107;border-color:#ffc107;color:#212529}.btn-warning:visited{color:#212529}.btn-warning:hover{background-color:#e0a800;border-color:#d39e00;color:#212529}.btn-warning.focus,.btn-warning:focus{background-color:#e0a800;border-color:#d39e00;box-shadow:0 0 0 .2rem rgba(255,193,7,0.5);color:#212529}.btn-warning.disabled,.btn-warning:disabled{background-color:#ffc107;border-color:#ffc107;color:#212529}.btn-warning.active:not(:disabled):not(.disabled),.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{background-color:#d39e00;border-color:#c69500;color:#212529}.btn-warning.active:not(:disabled):not(.disabled):focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,0.5)}.btn-danger{background-color:#dc3545;border-color:#dc3545;color:#fff}.btn-danger:visited{color:#fff}.btn-danger:hover{background-color:#c82333;border-color:#bd2130;color:#fff}.btn-danger.focus,.btn-danger:focus{background-color:#c82333;border-color:#bd2130;box-shadow:0 0 0 .2rem rgba(220,53,69,0.5);color:#fff}.btn-danger.disabled,.btn-danger:disabled{background-color:#dc3545;border-color:#dc3545;color:#fff}.btn-danger.active:not(:disabled):not(.disabled),.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{background-color:#bd2130;border-color:#b21f2d;color:#fff}.btn-danger.active:not(:disabled):not(.disabled):focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,0.5)}.btn-light{background-color:#f8f9fa;border-color:#f8f9fa;color:#212529}.btn-light:visited{color:#212529}.btn-light:hover{background-color:#e2e6ea;border-color:#dae0e5;color:#212529}.btn-light.focus,.btn-light:focus{background-color:#e2e6ea;border-color:#dae0e5;box-shadow:0 0 0 .2rem rgba(248,249,250,0.5);color:#212529}.btn-light.disabled,.btn-light:disabled{background-color:#f8f9fa;border-color:#f8f9fa;color:#212529}.btn-light.active:not(:disabled):not(.disabled),.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{background-color:#dae0e5;border-color:#d3d9df;color:#212529}.btn-light.active:not(:disabled):not(.disabled):focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,0.5)}.btn-dark{background-color:#343a40;border-color:#343a40;color:#fff}.btn-dark:visited{color:#fff}.btn-dark:hover{background-color:#23272b;border-color:#1d2124;color:#fff}.btn-dark.focus,.btn-dark:focus{background-color:#23272b;border-color:#1d2124;box-shadow:0 0 0 .2rem rgba(52,58,64,0.5);color:#fff}.btn-dark.disabled,.btn-dark:disabled{background-color:#343a40;border-color:#343a40;color:#fff}.btn-dark.active:not(:disabled):not(.disabled),.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{background-color:#1d2124;border-color:#171a1d;color:#fff}.btn-dark.active:not(:disabled):not(.disabled):focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,0.5)}.btn-outline-primary{border-color:#007bff;color:#007bff}.btn-outline-primary:visited{color:#007bff}.btn-outline-primary:hover{background-color:#007bff;border-color:#007bff;color:#fff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{background-color:transparent;color:#007bff}.btn-outline-primary.active:not(:disabled):not(.disabled),.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{background-color:#007bff;border-color:#007bff;color:#fff}.btn-outline-primary.active:not(:disabled):not(.disabled):focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,0.5)}.btn-outline-secondary{border-color:#6c757d;color:#6c757d}.btn-outline-secondary:visited{color:#6c757d}.btn-outline-secondary:hover{background-color:#6c757d;border-color:#6c757d;color:#fff}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{background-color:transparent;color:#6c757d}.btn-outline-secondary.active:not(:disabled):not(.disabled),.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{background-color:#6c757d;border-color:#6c757d;color:#fff}.btn-outline-secondary.active:not(:disabled):not(.disabled):focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,0.5)}.btn-outline-success{border-color:#28a745;color:#28a745}.btn-outline-success:visited{color:#28a745}.btn-outline-success:hover{background-color:#28a745;border-color:#28a745;color:#fff}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{background-color:transparent;color:#28a745}.btn-outline-success.active:not(:disabled):not(.disabled),.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{background-color:#28a745;border-color:#28a745;color:#fff}.btn-outline-success.active:not(:disabled):not(.disabled):focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,0.5)}.btn-outline-info{border-color:#17a2b8;color:#17a2b8}.btn-outline-info:visited{color:#17a2b8}.btn-outline-info:hover{background-color:#17a2b8;border-color:#17a2b8;color:#fff}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,0.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{background-color:transparent;color:#17a2b8}.btn-outline-info.active:not(:disabled):not(.disabled),.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{background-color:#17a2b8;border-color:#17a2b8;color:#fff}.btn-outline-info.active:not(:disabled):not(.disabled):focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,0.5)}.btn-outline-warning{border-color:#ffc107;color:#ffc107}.btn-outline-warning:visited{color:#ffc107}.btn-outline-warning:hover{background-color:#ffc107;border-color:#ffc107;color:#212529}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,0.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{background-color:transparent;color:#ffc107}.btn-outline-warning.active:not(:disabled):not(.disabled),.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{background-color:#ffc107;border-color:#ffc107;color:#212529}.btn-outline-warning.active:not(:disabled):not(.disabled):focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,0.5)}.btn-outline-danger{border-color:#dc3545;color:#dc3545}.btn-outline-danger:visited{color:#dc3545}.btn-outline-danger:hover{background-color:#dc3545;border-color:#dc3545;color:#fff}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,0.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{background-color:transparent;color:#dc3545}.btn-outline-danger.active:not(:disabled):not(.disabled),.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{background-color:#dc3545;border-color:#dc3545;color:#fff}.btn-outline-danger.active:not(:disabled):not(.disabled):focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,0.5)}.btn-outline-light{border-color:#f8f9fa;color:#f8f9fa}.btn-outline-light:visited{color:#f8f9fa}.btn-outline-light:hover{background-color:#f8f9fa;border-color:#f8f9fa;color:#212529}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,0.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{background-color:transparent;color:#f8f9fa}.btn-outline-light.active:not(:disabled):not(.disabled),.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{background-color:#f8f9fa;border-color:#f8f9fa;color:#212529}.btn-outline-light.active:not(:disabled):not(.disabled):focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,0.5)}.btn-outline-dark{border-color:#343a40;color:#343a40}.btn-outline-dark:visited{color:#343a40}.btn-outline-dark:hover{background-color:#343a40;border-color:#343a40;color:#fff}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,0.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{background-color:transparent;color:#343a40}.btn-outline-dark.active:not(:disabled):not(.disabled),.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{background-color:#343a40;border-color:#343a40;color:#fff}.btn-outline-dark.active:not(:disabled):not(.disabled):focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,0.5)}.btn-link{color:#007bff;font-weight:400;text-decoration:none}.btn-link:hover{color:#0056b3;text-decoration:underline}.btn-link.focus,.btn-link:focus{box-shadow:none;text-decoration:underline}.btn-link.disabled,.btn-link:disabled{color:#6c757d;pointer-events:none}.btn-group-lg>.btn,.btn-lg{border-radius:.3rem;font-size:1.25rem;line-height:1.5;padding:.5rem 1rem}.btn-group-sm>.btn,.btn-sm{border-radius:.2rem;font-size:.875rem;line-height:1.5;padding:.25rem .5rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input.btn-block[type=button],input.btn-block[type=reset],input.btn-block[type=submit]{width:100%}.stretched-link::after{background-color:rgba(0,0,0,0);bottom:0;content:'';left:0;pointer-events:auto;position:absolute;right:0;top:0;z-index:1}.text-wrap{white-space:normal !important}.card{background-clip:border-box;background-color:#fff;border:1px solid rgba(0,0,0,0.125);border-radius:.25rem;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;position:relative;word-wrap:break-word}.card>hr{margin-left:0;margin-right:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;min-height:1px;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-bottom:0;margin-top:-.375rem}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{background-color:rgba(0,0,0,0.03);border-bottom:1px solid rgba(0,0,0,0.125);margin-bottom:0;padding:.75rem 1.25rem}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{background-color:rgba(0,0,0,0.03);border-top:1px solid rgba(0,0,0,0.125);padding:.75rem 1.25rem}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{border-bottom:0;margin-bottom:-.75rem;margin-left:-.625rem;margin-right:-.625rem}.card-header-pills{margin-left:-.625rem;margin-right:-.625rem}.card-img-overlay{bottom:0;left:0;padding:1.25rem;position:absolute;right:0;top:0}.card-img,.card-img-bottom,.card-img-top{-ms-flex-negative:0;flex-shrink:0;width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-left-radius:calc(.25rem - 1px);border-bottom-right-radius:calc(.25rem - 1px)}.w-100{width:100% !important}.shadow{box-shadow:0 0.5rem 1rem rgba(0,0,0,0.15) !important}.bg-primary{background-color:#007bff !important}button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc !important}a.bg-primary:focus,a.bg-primary:hover{background-color:#0062cc !important}a.text-primary:focus,a.text-primary:hover{color:#121416 !important}.bg-secondary{background-color:#6c757d !important}button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62 !important}a.bg-secondary:focus,a.bg-secondary:hover{background-color:#545b62 !important}a.text-secondary:focus,a.text-secondary:hover{color:#121416 !important}.bg-success{background-color:#28a745 !important}button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34 !important}a.bg-success:focus,a.bg-success:hover{background-color:#1e7e34 !important}a.text-success:focus,a.text-success:hover{color:#121416 !important}.bg-info{background-color:#17a2b8 !important}button.bg-info:focus,button.bg-info:hover{background-color:#117a8b !important}a.bg-info:focus,a.bg-info:hover{background-color:#117a8b !important}a.text-info:focus,a.text-info:hover{color:#121416 !important}.bg-warning{background-color:#ffc107 !important}button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00 !important}a.bg-warning:focus,a.bg-warning:hover{background-color:#d39e00 !important}a.text-warning:focus,a.text-warning:hover{color:#121416 !important}.bg-danger{background-color:#dc3545 !important}button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130 !important}a.bg-danger:focus,a.bg-danger:hover{background-color:#bd2130 !important}a.text-danger:focus,a.text-danger:hover{color:#121416 !important}.bg-light{background-color:#f8f9fa !important}button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5 !important}a.bg-light:focus,a.bg-light:hover{background-color:#dae0e5 !important}a.text-light:focus,a.text-light:hover{color:#121416 !important}.bg-dark{background-color:#343a40 !important}button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124 !important}a.bg-dark:focus,a.bg-dark:hover{background-color:#1d2124 !important}a.text-dark:focus,a.text-dark:hover{color:#121416 !important}.bg-white{background-color:#fff !important}button.bg-white:focus,button.bg-white:hover{background-color:#e6e6e6 !important}a.bg-white:focus,a.bg-white:hover{background-color:#e6e6e6 !important}a.text-white:focus,a.text-white:hover{color:#121416 !important}.text-primary{color:#007bff !important}.text-secondary{color:#6c757d !important}.text-success{color:#28a745 !important}.text-info{color:#17a2b8 !important}.text-warning{color:#ffc107 !important}.text-danger{color:#dc3545 !important}.text-light{color:#f8f9fa !important}.text-dark{color:#343a40 !important}.text-white{color:#fff !important}.text-body{color:#212529 !important}.text-muted{color:#6c757d !important}.text-black-50{color:rgba(0,0,0,0.5) !important}.text-white-50{color:rgba(255,255,255,0.5) !important}.bg-transparent{background-color:transparent !important}.text-justify{text-align:justify !important}.text-left{text-align:left !important}.text-right{text-align:right !important}.text-center{text-align:center !important}.font-weight-light{font-weight:300 !important}.font-weight-lighter{font-weight:lighter !important}.font-weight-normal{font-weight:400 !important}.font-weight-bold{font-weight:700 !important}.font-weight-bolder{font-weight:bolder !important}.font-italic{font-style:italic !important}.container{margin-left:auto;margin-right:auto;padding-left:15px;padding-right:15px;width:100%}@media (min-width: 576px){.container{max-width:540px}}@media (min-width: 768px){.container{max-width:720px}}@media (min-width: 992px){.container{max-width:960px}}@media (min-width: 1200px){.container{max-width:1140px}}.container-fluid,.container-lg,.container-md,.container-sm,.container-xl{margin-left:auto;margin-right:auto;padding-left:15px;padding-right:15px;width:100%}@media (min-width: 576px){.container,.container-sm{max-width:540px}}@media (min-width: 768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width: 992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width: 1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-left:-15px;margin-right:-15px}.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{padding-left:15px;padding-right:15px;position:relative;width:100%}@media (min-width: 576px){.col-sm{flex-basis:0;flex-grow:1;-ms-flex-positive:1;-ms-flex-preferred-size:0;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;max-width:100%;width:auto}.col-sm-1{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-sm-2{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-sm-5{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-sm-8{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-sm-11{-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}}@media (min-width: 768px){.col-md{flex-basis:0;flex-grow:1;-ms-flex-positive:1;-ms-flex-preferred-size:0;max-width:100%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;max-width:100%;width:auto}.col-md-1{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-md-2{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-md-5{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-md-8{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-md-11{-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}}@media (min-width: 992px){.col-lg{flex-basis:0;flex-grow:1;-ms-flex-positive:1;-ms-flex-preferred-size:0;max-width:100%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;max-width:100%;width:auto}.col-lg-1{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-lg-2{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-lg-5{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-lg-8{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-lg-11{-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}}@media (min-width: 1200px){.col-xl{flex-basis:0;flex-grow:1;-ms-flex-positive:1;-ms-flex-preferred-size:0;max-width:100%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;max-width:100%;width:auto}.col-xl-1{-ms-flex:0 0 8.33333%;flex:0 0 8.33333%;max-width:8.33333%}.col-xl-2{-ms-flex:0 0 16.66667%;flex:0 0 16.66667%;max-width:16.66667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.33333%;flex:0 0 33.33333%;max-width:33.33333%}.col-xl-5{-ms-flex:0 0 41.66667%;flex:0 0 41.66667%;max-width:41.66667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.33333%;flex:0 0 58.33333%;max-width:58.33333%}.col-xl-8{-ms-flex:0 0 66.66667%;flex:0 0 66.66667%;max-width:66.66667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.33333%;flex:0 0 83.33333%;max-width:83.33333%}.col-xl-11{-ms-flex:0 0 91.66667%;flex:0 0 91.66667%;max-width:91.66667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}}.d-flex{display:-ms-flexbox !important;display:flex !important}.sphinx-bs,.sphinx-bs *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sphinx-bs p{margin-top:0} diff --git a/_panels_static/panels-main.c949a650a448cc0ae9fd3441c0e17fb0.css b/_panels_static/panels-main.c949a650a448cc0ae9fd3441c0e17fb0.css new file mode 100644 index 0000000000..fc14abc85d --- /dev/null +++ b/_panels_static/panels-main.c949a650a448cc0ae9fd3441c0e17fb0.css @@ -0,0 +1 @@ +details.dropdown .summary-title{padding-right:3em !important;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}details.dropdown:hover{cursor:pointer}details.dropdown .summary-content{cursor:default}details.dropdown summary{list-style:none;padding:1em}details.dropdown summary .octicon.no-title{vertical-align:middle}details.dropdown[open] summary .octicon.no-title{visibility:hidden}details.dropdown summary::-webkit-details-marker{display:none}details.dropdown summary:focus{outline:none}details.dropdown summary:hover .summary-up svg,details.dropdown summary:hover .summary-down svg{opacity:1}details.dropdown .summary-up svg,details.dropdown .summary-down svg{display:block;opacity:.6}details.dropdown .summary-up,details.dropdown .summary-down{pointer-events:none;position:absolute;right:1em;top:.75em}details.dropdown[open] .summary-down{visibility:hidden}details.dropdown:not([open]) .summary-up{visibility:hidden}details.dropdown.fade-in[open] summary~*{-moz-animation:panels-fade-in .5s ease-in-out;-webkit-animation:panels-fade-in .5s ease-in-out;animation:panels-fade-in .5s ease-in-out}details.dropdown.fade-in-slide-down[open] summary~*{-moz-animation:panels-fade-in .5s ease-in-out, panels-slide-down .5s ease-in-out;-webkit-animation:panels-fade-in .5s ease-in-out, panels-slide-down .5s ease-in-out;animation:panels-fade-in .5s ease-in-out, panels-slide-down .5s ease-in-out}@keyframes panels-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes panels-slide-down{0%{transform:translate(0, -10px)}100%{transform:translate(0, 0)}}.octicon{display:inline-block;fill:currentColor;vertical-align:text-top}.tabbed-content{box-shadow:0 -.0625rem var(--tabs-color-overline),0 .0625rem var(--tabs-color-underline);display:none;order:99;padding-bottom:.75rem;padding-top:.75rem;width:100%}.tabbed-content>:first-child{margin-top:0 !important}.tabbed-content>:last-child{margin-bottom:0 !important}.tabbed-content>.tabbed-set{margin:0}.tabbed-set{border-radius:.125rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.tabbed-set>input{opacity:0;position:absolute}.tabbed-set>input:checked+label{border-color:var(--tabs-color-label-active);color:var(--tabs-color-label-active)}.tabbed-set>input:checked+label+.tabbed-content{display:block}.tabbed-set>input:focus+label{outline-style:auto}.tabbed-set>input:not(.focus-visible)+label{outline:none;-webkit-tap-highlight-color:transparent}.tabbed-set>label{border-bottom:.125rem solid transparent;color:var(--tabs-color-label-inactive);cursor:pointer;font-size:var(--tabs-size-label);font-weight:700;padding:1em 1.25em .5em;transition:color 250ms;width:auto;z-index:1}html .tabbed-set>label:hover{color:var(--tabs-color-label-active)} diff --git a/_panels_static/panels-variables.06eb56fa6e07937060861dad626602ad.css b/_panels_static/panels-variables.06eb56fa6e07937060861dad626602ad.css new file mode 100644 index 0000000000..adc6166222 --- /dev/null +++ b/_panels_static/panels-variables.06eb56fa6e07937060861dad626602ad.css @@ -0,0 +1,7 @@ +:root { +--tabs-color-label-active: hsla(231, 99%, 66%, 1); +--tabs-color-label-inactive: rgba(178, 206, 245, 0.62); +--tabs-color-overline: rgb(207, 236, 238); +--tabs-color-underline: rgb(207, 236, 238); +--tabs-size-label: 1rem; +} \ No newline at end of file diff --git a/_sources/docs.rst.txt b/_sources/docs.rst.txt new file mode 100644 index 0000000000..3f68441758 --- /dev/null +++ b/_sources/docs.rst.txt @@ -0,0 +1,265 @@ +.. vineyard documentation master file, created by + sphinx-quickstart on Tue Aug 27 10:19:05 2019. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +.. meta:: + :description: Vineyard (v6d), a CNCF sandbox project, is an in-memory immutable data manager + that provides **out-of-the-box high-level** abstraction and **zero-copy in-memory** sharing for + distributed data in big data tasks, such as graph analytics (e.g., `GraphScope`_), numerical + computing (e.g., `Mars`_), and machine learning. + :keywords: distributed-systems, distributed, shared-memory, graph-analytics, in-memory-storage, + big-data-analytics, distributed-comp + +.. figure:: images/vineyard-logo-rect.png + :width: 397 + :alt: Vineyard: an in-memory immutable data manager + :target: https://v6d.io + + *an in-memory immutable data manager* + +|PyPI| |FAQ| |Discussion| |Slack| |License| |ACM DL| + +Why bother? +----------- + +Sharing intermediate data between systems in modern big data and AI workflows +can be challenging, often causing significant bottlenecks in such jobs. Let's +consider the following fraud detection pipeline: + +.. figure:: images/fraud-detection-job.jpg + :width: 75% + :alt: A real-life fraud detection job + + A real-life fraud detection job + +From the pipeline, we observed: + +1. Users usually prefer to program with dedicated computing systems for different tasks in the + same applications, such as SQL and Python. + + **Integrating a new computing system into production environments demands high technical + effort to align with existing production environments in terms of I/O, failover, etc.** + +2. Data could be polymorphic. Non-relational data, such as tensors, dataframes (in Pandas) and + graphs/networks (in `GraphScope`_) are becoming increasingly prevalent. Tables and SQL may + not be the best way to store, exchange, or process them. + + **Transforming the data back and forth between different systems as "tables" could + result in a significant overhead.** + +3. Saving/loading the data to/from the external storage requires numerous memory copies and + incurs high IO costs. + +What is Vineyard? +----------------- + +Vineyard (v6d) is an **in-memory immutable data manager** that offers **out-of-the-box high-level** +abstraction and **zero-copy sharing** for distributed data in big data tasks, such as +graph analytics (e.g., `GraphScope`_), numerical computing (e.g., `Mars`_), and machine learning. + +Features +^^^^^^^^ + +Efficient data sharing +~~~~~~~~~~~~~~~~~~~~~~ + +Vineyard shares immutable data across different systems using shared memory without extra overheads, +eliminating the overhead of serialization/deserialization and IO when exchanging immutable +data between systems. + +Out-of-the-box data abstraction +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Vineyard defines a metadata-payload separated data model to capture the payload commonalities and +method commonalities between sharable objects in different programming languages and different +computing systems in a unified way. + +The :ref:`VCDL` (Vineyard Component Description Language) is specifically designed to annotate +sharable members and methods, enabling automatic generation of boilerplate code for minimal +integration effort. + +Pluggable I/O routines +~~~~~~~~~~~~~~~~~~~~~~ + +In many big data analytical tasks, a substantial portion of the workload consists of boilerplate +routines that are unrelated to the core computation. These routines include various IO adapters, +data partition strategies, and migration jobs. Due to different data structure abstractions across +systems, these routines are often not easily reusable, leading to increased complexity and redundancy. + +Vineyard provides common manipulation routines for immutable data as drivers, which extend +the capabilities of data structures by registering appropriate drivers. This enables out-of-the-box +reuse of boilerplate components across diverse computation jobs. + +Data orchestration on Kubernetes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Vineyard provides efficient distributed data sharing in cloud-native environments by embracing +cloud-native big data processing. Kubernetes helps Vineyard leverage the scale-in/out and +scheduling abilities of Kubernetes. + +Use cases +^^^^^^^^^ + +.. panels:: + :header: text-center + :container: container-lg pb-4 + :column: col-lg-4 col-md-4 col-sm-4 col-xs-12 p-2 + :body: text-center + + .. link-button:: # + :type: url + :text: Object manager + :classes: btn-block stretched-link + + Put and get arbitrary objects using Vineyard, in a zero-copy way! + + --- + + .. link-button:: # + :type: url + :text: Cross-system sharing + :classes: btn-block stretched-link + + Share large objects across computing systems. + + --- + + .. link-button:: # + :type: url + :text: Data orchestration + :classes: btn-block stretched-link + + Vineyard coordinates the flow of objects and jobs on Kubernetes based on data-aware scheduling. + +Get started now! +---------------- + +.. panels:: + :header: text-center + :column: col-lg-12 p-2 + + .. link-button:: notes/getting-started + :type: ref + :text: User Guides + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Get started with Vineyard. + + --- + + .. link-button:: notes/cloud-native/deploy-kubernetes + :type: ref + :text: Deploy on Kubernetes + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Deploy Vineyard on Kubernetes and accelerate big-data analytical workflows on cloud-native + infrastructures. + + --- + + .. link-button:: tutorials/tutorials + :type: ref + :text: Tutorials + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Explore use cases and tutorials where Vineyard can bring added value. + + --- + + .. link-button:: notes/developers + :type: ref + :text: Getting Involved + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Get involved and become part of the Vineyard community. + + --- + + .. link-button:: notes/developers/faq + :type: ref + :text: FAQ + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Frequently asked questions and discussions during the adoption of Vineyard. + +Read the Paper +-------------- + +- Wenyuan Yu, Tao He, Lei Wang, Ke Meng, Ye Cao, Diwen Zhu, Sanhong Li, Jingren Zhou. + `Vineyard: Optimizing Data Sharing in Data-Intensive Analytics `_. + ACM SIG Conference on Management of Data (SIGMOD), industry, 2023. |ACM DL|. + +Vineyard is a `CNCF sandbox project`_ and is made successful by its community. + +.. image:: https://v6d.io/_static/cncf-color.svg + :width: 400 + :alt: Vineyard is a CNCF sandbox project + +.. toctree:: + :maxdepth: 1 + :caption: User Guides + :hidden: + + notes/getting-started.rst + notes/architecture.rst + notes/key-concepts.rst + +.. toctree:: + :maxdepth: 1 + :caption: Cloud-Native + :hidden: + + notes/cloud-native/deploy-kubernetes.rst + notes/cloud-native/vineyard-operator.rst + Command-line tool + +.. toctree:: + :maxdepth: 1 + :caption: Tutorials + :hidden: + + tutorials/data-processing.rst + tutorials/kubernetes.rst + tutorials/extending.rst + +.. toctree:: + :maxdepth: 1 + :caption: Integration + :hidden: + + notes/integration-bigdata.rst + notes/integration-orchestration.rst + +.. toctree:: + :maxdepth: 2 + :caption: API Reference + :hidden: + + notes/references.rst + +.. toctree:: + :maxdepth: 1 + :caption: Developer Guides + :hidden: + + notes/developers.rst + notes/developers/faq.rst + +.. _Mars: https://github.com/mars-project/mars +.. _GraphScope: https://github.com/alibaba/GraphScope +.. _CNCF sandbox project: https://www.cncf.io/sandbox-projects/ + +.. |PyPI| image:: https://img.shields.io/pypi/v/vineyard?color=blue + :target: https://pypi.org/project/vineyard +.. |FAQ| image:: https://img.shields.io/badge/-FAQ-blue?logo=Read%20The%20Docs + :target: https://v6d.io/notes/faq.html +.. |Discussion| image:: https://img.shields.io/badge/Discuss-Ask%20Questions-blue?logo=GitHub + :target: https://github.com/v6d-io/v6d/discussions +.. |Slack| image:: https://img.shields.io/badge/Slack-Join%20%23vineyard-purple?logo=Slack + :target: https://slack.cncf.io/ +.. |License| image:: https://img.shields.io/github/license/v6d-io/v6d + :target: https://github.com/v6d-io/v6d/blob/main/LICENSE + +.. |ACM DL| image:: https://img.shields.io/badge/ACM%20DL-10.1145%2F3589780-blue + :target: https://dl.acm.org/doi/10.1145/3589780 diff --git a/_sources/notes/architecture.rst.txt b/_sources/notes/architecture.rst.txt new file mode 100644 index 0000000000..72e8d77d00 --- /dev/null +++ b/_sources/notes/architecture.rst.txt @@ -0,0 +1,190 @@ +.. _architecture-of-vineyard: + +Architecture +============ + +Overview +-------- + +The following figure illustrates the architecture of Vineyard. + +.. figure:: ../images/vineyard_arch.jpg + :width: 75% + :alt: Architecture of Vineyard + + Architecture of Vineyard + +Server side +^^^^^^^^^^^ + +On the server (daemon) side (i.e., the aforementioned Vineyard instance), there are +three primary components: + +1. The **shared memory** is the memory space in Vineyard that is shared with Vineyard + clients via the UNIX domain socket through memory mapping. + + As previously mentioned, the partitions of the distributed data reside in the + shared memory of the corresponding Vineyard instance in the cluster. + +2. The **metadata manager** is responsible for managing the metadata of the data stored + in Vineyard. + + The metadata manager maintains the metadata (structures, layouts, and properties) of + the data to provide high-level abstractions (e.g., graphs, tensors, dataframes). + The metadata managers in a Vineyard cluster communicate with each other through + the backend key-value store, such as etcd server, to ensure the consistency of the + distributed data stored in Vineyard. + +3. The **IPC/RPC servers** manage the IPC/RPC connections from Vineyard + clients for data sharing. + + Specifically, the client can obtain the metadata of the data stored in Vineyard through + both IPC and RPC connections. However, to access the data partition, the client must connect + to the Vineyard instance via the UNIX domain socket, as the data + sharing occurs through the system call of memory mapping, which requires the client to be on + the same machine as the Vineyard instance. + +.. _client-side: + +Client side +^^^^^^^^^^^ + +On the client side, the core component is the **Vineyard client**. The client side +includes both low-level APIs for accessing Vineyard instances in a precise +manner and high-level APIs for data structure sharing, manipulation, and +routine reuse (e.g., I/O drivers). More specifically, + +1. The **IPC client** communicates with *local* Vineyard instances by connecting + to the UNIX domain socket. + + The IPC client is used to establish an IPC connection between the Vineyard server and + the client, enabling memory-sharing (by :code:`mmap` and transferring the file descriptor) + between the Vineyard server and the computing engines. + +2. The **RPC client** communicates with *remote* Vineyard instances by connecting + to the TCP port that the Vineyard daemon is bound to. + + Unlike the IPC client, the RPC doesn't allow memory-sharing between processes + but is useful for retrieving the metadata of objects in the Vineyard cluster. + +3. The **builders and resolvers** for out-of-the-box high-level data abstractions + offer a convenient way for applications to consume objects in Vineyard and + produce result objects into Vineyard. + + The builders and resolvers adopt an extensible design where users can register + their own builders and resolvers for their newly defined data types, as well as + new builders and resolvers that build ad-hoc engine-specific data structures + as Vineyard objects and wrap Vineyard objects as engine-specific data types + at a low cost. + + The builders, resolvers, and the registry are part of the language-specific + SDKs of Vineyard. Currently, Python and C++ are officially supported, and the Rust + and Go SDKs are under heavy development. + +4. The **pluggable drivers** assign specific functionalities to certain types of data + in Vineyard. + + In particular, I/O drivers synchronize with external storages such as databases and file + systems to read data into and write data from Vineyard, while partition and + re-partition drivers reorganize the distributed graphs stored in Vineyard to + balance the workload. + + .. note:: + + The drivers typically employ the low-level APIs for precise operations. + +5. **Object migration** is the mechanism implemented on the client side to + migrate objects between Vineyard instances in a cluster. Object migration + is usually needed when the computing engines cannot be scheduled to co-locate + with the data required by the jobs. + + Object migration is implemented on the client side as a process pair where the + sender and receiver are both connected to (different) Vineyard instances and + communicate with each other using TCP to move objects between Vineyard instances. + We don't put the object migration on the server side to decouple the functionalities + and allow users to register a more efficient object migration implemented on + their own deployment infrastructures, e.g.,leveraging RDMA and other high-performance + network technologies. + +Core features +------------- + +Zero-cost in-memory data sharing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Vineyard provides zero-cost data sharing through memory-mapping, as data objects +in Vineyard are immutable. When an object is created, we allocate blobs in +Vineyard to store the data payload. On the other hand, when retrieving the object, +we map the blob from the Vineyard instance into the application process using +inter-process memory mapping techniques, ensuring that no memory copy is involved +in sharing the data payload. + +Distributed data sharing in big data tasks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By examining the practices of big data tasks such as numeric computing, machine learning, +and graph analysis, we have identified four key properties of the data involved: + ++ Distributed and each partitioned fragment usually fits into memory; ++ Immutable, i.e., never modified after creation; ++ With complex structure, e.g., graph in CSR format; ++ Required to share between different computation systems and programming languages. + +Vineyard is designed to address these challenges with: + ++ Composable design for Vineyard objects; ++ Immutable zero-cost in-memory data sharing via memory mapping; ++ Out-of-the-box high-level data abstraction for complex data structures; ++ Extensible design for builder/resolver/driver, enabling flexible cross-system and + cross-language data sharing. + +In general, Vineyard's design choices are fully determined by addressing +the difficulties in handling large-scale distributed data in practice. + +Out-of-the-box high-level data abstraction +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Vineyard objects are stored with structures and high-level abstractions. +For instance, a graph with CSR format in Vineyard stores the index along with +the vertices and edges, enabling operations like edge iteration based on the +index. This means users don't have to implement the index-building +function and edge iterators themselves, which is often required in +existing big data practices. + +Convenient data integration +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The extensible design of builder/resolver/driver allows for convenient extension +of existing Vineyard objects to different programming languages. Moreover, +with codegen tools in Vineyard, users can easily transplant their +data structures into Vineyard with only a few annotations. + +Data orchestration in a Python notebook +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Using Vineyard as the common data orchestration engine throughout the end-to-end +big data processing, users can hold large-scale distributed data as variables +of Vineyard objects in Python. As long as the computation modules +involved provide Python APIs, users can write down the entire processing +pipeline in a Python notebook. By running the Python script, users can +manage trillions of data and different computation systems in the background +distributedly across the cluster. + +Non-goals and limitations +------------------------- + +*NO* mutable objects +^^^^^^^^^^^^^^^^^^^^ + +Once a Vineyard object is created and sealed in the Vineyard instance, it +becomes immutable and can NOT be modified anymore. Thus, Vineyard is not +suitable for use as a data cache to store mutable data that changes +rapidly along the processing pipeline. + +*NO* instant remote data accessing +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The partitions of distributed data are stored distributedly in corresponding +Vineyard instances of the cluster. Only the client on the same machine can access +the data partition. In order to access a remote partition, data migration APIs of +Vineyard can be invoked to trigger the migration process, but not for instant accessing. diff --git a/_sources/notes/cloud-native/deploy-kubernetes.rst.txt b/_sources/notes/cloud-native/deploy-kubernetes.rst.txt new file mode 100644 index 0000000000..0d94b7b24e --- /dev/null +++ b/_sources/notes/cloud-native/deploy-kubernetes.rst.txt @@ -0,0 +1,200 @@ +.. _deploy-on-kubernetes: + +Deploy on Kubernetes +==================== + +Vineyard is managed by the :ref:`vineyard-operator` on Kubernetes. + +Install vineyard-operator +------------------------- + +There are two recommended methods for installing the vineyard operator: using Helm (preferred) or +installing directly from the source code. + +.. note:: + + Prior to installing the vineyard operator, ensure that you have a Kubernetes cluster and kubectl + installed. In this guide, we will use `kind`_ to create a cluster. + +Before proceeding with the vineyard installation, it is essential to install cert-manager, as it is required +by the webhook components within the vineyard operator: + +Option #1: Install from helm chart (recommended) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: bash + + $ helm repo add vineyard https://vineyard.oss-ap-southeast-1.aliyuncs.com/charts/ + $ helm repo update + $ helm install vineyard-operator vineyard/vineyard-operator \ + --namespace vineyard-system \ + --create-namespace + +Wait for the vineyard operator until ready. + +Option #2: Install form source code +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1. Clone the vineyard repo: + + .. code:: bash + + $ git clone https://github.com/v6d-io/v6d.git + +2. Build the vineyard operator's Docker image: + + .. code:: bash + + $ cd k8s + $ make -C k8s docker-build + + .. caution:: + + With `kind`_, you need to first import the image into the kind cluster: + + .. code:: bash + + $ kind load docker-image vineyardcloudnative/vineyard-operator:latest + +3. Install the cert-manager + + .. code:: bash + + $ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.yaml + + .. note:: + + Please wait the cert-manager for a while until it is ready before installing the + vineyard operator. + +4. Next, deploy the vineyard operator: + + .. code:: bash + + $ make -C k8s deploy + +Wait vineyard-operator ready +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Once the operator is installed, its deployment can be checked using :code:`kubectl`: + +.. code:: bash + + $ kubectl get all -n vineyard-system + +.. admonition:: Expected output + :class: admonition-details + + .. code:: bash + + NAME READY STATUS RESTARTS AGE + pod/vineyard-controller-manager-5c6f4bc454-8xm8q 2/2 Running 0 62m + + NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + service/vineyard-controller-manager-metrics-service ClusterIP 10.96.240.173 8443/TCP 62m + service/vineyard-webhook-service ClusterIP 10.96.41.132 443/TCP 62m + + NAME READY UP-TO-DATE AVAILABLE AGE + deployment.apps/vineyard-controller-manager 1/1 1 1 62m + + NAME DESIRED CURRENT READY AGE + replicaset.apps/vineyard-controller-manager-5c6f4bc454 1 1 1 62m + +Create vineyard cluster +----------------------- + +Once the vineyard operator becomes ready, you can create a vineyard cluster by creating a +:code:`Vineyardd` `CRD`_. The following is an example of creating a vineyard cluster with 3 daemon +replicas: + +.. code:: yaml + + $ cat < 2379/TCP 48s + service/etcd0 ClusterIP 10.96.128.87 2379/TCP,2380/TCP 48s + service/etcd1 ClusterIP 10.96.72.116 2379/TCP,2380/TCP 48s + service/etcd2 ClusterIP 10.96.99.182 2379/TCP,2380/TCP 48s + service/vineyard-controller-manager-metrics-service ClusterIP 10.96.240.173 8443/TCP 72s + service/vineyard-webhook-service ClusterIP 10.96.41.132 443/TCP 72s + service/vineyardd-sample-rpc ClusterIP 10.96.102.183 9600/TCP 48s + + NAME READY UP-TO-DATE AVAILABLE AGE + deployment.apps/vineyard-controller-manager 1/1 1 1 72s + deployment.apps/vineyardd-sample 3/3 3 3 48s + + NAME DESIRED CURRENT READY AGE + replicaset.apps/vineyard-controller-manager-5c6f4bc454 1 1 1 72s + replicaset.apps/vineyardd-sample-5cc797668f 3 3 3 48s + +References +---------- + +In addition to deploying and managing the vineyard cluster, the operator plays a crucial role in scheduling +workloads on vineyard. This optimizes data sharing between tasks in workflows and triggers necessary data +movement or transformation tasks. Detailed references and examples can be found in :code:`vineyard-operator`. + +To simplify interactions with vineyard on Kubernetes, we offer a command-line tool, :code:`vineyardctl`, which +automates much of the boilerplate configuration required when deploying workflows with vineyard on Kubernetes. + +.. panels:: + :header: text-center + :column: col-lg-12 p-2 + + .. link-button:: ./vineyard-operator + :type: ref + :text: Vineyard operator + :classes: btn-block stretched-link text-left + ^^^^^^^^^^^^ + Vineyard operator manages vineyard cluster and orchestrates shared objects on Kubernetes. + + --- + + .. link-button:: ./vineyardctl + :type: ref + :text: vineyardctl + :classes: btn-block stretched-link text-left + ^^^^^^^^^^^^ + :code:`vineyardctl` is the command-line tool for working with the Vineyard Operator. + +.. _kind: https://kind.sigs.k8s.io +.. _CRD: https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions diff --git a/_sources/notes/cloud-native/vineyard-operator.rst.txt b/_sources/notes/cloud-native/vineyard-operator.rst.txt new file mode 100644 index 0000000000..138e0130b2 --- /dev/null +++ b/_sources/notes/cloud-native/vineyard-operator.rst.txt @@ -0,0 +1,1882 @@ +.. _vineyard-operator: + +Vineyard Operator +================= + +Architecture +------------ + +The following figure demonstrates the architecture of vineyard operator. + +.. figure:: ../../images/vineyard_operator_arch.png + :width: 75% + :alt: Architecture of vineyard operator + + Architecture of vineyard operator + +.. contents:: Table of Contents + :depth: 2 + :local: + :class: this-will-duplicate-information-and-it-is-still-useful-here + +Create a vineyard Cluster +------------------------- + +After successfully installing the vineyard operator (refer to :ref:`deploy-on-kubernetes` +for installation details), you can effortlessly create a vineyard cluster by utilizing +the :code:`Vineyardd` CRD. The following example demonstrates the creation of a vineyard +cluster with 3 daemon replicas: + +.. note:: + + The namespace of the vineyard cluster must be the same as the namespace of the + vineyard operator, as the vineyard cluster will use the vineyard operator's + service account. + +.. code:: yaml + + $ cat < 2379/TCP 48s + service/etcd0 ClusterIP 10.96.128.87 2379/TCP,2380/TCP 48s + service/etcd1 ClusterIP 10.96.72.116 2379/TCP,2380/TCP 48s + service/etcd2 ClusterIP 10.96.99.182 2379/TCP,2380/TCP 48s + service/vineyard-controller-manager-metrics-service ClusterIP 10.96.240.173 8443/TCP 72s + service/vineyard-webhook-service ClusterIP 10.96.41.132 443/TCP 72s + service/vineyardd-sample-rpc ClusterIP 10.96.102.183 9600/TCP 48s + + NAME READY UP-TO-DATE AVAILABLE AGE + deployment.apps/vineyard-controller-manager 1/1 1 1 72s + deployment.apps/vineyardd-sample 3/3 3 3 48s + + NAME DESIRED CURRENT READY AGE + replicaset.apps/vineyard-controller-manager-5c6f4bc454 1 1 1 72s + replicaset.apps/vineyardd-sample-5cc797668f 3 3 3 48s + +The detailed configuration entries for creating a vineyard cluster are listed as follows, + +.. admonition:: Vineyardd Configurations + :class: admonition-details + + .. list-table:: + :widths: 15 10 60 15 + :header-rows: 1 + + * - Option Name + - Type + - Description + - Default Value + + * - replicas + - int + - The replicas of vineyardd. + - 3 + + * - | etcdReplicas + - int + - The etcd replicas of vineyard + - 1 + + * - | vineyard. + | image + - string + - The image name of vineyardd container. + - | "vineyardcloudnative/ + | vineyardd:latest" + + * - | vineyard. + | imagePullPolicy + - string + - The image pull policy of vineyardd image. + - nil + + * - | vineyard. + | syncCRDs + - bool + - Synchronize CRDs when persisting objects + - true + + * - | vineyard. + | socket + - string + - The ipc socket file of vineyardd. + - nil + + * - | vineyard. + | size + - string + - The shared memory size for vineyardd. + - nil + + * - | vineyard. + | reserveMemory + - bool + - Reserving enough physical memory pages for vineyardd. + - false + + * - | vineyard. + | streamThreshold + - int64 + - The memory threshold of streams + (percentage of total memory) + - nil + + * - | vineyard. + | spill. + | Name + - string + - The name of the spill config, + if set we'll enable the spill module. + - nil + + * - | vineyard. + | spill. + | path + - string + - The path of spilling. + - nil + + * - | vineyard. + | spill. + | spillLowerRate + - string + - The low watermark of spilling memory. + - nil + + * - | vineyard. + | spill. + | spillUpperRate + - string + - The high watermark of triggering spilling. + - nil + + * - | vineyard. + | spill. + | persistent + | VolumeSpec + - | corev1. + | Persistent + | VolumeSpec + - The PV of the spilling for persistent storage. + - nil + + * - | vineyard. + | spill. + | persistent + | VolumeClaimSpec + - | corev1. + | Persistent + | VolumeClaimSpec + - The PVC of the spilling for the persistent storage. + - nil + + * - | vineyard. + | env + - []corev1.EnvVar + - The environment of vineyardd. + - nil + + * - | vineyard. + | env + - []corev1.EnvVar + - The environment of vineyardd. + - nil + + * - | pluginImage. + | backupImage + - string + - The image of backup operation + - "ghcr.io/v6d-io/v6d/backup-job" + + * - | pluginImage. + | recoverImage + - string + - The image of recover operation + - "ghcr.io/v6d-io/v6d/recover-job" + + * - | pluginImage. + | daskRepartitionImage + - string + - The image of dask repartition operation + - "ghcr.io/v6d-io/v6d/dask-repartition" + + * - | pluginImage. + | localAssemblyImage + - string + - The image of local assembly operation + - "ghcr.io/v6d-io/v6d/local-assembly" + + * - | pluginImage. + | distributedAssemblyImage + - string + - The image of distributed assembly operation + - "ghcr.io/v6d-io/v6d/distributed-assembly" + + * - | metric. + | image + - string + - The image name of metric. + - nil + + * - | metric. + | imagePullPolicy + - string + - The image pull policy of metric. + - nil + + * - | service. + | type + - string + - The service type of vineyardd service. + - nil + + * - | service. + | port + - int + - The service port of vineyardd service + - nil + + * - | volume. + | pvcName + - string + - The pvc name of vineyard socket. + - nil + + * - | volume. + | mountPath + - string + - The mount path of pvc. + - nil + +Installing vineyard as sidecar +------------------------------ + +Vineyard can be seamlessly integrated as a sidecar container within a pod. We offer the `Sidecar` +Custom Resource Definition (CRD) for configuring and managing the sidecar container. The `Sidecar` +CRD shares many similarities with the `Vineyardd` CRD, and the following list presents all +available configurations. + +.. admonition:: Sidecar Configurations + :class: admonition-details + + .. list-table:: + :widths: 15 10 60 15 + :header-rows: 1 + + * - Option Name + - Type + - Description + - Default Value + + * - selector + - string + - The label selector of your app workload. Use '=' to separate key and value. + - "" + + * - replicas + - int + - The replicas of your workload that needs to injected with vineyard sidecar. + - 0 + + * - | vineyard. + | image + - string + - The image name of vineyard sidecar container. + - | "vineyardcloudnative/ + | vineyardd:latest" + + * - | vineyard. + | imagePullPolicy + - string + - The image pull policy of vineyard sidecar image. + - nil + + * - | vineyard. + | syncCRDs + - bool + - Synchronize CRDs when persisting objects + - true + + * - | vineyard. + | socket + - string + - The ipc socket file of vineyard sidecar. + - nil + + * - | vineyard. + | size + - string + - The shared memory size for vineyard sidecar. + - nil + + * - | vineyard. + | reserveMemory + - bool + - Reserving enough physical memory pages for vineyardd. + - false + + * - | vineyard. + | streamThreshold + - int64 + - The memory threshold of streams + (percentage of total memory) + - nil + + * - | vineyard. + | spill. + | Name + - string + - The name of the spill config, + if set we'll enable the spill module. + - nil + + * - | vineyard. + | spill. + | path + - string + - The path of spilling. + - nil + + * - | vineyard. + | spill. + | spillLowerRate + - string + - The low watermark of spilling memory. + - nil + + * - | vineyard. + | spill. + | spillUpperRate + - string + - The high watermark of triggering spilling. + - nil + + * - | vineyard. + | spill. + | persistent + | VolumeSpec + - | corev1. + | Persistent + | VolumeSpec + - The PV of the spilling for persistent storage. + - nil + + * - | vineyard. + | spill. + | persistent + | VolumeClaimSpec + - | corev1. + | Persistent + | VolumeClaimSpec + - The PVC of the spilling for the persistent storage. + - nil + + * - | vineyard. + | env + - []corev1.EnvVar + - The environment of vineyard sidecar. + - nil + + * - | vineyard. + | memory + - string + - The requested memory of vineyard sidecar container. + - "" + + * - | vineyard. + | cpu + - string + - The requested cpu of vineyard sidecar container. + - "" + + * - | metric. + | enable + - bool + - Enable the metrics in vineyard sidecar. + - false + + * - | metric. + | image + - string + - The image name of metric. + - nil + + * - | metric. + | imagePullPolicy + - string + - The image pull policy of metric. + - nil + + * - | service. + | type + - string + - The service type of vineyard sidecar service. + - nil + + * - | service. + | port + - int + - The service port of vineyard sidecar service + - nil + + * - | volume. + | pvcName + - string + - The pvc name of vineyard socket. + - nil + + * - | volume. + | mountPath + - string + - The mount path of pvc. + - nil + +Besides, We provide some labels and annotations to help users to use the sidecar in vineyard operator. +The following are all labels that we provide: + +.. list-table:: Sidecar Configurations + :widths: 25 15 60 + :header-rows: 1 + + * - Name + - Yaml Fields + - Description + + * - "sidecar.v6d.io/enabled" + - labels + - Enable the sidecar. + + * - "sidecar.v6d.io/name" + - annotations + - The name of sidecar cr. If the name is `default`, the default sidecar cr will be created. + +There are two methods to install vineyard as a sidecar: + +- Utilize the **default sidecar configuration**. Users should add two annotations, + **sidecar.v6d.io/enabled: true** and **sidecar.v6d.io/name: default**, to their app's YAML. + This will create a default sidecar Custom Resource (CR) for observation. + +- Employ the **custom sidecar configuration**. Users must first create a custom sidecar CR, + such as `sidecar-demo`, and then add two annotations, **sidecar.v6d.io/enabled: true** and + **sidecar.v6d.io/name: sidecar-demo**, to their app's YAML. + +The following example demonstrates how to install vineyard as a sidecar container within a +pod. First, install the vineyard operator according to the previous steps, and then create +a namespace with the specific label `sidecar-injection: enabled` to enable the sidecar. + +.. code:: bash + + $ kubectl create namespace vineyard-job + $ kubectl label namespace vineyard-job sidecar-injection=enabled + + +Next, use the following YAML to inject the default sidecar into the pod. + +.. note:: + + Please configure the command field of your app container to be in the format + **["/bin/sh" or "/bin/bash", "-c", (your app command)]**. After injecting the vineyard + sidecar, the command field will be modified to **["/bin/sh" or "/bin/bash", "-c", + while [ ! -e /var/run/vineyard.sock ]; do sleep 1; done;" + (your app command)]** to + ensure that the vineyard sidecar is ready before the app container starts. + +.. code:: yaml + + $ cat < node1 (consume 0-3 chunks) + replica2 -> node1 (consume 4-7 chunks) + replica3 -> node2 (consume 9-11 chunks, the other chunks will be migrated to the node) + +Utilizing the Vineyard Scheduler +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The Vineyard scheduler is integrated into the Vineyard operator and deployed alongside it. +This scheduler plugin relies on specific annotations and labels to provide necessary input +information. The required configurations are listed below in a clear and comprehensive manner: + +.. admonition:: Scheduler Plugin Configurations + :class: admonition-details + + .. list-table:: + :widths: 25 15 60 + :header-rows: 1 + + * - Name + - Yaml Fields + - Description + + * - "scheduling.k8s.v6d.io/required" + - annotations + - All jobs required by the job. If there are + more than two tasks, use the concatenator '.' + to concatenate them into a string. + E.g. `job1.job2.job3`. + If there is no required jobs, set `none`. + + * - "scheduling.k8s.v6d.io/vineyardd" + - labels + - The name or namespaced name of vineyardd. e.g., + `vineyard-sample` or + `vineyard-system/vineyard-sample`. + + * - "scheduling.k8s.v6d.io/job "" + - labels + - The job name. + + * - "schedulerName" + - spec + - The vineyard scheduler's name, and the + default value is `vineyard-scheduler`. + +In this section, we will demonstrate a comprehensive example of utilizing the Vineyard +scheduler. To begin, ensure that the Vineyard operator and Vineyard daemon server are +installed by following the steps outlined earlier. Then, proceed to deploy `workflow-job1`_ +as shown below. + +.. code:: bash + + $ kubectl create ns vineyard-job + +.. code:: yaml + + $ cat < 1 kind-worker2 + o001c8729e4590626 o001c8729e4590626 s001c8729e458f47a vineyard::Tensor 2 kind-worker3 + + # when a job is scheduled, the scheduler will create a configmap to record the globalobject id + # that the next job will consume. + $ kubectl get configmap v6d-workflow-demo-job1 -n vineyard-job -o yaml + apiVersion: v1 + data: + kind-worker3: o001c8729e4590626 + v6d-workflow-demo-job1: o001c8729e49e06b8 + kind: ConfigMap + ... + +Then deploy the `workflow-job2`_ as follows. + +.. code:: yaml + + $ cat < operation -> job2. + +``` +vineyardctl create operation [flags] +``` + +**SEE ALSO** + +* [vineyardctl create](#vineyardctl-create) - Create a vineyard jobs on kubernetes + +### Examples + +```shell + # create a local assembly operation between job1 and job2 + vineyardctl create operation --name assembly \ + --type local \ + --require job1 \ + --target job2 \ + --timeoutSeconds 600 + + # create a distributed assembly operation between job1 and job2 + vineyardctl create operation --name assembly \ + --type distributed \ + --require job1 \ + --target job2 \ + --timeoutSeconds 600 + + # create a dask repartition operation between job1 and job2 + vineyardctl create operation --name repartition \ + --type dask \ + --require job1 \ + --target job2 \ + --timeoutSeconds 600 +``` + +### Options + +``` + -h, --help help for operation + --kind string the kind of operation, including "assembly" and "repartition" + --name string the name of operation + --require string the job that need an operation to be executed + --target string the job that need to be executed before this operation + --timeoutSeconds int the timeout seconds of operation (default 600) + --type string the type of operation: for assembly, it can be "local" or "distributed"; for repartition, it can be "dask" +``` + +## `vineyardctl create recover` + +Create a recover cr to recover the current vineyard cluster on kubernetes + +### Synopsis + +Recover the current vineyard cluster on kubernetes. You could +recover all objects from a backup of vineyard cluster. Usually, +the recover crd should be created in the same namespace of +the backup job. + +Notice, the command is used to create a recover cr for the +vineyard operator and you must deploy the vineyard operator +and vineyard cluster before using it. + +``` +vineyardctl create recover [flags] +``` + +**SEE ALSO** + +* [vineyardctl create](#vineyardctl-create) - Create a vineyard jobs on kubernetes + +### Examples + +```shell + # create a recover cr for a backup job in the same namespace + vineyardctl create recover --backup-name vineyardd-sample -n vineyard-system +``` + +### Options + +``` + --backup-name string the name of backup job (default "vineyard-backup") + -h, --help help for recover + --recover-name string the name of recover job (default "vineyard-recover") +``` + +## `vineyardctl delete` + +Delete the vineyard components from kubernetes + +**SEE ALSO** + +* [vineyardctl](#vineyardctl) - vineyardctl is the command-line tool for interact with the Vineyard Operator. +* [vineyardctl delete backup](#vineyardctl-delete-backup) - Delete the backup job on kubernetes +* [vineyardctl delete cert-manager](#vineyardctl-delete-cert-manager) - Delete the cert-manager on kubernetes +* [vineyardctl delete operation](#vineyardctl-delete-operation) - Delete the operation from kubernetes +* [vineyardctl delete operator](#vineyardctl-delete-operator) - Delete the vineyard operator from kubernetes +* [vineyardctl delete recover](#vineyardctl-delete-recover) - Delete the recover job from kubernetes +* [vineyardctl delete vineyard-cluster](#vineyardctl-delete-vineyard-cluster) - Delete the vineyard cluster from kubernetes +* [vineyardctl delete vineyard-deployment](#vineyardctl-delete-vineyard-deployment) - delete vineyard-deployment will delete the vineyard deployment without vineyard operator +* [vineyardctl delete vineyardd](#vineyardctl-delete-vineyardd) - Delete the vineyardd cluster from kubernetes + +### Examples + +```shell + # delete the default vineyard cluster on kubernetes + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config delete + + # delete the default vineyard operator on kubernetes + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config delete operator + + # delete the default cert-manager on kubernetes + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config delete cert-manager + + # delete the default vineyardd on kubernetes + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config delete vineyardd +``` + +### Options + +``` + -h, --help help for delete +``` + +## `vineyardctl delete backup` + +Delete the backup job on kubernetes + +### Synopsis + +Delete the backup job on kubernetes. + +``` +vineyardctl delete backup [flags] +``` + +**SEE ALSO** + +* [vineyardctl delete](#vineyardctl-delete) - Delete the vineyard components from kubernetes + +### Examples + +```shell + # delete the default backup job + vineyardctl delete backup +``` + +### Options + +``` + --backup-name string the name of backup job (default "vineyard-backup") + -h, --help help for backup +``` + +## `vineyardctl delete cert-manager` + +Delete the cert-manager on kubernetes + +### Synopsis + +Delete the cert-manager in the cert-manager namespace. +The default version of cert-manager is v1.9.1. + +``` +vineyardctl delete cert-manager [flags] +``` + +**SEE ALSO** + +* [vineyardctl delete](#vineyardctl-delete) - Delete the vineyard components from kubernetes + +### Examples + +```shell + # delete the default version(v1.9.1) of cert-manager + vineyardctl --kubeconfig $HOME/.kube/config delete cert-manager +``` + +### Options + +``` + -h, --help help for cert-manager +``` + +## `vineyardctl delete operation` + +Delete the operation from kubernetes + +``` +vineyardctl delete operation [flags] +``` + +**SEE ALSO** + +* [vineyardctl delete](#vineyardctl-delete) - Delete the vineyard components from kubernetes + +### Examples + +```shell + # delete the operation named "assembly-test" in the "vineyard-system" namespace + vineyardctl delete operation --name assembly-test +``` + +### Options + +``` + -h, --help help for operation + --name string the name of operation +``` + +## `vineyardctl delete operator` + +Delete the vineyard operator from kubernetes + +``` +vineyardctl delete operator [flags] +``` + +**SEE ALSO** + +* [vineyardctl delete](#vineyardctl-delete) - Delete the vineyard components from kubernetes + +### Examples + +```shell + # delete the default vineyard operator in the vineyard-system namespace + vineyardctl delete operator + + # delete the vineyard operator in a specific namespace + vineyardctl delete operator -n +``` + +### Options + +``` + -h, --help help for operator +``` + +## `vineyardctl delete recover` + +Delete the recover job from kubernetes + +``` +vineyardctl delete recover [flags] +``` + +**SEE ALSO** + +* [vineyardctl delete](#vineyardctl-delete) - Delete the vineyard components from kubernetes + +### Examples + +```shell + # delete the default recover job on kubernetes + vineyardctl delete recover +``` + +### Options + +``` + -h, --help help for recover + --recover-name string the name of recover job (default "vineyard-recover") +``` + +## `vineyardctl delete vineyard-cluster` + +Delete the vineyard cluster from kubernetes + +``` +vineyardctl delete vineyard-cluster [flags] +``` + +**SEE ALSO** + +* [vineyardctl delete](#vineyardctl-delete) - Delete the vineyard components from kubernetes + +### Examples + +```shell + # delete the default vineyard cluster on kubernetes + vineyardctl delete vineyard-cluster +``` + +### Options + +``` + -h, --help help for vineyard-cluster +``` + +## `vineyardctl delete vineyard-deployment` + +delete vineyard-deployment will delete the vineyard deployment without vineyard operator + +``` +vineyardctl delete vineyard-deployment [flags] +``` + +**SEE ALSO** + +* [vineyardctl delete](#vineyardctl-delete) - Delete the vineyard components from kubernetes + +### Examples + +```shell + # delete the default vineyard deployment in the vineyard-system namespace + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config delete vineyard-deployment + + # delete the vineyard deployment with specific name in the vineyard-system namespace + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config delete vineyard-deployment \ + --name vineyardd-0 +``` + +### Options + +``` + -h, --help help for vineyard-deployment + --name string the name of vineyardd (default "vineyardd-sample") +``` + +## `vineyardctl delete vineyardd` + +Delete the vineyardd cluster from kubernetes + +``` +vineyardctl delete vineyardd [flags] +``` + +**SEE ALSO** + +* [vineyardctl delete](#vineyardctl-delete) - Delete the vineyard components from kubernetes + +### Examples + +```shell + # delete the default vineyardd cluster(vineyardd-sample) in the default namespace + vineyardctl delete vineyardd + + # delete the specific vineyardd cluster in the vineyard-system namespace + vineyardctl -n vineyard-system delete vineyardd --name vineyardd-test +``` + +### Options + +``` + -h, --help help for vineyardd + --name string the name of vineyardd (default "vineyardd-sample") +``` + +## `vineyardctl deploy` + +Deploy the vineyard components on kubernetes + +**SEE ALSO** + +* [vineyardctl](#vineyardctl) - vineyardctl is the command-line tool for interact with the Vineyard Operator. +* [vineyardctl deploy backup-job](#vineyardctl-deploy-backup-job) - Deploy a backup job of vineyard cluster on kubernetes +* [vineyardctl deploy cert-manager](#vineyardctl-deploy-cert-manager) - Deploy the cert-manager on kubernetes +* [vineyardctl deploy operator](#vineyardctl-deploy-operator) - Deploy the vineyard operator on kubernetes +* [vineyardctl deploy recover-job](#vineyardctl-deploy-recover-job) - Deploy a recover job to recover a backup of current vineyard cluster on kubernetes +* [vineyardctl deploy vineyard-cluster](#vineyardctl-deploy-vineyard-cluster) - Deploy the vineyard cluster from kubernetes +* [vineyardctl deploy vineyard-deployment](#vineyardctl-deploy-vineyard-deployment) - DeployVineyardDeployment builds and deploy the yaml file of vineyardd without vineyard operator +* [vineyardctl deploy vineyardd](#vineyardctl-deploy-vineyardd) - Deploy the vineyardd on kubernetes + +### Examples + +```shell + # deploy the default vineyard cluster on kubernetes + vineyardctl --kubeconfig $HOME/.kube/config deploy vineyard-cluster + + # deploy the vineyard operator on kubernetes + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy operator + + # deploy the cert-manager on kubernetes + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy cert-manager + + # deploy the vineyardd on kubernetes + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy vineyardd +``` + +### Options + +``` + -h, --help help for deploy +``` + +## `vineyardctl deploy backup-job` + +Deploy a backup job of vineyard cluster on kubernetes + +### Synopsis + +Deploy the backup job for the vineyard cluster on kubernetes, +which will backup all objects of the current vineyard cluster +quickly. For persistent storage, you could specify the pv spec +and pv spec and the related pv and pvc will be created automatically. +Also, you could also specify the existing pv and pvc name to use + +``` +vineyardctl deploy backup-job [flags] +``` + +**SEE ALSO** + +* [vineyardctl deploy](#vineyardctl-deploy) - Deploy the vineyard components on kubernetes + +### Examples + +```shell + # deploy a backup job for all vineyard objects of the vineyard + # cluster on kubernetes and you could define the pv and pvc + # spec from json string as follows + vineyardctl deploy backup-job \ + --vineyard-deployment-name vineyardd-sample \ + --vineyard-deployment-namespace vineyard-system \ + --path /var/vineyard/dump \ + --pv-pvc-spec '{ + "pv-spec": { + "capacity": { + "storage": "1Gi" + }, + "accessModes": [ + "ReadWriteOnce" + ], + "storageClassName": "manual", + "hostPath": { + "path": "/var/vineyard/dump" + } + }, + "pvc-spec": { + "storageClassName": "manual", + "accessModes": [ + "ReadWriteOnce" + ], + "resources": { + "requests": { + "storage": "1Gi" + } + } + } + }' + + # deploy a backup job for the vineyard cluster on kubernetes + # you could define the pv and pvc spec from yaml string as follows + vineyardctl deploy backup-job \ + --vineyard-deployment-name vineyardd-sample \ + --vineyard-deployment-namespace vineyard-system \ + --path /var/vineyard/dump \ + --pv-pvc-spec \ + ' + pv-spec: + capacity: + storage: 1Gi + accessModes: + - ReadWriteOnce + storageClassName: manual + hostPath: + path: "/var/vineyard/dump" + pvc-spec: + storageClassName: manual + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + ' + + # deploy a backup job for specific vineyard objects of the vineyard + # cluster on kubernetes. + cat pv-pvc.json | vineyardctl deploy backup-job \ + --vineyard-deployment-name vineyardd-sample \ + --vineyard-deployment-namespace vineyard-system \ + --objectIDs "o000018d29207fd01,o000018d80d264010" \ + --path /var/vineyard/dump + + # Assume you have already deployed a pvc named "pvc-sample", you + # could use them as the backend storage for the backup job as follows + vineyardctl deploy backup-job \ + --vineyard-deployment-name vineyardd-sample \ + --vineyard-deployment-namespace vineyard-system \ + --path /var/vineyard/dump \ + --pvc-name pvc-sample + + # The namespace to deploy the backup and recover job must be the same + # as the vineyard cluster namespace. + # Assume the vineyard cluster is deployed in the namespace "test", you + # could deploy the backup job as follows + vineyardctl deploy backup-job \ + --vineyard-deployment-name vineyardd-sample \ + --vineyard-deployment-namespace test \ + --namespace test \ + --path /var/vineyard/dump \ + --pvc-name pvc-sample +``` + +### Options + +``` + --backup-name string the name of backup job (default "vineyard-backup") + -h, --help help for backup-job + --objectIDs strings the specific objects to be backed up + --path string the path of the backup data + --pv-pvc-spec string the PersistentVolume and PersistentVolumeClaim of the backup data + --pvc-name string the name of an existing PersistentVolumeClaim + --vineyard-deployment-name string the name of vineyard deployment + --vineyard-deployment-namespace string the namespace of vineyard deployment +``` + +## `vineyardctl deploy cert-manager` + +Deploy the cert-manager on kubernetes + +### Synopsis + +Deploy the cert-manager in the cert-manager namespace. The default +version of cert-manager is v1.9.1. + +``` +vineyardctl deploy cert-manager [flags] +``` + +**SEE ALSO** + +* [vineyardctl deploy](#vineyardctl-deploy) - Deploy the vineyard components on kubernetes + +### Examples + +```shell + # install the default version(v1.9.1) in the cert-manager namespace + # wait for the cert-manager to be ready(default option) + vineyardctl --kubeconfig $HOME/.kube/config deploy cert-manager + + # install the default version(v1.9.1) in the cert-manager namespace + # not to wait for the cert-manager to be ready, but we does not recommend + # to do this, because there may be errors caused by the cert-manager + # not ready + vineyardctl --kubeconfig $HOME/.kube/config deploy cert-manager \ + --wait=false +``` + +### Options + +``` + -h, --help help for cert-manager +``` + +## `vineyardctl deploy operator` + +Deploy the vineyard operator on kubernetes + +### Synopsis + +Deploy the vineyard operator on kubernetes. + +``` +vineyardctl deploy operator [flags] +``` + +**SEE ALSO** + +* [vineyardctl deploy](#vineyardctl-deploy) - Deploy the vineyard components on kubernetes + +### Examples + +```shell + # deploy the vineyard operator on the 'vineyard-system' namespace + vineyardctl deploy operator + + # deploy the vineyard operator on the existing namespace + vineyardctl deploy operator -n my-custom-namespace + + # deploy the vineyard operator on the new namespace + vineyardctl deploy operator -n a-new-namespace-name --create-namespace +``` + +### Options + +``` + -h, --help help for operator +``` + +## `vineyardctl deploy recover-job` + +Deploy a recover job to recover a backup of current vineyard cluster on kubernetes + +### Synopsis + +Deploy the recover job for vineyard cluster on kubernetes, which +will recover all objects from a backup of vineyard cluster. Usually, +the recover job should be created in the same namespace of +the backup job. + +``` +vineyardctl deploy recover-job [flags] +``` + +**SEE ALSO** + +* [vineyardctl deploy](#vineyardctl-deploy) - Deploy the vineyard components on kubernetes + +### Examples + +```shell + # Deploy a recover job for the vineyard deployment in the same namespace. + # After the recover job finished, the command will create a kubernetes + # configmap named [recover-name]+"-mapping-table" that contains the + # mapping table from the old vineyard objects to the new ones. + # + # If you create the recover job as follows, you can get the mapping table via + # "kubectl get configmap vineyard-recover-mapping-table -n vineyard-system -o yaml" + # the left column is the old object id, and the right column is the new object id. + vineyardctl deploy recover-job \ + --vineyard-deployment-name vineyardd-sample \ + --vineyard-deployment-namespace vineyard-system \ + --recover-path /var/vineyard/dump \ + --pvc-name vineyard-backup +``` + +### Options + +``` + -h, --help help for recover-job + --pvc-name string the name of an existing PersistentVolumeClaim + --recover-name string the name of recover job (default "vineyard-recover") + --recover-path string the path of recover job + --vineyard-deployment-name string the name of vineyard deployment + --vineyard-deployment-namespace string the namespace of vineyard deployment +``` + +## `vineyardctl deploy vineyard-cluster` + +Deploy the vineyard cluster from kubernetes + +``` +vineyardctl deploy vineyard-cluster [flags] +``` + +**SEE ALSO** + +* [vineyardctl deploy](#vineyardctl-deploy) - Deploy the vineyard components on kubernetes + +### Examples + +```shell + # deploy the default vineyard cluster on kubernetes + vineyardctl deploy vineyard-cluster +``` + +### Options + +``` + -h, --help help for vineyard-cluster +``` + +## `vineyardctl deploy vineyard-deployment` + +DeployVineyardDeployment builds and deploy the yaml file of vineyardd without vineyard operator + +### Synopsis + +Builds and deploy the yaml file of vineyardd the vineyardd +without vineyard operator. You could deploy a customized +vineyardd from stdin or file. + +``` +vineyardctl deploy vineyard-deployment [flags] +``` + +**SEE ALSO** + +* [vineyardctl deploy](#vineyardctl-deploy) - Deploy the vineyard components on kubernetes + +### Examples + +```shell + # deploy the default vineyard deployment on kubernetes + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config \ + deploy vineyard-deployment + + # deploy the vineyard deployment with customized image + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config \ + deploy vineyard-deployment --image vineyardcloudnative/vineyardd:v0.12.2 +``` + +### Options + +``` + --etcd.replicas int the number of etcd replicas in a vineyard cluster (default 1) + -f, --file string the path of vineyardd + -h, --help help for vineyard-deployment + --name string the name of vineyardd (default "vineyardd-sample") + --owner-references string The owner reference of all vineyard deployment resources + --pluginImage.backupImage string the backup image of vineyardd (default "ghcr.io/v6d-io/v6d/backup-job") + --pluginImage.daskRepartitionImage string the dask repartition image of vineyardd workflow (default "ghcr.io/v6d-io/v6d/dask-repartition") + --pluginImage.distributedAssemblyImage string the distributed image of vineyard workflow (default "ghcr.io/v6d-io/v6d/distributed-assembly") + --pluginImage.localAssemblyImage string the local assembly image of vineyardd workflow (default "ghcr.io/v6d-io/v6d/local-assembly") + --pluginImage.recoverImage string the recover image of vineyardd (default "ghcr.io/v6d-io/v6d/recover-job") + --replicas int the number of vineyardd replicas (default 3) + --vineyardd.cpu string the cpu requests and limits of vineyard container + --vineyardd.envs strings The environment variables of vineyardd + --vineyardd.image string the image of vineyardd (default "vineyardcloudnative/vineyardd:latest") + --vineyardd.imagePullPolicy string the imagePullPolicy of vineyardd (default "IfNotPresent") + --vineyardd.memory string the memory requests and limits of vineyard container + --vineyardd.metric.enable enable metrics of vineyardd + --vineyardd.metric.image string the metic image of vineyardd (default "vineyardcloudnative/vineyard-grok-exporter:latest") + --vineyardd.metric.imagePullPolicy string the imagePullPolicy of the metric image (default "IfNotPresent") + --vineyardd.reserve_memory Reserving enough physical memory pages for vineyardd + --vineyardd.service.port int the service port of vineyard service (default 9600) + --vineyardd.service.type string the service type of vineyard service (default "ClusterIP") + --vineyardd.size string The size of vineyardd. You can use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. Defaults "", means not limited + --vineyardd.socket string The directory on host for the IPC socket file. The namespace and name will be replaced with your vineyard config (default "/var/run/vineyard-kubernetes/{{.Namespace}}/{{.Name}}") + --vineyardd.spill.config string If you want to enable the spill mechanism, please set the name of spill config + --vineyardd.spill.path string The path of spill config + --vineyardd.spill.pv-pvc-spec string the json string of the persistent volume and persistent volume claim + --vineyardd.spill.spillLowerRate string The low watermark of spilling memory (default "0.3") + --vineyardd.spill.spillUpperRate string The high watermark of spilling memory (default "0.8") + --vineyardd.streamThreshold int memory threshold of streams (percentage of total memory) (default 80) + --vineyardd.syncCRDs enable metrics of vineyardd (default true) + --vineyardd.volume.mountPath string Set the mount path for the pvc + --vineyardd.volume.pvcname string Set the pvc name for storing the vineyard objects persistently +``` + +## `vineyardctl deploy vineyardd` + +Deploy the vineyardd on kubernetes + +### Synopsis + +Deploy the vineyardd on kubernetes. You could deploy a +customized vineyardd from stdin or file. + +``` +vineyardctl deploy vineyardd [flags] +``` + +**SEE ALSO** + +* [vineyardctl deploy](#vineyardctl-deploy) - Deploy the vineyard components on kubernetes + +### Examples + +```shell + # deploy the default vineyard on kubernetes + # wait for the vineyardd to be ready(default option) + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy vineyardd + + # not to wait for the vineyardd to be ready + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy vineyardd \ + --wait=false + + # deploy the vineyardd from a yaml file + vineyardctl --kubeconfig $HOME/.kube/config deploy vineyardd --file vineyardd.yaml + + # deploy the vineyardd with customized image + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy vineyardd \ + --image vineyardd:v0.12.2 + + # deploy the vineyardd with spill mechanism on persistent storage from json string + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy vineyardd \ + --vineyardd.spill.config spill-path \ + --vineyardd.spill.path /var/vineyard/spill \ + --vineyardd.spill.pv-pvc-spec '{ + "pv-spec": { + "capacity": { + "storage": "1Gi" + }, + "accessModes": [ + "ReadWriteOnce" + ], + "storageClassName": "manual", + "hostPath": { + "path": "/var/vineyard/spill" + } + }, + "pvc-spec": { + "storageClassName": "manual", + "accessModes": [ + "ReadWriteOnce" + ], + "resources": { + "requests": { + "storage": "512Mi" + } + } + } + }' + + # deploy the vineyardd with spill mechanism on persistent storage from yaml string + vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy vineyardd \ + --vineyardd.spill.config spill-path \ + --vineyardd.spill.path /var/vineyard/spill \ + --vineyardd.spill.pv-pvc-spec \ + ' + pv-spec: + capacity: + storage: 1Gi + accessModes: + - ReadWriteOnce + storageClassName: manual + hostPath: + path: "/var/vineyard/spill" + pvc-spec: + storageClassName: manual + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 512Mi + ' + +# deploy the vineyardd with spill mechanism on persistent storage from json file + # also you could use the yaml file + cat pv-pvc.json | vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy vineyardd \ + --vineyardd.spill.config spill-path \ + --vineyardd.spill.path /var/vineyard/spill \ + - +``` + +### Options + +``` + --etcd.replicas int the number of etcd replicas in a vineyard cluster (default 1) + -f, --file string the path of vineyardd + -h, --help help for vineyardd + --name string the name of vineyardd (default "vineyardd-sample") + --pluginImage.backupImage string the backup image of vineyardd (default "ghcr.io/v6d-io/v6d/backup-job") + --pluginImage.daskRepartitionImage string the dask repartition image of vineyardd workflow (default "ghcr.io/v6d-io/v6d/dask-repartition") + --pluginImage.distributedAssemblyImage string the distributed image of vineyard workflow (default "ghcr.io/v6d-io/v6d/distributed-assembly") + --pluginImage.localAssemblyImage string the local assembly image of vineyardd workflow (default "ghcr.io/v6d-io/v6d/local-assembly") + --pluginImage.recoverImage string the recover image of vineyardd (default "ghcr.io/v6d-io/v6d/recover-job") + --replicas int the number of vineyardd replicas (default 3) + --vineyardd.cpu string the cpu requests and limits of vineyard container + --vineyardd.envs strings The environment variables of vineyardd + --vineyardd.image string the image of vineyardd (default "vineyardcloudnative/vineyardd:latest") + --vineyardd.imagePullPolicy string the imagePullPolicy of vineyardd (default "IfNotPresent") + --vineyardd.memory string the memory requests and limits of vineyard container + --vineyardd.metric.enable enable metrics of vineyardd + --vineyardd.metric.image string the metic image of vineyardd (default "vineyardcloudnative/vineyard-grok-exporter:latest") + --vineyardd.metric.imagePullPolicy string the imagePullPolicy of the metric image (default "IfNotPresent") + --vineyardd.reserve_memory Reserving enough physical memory pages for vineyardd + --vineyardd.service.port int the service port of vineyard service (default 9600) + --vineyardd.service.type string the service type of vineyard service (default "ClusterIP") + --vineyardd.size string The size of vineyardd. You can use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. Defaults "", means not limited + --vineyardd.socket string The directory on host for the IPC socket file. The namespace and name will be replaced with your vineyard config (default "/var/run/vineyard-kubernetes/{{.Namespace}}/{{.Name}}") + --vineyardd.spill.config string If you want to enable the spill mechanism, please set the name of spill config + --vineyardd.spill.path string The path of spill config + --vineyardd.spill.pv-pvc-spec string the json string of the persistent volume and persistent volume claim + --vineyardd.spill.spillLowerRate string The low watermark of spilling memory (default "0.3") + --vineyardd.spill.spillUpperRate string The high watermark of spilling memory (default "0.8") + --vineyardd.streamThreshold int memory threshold of streams (percentage of total memory) (default 80) + --vineyardd.syncCRDs enable metrics of vineyardd (default true) + --vineyardd.volume.mountPath string Set the mount path for the pvc + --vineyardd.volume.pvcname string Set the pvc name for storing the vineyard objects persistently +``` + +## `vineyardctl get` + +Get vineyard objects, metadatas, blobs or cluster-info + +**SEE ALSO** + +* [vineyardctl](#vineyardctl) - vineyardctl is the command-line tool for interact with the Vineyard Operator. +* [vineyardctl get cluster-info](#vineyardctl-get-cluster-info) - Get vineyard cluster info + +### Examples + +```shell + # Connect the vineyardd deployment with IPC client + # Get the cluster info and output as table + vineyardctl get cluster-info --deployment-name vineyardd-sample -n vineyard-system +``` + +### Options + +``` + -h, --help help for get +``` + +## `vineyardctl get cluster-info` + +Get vineyard cluster info + +### Synopsis + +Get vineyard cluster info, including +the instanceId, hostName, node name and so on. + +``` +vineyardctl get cluster-info [flags] +``` + +**SEE ALSO** + +* [vineyardctl get](#vineyardctl-get) - Get vineyard objects, metadatas, blobs or cluster-info + +### Examples + +```shell + # Get the cluster info of vineyard deployment and output as table + vineyardctl get cluster-info --deployment-name vineyardd-sample -n vineyard-system + + # Get the cluster info of vineyard deployment and output as json + vineyardctl get cluster-info --deployment-name vineyardd-sample -n vineyard-system -o json + + # Get the cluster info via IPC socket + vineyardctl get cluster-info --ipc-socket /var/run/vineyard.sock +``` + +### Options + +``` + --deployment-name string the name of vineyard deployment + -o, --format string the output format, support table or json, default is table (default "table") + --forward-port int the forward port of vineyard deployment (default 9600) + -h, --help help for cluster-info + --ipc-socket string vineyard IPC socket path + --port int the port of vineyard deployment (default 9600) + --rpc-socket string vineyard RPC socket path +``` + +## `vineyardctl inject` + +Inject the vineyard sidecar container into a workload + +### Synopsis + +Inject the vineyard sidecar container into a workload. You can +input a workload yaml or a workload json and then get the injected +workload and some etcd manifests from the output. The workload can +be a pod or a deployment or a statefulset, etc. + +The output is a set of manifests that includes the injected workload, +the rpc service, the etcd service and the etcd cluster(e.g. several +pods and services). + +If you have a pod yaml: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: python +spec: + containers: + - name: python + image: python:3.10 + command: ["python", "-c", "import time; time.sleep(100000)"] +``` +Then, you can use the following command to inject the vineyard sidecar + +$ vineyardctl inject -f pod.yaml + +After running the command, the output is as follows: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + labels: + app.vineyard.io/name: vineyard-sidecar + app.vineyard.io/role: etcd + etcd_node: vineyard-sidecar-etcd-0 + name: vineyard-sidecar-etcd-0 + namespace: null + ownerReferences: [] +spec: + containers: + - command: + - etcd + - --name + - vineyard-sidecar-etcd-0 + - --initial-advertise-peer-urls + - http://vineyard-sidecar-etcd-0:2380 + - --advertise-client-urls + - http://vineyard-sidecar-etcd-0:2379 + - --listen-peer-urls + - http://0.0.0.0:2380 + - --listen-client-urls + - http://0.0.0.0:2379 + - --initial-cluster + - vineyard-sidecar-etcd-0=http://vineyard-sidecar-etcd-0:2380 + - --initial-cluster-state + - new + image: vineyardcloudnative/vineyardd:latest + name: etcd + ports: + - containerPort: 2379 + name: client + protocol: TCP + - containerPort: 2380 + name: server + protocol: TCP + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + labels: + etcd_node: vineyard-sidecar-etcd-0 + name: vineyard-sidecar-etcd-0 + namespace: null + ownerReferences: [] +spec: + ports: + - name: client + port: 2379 + protocol: TCP + targetPort: 2379 + - name: server + port: 2380 + protocol: TCP + targetPort: 2380 + selector: + app.vineyard.io/role: etcd + etcd_node: vineyard-sidecar-etcd-0 +--- +apiVersion: v1 +kind: Service +metadata: + name: vineyard-sidecar-etcd-service + namespace: null + ownerReferences: [] +spec: + ports: + - name: vineyard-sidecar-etcd-for-vineyard-port + port: 2379 + protocol: TCP + targetPort: 2379 + selector: + app.vineyard.io/name: vineyard-sidecar + app.vineyard.io/role: etcd +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.vineyard.io/name: vineyard-sidecar + name: vineyard-sidecar-rpc + namespace: null + ownerReferences: [] +spec: + ports: + - name: vineyard-rpc + port: 9600 + protocol: TCP + selector: + app.vineyard.io/name: vineyard-sidecar + app.vineyard.io/role: vineyardd + type: ClusterIP +--- +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + labels: + app.vineyard.io/name: vineyard-sidecar + app.vineyard.io/role: vineyardd + name: python + ownerReferences: [] +spec: + containers: + - command: + - python + - -c + - while [ ! -e /var/run/vineyard.sock ]; do sleep 1; done;import time; time.sleep(100000) + env: + - name: VINEYARD_IPC_SOCKET + value: /var/run/vineyard.sock + image: python:3.10 + name: python + resources: {} + volumeMounts: + - mountPath: /var/run + name: vineyard-socket + - command: + - /bin/bash + - -c + - | + /usr/bin/wait-for-it.sh -t 60 vineyard-sidecar-etcd-service..svc.cluster.local:2379; \ + sleep 1; /usr/local/bin/vineyardd --sync_crds true --socket /var/run/vineyard.sock --size \ + --stream_threshold 80 --etcd_cmd etcd --etcd_prefix /vineyard --etcd_endpoint http://vineyard-sidecar-etcd-service:2379 + env: + - name: VINEYARDD_UID + value: null + - name: VINEYARDD_NAME + value: vineyard-sidecar + - name: VINEYARDD_NAMESPACE + value: null + image: vineyardcloudnative/vineyardd:latest + imagePullPolicy: IfNotPresent + name: vineyard-sidecar + ports: + - containerPort: 9600 + name: vineyard-rpc + protocol: TCP + resources: + limits: null + requests: null + volumeMounts: + - mountPath: /var/run + name: vineyard-socket + volumes: + - emptyDir: {} + name: vineyard-socket +status: {} +``` + +Next, we will introduce a simple example to show the injection with +the apply-resources flag. + +Assume you have the following workload yaml: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + # Notice, you must set the namespace here + namespace: vineyard-job +spec: + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + ports: + - containerPort: 80 +``` + +Then, you can use the following command to inject the vineyard sidecar +which means that all resources will be created during the injection except +the workload itself. The workload should be created by users. + +$ vineyardctl inject -f workload.yaml --apply-resources + +After running the command, the main output(removed some unnecessary fields) +is as follows: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + name: nginx-deployment + namespace: vineyard-job +spec: + selector: + matchLabels: + app: nginx +template: + metadata: + labels: + app: nginx + # the default sidecar name is vineyard-sidecar + app.vineyard.io/name: vineyard-sidecar + spec: + containers: + - command: null + image: nginx:1.14.2 + name: nginx + ports: + - containerPort: 80 + volumeMounts: + - mountPath: /var/run + name: vineyard-socket + - command: + - /bin/bash + - -c + - | + /usr/bin/wait-for-it.sh -t 60 vineyard-sidecar-etcd-service.vineyard-job.svc.cluster.local:2379; \ + sleep 1; /usr/local/bin/vineyardd --sync_crds true --socket /var/run/vineyard.sock \ + --stream_threshold 80 --etcd_cmd etcd --etcd_prefix /vineyard \ + --etcd_endpoint http://vineyard-sidecar-etcd-service:2379 + env: + - name: VINEYARDD_UID + value: null + - name: VINEYARDD_NAME + value: vineyard-sidecar + - name: VINEYARDD_NAMESPACE + value: vineyard-job + image: vineyardcloudnative/vineyardd:latest + imagePullPolicy: IfNotPresent + name: vineyard-sidecar + ports: + - containerPort: 9600 + name: vineyard-rpc + protocol: TCP + volumeMounts: + - mountPath: /var/run + name: vineyard-socket + volumes: + - emptyDir: {} + name: vineyard-socket +``` + +The sidecar template can be accessed from the following link: +https://github.com/v6d-io/v6d/blob/main/k8s/pkg/templates/sidecar/injection-template.yaml +also you can get some inspiration from the doc link: +https://v6d.io/notes/cloud-native/vineyard-operator.html#installing-vineyard-as-sidecar + +``` +vineyardctl inject [flags] +``` + +**SEE ALSO** + +* [vineyardctl](#vineyardctl) - vineyardctl is the command-line tool for interact with the Vineyard Operator. + +### Examples + +```shell + # use json format to output the injected workload + # notice that the output is a json string of all manifests + # it looks like: + # { + # "workload": "workload json string", + # "rpc_service": "rpc service json string", + # "etcd_service": "etcd service json string", + # "etcd_internal_service": [ + # "etcd internal service json string 1", + # "etcd internal service json string 2", + # "etcd internal service json string 3" + # ], + # "etcd_pod": [ + # "etcd pod json string 1", + # "etcd pod json string 2", + # "etcd pod json string 3" + # ] + # } + vineyardctl inject -f workload.yaml -o json + + # inject the default vineyard sidecar container into a workload + # output all injected manifests and then deploy them + vineyardctl inject -f workload.yaml | kubectl apply -f - + + # if you only want to get the injected workload yaml rather than + # all manifests that includes the etcd cluster and the rpc service, + # you can enable the apply-resources and then the manifests will be + # created during the injection, finally you will get the injected + # workload yaml + vineyardctl inject -f workload.yaml --apply-resources +``` + +### Options + +``` + --apply-resources Whether to apply the resources including the etcd cluster and the rpc service if you enable this flag, the etcd cluster and the rpc service will be created during the injection + --etcd-replicas int The number of etcd replicas (default 1) + -f, --file string The yaml of workload + -h, --help help for inject + --name string The name of sidecar (default "vineyard-sidecar") + -o, --output string The output format of the command, support yaml and json (default "yaml") + --owner-references string The owner reference of all injectied resources + --resource string The resource of workload + --sidecar.cpu string the cpu requests and limits of vineyard container + --sidecar.envs strings The environment variables of vineyardd + --sidecar.image string the image of vineyardd (default "vineyardcloudnative/vineyardd:latest") + --sidecar.imagePullPolicy string the imagePullPolicy of vineyardd (default "IfNotPresent") + --sidecar.memory string the memory requests and limits of vineyard container + --sidecar.metric.enable enable metrics of vineyardd + --sidecar.metric.image string the metic image of vineyardd (default "vineyardcloudnative/vineyard-grok-exporter:latest") + --sidecar.metric.imagePullPolicy string the imagePullPolicy of the metric image (default "IfNotPresent") + --sidecar.reserve_memory Reserving enough physical memory pages for vineyardd + --sidecar.service.port int the service port of vineyard service (default 9600) + --sidecar.service.type string the service type of vineyard service (default "ClusterIP") + --sidecar.size string The size of vineyardd. You can use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. Defaults "", means not limited + --sidecar.socket string The directory on host for the IPC socket file. The namespace and name will be replaced with your vineyard config (default "/var/run/vineyard-kubernetes/{{.Namespace}}/{{.Name}}") + --sidecar.spill.config string If you want to enable the spill mechanism, please set the name of spill config + --sidecar.spill.path string The path of spill config + --sidecar.spill.pv-pvc-spec string the json string of the persistent volume and persistent volume claim + --sidecar.spill.spillLowerRate string The low watermark of spilling memory (default "0.3") + --sidecar.spill.spillUpperRate string The high watermark of spilling memory (default "0.8") + --sidecar.streamThreshold int memory threshold of streams (percentage of total memory) (default 80) + --sidecar.syncCRDs enable metrics of vineyardd (default true) + --sidecar.volume.mountPath string Set the mount path for the pvc + --sidecar.volume.pvcname string Set the pvc name for storing the vineyard objects persistently +``` + +## `vineyardctl ls` + +List vineyard objects, metadatas or blobs + +**SEE ALSO** + +* [vineyardctl](#vineyardctl) - vineyardctl is the command-line tool for interact with the Vineyard Operator. +* [vineyardctl ls blobs](#vineyardctl-ls-blobs) - List vineyard blobs +* [vineyardctl ls metadatas](#vineyardctl-ls-metadatas) - List vineyard metadatas +* [vineyardctl ls objects](#vineyardctl-ls-objects) - List vineyard objects + +### Examples + +```shell + # Connect the vineyardd server with IPC client + # List the vineyard objects no more than 10 + vineyardctl ls objects --limit 10 --ipc-socket /var/run/vineyard.sock + + # List the vineyard blobs no more than 10 + vineyardctl ls blobs --limit 10 --ipc-socket /var/run/vineyard.sock + + # List the vineyard objects with the specified pattern + vineyardctl ls objects --pattern "vineyard::Tensor<.*>" --regex --ipc-socket /var/run/vineyard.sock + + # Connect the vineyardd server with RPC client + # List the vineyard metadatas no more than 1000 + vineyardctl ls metadatas --rpc-socket 127.0.0.1:9600 --limit 1000 + + # Connect the vineyard deployment with PRC client + # List the vineyard objects no more than 1000 + vineyardctl ls objects --deployment-name vineyardd-sample -n vineyard-system +``` + +### Options + +``` + -h, --help help for ls +``` + +## `vineyardctl ls blobs` + +List vineyard blobs + +### Synopsis + +List vineyard blobs and only support IPC socket. +If you don't specify the ipc socket every time, you can set it as the +environment variable VINEYARD_IPC_SOCKET. + +``` +vineyardctl ls blobs [flags] +``` + +**SEE ALSO** + +* [vineyardctl ls](#vineyardctl-ls) - List vineyard objects, metadatas or blobs + +### Examples + +```shell + # List no more than 10 vineyard blobs + vineyardctl ls blobs --limit 10 --ipc-socket /var/run/vineyard.sock + + # List no more than 1000 vineyard blobs + vineyardctl ls blobs --ipc-socket /var/run/vineyard.sock --limit 1000 + + # List vineyard blobs with the name matching + vineyardctl ls blobs --pattern "vineyard::Tensor<.*>" --regex --ipc-socket /var/run/vineyard.sock + + # List vineyard blobs with the regex pattern + vineyardctl ls blobs --pattern "*DataFrame*" --ipc-socket /var/run/vineyard.sock + + # If you set the environment variable VINEYARD_IPC_SOCKET + # you can use the following command to list vineyard blobs + vineyardctl ls blobs --limit 1000 +``` + +### Options + +``` + --deployment-name string the name of vineyard deployment + -o, --format string the output format, support table or json, default is table (default "table") + --forward-port int the forward port of vineyard deployment (default 9600) + -h, --help help for blobs + --ipc-socket string vineyard IPC socket path + -l, --limit int maximum number of objects to return (default 5) + --port int the port of vineyard deployment (default 9600) + --rpc-socket string vineyard RPC socket path +``` + +## `vineyardctl ls metadatas` + +List vineyard metadatas + +### Synopsis + +List vineyard metadatas and support IPC socket, +RPC socket and vineyard deployment. If you don't specify the ipc socket or rpc socket +every time, you can set it as the environment variable VINEYARD_IPC_SOCKET or +VINEYARD_RPC_SOCKET. + +``` +vineyardctl ls metadatas [flags] +``` + +**SEE ALSO** + +* [vineyardctl ls](#vineyardctl-ls) - List vineyard objects, metadatas or blobs + +### Examples + +```shell + # List no more than 10 vineyard metadatas + vineyardctl ls metadatas --limit 10 --ipc-socket /var/run/vineyard.sock + + # List no more than 1000 vineyard metadatas + vineyardctl ls metadatas --rpc-socket 127.0.0.1:9600 --limit 1000 + + # List vineyard metadatas with the name matching the regex pattern + vineyardctl ls metadatas --pattern "vineyard::Blob" --ipc-socket /var/run/vineyard.sock + + # List vineyard metadatas of the vineyard deployment + vineyardctl ls metadatas --deployment-name vineyardd-sample -n vineyard-system --limit 1000 + + # List vineyard metadatas sorted by the instance id + vineyardctl ls metadatas --sorted-key instance_id --limit 1000 --ipc-socket /var/run/vineyard.sock + + # List vineyard metadatas sorted by the type and print the output as json format + vineyardctl ls metadatas --sorted-key type --limit 1000 --format json --ipc-socket /var/run/vineyard.sock +``` + +### Options + +``` + --deployment-name string the name of vineyard deployment + -o, --format string the output format, support table or json, default is table (default "table") + --forward-port int the forward port of vineyard deployment (default 9600) + -h, --help help for metadatas + --ipc-socket string vineyard IPC socket path + -l, --limit int maximum number of objects to return (default 5) + -p, --pattern string string that will be matched against the object’s typenames (default "*") + --port int the port of vineyard deployment (default 9600) + -r, --regex regex pattern to match the object’s typenames + --rpc-socket string vineyard RPC socket path + -k, --sorted-key string key to sort the objects, support: + - id: object id, the default value. + - typename: object typename, e.g. tensor, dataframe, etc. + - type: object type, e.g. global, local, etc. + - instance_id: object instance id. (default "id") +``` + +## `vineyardctl ls objects` + +List vineyard objects + +### Synopsis + +List vineyard objects and support IPC socket, +RPC socket and vineyard deployment. If you don't specify the ipc socket or rpc socket +every time, you can set it as the environment variable VINEYARD_IPC_SOCKET or +VINEYARD_RPC_SOCKET. + +``` +vineyardctl ls objects [flags] +``` + +**SEE ALSO** + +* [vineyardctl ls](#vineyardctl-ls) - List vineyard objects, metadatas or blobs + +### Examples + +```shell + # List no more than 10 vineyard objects + vineyardctl ls objects --limit 10 --ipc-socket /var/run/vineyard.sock + + # List any vineyard objects and no more than 1000 objects + vineyardctl ls objects --pattern "*" --ipc-socket /var/run/vineyard.sock --limit 1000 + + # List vineyard objects with the name matching the regex pattern + vineyardctl ls objects --pattern "vineyard::Tensor<.*>" --regex --ipc-socket /var/run/vineyard.sock + + # List vineyard objects and output as json format + vineyardctl ls objects --format json --ipc-socket /var/run/vineyard.sock + + # List vineyard objects sorted by the typename + vineyardctl ls objects --sorted-key typename --limit 1000 --ipc-socket /var/run/vineyard.sock +``` + +### Options + +``` + --deployment-name string the name of vineyard deployment + -o, --format string the output format, support table or json, default is table (default "table") + --forward-port int the forward port of vineyard deployment (default 9600) + -h, --help help for objects + --ipc-socket string vineyard IPC socket path + -l, --limit int maximum number of objects to return (default 5) + -p, --pattern string string that will be matched against the object’s typenames (default "*") + --port int the port of vineyard deployment (default 9600) + -r, --regex regex pattern to match the object’s typenames + --rpc-socket string vineyard RPC socket path + -k, --sorted-key string key to sort the objects, support: + - id: object id, the default value. + - typename: object typename, e.g. tensor, dataframe, etc. + - type: object type, e.g. global, local, etc. + - instance_id: object instance id. (default "id") +``` + +## `vineyardctl manager` + +Start the manager of vineyard operator + +``` +vineyardctl manager [flags] +``` + +**SEE ALSO** + +* [vineyardctl](#vineyardctl) - vineyardctl is the command-line tool for interact with the Vineyard Operator. + +### Examples + +```shell + # start the manager of vineyard operator with default configuration + # (Enable the controller, webhooks and scheduler) + vineyardctl manager + + # start the manager of vineyard operator without webhooks + vineyardctl manager --enable-webhook=false + + # start the manager of vineyard operator without scheduler + vineyardctl manager --enable-scheduler=false + + # only start the controller + vineyardctl manager --enable-webhook=false --enable-scheduler=false +``` + +### Options + +``` + --enable-scheduler Enable scheduler for controller manager. (default true) + --enable-webhook Enable webhook for controller manager. (default true) + --health-probe-bind-address string The address the probe endpoint binds to. (default ":8081") + -h, --help help for manager + --leader-elect Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager. + --metrics-bind-address string The address the metric endpoint binds to. (default "127.0.0.1:8080") + --scheduler-config-file string The location of scheduler plugin's configuration file. (default "/etc/kubernetes/scheduler.yaml") +``` + +## `vineyardctl schedule` + +Schedule a workload or a workflow to existing vineyard cluster. + +**SEE ALSO** + +* [vineyardctl](#vineyardctl) - vineyardctl is the command-line tool for interact with the Vineyard Operator. +* [vineyardctl schedule workflow](#vineyardctl-schedule-workflow) - Schedule a workflow based on the vineyard cluster +* [vineyardctl schedule workload](#vineyardctl-schedule-workload) - Schedule the workload to a vineyard cluster + +### Examples + +```shell + # Schedule a workload to a vineyard cluster + # it will add PodAffinity to the workload + vineyardctl schedule workload --resource '{kubernetes workload json string}' + + # schedule a workflow to the vineyard cluster + # it will use the best-effort scheduling strategy + vineyardctl schedule workflow --file workflow.yaml +``` + +### Options + +``` + -h, --help help for schedule +``` + +## `vineyardctl schedule workflow` + +Schedule a workflow based on the vineyard cluster + +### Synopsis + +Schedule a workflow based on the vineyard cluster. +It will apply the workflow to kubernetes cluster and deploy the workload +of the workflow on the vineyard cluster with the best-fit strategy. + +``` +vineyardctl schedule workflow [flags] +``` + +**SEE ALSO** + +* [vineyardctl schedule](#vineyardctl-schedule) - Schedule a workload or a workflow to existing vineyard cluster. + +### Examples + +```shell + # schedule a workflow to the vineyard cluster with the best-fit strategy + vineyardctl schedule workflow --file workflow.yaml + + # schedule a workflow without CRD installed + # Notice, it only works for the workflow built by pods + vineyardctl schedule workflow --file pod-workflow.yaml --without-crd +``` + +### Options + +``` + -f, --file string the path of workflow file + -h, --help help for workflow + --without-crd whether the CRD(especially for GlobalObject and LocalObject) is installed +``` + +## `vineyardctl schedule workload` + +Schedule the workload to a vineyard cluster + +### Synopsis + +Schedule the workload to a vineyard cluster. +It will add the podAffinity to the workload so that the workload +will be scheduled to the vineyard cluster. Besides, if the workload +does not have the socket volumeMount and volume, it will add one. + +Assume you have the following workload yaml: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: python-client + # Notice, you must set the namespace here + namespace: vineyard-job +spec: + selector: + matchLabels: + app: python + template: + metadata: + labels: + app: python + spec: + containers: + - name: python + image: python:3.10 + command: ["python", "-c", "import time; time.sleep(100000)"] +``` + +Then you can run the following command to add the podAffinity and socket volume +to the workload yaml: + +$ vineyard schedule workload -f workload.yaml -o yaml + +After that, you will get the following workload yaml: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + name: python-client + namespace: vineyard-job +spec: + selector: + matchLabels: + app: python + strategy: {} + template: + metadata: + creationTimestamp: null + labels: + app: python + spec: + affinity: + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app.kubernetes.io/instance + operator: In + values: + - vineyard-system-vineyardd-sample + namespaces: + - vineyard-system + topologyKey: kubernetes.io/hostname + + containers: + - command: + - python + - -c + - import time; time.sleep(100000) + env: + - name: VINEYARD_IPC_SOCKET + value: /var/run/vineyard.sock + image: python:3.10 + name: python + resources: {} + volumeMounts: + - mountPath: /var/run + name: vineyard-socket + volumes: + - hostPath: + path: /var/run/vineyard-kubernetes/vineyard-system/vineyardd-sample + name: vineyard-socket +``` + +``` +vineyardctl schedule workload [flags] +``` + +**SEE ALSO** + +* [vineyardctl schedule](#vineyardctl-schedule) - Schedule a workload or a workflow to existing vineyard cluster. + +### Examples + +```shell + # Add the podAffinity to the workload yaml + vineyardctl schedule workload -f workload.yaml \ + --vineyardd-name vineyardd-sample \ + --vineyardd-namespace vineyard-system + + # Add the podAffinity to the workload for the specific vineyard cluster + vineyardctl schedule workload --resource '{ + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": "web-server" + }, + "spec": { + "selector": { + "matchLabels": { + "app": "web-store" + } + }, + "replicas": 3, + "template": { + "metadata": { + "labels": { + "app": "web-store" + } + }, + "spec": { + "affinity": { + "podAntiAffinity": { + "requiredDuringSchedulingIgnoredDuringExecution": [ + { + "labelSelector": { + "matchExpressions": [ + { + "key": "app", + "operator": "In", + "values": [ + "web-store" + ] + } + ] + }, + "topologyKey": "kubernetes.io/hostname" + } + ] + }, + "podAffinity": { + "requiredDuringSchedulingIgnoredDuringExecution": [ + { + "labelSelector": { + "matchExpressions": [ + { + "key": "app", + "operator": "In", + "values": [ + "store" + ] + } + ] + }, + "topologyKey": "kubernetes.io/hostname" + } + ] + } + }, + "containers": [ + { + "name": "web-app", + "image": "nginx:1.16-alpine" + } + ] + } + } + } + }' \ + --vineyardd-name vineyardd-sample \ + --vineyardd-namespace vineyard-system +``` + +### Options + +``` + -f, --file string the file path of workload + -h, --help help for workload + -o, --output string the output format for vineyardctl schedule workload command (default "json") + --resource string the json string of kubernetes workload + --vineyardd-name string the namespace of vineyard cluster (default "vineyardd-sample") + --vineyardd-namespace string the namespace of vineyard cluster (default "vineyard-system") +``` diff --git a/_sources/notes/developers.rst.txt b/_sources/notes/developers.rst.txt new file mode 100644 index 0000000000..67c45449bd --- /dev/null +++ b/_sources/notes/developers.rst.txt @@ -0,0 +1,82 @@ +Getting Involved +---------------- + +.. toctree:: + :maxdepth: 1 + :caption: TOC + :hidden: + + developers/build-from-source.rst + developers/contributing.rst + developers/troubleshooting.rst + developers/roadmap.rst + +Vineyard is an open-source project that was accepted into the CNCF sandbox in April 2021. +It has been successfully developed and maintained by the open-source community. We are +committed to engaging community members to help us improve Vineyard. You will find our +community welcoming and responsive by joining our Github discussions or Slack channel: + +.. panels:: + :container: container-lg pb-4 + :column: col-lg-4 col-md-4 col-sm-4 col-xs-12 p-2 + :body: text-center + + .. link-button:: https://github.com/v6d-io/v6d/discussions + :type: url + :text: Github Discussions + :classes: btn-block stretched-link + + :fa:`github` + + --- + + .. link-button:: http://slack.cncf.io + :type: url + :text: Slack + :classes: btn-block stretched-link + + :fa:`slack` + +To modify the Vineyard source code, you will need to set up the development environment +and build the project from source. Follow the instructions below: + +.. panels:: + :container: container-lg pb-4 + :column: col-lg-6 col-md-6 col-sm-6 col-xs-12 p-2 + :body: text-center card-body-less-padding + + .. link-button:: developers/build-from-source + :type: ref + :text: Building from source + :classes: btn-block stretched-link + +If you encounter any issues during your journey with Vineyard, you may find solutions in: + +.. panels:: + :container: container-lg pb-4 + :column: col-lg-4 col-md-4 col-sm-4 col-xs-12 p-2 + :body: text-center card-body-less-padding + + .. link-button:: developers/troubleshooting + :type: ref + :text: Troubleshooting + :classes: btn-block stretched-link + + --- + + .. link-button:: https://github.com/v6d-io/v6d/issues + :type: url + :text: Github Issues + :classes: btn-block stretched-link + +We also have a public roadmap that outlines our future goals and highlights our ongoing efforts: + +.. panels:: + :container: container-lg pb-4 + :column: col-lg-4 col-md-4 col-sm-4 col-xs-12 p-2 + :body: text-center card-body-less-padding + + .. link-button:: developers/roadmap + :type: ref + :text: Our Roadmap + :classes: btn-block stretched-link diff --git a/_sources/notes/developers/build-from-source.rst.txt b/_sources/notes/developers/build-from-source.rst.txt new file mode 100644 index 0000000000..c9fd0f3f3b --- /dev/null +++ b/_sources/notes/developers/build-from-source.rst.txt @@ -0,0 +1,183 @@ +Building from source +==================== + +Install vineyard +---------------- + +Vineyard is distributed as a `python package `_ +and can be easily installed with :code:`pip`: + +.. code:: shell + + pip3 install vineyard + +Install etcd +------------ + +Vineyard is based on `etcd `_, please refer the `doc `_ to install it. + +Install from source +------------------- + +Vineyard is open source on Github: `https://github.com/v6d-io/v6d `_. +You can obtain the source code using ``git``: + +.. code:: console + + git clone https://github.com/v6d-io/v6d + cd v6d + git submodule update --init + +Prepare dependencies +^^^^^^^^^^^^^^^^^^^^ + +Vineyard can be built and deployed on common Unix-like systems. Vineyard has been +fully tests with C++ compilers that supports C++ 14. + +Dependencies +~~~~~~~~~~~~ + +Vineyard requires the following software as dependencies to build and run: + ++ apache-arrow >= 3.0.0 ++ gflags ++ glog ++ boost ++ mpi, for the graph data structure module + +If you want to build the vineyard server, the following additional libraries are needed: + ++ protobuf ++ grpc + +And the following python packages are required: + ++ libclang + + Can be installed using pip + + .. code:: shell + + pip3 install libclang + +Install on Ubuntu (or Debian) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Vineyard has been fully tested on Ubuntu 20.04. The dependencies can be installed by + +.. code:: shell + + apt-get install -y ca-certificates \ + cmake \ + doxygen \ + libboost-all-dev \ + libcurl4-openssl-dev \ + libgflags-dev \ + libgoogle-glog-dev \ + libgrpc-dev \ + libgrpc++-dev \ + libmpich-dev \ + libprotobuf-dev \ + libssl-dev \ + libunwind-dev \ + libz-dev \ + protobuf-compiler-grpc \ + python3-pip \ + wget + +Then install the apache-arrow (see also `https://arrow.apache.org/install `_): + +.. code:: shell + + wget https://apache.jfrog.io/artifactory/arrow/$(lsb_release --id --short | tr 'A-Z' 'a-z')/apache-arrow-apt-source-latest-$(lsb_release --codename --short).deb \ + -O /tmp/apache-arrow-apt-source-latest-$(lsb_release --codename --short).deb + apt install -y -V /tmp/apache-arrow-apt-source-latest-$(lsb_release --codename --short).deb + apt update -y + apt install -y libarrow-dev + +Dependencies on MacOS +~~~~~~~~~~~~~~~~~~~~~ + +Vineyard has been tested on MacOS as well, the dependencies can be installed using :code:`brew`: + +.. code:: shell + + brew install apache-arrow boost gflags glog grpc protobuf llvm mpich openssl zlib autoconf + +Building vineyard +^^^^^^^^^^^^^^^^^ + +After the required dependencies are installed, you do an out-of-source build using **CMake**: + +.. tip:: + + We recommend to use the brew installed LLVM as the compiler for building vineyard on MacOS, + which can be accomplished by setting the environment variable :code:`CC` and :code:`CXX`: + + .. code:: + + export CC=$(brew --prefix llvm)/bin/clang + export CXX=$(brew --prefix llvm)/bin/clang++ + +.. code:: shell + + mkdir build + cd build + cmake .. + make -j$(nproc) + sudo make install # optionally + +You will see vineyard server binary under the ``bin`` directory, and static or shared linked +libraries will be placed under the ``lib-shared`` folder. + +Building python wheels +^^^^^^^^^^^^^^^^^^^^^^ + +After building the vineyard library successfully, you can package an install wheel distribution by + +.. code:: shell + + python3 setup.py bdist_wheel + +Install vineyardctl +------------------- + +Vineyardctl is available on the Github release page, you can download the binary as follows: + +.. code:: shell + + export LATEST_TAG=$(curl -s "https://api.github.com/repos/v6d-io/v6d/tags" | jq -r '.[0].name') + export OS=$(uname -s | tr '[:upper:]' '[:lower:]') + export ARCH=${$(uname -m)/x86_64/amd64} + curl -Lo vineyardctl https://github.com/v6d-io/v6d/releases/download/$LATEST_TAG/vineyardctl-$LATEST_TAG-$OS-$ARCH + chmod +x vineyardctl + sudo mv vineyardctl /usr/local/bin/ + + +Building the documentation +-------------------------- + +Vineyard documentation is organized and generated by sphinx. There are other packages that +help us build the documentation, which can be easily installed using ``pip``: + +.. code:: shell + + pip3 install -r requirements.txt -r requirements-dev.txt + +Once installed, you could go to the `docs/` directory and build the documentation by + +.. code:: shell + + cd docs/ # skip if you are already there + make html + +Building on various platforms +----------------------------- + +Vineyard is continuously tested on various platforms and you may find building and installation steps +from our CI: + +- `Ubuntu `_ +- `MacOS `_ +- `CentOS `_ +- `Arch Linux `_ diff --git a/_sources/notes/developers/contributing.rst.txt b/_sources/notes/developers/contributing.rst.txt new file mode 100644 index 0000000000..fe48147cb8 --- /dev/null +++ b/_sources/notes/developers/contributing.rst.txt @@ -0,0 +1,4 @@ +.. This file is just a placeholder to refer the top-level CONTRIBUTING.rst + to sphinx doc workspace. + +.. include:: ../../../CONTRIBUTING.rst diff --git a/_sources/notes/developers/faq.rst.txt b/_sources/notes/developers/faq.rst.txt new file mode 100644 index 0000000000..7a3d18a5f3 --- /dev/null +++ b/_sources/notes/developers/faq.rst.txt @@ -0,0 +1,122 @@ +Frequently Asked Questions +========================== + +This *FAQ* page compiles questions frequently asked by our end users to provide +informative and concise answers. If the following sections do not address your +concerns, please feel free to `open an issue`_ or `post it to discussions`_. + +1. *What are the objects in vineyard?* + + A global object is composed of multiple local objects distributed across the cluster, + with each local object stored in a single vineyard daemon (ensuring that a local object + can always fit into the memory of a single machine). + + These local objects represent partitions of the global object (e.g., partitioned dataframes + within a large dataframe, graph fragments within a vast graph). Generally, a global object + serves as an abstraction for the input or output of a parallel-processing workload, while + a local object corresponds to the input or output of an individual worker within that workload. + +2. *Can multiple readers access the same data simultaneously in vineyard?* + + Absolutely. Vineyard stores objects as **immutable** entities, which are shared + among readers' processes through memory mapping. This ensures safe and concurrent + access to objects by multiple readers without any conflicts. + +3. *How can I launch a cluster with multiple vineyardd instances?* + + A vineyard daemon server represents a single vineyard instance within a vineyard cluster. To + initiate a vineyard cluster, simply start the ``vineyardd`` process on all the + machines within the cluster, ensuring that these vineyard instances can register with + the same ``etcd_endpoint``. The default value for ``etcd_endpoint`` is + ``http://127.0.0.1:2379``, and if the etcd servers are not already running on the cluster, + ``vineyard`` will automatically launch the ``etcd_endpoint``. + + For additional parameter settings, refer to the help documentation by running + ``python3 -m vineyard --help``. + +4. *Is Kubernetes a necessity for vineyard?* + + No, Kubernetes is not a necessity for vineyard. However, deploying vineyard on Kubernetes + allows users to benefit from the flexible resource management offered by cloud-native + deployments for their application workloads. Additionally, the scheduler plugin assists + in co-locating worker pods with the data for improved data-work alignment. + +5. *How does vineyard achieve IPC and memory sharing (i.e., zero-copy sharing) on Kubernetes?* + + Inter-process memory sharing can be challenging in Kubernetes, but it is achievable. When + deployed on Kubernetes, vineyard exposes its UNIX-domain socket as a :code:`PersistentVolume`. + This volume can be mounted into the job's pod, allowing the socket to be used for IPC + connections to the vineyard daemon. Memory sharing is accomplished by mounting a volume of + medium :code:`Memory` into both the vineyard daemon's pod and the job's pod. + +6. *How does vineyard's stream differ from similar systems, such as Kafka?* + + Vineyard's stream is an abstraction of a sequence of objects, where each object typically + represents a small portion of the entire object (e.g., a mini-batch of a tensor). This + abstraction is designed to support cross-engine pipelining between consecutive workers in + a data analytics pipeline (e.g., a dataframe engine generating training data while the + subsequent machine learning engine consumes the data and trains the model simultaneously). + + The primary distinction between vineyard's stream and traditional stream frameworks like + Kafka is that data in vineyard's stream is still abstracted as (high-level) objects and + can be consumed in a zero-copy manner, similar to normal objects in vineyard. In contrast, + Kafka is designed for stream processing applications and abstracts data as (low-level) + messages. Utilizing Kafka in the aforementioned scenario would still incur (de)serialization + and memory copy costs. + +7. *Does vineyard support accessing remote objects?* + + Yes, vineyard's RPC client can access the metadata of an object, regardless of whether + the object is local or remote. This capability enables users and internal operators to + examine essential information (e.g., chunk axis, size) about an object, assisting in + decision-making processes related to object management (e.g., determining the need for + repartitioning, planning the next workload). + +8. *How does migration work in vineyard? Is it automatically triggered?* + + Consider a scenario where workload *A* produces a global object *O*, and the subsequent + workload *B* consumes *O* as input. In a Kubernetes cluster with multiple hosts (e.g., + *h1*, *h2*, *h3*, *h4*), if *A* has two worker pods on *h1* and *h2*, the local objects + (i.e., *O1* and *O2*) of *O* are stored on *h1* and *h2*, respectively. + + If the two worker pods of *B* (i.e., *B1* and *B2*) are placed on *h1* and *h3*, *B1* + can access *O1* locally via memory mapping. However, *B2* (on *h3*) cannot access *O2* + since it resides on *h2*. In this situation, a utility program distributed with vineyard + in the :code:`initContainer` of *B2* triggers the migration of *O2* from *h2* to *h3*, + enabling pod *B2* to access *O2* locally. + + Although data migration incurs a cost, the scheduler plugin has been developed to + prioritize *h2* when launching *B2*, minimizing the need for migration whenever possible. + +9. *What's the minimal Kubernetes version requirement for vineyard operator?* + + At present, we only test the vineyard operator based on Kubernetes 1.24.0. + So we highly recommend using Kubernetes 1.24.0 or above. + +10. *Why the vineyard operator can't be deployed on Kubernetes?* + + If you use the helm to deploy the vineyard operator, you may find the vineyard operator + can't be deployed successfully after a long time. In this case, you should check whether + the command contains the flag `--wait`. If so, you should remove the flag `--wait` and + try to install the operator again. + +11. *How to connect to the vineyard cluster deployed by the vineyard operator?* + + There are two ways to connect to the vineyard cluster deployed by the vineyard operator: + + - `Through IPC`. Create a pod with the specific labels so that the pod can be scheduled + to the node where the vineyard cluster is deployed. + + - `Through RPC`. Connect to the vineyard cluster through the RPC service exposed by the + vineyard operator. You could refer to the `guide`_ for more details. + +12. *Is there a way to install the vineyard cluster on Kubernetes quickly?* + + To reduce the complexity of the installation, we provide a `command line tool`_ + to install the vineyard cluster on Kubernetes quickly. + +.. _open an issue: https://github.com/v6d-io/v6d/issues/new +.. _post it to discussions: https://github.com/v6d-io/v6d/discussions/new +.. _cert-manager: https://cert-manager.io/ +.. _guide: ../../tutorials/kubernetes/using-vineyard-operator.rst +.. _command line tool: ../../notes/cloud-native/vineyardctl.md diff --git a/_sources/notes/developers/roadmap.rst.txt b/_sources/notes/developers/roadmap.rst.txt new file mode 100644 index 0000000000..1d7f9b63a2 --- /dev/null +++ b/_sources/notes/developers/roadmap.rst.txt @@ -0,0 +1,126 @@ +Roadmap +======= + +Vineyard aims to serve as an open-source in-memory immutable data manager. We +cut a major release once a year, a minor release for about every two months, +and a patch release every one or two weeks. + +The roadmap for major vineyard releases are listed as follows: + +v0.8.0 +------ + +Vineyard *v0.8.0* will deliver the first implementation of the following +important features and will be hopefully release in the later Aug, 2022: + +- Filesystem view of vineyard objects: vineyard objects can be accessed like + files on a filesystem in a high-performance fashion. Such a feature would + greatly ease the integration of computing processes with vineyard. +- Copy-on-realloc and data lineage: the mutation support would be extended + from blobs to general objects with a carefully concurrency-control design. +- Transparent object spilling: objects in vineyard can be spilled to disk + when they are too large to fit in memory. +- Sharing GPU memory between processes of different compute engines: we are + working on shared memory on devices to enable boarder applications that + can benefit from the shared vineyard store, especially for deep learning + frameworks and GNN frameworks. + +v0.7.0 +------ + +Vineyard *v0.7.0* will be released in later July, 2022. Vineyard v0.7.0 will +introduces the following experimental features to ease the integration of +various kinds of workloads with Vineyard: + +- Limited mutation support on blobs: starts from vineyard *v0.7.0*, unsealed + blobs can be get by other clients with an :code:`unsafe` flag to ease the + integration of some online storage engines. +- Limited support for remote data accessing using the RPC client: vineyard + *v0.7.0* will bring the feature about creating and accessing remote blobs + using the RPC client. It would be greatly helpful for some specific deployment + and the cost of remote data sourcing to vineyard is tolerable. + +v0.6.0 +------ + +We plan to release the *v0.6.0* version before tne end of June, 2022. The *v0.6.0* +release will include the following enhancement: + +- Better compatibility on various platforms (e.g., CentOS and ArchLinux), and process + platform-specific features like `LD_LIBRARY_PATH` and `libunwind` dependency + carefully. +- Ensure the backwards compatibility with various third-party integrations, e.g., + apache-airflow. +- Vineyard v0.6.0 will be available from `homebrew `_. + +v0.5.0 +------ + +We plan to release the first preliminary version for the Rust SDK and Go SDK +in vineyard *v0.5.0*, that is expected to be delivered in later May, 2022. + +In vineyard *v0.5.0*, we will investigate the opportunity about code generation +based on the metadata of vineyard objects, i.e., we could generate the data +structure definition based on the structure of metadata in runtime (for Python) +and in compile time (even maybe in runtime) for C++ and Rust. + +The integration with Kubernetes (especially the CSI part) will be another key +improvement for *v0.5.0*. + +Further details about release for *v0.5.0* will be added later. + +v0.4.0 +------ + +The release of vineyard *v0.4.0*, will be hopefully released before April, 2022, will +be a follow-up bugfix releases after *v0.3.0*. The version *v0.4.0* makes the +kubernetes related components better. + ++ Improve the robustness of the scheduler plugin. ++ Refine the definition of CRDs. ++ Distribute the vineyard operator to artifact hub as a chart, to make it available for more users. + +v0.3.0 +------ + +We plan to release *v0.3.0* by the end of 2021. vineyard *v0.3.0* will be the first major +stable releases with fully kubernetes support, which will include: + ++ A stable CRD definition for ``LocalObject`` and ``GlobalObject`` to represents vineyard objects + as kubernetes resources. ++ A full-features scheduler plugin for kubernetes, as well as a custom controller that manages + objects (custom resources) in vineyard cluster. ++ A refined version of Helm integration. ++ Application-aware far memory will be included in v0.3.0 as an experimental feature. + +v0.2.0 +------ + +Vineyard *v0.2.0* will address the issue about Python ecosystem compatibility, I/O, and +the kubernetes integration. Vineyard v0.2.0 will take about half of a year with several bugfix +release to testing the design and APIs to reach a stable stable state. + ++ Vineyard *v0.2.0* will support any *filesystem-spec*-compatible data source/sink as well as file + format. ++ Vineyard *v0.2.0* will support Python ecosystem (especially numpy and pandas) better. ++ Vineyard *v0.2.0* will include basic Helm integration for deploying on Kubernetes as a ``DaemonSet``. ++ A prototype of scheduler plugin to do data locality scheduling will be included into vineyard v0.2.0 + to demonstrates the capability about co-scheduling job and data in kubernetes brought by vineyard. ++ Match the criterion of CNCF sandbox project. + +v0.1.0 +------ + +Vineyard *v0.1.0* is the first release after open source. This version includes: + ++ Complete functionality for both server and client. ++ Complete Python SDK. ++ User-friendly package distribution on pypi (for python SDK) and on dockerhub (for vineyardd server). + +Release Notes +------------- + +For more details about what changes happened for every version, please refer to +our `releases notes`_ as well. + +.. _releases notes: https://github.com/v6d-io/v6d/releases diff --git a/_sources/notes/developers/troubleshooting.rst.txt b/_sources/notes/developers/troubleshooting.rst.txt new file mode 100644 index 0000000000..68abee637d --- /dev/null +++ b/_sources/notes/developers/troubleshooting.rst.txt @@ -0,0 +1,49 @@ +Troubleshooting +=============== + +This page provides guidance for addressing common issues that may arise when +working with Vineyard. + +.. Installation Errors +.. ------------------- + +Vineyard Fails to Start +----------------------- + +1. Improper Etcd Configuration + + If you encounter the following error when sending requests to Vineyard: + + .. code:: + + Etcd error: etcdserver: too many operations in txn request, error code: 3 + + This indicates that your Etcd configuration is not set up correctly and does not support + more than 128 operations within a single transaction. To resolve this issue, check your Etcd + startup parameters and increase the :code:`--max-txn-ops` value, for example, to :code:`102400`. + +2. bind: Permission Denied Error When Launching vineyardd + + The Vineyard server uses a UNIX-domain socket for IPC connections and memory sharing with clients. + By default, the UNIX-domain socket is located at :code:`/var/run/vineyard.sock`, which typically + requires root permission. + + To launch vineyardd, you can either: + + + Run the :code:`vineyardd` command with :code:`sudo`, + + Or, specify a different location for the UNIX-domain socket that does not require root permission + using the :code:`--socket` command line argument, e.g., + .. code:: bash + + python3 -m vineyard --socket=/tmp/vineyard.sock + +Vineyard Issues on Kubernetes +----------------------------- + +1. Etcd Pod Resource Limitations in Kubernetes Deployment + + We have observed that etcd performance may degrade when a Vineyard client persists a large + object, particularly in Kubernetes deployments where the CPU cores of the etcd pod are limited by + cgroups. In such cases, users should increase the CPU resources allocated to the etcd pod. For + more information on etcd tuning, please refer to the `Hardware recommendations + `_ section in the etcd documentation. diff --git a/_sources/notes/getting-started.rst.txt b/_sources/notes/getting-started.rst.txt new file mode 100644 index 0000000000..a1b117337d --- /dev/null +++ b/_sources/notes/getting-started.rst.txt @@ -0,0 +1,236 @@ +Getting Started +=============== + +.. _getting-started: + +Installing vineyard +------------------- + +Vineyard is distributed as a `Python package`_ and can be effortlessly installed using :code:`pip`: + +.. code:: console + + $ pip3 install vineyard + +Launching vineyard server +------------------------- + +.. code:: console + + $ python3 -m vineyard + +A vineyard daemon server will be launched with default settings. By default, :code:`/var/run/vineyard.sock` +will be used by vineyardd to listen for incoming IPC connections. + +To stop the running vineyardd instance, simply press :code:`Ctrl-C` in the terminal. + +.. tip:: + + If you encounter errors like ``cannot launch vineyardd on '/var/run/vineyard.sock': + Permission denied,``, it means **you don't have the permission** to create a UNIX-domain + socket at :code:`/var/run/vineyard.sock`. You can either: + + - Run vineyard as root, using ``sudo``: + + .. code:: console + + $ sudo -E python3 -m vineyard + + - Or, change the socket path to a writable location with the ``--socket`` command + line option: + + .. code:: console + + $ python3 -m vineyard --socket /tmp/vineyard.sock + +Connecting to vineyard +---------------------- + +Once launched, you can call :code:`vineyard.connect` with the socket name to initiate a vineyard client +from Python: + +.. code:: python + + >>> import vineyard + >>> client = vineyard.connect('/var/run/vineyard.sock') + +Storing and Retrieving Python Objects +------------------------------------- + +Vineyard is designed as an in-memory object store and offers two high-level APIs :code:`put` and +:code:`get` for creating and accessing shared objects, enabling seamless interoperability with the Python +ecosystem. The former returns a :code:`vineyard.ObjectID` upon success, which can be used +to retrieve shared objects from vineyard using the latter. + +In the following example, we use :code:`client.put()` to build a vineyard object from the numpy +ndarray ``arr``, which returns the ``object_id`` - a unique identifier in vineyard representing +the object. Given the ``object_id``, we can obtain a shared-memory object from vineyard with the +:code:`client.get()` method. + +.. code:: python + + >>> import numpy as np + >>> + >>> object_id = client.put(np.random.rand(2, 4)) + >>> object_id + o0015c78883eddf1c + >>> + >>> shared_array = client.get(object_id) + >>> shared_array + ndarray([[0.39736989, 0.38047846, 0.01948815, 0.38332264], + [0.61671189, 0.48903213, 0.03875045, 0.5873005 ]]) + +.. note:: + + :code:`shared_array` does not allocate extra memory in the Python process; instead, it shares memory + with the vineyard server via `mmap`_ in a zero-copy process. + +The sharable objects can be complex and nested. Like numpy ndarray, the pandas dataframe ``df`` can +be seamlessly stored in vineyard and retrieved with the ``.put()`` and ``.get()`` methods as follows: + +.. code:: python + + >>> import pandas as pd + >>> + >>> df = pd.DataFrame({'u': [0, 0, 1, 2, 2, 3], + >>> 'v': [1, 2, 3, 3, 4, 4], + >>> 'weight': [1.5, 3.2, 4.7, 0.3, 0.8, 2.5]}) + >>> object_id = client.put(df) + >>> + >>> shared_dataframe = client.get(object_id) + >>> shared_dataframe + u v weight + 0 0 1 1.5 + 1 0 2 3.2 + 2 1 3 4.7 + 3 2 3 0.3 + 4 2 4 0.8 + 5 3 4 2.5 + +Under the hood, vineyard implements a builder/resolver mechanism to represent arbitrary +data structures as *vineyard objects* and resolve them back to native values in the corresponding +programming languages and computing systems. See also :ref:`divein-driver-label` for more information. + +Sharing objects between tasks +----------------------------- + +Vineyard is designed for sharing intermediate data between tasks. The following example +demonstrates how a dataframe can be passed between two **processes** using vineyard, namely +the producer and consumer in the example below: + +.. code:: python + + import multiprocessing as mp + import vineyard + + import numpy as np + import pandas as pd + + socket = '/var/run/vineyard.sock' + + def produce(name): + client = vineyard.connect(socket) + client.put(pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD')), + persist=True, name=name) + + def consume(name): + client = vineyard.connect(socket) + print(client.get(name=name).sum()) + + if __name__ == '__main__': + name = 'dataset' + + producer = mp.Process(target=produce, args=(name,)) + producer.start() + consumer = mp.Process(target=consume, args=(name,)) + consumer.start() + + producer.join() + consumer.join() + +Running the code above, you should see the following output: + +.. code:: text + + A -4.529080 + B -2.969152 + C -7.067356 + D 4.003676 + dtype: float64 + +Next steps +---------- + +Beyond the core functionality of sharing objects between tasks, vineyard also provides: + +- Distributed objects and stream abstraction over immutable chunks; +- An IDL (:ref:`vcdl`) that helps integrate vineyard with other systems at minimal cost; +- A mechanism of pluggable drivers for various tasks that serve as the glue + between the core compute engine and the external world, e.g., data sources, data + sinks; +- Integration with Kubernetes for sharing between tasks in workflows deployed + on cloud-native infrastructures. + +.. panels:: + :header: text-center + :column: col-lg-12 p-2 + + .. link-button:: architecture + :type: ref + :text: Architecture + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Overview of vineyard. + +Learn more about vineyard's key concepts from the following user guides: + +.. panels:: + :header: text-center + :container: container-lg pb-4 + :column: col-lg-4 col-md-4 col-sm-4 col-xs-12 p-2 + :body: text-center + + .. link-button:: key-concepts/objects + :type: ref + :text: Vineyard Objects + :classes: btn-block stretched-link + + Explore the design of the object model in vineyard. + + --- + + .. link-button:: key-concepts/vcdl + :type: ref + :text: VCDL + :classes: btn-block stretched-link + + Discover how vineyard integrates with other computing systems. + + --- + + .. link-button:: key-concepts/io-drivers + :type: ref + :text: I/O Drivers + :classes: btn-block stretched-link + + Understand the design and implementation of pluggable routines for I/O, repartition, + migration, and more. + +Vineyard is a natural fit for cloud-native computing, where it can be deployed and +managed by the *vineyard operator*, providing data-aware scheduling for data analytical +workflows to achieve efficient data sharing on Kubernetes. More details about vineyard +on Kubernetes can be found here: + +.. panels:: + :header: text-center + :column: col-lg-12 p-2 + + .. link-button:: cloud-native/deploy-kubernetes + :type: ref + :text: Kubernetes + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Deploy vineyard on Kubernetes and accelerate your big-data workflows. + +.. _Python package: https://pypi.org/project/vineyard +.. _mmap: https://man7.org/linux/man-pages/man2/mmap.2.html diff --git a/_sources/notes/integration-bigdata.rst.txt b/_sources/notes/integration-bigdata.rst.txt new file mode 100644 index 0000000000..e9382f784a --- /dev/null +++ b/_sources/notes/integration-bigdata.rst.txt @@ -0,0 +1,34 @@ +Big-data on Vineyard +==================== + +.. toctree:: + :maxdepth: 1 + :caption: TOC + :hidden: + + integration/dask.rst + integration/ml.rst + +Vineyard serves as a powerful data-sharing engine, seamlessly integrating with +a variety of big-data computing platforms. This includes machine learning +frameworks and the distributed data processing engine, Dask. + +.. panels:: + :header: text-center + :column: col-lg-12 p-2 + + .. link-button:: integration/ml + :type: ref + :text: Machine Learning + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Executing machine learning workflows on top of vineyard. + + --- + + .. link-button:: integration/dask + :type: ref + :text: Dask + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Using vineyard as the data source / sink of dask computations. diff --git a/_sources/notes/integration-orchestration.rst.txt b/_sources/notes/integration-orchestration.rst.txt new file mode 100644 index 0000000000..9b354750ad --- /dev/null +++ b/_sources/notes/integration-orchestration.rst.txt @@ -0,0 +1,46 @@ +Workflow orchestration +====================== + +.. toctree:: + :maxdepth: 1 + :caption: TOC + :hidden: + + integration/airflow.rst + integration/kedro.md + +Vineyard seamlessly integrates with the workflow orchestration engines, e.g., +Apache Airflow and Kedro, enabling users to effortlessly incorporate Vineyard +into their workflows for enhanced performance. + +Moreover, the Airflow integration empowers users to work with large Python objects +featuring complex data types (e.g., :code:`pandas.DataFrame`) at minimal cost, while +eliminating the need for cumbersome :code:`pickle.dump/loads` operations. + +.. panels:: + :header: text-center + :column: col-lg-12 p-2 + + .. link-button:: integration/airflow + :type: ref + :text: Airflow + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Airflow uses vineyard as the XCom backend to efficiently handle complex data in Python. + +The Kedro integration enables users to easily share large data objects across +nodes in a pipeline and eliminates the high cost of (de)serialization and I/O +compared with alternatives like AWS S3 or Minio, without the need to modify +the pipeline code intrusively, and provides seamless user experience when scaling +pipelines to Kubernetes. + +.. panels:: + :header: text-center + :column: col-lg-12 p-2 + + .. link-button:: integration/kedro + :type: ref + :text: Kedro + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Kedro uses vineyard as a `DataSet` implementation for efficient intermediate data sharing. diff --git a/_sources/notes/integration/airflow.rst.txt b/_sources/notes/integration/airflow.rst.txt new file mode 100644 index 0000000000..11d0163507 --- /dev/null +++ b/_sources/notes/integration/airflow.rst.txt @@ -0,0 +1,227 @@ +Airflow on Vineyard +=================== + +Big data analytical pipelines often involve various types of workloads, each +requiring a dedicated computing system to complete the task. Intermediate +data flows between tasks in the pipeline, and the additional cost of transferring data +accounts for a significant portion of the end-to-end performance in real-world deployments, +making optimization a challenging task. + +Integrating Vineyard with Airflow presents opportunities to alleviate this problem. + +Introducing Airflow +------------------- + +Airflow is a platform that enables users to programmatically author, schedule, and +monitor workflows. Users organize tasks in a Directed Acyclic Graph (DAG), and the +Airflow scheduler executes the tasks on workflows while adhering to the specified +dependencies. + +Consider the following ETL workflow as an example [1]_, + +.. code:: python + + @dag(schedule_interval=None, start_date=days_ago(2), tags=['example']) + def tutorial_taskflow_api_etl(): + @task() + def extract(): + data_string = '{"1001": 301.27, "1002": 433.21, "1003": 502.22}' + + order_data_dict = json.loads(data_string) + return order_data_dict + + @task(multiple_outputs=True) + def transform(order_data_dict: dict): + return {"total_order_value": total_order_value} + + @task() + def load(total_order_value: float): + print(f"Total order value is: {total_order_value:.2f}") + + order_data = extract() + order_summary = transform(order_data) + + + tutorial_etl_dag = tutorial_taskflow_api_etl() + +It forms the following DAG, including three individual tasks as the nodes, and +runs the tasks sequentially based on their data This forms a DAG, including +three individual tasks as nodes, and edges between nodes that describe the +data dependency relations. The Airflow scheduler runs the tasks sequentially +based on their data dependencies.dependencies. Airflow ETL Workflow + +Airflow on Vineyard +------------------- + +The Rationale for Airflow on Vineyard +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Airflow excels at defining and orchestrating complex workflows. However, managing +data flow within the pipeline remains a challenge. Airflow relies on database +backends such as SQLite, MySQL, and PostgreSQL to store intermediate data between +tasks. In real-world scenarios, large-scale data, such as large tensors, dataframes, +and distributed graphs, cannot fit into these databases. As a result, external +storage systems like HDFS and S3 are used to store intermediate data, with only +an identifier stored in the database. + +Utilizing external storage systems to share intermediate data among tasks in big +data analytical pipelines incurs performance costs due to data copying, +serialization/deserialization, and network data transfer. + +Vineyard is designed to efficiently share intermediate in-memory data for big data +analytical pipelines, making it a natural fit for workloads on Airflow. + +How Vineyard Enhances Airflow +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Airflow allows users to register an external **XCom** backend, which is precisely +what Vineyard is designed for. + +Vineyard serves as an *XCom* backend for Airflow workers, enabling the transfer of +large-scale data objects between tasks without relying on Airflow's database backend +or external storage systems like HDFS. The Vineyard XCom backend also handles object +migration when the required inputs are not located where the task is scheduled to +execute. + +Vineyard's XCom backend achieves its functionality by injecting hooks into the +processes of saving values to the backend and fetching values from the backend, +as described below: + +.. code:: python + + class VineyardXCom(BaseXCom): + + @staticmethod + def serialize_value(value: Any): + """ Store the value to vineyard server, and serialized the result + Object ID to save it into the backend database later. + """ + + @staticmethod + def deserialize_value(result: "XCom") -> Any: + """ Obtain the Object ID after deserialization, and fetching the + underlying value from vineyard. + + This value is resolved from vineyard objects in a zero-copy + fashion. + """ + + +Addressing Distributed Deployment Challenges +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Airflow supports parallel task execution across multiple workers to efficiently +process complex workflows. In a distributed deployment (using the `CeleryExecutor`), +tasks sharing intermediate data might be scheduled on different workers, necessitating +remote data access. + +Vineyard seamlessly handles object migration for various data types. In the XCom backend, +when the IPC client encounters remote objects, it triggers a migration action to move +the objects to the local worker, ensuring input data is readily available before task +execution. + +This transparent object migration simplifies complex data operations and movement, +allowing data scientists to focus on computational logic when developing big data +applications on Airflow. + +Running Vineyard + Airflow +-------------------------- + +Users can try Airflow provider for Vineyard by the following steps: + +1. Install required packages: + + .. code:: bash + + pip3 install airflow-provider-vineyard + +2. Configure Vineyard locally + + The vineyard server can be easier launched locally with the following command: + + .. code:: bash + + python -m vineyard --socket=/tmp/vineyard.sock + + See also our documentation about `launching vineyard`_. + +3. Configure Airflow to use the vineyard XCom backend by specifying the environment + variable + + .. code:: bash + + export AIRFLOW__CORE__XCOM_BACKEND=vineyard.contrib.airflow.xcom.VineyardXCom + + and configure the location of UNIX-domain IPC socket for vineyard client by + + .. code:: bash + + export AIRFLOW__VINEYARD__IPC_SOCKET=/tmp/vineyard.sock + + or + + .. code:: bash + + export VINEYARD_IPC_SOCKET=/tmp/vineyard.sock + +4. Launching your airflow scheduler and workers, and run the following DAG as example, + + .. code:: python + + import numpy as np + import pandas as pd + + from airflow.decorators import dag, task + from airflow.utils.dates import days_ago + + default_args = { + 'owner': 'airflow', + } + + @dag(default_args=default_args, schedule_interval=None, start_date=days_ago(2), tags=['example']) + def taskflow_etl_pandas(): + @task() + def extract(): + order_data_dict = pd.DataFrame({ + 'a': np.random.rand(100000), + 'b': np.random.rand(100000), + }) + return order_data_dict + + @task(multiple_outputs=True) + def transform(order_data_dict: dict): + return {"total_order_value": order_data_dict["a"].sum()} + + @task() + def load(total_order_value: float): + print(f"Total order value is: {total_order_value:.2f}") + + order_data = extract() + order_summary = transform(order_data) + load(order_summary["total_order_value"]) + + taskflow_etl_pandas_dag = taskflow_etl_pandas() + +In the example above, the `extract` and `transform` tasks share a `pandas.DataFrame` as +intermediate data. This presents a challenge, as the DataFrame cannot be pickled, and when +dealing with large data, it cannot fit into the backend databases of Airflow. + +This example is adapted from the Airflow documentation. For more information, refer to the +`Tutorial on the Taskflow API`_. + +Further Ahead +------------- + +The Airflow provider for Vineyard, currently in its experimental stage, demonstrates +significant potential for efficiently and flexibly sharing large-scale intermediate data +in big data analytical workflows within Airflow. + +The Airflow community is actively working to enhance support for modern big data and AI +applications. We believe that the integration of Vineyard, Airflow, and other cloud-native +infrastructures can provide a more effective and efficient solution for data scientists. + + +.. [1] See: https://airflow.apache.org/docs/apache-airflow/stable/tutorial_taskflow_api.html + +.. _launching vineyard: https://v6d.io/notes/getting-started.html#starting-vineyard-server +.. _Tutorial on the Taskflow API: https://airflow.apache.org/docs/apache-airflow/stable/tutorial_taskflow_api.html diff --git a/_sources/notes/integration/dask.rst.txt b/_sources/notes/integration/dask.rst.txt new file mode 100644 index 0000000000..628d1906a8 --- /dev/null +++ b/_sources/notes/integration/dask.rst.txt @@ -0,0 +1,150 @@ +Dask on Vineyard +================ + +The integration with Dask enables dask.array and dask.dataframe to be seamlessly persisted in +and retrieved from Vineyard. In the following sections, we demonstrate how Vineyard simplifies +the implementation of an example that utilizes Dask for data preprocessing and TensorFlow for +distributed learning, as previously showcased in the blog_. + +The Deployment +-------------- + +.. image:: ../../images/dask-tf.jpg + :alt: Dask Tensorflow Workflow + +As illustrated in the figure above, we employ two machines for the distributed tasks for +demonstration purposes. The Vineyard daemon processes are launched on both machines, along +with the Dask workers. The Dask scheduler is initiated on the first machine, where we also +run the Dask preprocessing program in the first step, as the Dask scheduler manages the +distribution of computation tasks among its workers. + +In the second step, we execute the training program on both machines with different **TF_CONFIG** +settings. For details on configuring the setup, please refer to the `documentation`_. + +Preprocessing in Dask +--------------------- + +In this step, we load the mnist data and duplicate it to simulate the parallel processing as same as the blog_. + +.. code:: python + + from vineyard.core.builder import builder_context + from vineyard.contrib.dask.dask import dask_context + + def dask_preprocess(dask_scheduler): + def get_mnist(): + (x_train, y_train), _ = tf.keras.datasets.mnist.load_data() + # The `x` arrays are in uint8 and have values in the [0, 255] range. + # You need to convert them to float64 with values in the [0, 1] range. + x_train = x_train / np.float64(255) + y_train = y_train.astype(np.int64) + return pd.DataFrame({'x': list(x_train), 'y': y_train}) + + with dask_context(): + datasets = [delayed(get_mnist)() for i in range(20)] + dfs = [dd.from_delayed(ds) for ds in datasets] + gdf = dd.concat(dfs) + gdf_id = vineyard.connect().put(gdf, dask_scheduler=dask_scheduler) + + return gdf_id + +Here the returned **gdf_id** is the ObjectID of a **vineyard::GlobalDataFrame** +which consists of 20 partitions (10 partitions on each machine). + +Training in Tensorflow +---------------------- + +In this step, we use the preprocessed data **gdf_id** to train a model distributedly +in keras of Tensorflow. + +.. code:: python + + from vineyard.contrib.ml.tensorflow import register_tf_types + from vineyard.core.resolver import resolver_context + + def mnist_dataset(gdf_id, batch_size): + with resolver_context() as resolver: + # register the resolver for tensorflow Dataset to the resolver_context + register_tf_types(None, resolver) + train_datasets = vineyard.connect().get(gdf_id, data='x', label='y') + train_datasets = train_datasets.repeat().batch(batch_size) + + options = tf.data.Options() + options.experimental_distribute.auto_shard_policy = tf.data.experimental.AutoShardPolicy.OFF + train_datasets_no_auto_shard = train_datasets.with_options(options) + return train_datasets_no_auto_shard + + def build_and_compile_cnn_model(): + model = tf.keras.Sequential([ + tf.keras.layers.InputLayer(input_shape=(28, 28)), + tf.keras.layers.Reshape(target_shape=(28, 28, 1)), + tf.keras.layers.Conv2D(32, 3, activation='relu'), + tf.keras.layers.Flatten(), + tf.keras.layers.Dense(128, activation='relu'), + tf.keras.layers.Dense(10) + ]) + model.compile( + loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), + optimizer=tf.keras.optimizers.SGD(learning_rate=0.001), + metrics=['accuracy']) + return model + + def train(gdf_id): + per_worker_batch_size = 64 + strategy = tf.distribute.MultiWorkerMirroredStrategy() + train_dataset = mnist_dataset(gdf_id, per_worker_batch_size) + + with strategy.scope(): + multi_worker_model = mnist.build_and_compile_cnn_model() + + multi_worker_model.fit(train_dataset, epochs=3, steps_per_epoch=70) + +To utilize the preprocessed data, we first register the resolvers capable of resolving a +**vineyard::GlobalDataFrame** distributed across multiple workers within the resolver_context. +Subsequently, we can directly obtain the **tf.data.Dataset** from Vineyard using the **get** +method. + +.. note:: + + It is essential to specify the column names for the data and label, as they were set in + the previous step. + +Transfer Learning +----------------- + +In this section, we demonstrate how the dask-vineyard integration can be effectively utilized +in transfer learning scenarios. Transfer learning is a technique where a pre-trained deep +learning model is used to compute features for downstream models. Storing these features in +memory is advantageous, as it eliminates the need to recompute features or incur significant +I/O costs by repeatedly reading them from disk. We will refer to the featurization_ example +and use the tf_flowers_ dataset as a **dask.array**. We will employ the pre-trained **ResNet50** +model to generate features and subsequently store them in Vineyard. The resulting global +tensor in Vineyard will consist of 8 partitions, each containing 400 data slots. + +.. code:: python + + def get_images(idx, num): + paths = list(Path("flower_photos").rglob("*.jpg"))[idx::num] + data = [] + for p in paths: + with open(p,'rb') as f: + img = Image.open(io.BytesIO(f.read())).resize([224, 224]) + arr = preprocess_input(img_to_array(img)) + data.append(arr) + return np.array(data) + + def featurize(v, block_id=None): + model = ResNet50(include_top=False) + preds = model.predict(np.stack(v)) + return preds.reshape(400, 100352) + + imgs = [da.from_delayed(delayed(get_images)(i,8), shape=(400, 244, 244, 3), dtype='float') for i in range(8)] + imgs = da.concatenate(imgs, axis=0) + res = imgs.map_blocks(featurize, chunks=(400,100352), drop_axis=[2,3], dtype=float) + global_tensor_id = vineyard.connect().put(res, dask_scheduler=dask_scheduler) + + +.. _documentation: https://www.tensorflow.org/tutorials/distribute/multi_worker_with_keras +.. _blog: http://matthewrocklin.com/blog/work/2017/02/11/dask-tensorflow +.. _featurization: https://docs.databricks.com/_static/notebooks/deep-learning/deep-learning-transfer-learning-keras.html +.. _tf_flowers: https://www.tensorflow.org/datasets/catalog/tf_flowers diff --git a/_sources/notes/integration/kedro.md.txt b/_sources/notes/integration/kedro.md.txt new file mode 100644 index 0000000000..c0cb65e339 --- /dev/null +++ b/_sources/notes/integration/kedro.md.txt @@ -0,0 +1,270 @@ +Kedro Vineyard Plugin +===================== + +The Kedro vineyard plugin contains components (e.g., `DataSet` and `Runner`) +to share intermediate data among nodes in Kedro pipelines using vineyard. + +Kedro on Vineyard +----------------- + +Vineyard works as the *DataSet* provider for kedro workers to allow transferring +large-scale data objects between tasks that cannot be efficiently serialized and +is not suitable for `pickle`, without involving external storage systems like +AWS S3 (or Minio as an alternative). The Kedro vineyard plugin handles object migration +as well when the required inputs are not located where the task is scheduled to execute. + +Requirements +------------ + +The following packages are needed to run Kedro on vineyard, + +- kedro >= 0.18 +- vineyard >= 0.14.5 + +Configuration +------------- + +1. Install required packages: + + pip3 install vineyard-kedro + +2. Configure Vineyard locally + + The vineyard server can be easier launched locally with the following command: + + python3 -m vineyard --socket=/tmp/vineyard.sock + + See also our documentation about [Launching Vineyard][1]. + +3. Configure the environment variable to tell Kedro vineyard plugin how to connect to the + vineyardd server: + + export VINEYARD_IPC_SOCKET=/tmp/vineyard.sock + +Usage +----- + +After installing the dependencies and preparing the vineyard server, you can execute the +Kedro workflows as usual and benefits from vineyard for intermediate data sharing. + +We take the [Iris example][2] as an example, + +```bash +$ kedro new --starter=pandas-iris +``` + +The nodes in this pipeline look like + +```python +def split_data( + data: pd.DataFrame, parameters: Dict[str, Any] +) -> Tuple[pd.DataFrame, pd.DataFrame, pd.Series, pd.Series]: + data_train = data.sample( + frac=parameters["train_fraction"], random_state=parameters["random_state"] + ) + data_test = data.drop(data_train.index) + + X_train = data_train.drop(columns=parameters["target_column"]) + X_test = data_test.drop(columns=parameters["target_column"]) + y_train = data_train[parameters["target_column"]] + y_test = data_test[parameters["target_column"]] + + return X_train, X_test, y_train, y_test + + +def make_predictions( + X_train: pd.DataFrame, X_test: pd.DataFrame, y_train: pd.Series +) -> pd.Series: + X_train_numpy = X_train.to_numpy() + X_test_numpy = X_test.to_numpy() + + squared_distances = np.sum( + (X_train_numpy[:, None, :] - X_test_numpy[None, :, :]) ** 2, axis=-1 + ) + nearest_neighbour = squared_distances.argmin(axis=0) + y_pred = y_train.iloc[nearest_neighbour] + y_pred.index = X_test.index + + return y_pred +``` + +You can see that the intermediate data between `split_data` and `make_predictions` is some pandas +dataframes and series. + +Try running the pipeline without vineyard, + +```bash +$ cd iris +$ kedro run +[05/25/23 11:38:56] INFO Kedro project iris session.py:355 +[05/25/23 11:38:57] INFO Loading data from 'example_iris_data' (CSVDataSet)... data_catalog.py:343 + INFO Loading data from 'parameters' (MemoryDataSet)... data_catalog.py:343 + INFO Running node: split: split_data([example_iris_data,parameters]) -> [X_train,X_test,y_train,y_test] node.py:329 + INFO Saving data to 'X_train' (MemoryDataSet)... data_catalog.py:382 + INFO Saving data to 'X_test' (MemoryDataSet)... data_catalog.py:382 + INFO Saving data to 'y_train' (MemoryDataSet)... data_catalog.py:382 + INFO Saving data to 'y_test' (MemoryDataSet)... data_catalog.py:382 + INFO Completed 1 out of 3 tasks sequential_runner.py:85 + INFO Loading data from 'X_train' (MemoryDataSet)... data_catalog.py:343 + INFO Loading data from 'X_test' (MemoryDataSet)... data_catalog.py:343 + INFO Loading data from 'y_train' (MemoryDataSet)... data_catalog.py:343 + INFO Running node: make_predictions: make_predictions([X_train,X_test,y_train]) -> [y_pred] node.py:329 +... +``` + +You can see that the intermediate data is shared with memory. When kedro is deploy to a cluster, e.g., +to [argo workflow][3], the `MemoryDataSet` is not applicable anymore and you will need to setup the +AWS S3 or Minio service and sharing those intermediate data as CSV files. + +```yaml +X_train: + type: pandas.CSVDataSet + filepath: s3://testing/data/02_intermediate/X_train.csv + credentials: minio + +X_test: + type: pandas.CSVDataSet + filepath: s3://testing/data/02_intermediate/X_test.csv + credentials: minio + +y_train: + type: pandas.CSVDataSet + filepath: s3://testing/data/02_intermediate/y_train.csv + credentials: minio +``` + +It might be inefficient for pickling pandas dataframes when data become larger. With the kedro +vineyard plugin, you can run the pipeline with vineyard as the intermediate data medium by + +```bash +$ kedro run --runner vineyard.contrib.kedro.runner.SequentialRunner +[05/25/23 11:45:34] INFO Kedro project iris session.py:355 + INFO Loading data from 'example_iris_data' (CSVDataSet)... data_catalog.py:343 + INFO Loading data from 'parameters' (MemoryDataSet)... data_catalog.py:343 + INFO Running node: split: split_data([example_iris_data,parameters]) -> [X_train,X_test,y_train,y_test] node.py:329 + INFO Saving data to 'X_train' (VineyardDataSet)... data_catalog.py:382 + INFO Saving data to 'X_test' (VineyardDataSet)... data_catalog.py:382 + INFO Saving data to 'y_train' (VineyardDataSet)... data_catalog.py:382 + INFO Saving data to 'y_test' (VineyardDataSet)... data_catalog.py:382 + INFO Loading data from 'X_train' (VineyardDataSet)... data_catalog.py:343 + INFO Loading data from 'X_test' (VineyardDataSet)... data_catalog.py:343 + INFO Loading data from 'y_train' (VineyardDataSet)... data_catalog.py:343 + INFO Running node: make_predictions: make_predictions([X_train,X_test,y_train]) -> [y_pred] node.py:329 +... +``` + +Without any modification to your pipeline code, you can see that the intermediate data is shared +with vineyard using the `VineyardDataSet` and no longer suffers from the overhead of (de)serialization +and the I/O cost between external AWS S3 or Minio services. + +Like `kedro catalog create`, the Kedro vineyard plugin provides a command-line interface to generate +the catalog configuration for given pipeline, which will rewrite the unspecified intermediate data +to `VineyardDataSet`, e.g., + +```bash +$ kedro vineyard catalog create -p __default__ +``` + +You will get + +```yaml +X_test: + ds_name: X_test + type: vineyard.contrib.kedro.io.dataset.VineyardDataSet +X_train: + ds_name: X_train + type: vineyard.contrib.kedro.io.dataset.VineyardDataSet +y_pred: + ds_name: y_pred + type: vineyard.contrib.kedro.io.dataset.VineyardDataSet +y_test: + ds_name: y_test + type: vineyard.contrib.kedro.io.dataset.VineyardDataSet +y_train: + ds_name: y_train + type: vineyard.contrib.kedro.io.dataset.VineyardDataSet +``` + +Deploy to Kubernetes +-------------------- + +When the pipeline scales to Kubernetes, the interaction with the Kedro vineyard plugin is +still simple and non-intrusive. The plugin provides tools to prepare the docker image and +generate Argo workflow specification file for the Kedro pipeline. Next, we'll demonstrate +how to deploy pipelines to Kubernetes while leverage Vineyard for efficient intermediate +sharing between tasks step-by-step. + +1. Prepare the vineyard cluster (see also [Deploy on Kubernetes][5]): + + ```bash + # export your kubeconfig path here + $ export KUBECONFIG=/path/to/your/kubeconfig + + # install the vineyard operator + $ go run k8s/cmd/main.go deploy vineyard-cluster --create-namespace + ``` + +2. Install the argo server: + + ```bash + # install the argo server + $ kubectl create namespace argo + $ kubectl apply -n argo -f https://github.com/argoproj/argo-workflows/releases/download/v3.4.8/install.yaml + ``` + +3. Generate the iris demo project from the official template: + + ```bash + $ kedro new --starter=pandas-iris + ``` + +4. Build the Docker image for this iris demo project: + + ```bash + # walk to the iris demo root directory + $ cd iris + $ kedro vineyard docker build + ``` + + A Docker image named `iris` will be built successfully. The docker image + need to be pushed to your image registry, or loaded to the kind/minikube cluster, to be + available in Kubernetes. + + ```bash + $ docker images | grep iris + iris latest 3c92da8241c6 About a minute ago 690MB + ``` + +5. Next, generate the Argo workflow YAML file from the iris demo project: + + ```bash + $ kedro vineyard argo generate -i iris + + # check the generated Argo workflow YAML file, you can see the Argo workflow YAML file named `iris.yaml` + # is generated successfully. + $ ls -l argo-iris.yml + -rw-rw-r-- 1 root root 3685 Jun 12 23:55 argo-iris.yml + ``` + +6. Finally, submit the Argo workflow to Kubernetes: + + ```bash + $ argo submit -n argo argo-iris.yml + ``` + + You can interact with the Argo workflow using the `argo` command-line tool, e.g., + + ```bash + $ argo list workflows -n argo + NAME STATUS AGE DURATION PRIORITY MESSAGE + iris-sg6qf Succeeded 18m 30s 0 + ``` + +We have prepared a benchmark to evaluate the performance gain brought by vineyard for data +sharing when data scales, for more details, please refer to [this report][4]. + +[1]: https://v6d.io/notes/getting-started.html#starting-vineyard-server +[2]: https://docs.kedro.org/en/stable/get_started/new_project.html +[3]: https://docs.kedro.org/en/stable/deployment/argo.html#how-to-run-your-kedro-pipeline-using-argo-workflows +[4]: https://v6d.io/tutorials/data-processing/accelerate-data-sharing-in-kedro.html +[5]: https://v6d.io/notes/cloud-native/deploy-kubernetes.html diff --git a/_sources/notes/integration/ml.rst.txt b/_sources/notes/integration/ml.rst.txt new file mode 100644 index 0000000000..db9df06074 --- /dev/null +++ b/_sources/notes/integration/ml.rst.txt @@ -0,0 +1,295 @@ +Machine Learning with Vineyard +============================== + + +**Vineyard-ML**: A Vineyard package that integrates Machine Learning Frameworks to Vineyard. + +TensorFlow +---------- + +Using Numpy Data +^^^^^^^^^^^^^^^^ + +.. code:: python + + >>> import tensorflow as tf + >>> from vineyard.contrib.ml import tensorflow + >>> dataset = tf.data.Dataset.from_tensor_slices((data, label)) + >>> data_id = vineyard_client.put(dataset) + >>> vin_data = vineyard_client.get(data_id) + +Vineyard supports the ``tf.data.Dataset``. The ``vin_data`` will be a shared-memory object +from the vineyard. + +Using Dataframe +^^^^^^^^^^^^^^^ + +.. code:: python + + >>> import pandas as pd + >>> df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [5, 6, 7, 8], 'target': [1.0, 2.0, 3.0, 4.0]}) + >>> label = df.pop('target') + >>> dataset = tf.data.Dataset.from_tensor_slices((dict(df), label)) + >>> data_id = vineyard_client.put(dataset) + >>> vin_data = vineyard_client.get(data_id) + +Wrap the dataframe with ``tf.data.Dataset``. This enables the use of feature columns as a +bridge to map from the columns in Pandas Dataframe to features in Dataset. The +dataset should return a dictionary of column names (from the dataframe) that maps +to column values. The dataset should only contain ``numerical data``. + +Using RecordBatch of Pyarrow +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. code:: python + + >>> import pyarrow as pa + >>> arrays = [pa.array([1, 2, 3, 4]), pa.array([3.0, 4.0, 5.0, 6.0]), pa.array([0, 1, 0, 1])] + >>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'f1', 'label']) + >>> data_id = vineyard_client.put(batch) + >>> vin_data = vineyard_client.get(data_id) + +Vineyard supports direct integration of RecordBatch. The ``vin_data`` object will +be a TensorFlow Dataset, i.e. ``tf.data.Dataset``. Here the ``label`` row should be named as ``label``. + +Using Tables of Pyarrow +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: python + + >>> arrays = [pa.array([1, 2, 3, 4]), pa.array([3.0, 4.0, 5.0, 6.0]), pa.array([0, 1, 0, 1])] + >>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'f1', 'label']) + >>> batches = [batch]*3 + >>> table = pa.Table.from_batches(batches) + >>> data_id = vineyard_client.put(table) + >>> vin_data = vineyard_client.get(data_id) + +Vineyard supports direct integration of Tables as well. Here, the ``vin_data`` +object will be of type TensorFlow Dataset, i.e. ``tf.data.Dataset``. Here the ``label`` row +should be named as ``label``. + + +PyTorch +------- + +Using Numpy Data +^^^^^^^^^^^^^^^^ + +Vineyard supports ``Custom Datasets`` inherited from the PyTorch Dataset. + +.. code:: python + + >>> import torch + >>> from vineyard.contrib.ml import pytorch + >>> data_id = vineyard_client.put(dataset, typename='Tensor') + >>> vin_data = vineyard_client.get(data_id) + +The dataset object should be an object of the type CustomDataset class which is inherited +from ``torch.utils.data.Dataset`` class. Adding the typename as ``Tensor`` is important. +The ``vin_data`` will be of type ``torch.utils.data.TensorDataset``. + +Using Dataframe +^^^^^^^^^^^^^^^ + +.. code:: python + + >>> df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [5, 6, 7, 8], 'c': [1.0, 2.0, 3.0, 4.0]}) + >>> label = torch.tensor(df['c'].values.astype(np.float32)) + >>> data = torch.tensor(df.drop('c', axis=1).values.astype(np.float32)) + >>> dataset = torch.utils.data.TensorDataset(data, label) + >>> data_id = vineyard_client.put(dataset, typename='Dataframe', cols=['a', 'b', 'c'], label='c') + >>> vin_data = vineyard_client.get(data_id, label='c) + +While using the PyTorch form of the dataframe with vineyard, it is important to mention +the typename as ``Dataframe``, a list of column names in ``cols`` and the ``label`` +name in label tag. The ``vin_data`` will be of the form ``TensorDataset`` with +the label as mentioned with the label tag. If no value is passed to the label tag +vineyard will consider the default value which is the value of label passed in while +calling the ``put`` method + +Using RecordBatch of Pyarrow +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: python + + >>> import pyarrow as pa + >>> arrays = [pa.array([1, 2, 3, 4]), pa.array([3.0, 4.0, 5.0, 6.0]), pa.array([0, 1, 0, 1])] + >>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'f1', 'f2']) + >>> data_id = vineyard_client.put(batch) + >>> vin_data = vineyard_client.get(data_id, label='f2') + +The ``vin_data`` will be of the form ``TensorDataset`` with the label as mentioned +with the label tag. In this case it is important to mention the label tag. + +Using Tables of Pyarrow +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: python + + >>> arrays = [pa.array([1, 2, 3, 4]), pa.array([3.0, 4.0, 5.0, 6.0]), pa.array([0, 1, 0, 1])] + >>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'f1', 'f2']) + >>> batches = [batch]*3 + >>> table = pa.Table.from_batches(batches) + >>> data_id = vineyard_client.put(table) + >>> vin_data = vineyard_client.get(data_id, label='f2') + +The ``vin_data`` object will be of the form ``TensorDataset`` with the label as mentioned +with the label tag. In this case, it is important to mention the label tag. + +MxNet +----- + +Using Numpy Data +^^^^^^^^^^^^^^^^ + +Vineyard supports ``Array Datasets`` from the gluon.data of MxNet. + +.. code:: python + + >>> import mxnet as mx + >>> from vineyard.contrib.ml import mxnet + >>> dataset = mx.gluon.data.ArrayDataset((data, label)) + >>> data_id = vineyard_client.put(dataset, typename='Tensor') + >>> vin_data = vineyard_client.get(data_id) + +The dataset object should be an object of the type ArrayDataset from ``mxnet.gluon.data`` +class. Here, Adding the typename as ``Tensor`` is important. The ``vin_data`` will be +of type ``mxnet.gluon.data.ArrayDataset``. + +Using Dataframe +^^^^^^^^^^^^^^^ + +.. code:: python + + >>> df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [5, 6, 7, 8], 'c': [1.0, 2.0, 3.0, 4.0]}) + >>> label = df['c'].values.astype(np.float32) + >>> data = df.drop('c', axis=1).values.astype(np.float32) + >>> dataset = mx.gluon.data.ArrayDataset((data, label)) + >>> data_id = vineyard_client.put(dataset, typename='Dataframe', cols=['a', 'b', 'c'], label='c') + >>> vin_data = vineyard_client.get(data_id, label='c) + +While using the MxNet form of the dataframe with vineyard, it is important to mention +the typename as ``Dataframe``, a list of column names in ``cols`` and the ``label`` +name in label tag. The ``vin_data`` will be of the form ``ArrayDataset`` with +the label as mentioned with the label tag. If no value is passed to the label tag +vineyard will consider the default value which is the value of label passed in while +calling the ``put`` method + +Using RecordBatch of Pyarrow +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: python + + >>> import pyarrow as pa + >>> arrays = [pa.array([1, 2, 3, 4]), pa.array([3.0, 4.0, 5.0, 6.0]), pa.array([0, 1, 0, 1])] + >>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'f1', 'f2']) + >>> data_id = vineyard_client.put(batch) + >>> vin_data = vineyard_client.get(data_id, label='f2') + +The ``vin_data`` will be of the form ``ArrayDataset`` with the label as mentioned +with the label tag. In this case, it is important to mention the label tag. + +Using Tables of Pyarrow +^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: python + + >>> arrays = [pa.array([1, 2, 3, 4]), pa.array([3.0, 4.0, 5.0, 6.0]), pa.array([0, 1, 0, 1])] + >>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'f1', 'f2']) + >>> batches = [batch]*3 + >>> table = pa.Table.from_batches(batches) + >>> data_id = vineyard_client.put(table) + >>> vin_data = vineyard_client.get(data_id, label='f2') + +The ``vin_data`` object will be of the form ``ArrayDataset`` with the label as mentioned +with the label tag. In this case, it is important to mention the label tag. + +XGBoost +------- + +Vineyard supports resolving ``XGBoost::DMatrix`` from various kinds of vineyard data types. + +From Vineyard::Tensor +^^^^^^^^^^^^^^^^^^^^^ + +.. code:: python + + >>> arr = np.random.rand(4, 5) + >>> vin_tensor_id = vineyard_client.put(arr) + >>> dmatrix = vineyard_client.get(vin_tensor_id) + +The ``dmatrix`` will be a ``DMatrix`` instance with the same shape ``(4, 5)`` resolved from the ``Vineyard::Tensor`` +object with the id ``vin_tensor_id``. + +From Vineyard::DataFrame +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: python + + >>> df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [5, 6, 7, 8], 'c': [1.0, 2.0, 3.0, 4.0]}) + >>> vin_df_id = vineyard_client.put(df) + >>> dmatrix = vineyard_client.get(vin_df_id, label='a') + +The ``dmatrix`` will be a ``DMatrix`` instance with shape of ``(4, 2)`` and ``feature_names`` of ``['b', 'c']``. +While the label of ``dmatrix`` is the values of column ``a``. + +Sometimes the dataframe is a complex data structure and only ``one`` column will be used as the ``features``. +We support this case by providing the ``data`` kwarg. + +.. code:: python + + >>> df = pd.DataFrame({'a': [1, 2, 3, 4], + >>> 'b': [[5, 1.0, 4], [6, 2.0, 3], [7, 3.0, 2], [8, 9.0, 1]]}) + >>> vin_df_id = vineyard_client.put(df) + >>> dmatrix = vineyard_client.get(vin_df_id, data='b', label='a') + +The ``dmatrix`` will have the shape of ``(4, 3)`` corresponding to the values of column ``b``. +While the label is the values of column ``a``. + +From Vineyard::RecordBatch +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: python + + >>> import pyarrow as pa + >>> arrays = [pa.array([1, 2, 3, 4]), pa.array([3.0, 4.0, 5.0, 6.0]), pa.array([0, 1, 0, 1])] + >>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'f1', 'target']) + >>> vin_rb_id = vineyard_client.put(batch) + >>> dmatrix = vineyard_client.get(vin_rb_id, label='target') + +The ``dmatrix`` will have the shape of ``(4, 2)`` and ``feature_names`` of ``['f0', 'f1']``. +While the label is the values of column ``target``. + +From Vineyard::Table +^^^^^^^^^^^^^^^^^^^^ + +.. code:: python + + >>> arrays = [pa.array([1, 2]), pa.array([0, 1]), pa.array([0.1, 0.2])] + >>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'label', 'f2']) + >>> batches = [batch] * 3 + >>> table = pa.Table.from_batches(batches) + >>> vin_tab_id = vineyard_client.put(table) + >>> dmatrix = vineyard_client.get(vin_tab_id, label='label') + +The ``dmatrix`` will have the shape of ``(6, 2)`` and ``feature_names`` of ``['f0', 'f2']``. +While the label is the values of column ``label``. + +Nvidia-DALI +----------- + +Vineyard supports integration of ``Dali Pipelines``. + +.. code:: python + + >>> from nvidia.dali import pipeline_def + >>> pipeline = pipe(device_id=device_id, num_threads=num_threads, batch_size=batch_size) + >>> pipeline.build() + >>> pipe_out = pipeline.run() + >>> data_id = vineyard_client.put(pipe_out) + >>> vin_pipe = vineyard_client.get(data_id) + +In this case, the pipe is a ``pipeline_def`` function. The data received after executing pipe.run() can +be stored into vineyard. The Pipeline should only return two values, namely data and label. The return +type of the data and label values should be of type ``TensorList``. The ``vin_pipe`` object will be the +output of a simple in-built pipeline after executing the pipeline.build() and pipeline.run(). It will +simply return two values of type Pipeline. \ No newline at end of file diff --git a/_sources/notes/integration/ray.rst.txt b/_sources/notes/integration/ray.rst.txt new file mode 100644 index 0000000000..1ba5d32d40 --- /dev/null +++ b/_sources/notes/integration/ray.rst.txt @@ -0,0 +1,2 @@ +Ray on Vineyard +=============== diff --git a/_sources/notes/key-concepts.rst.txt b/_sources/notes/key-concepts.rst.txt new file mode 100644 index 0000000000..f16d5e3400 --- /dev/null +++ b/_sources/notes/key-concepts.rst.txt @@ -0,0 +1,77 @@ +Key Concepts +============ + +.. toctree:: + :maxdepth: 1 + :caption: TOC + :hidden: + + key-concepts/objects.rst + key-concepts/vcdl.rst + key-concepts/data-accessing.rst + key-concepts/streams.rst + key-concepts/io-drivers.rst + +The *User Guide* section offers an in-depth understanding of vineyard's design +and implementation. It covers detailed environment setup instructions, the +architecture, and the core features within the vineyard engine. + +*Additional information on vineyard's internals will be provided soon*. + +.. tip:: + + If you are new to vineyard, we recommend starting with the + `Getting Started `_ page for a smoother + introduction. + +Concepts +-------- + +.. panels:: + :header: text-center + :column: col-lg-12 p-2 + + .. link-button:: key-concepts/objects + :type: ref + :text: Vineyard Objects + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + The design space of vineyard objects. + + --- + + .. link-button:: key-concepts/vcdl + :type: ref + :text: VCDL and Integration + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + VCDL and how to integration vineyard with computing systems. + + --- + + .. link-button:: key-concepts/data-accessing + :type: ref + :text: Accessing Objects in Vineyard + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + The approaches that can be used to access various kinds of objects stored in + vineyard. + + --- + + .. link-button:: key-concepts/streams + :type: ref + :text: Stream in Vineyard + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + The stream abstraction upon the immutable data sharing storage and its usages. + + --- + + .. link-button:: key-concepts/io-drivers + :type: ref + :text: I/O Drivers + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Design and implementation of the builtin I/O drivers that eases the integration + of computing engines to existing infrastructure. diff --git a/_sources/notes/key-concepts/data-accessing.rst.txt b/_sources/notes/key-concepts/data-accessing.rst.txt new file mode 100644 index 0000000000..a1ffbecafb --- /dev/null +++ b/_sources/notes/key-concepts/data-accessing.rst.txt @@ -0,0 +1,284 @@ +Data Accessing +============== + +Vineyard is designed to support distributed object sharing and offers both IPCClient +and RPCClient for efficient data access. This section will guide you through various +methods of accessing objects within vineyard. For more information on vineyard object +basics, please refer to :ref:`metadata-and-payloads` and :ref:`distributed-objects`. + +IPCClient vs. RPCClient +----------------------- + +As depicted in the above figure, data is partitioned across different vineyard +instances. The concept of zero-copy sharing was explained in :ref:`architecture-of-vineyard`. +Memory mapping is only available for clients on the same instance, while metadata +is globally synchronized and accessible from clients connected to instances on other hosts. + +Vineyard provides two clients to support IPC and RPC scenarios: + +- IPC Client + + - Can only connect to instances deployed on the same host. + - Offers full support for local data access. Accessing local blobs is enabled + by zero-copy memory mapping. + +- RPC Client + + - Can connect to any instance with an enabled RPC endpoint. + - Provides limited support for remote data access. Creating and fetching remote + blobs incurs considerable network transfer overhead. + +Local vs. Remote +^^^^^^^^^^^^^^^^ + +Distributed shared objects are typically partitioned, with each vineyard instance managing +some chunks of the entire object. As shown in :ref:`distributed-objects`, a :code:`GlobalTensor` +is partitioned into three chunks, and each instance holds one chunk of type :code:`Tensor`. + +**From the perspective of computing engines**, distributed computing engines launch +workers on vineyard instances. Each worker connects to the co-located local instance and +is responsible for processing chunks in that local instance. For example, when starting a Dask +cluster on a vineyard cluster as illustrated in the picture above, each Dask worker is responsible +for executing computations on its local chunks. Some computing tasks require communication between +workers, such as aggregation. In these cases, the communication is performed by the computing +engine itself (in this case, the Dask cluster). + +.. tip:: + + We assume that the computing engines built upon vineyard are responsible for scheduling + tasks based on their awareness of the underlying data partitioning within the vineyard + cluster. + + This design is well-suited for commonly-used modern computing engines,such as GraphScope, + Spark, Presto, Dask, Mars, and Ray. + +Local Objects +------------- + +Creating and accessing local objects in vineyard can be easily achieved using :code:`put` and :code:`get` methods (see +:meth:`vineyard.IPCClient.put` and :meth:`vineyard.IPCClient.get`). + +.. code:: python + :caption: Effortlessly create and access local objects using :code:`put` and :code:`get` + + >>> import pandas as pd + >>> import vineyard + >>> import numpy as np + >>> + >>> vineyard_ipc_client = vineyard.connect("/tmp/vineyard.sock") + >>> + >>> df = pd.DataFrame(np.random.rand(10, 2)) + >>> + >>> # put object into vineyard + >>> r = vineyard_ipc_client.put(df) + >>> r, type(r) + (o00053008257020f8, vineyard._C.ObjectID) + >>> + >>> # get object from vineyard using object id + >>> data = vineyard_ipc_client.get(r) + >>> data + 0 1 + 0 0.534487 0.261941 + 1 0.901056 0.441583 + 2 0.687568 0.671564 + ... + +Vineyard provides low-level APIs to operate on metadatas and raw blobs as well. + +Accessing metadatas +^^^^^^^^^^^^^^^^^^^ + +The method :meth:`vineyard.IPCClient.get_meta` can be used to inspect metadata in the +vineyard cluster, which returns a :class:`vineyard.ObjectMeta` value: + +.. code:: python + :caption: Accessing metadata in vineyard + + >>> meta = vineyard_ipc_client.get_meta(r) + >>> meta.id + o00053008257020f8 + >>> meta.instance_id + 0 + >>> meta.typename + 'vineyard::DataFrame' + >>> meta + { + "instance_id": 0, + "nbytes": 0, + "signature": 1460186430481176, + "transient": true, + "typename": "vineyard::DataFrame" + "__values_-value-0": { + "global": false, + "id": "o0005300822f54d1c", + "instance_id": 0, + "nbytes": 80, + "order_": "\"F\"", + "shape_": "[10]", + "signature": 1460186388165810, + "transient": true, + "typename": "vineyard::Tensor", + "value_type_": "float64", + "value_type_meta_": ">> import vineyard + >>> vineyard_ipc_client = vineyard.connect("/tmp/vineyard.sock") + >>> + >>> # mock a data + >>> payload = b'abcdefgh1234567890uvwxyz' + >>> + >>> # create a blob builder + >>> buffer_builder = vineyard_ipc_client.create_blob(len(payload)) + >>> + >>> # copy the mocked data into the builder + >>> buffer_builder.copy(0, payload) + >>> + >>> # seal the builder then we will get a blob + >>> blob = buffer_builder.seal(vineyard_ipc_client) + +.. code:: python + :caption: Accessing local blobs + + >>> # get the blob from vineyard using object id + >>> blob = vineyard_ipc_client.get_blob(blob.id) + >>> blob, type(blob) + (Object <"o800532e4ab1f2087": vineyard::Blob>, vineyard._C.Blob) + >>> + >>> # inspect the value + >>> bytes(memoryview(blob)) + b'abcdefgh1234567890uvwxyz' + +Remote Objects +-------------- + +The RPC client enables inspection of remote object metadata and facilitates operations on blobs +within the remote cluster, while taking into account the associated network transfer costs. + +Inspecting metadata +^^^^^^^^^^^^^^^^^^^ + +The method :meth:`vineyard.RPCClient.get_meta` allows you to access object metadata in a similar +manner to :meth:`vineyard.IPCClient.get_meta`, but with the added capability of connecting to a +remote instance. + +.. code:: python + :caption: Metadata accessing using RPCClient + + >>> import vineyard + >>> vineyard_rpc_client = vineyard.connect("localhost", 9600) + >>> + >>> # the `r` from the above "Local Objects" section + >>> meta = vineyard_rpc_client.get_meta(r) + >>> meta.id + o00053008257020f8 + >>> meta.instance_id + 0 + >>> meta.typename + 'vineyard::DataFrame' + +Using remote blobs +^^^^^^^^^^^^^^^^^^ + +However, due to the absence of memory sharing between hosts, zero-copy data sharing is not feasible when +connecting to a vineyard instance that is not deployed on the same host as the client. Transferring data +over the network incurs significant costs, and vineyard requires users to explicitly issue a :code:`migrate` +command to move data from the remote instance to the local instance. For more details, please refer to +:ref:`Object Migration in Vineyard `. + +For added convenience, we also provide APIs to fetch remote blobs to the local client by transferring +payloads over the network. + +- :meth:`vineyard.RPCClient.create_remote_blob`: put a **filled** remote blob builder + :class:`vineyard.RemoteBlobBuilder` to connected remote instance. +- :meth:`vineyard.RPCClient.get_remote_blob`: obtain a remote blob :class:`vineyard.RemoteBlob` + from the vineyard cluster by copying over the network. +- :meth:`vineyard.RPCClient.get_remote_blobs`: obtain a set of remote blobs + :code:`List[vineyard.RemoteBlob]` from the vineyard cluster by copying over the network. + +.. warning:: + + Note that the :code:`remote` in the above APIs means the blob will be transferred using + TCP network. For large blobs, it implies a significant cost of time. + +.. code:: python + :caption: Creating remote blobs + + >>> import vineyard + >>> vineyard_rpc_client = vineyard.connect("localhost", 9600) + >>> + >>> # mock a data + >>> payload = b'abcdefgh1234567890uvwxyz' + >>> + >>> # create an empty blob builder + >>> remote_buffer_builder = vineyard.RemoteBlobBuilder(len(payload)) + >>> + >>> # copy the mocked data into the builder + >>> remote_buffer_builder.copy(0, payload) + >>> + >>> # create the remote blob using the RPCClient, with the `remote_buffer_builder` as argument + >>> remote_blob_id = vineyard_rpc_client.create_remote_blob(remote_buffer_builder) + +.. code:: python + :caption: Accessing remote blobs + + >>> # get the remote blob from vineyard using object id + >>> remote_blob = vineyard_rpc_client.get_remote_blob(remote_blob_id) + >>> remote_blob, type(remote_blob) + (, vineyard._C.RemoteBlob) + >>> + >>> # inspect the value of remote blob + >>> bytes(memoryview(remote_blob)) + b'abcdefgh1234567890uvwxyz' + +.. warning:: + + The APIs for creating blobs in :class:`vineyard.IPCClient` and :class:`vineyard.RPCClient` + have subtle differences. The :meth:`vineyard.IPCClient.create_blob` method first allocates + a shared memory buffer to create an empty blob builder, allowing the user to fill the buffer + and then seal it. In contrast, the :meth:`vineyard.RPCClient.create_remote_blob` method + creates a remote blob builder on-the-fly, enabling the user to fill the buffer and subsequently + use the client API to send the :code:`remote_buffer_builder` to the remote instance. + +Utilizing Distributed Objects +----------------------------- + +In the illustration at the beginning of this section, we demonstrate that vineyard is capable of sharing +distributed objects partitioned across multiple hosts. Accessing these distributed objects +in vineyard can be achieved through two distinct approaches: + +- Inspecting metadata using the :code:`RPCClient`: + + The metadata of global objects can be examined using the :class:`vineyard.RPCClient`. This allows + computing engines to understand the distribution of partitions of global tensors using the + RPCClient, and subsequently schedule jobs over those chunks based on the distribution information. + + Mars employs this method to consume distributed tensors and dataframes in vineyard. + +- Accessing local partitions of global objects using the :code:`IPCClient`: + + Another prevalent pattern for accessing shared global objects involves launching a worker on each + instance where the global object is partitioned. Then, using the :class:`vineyard.IPCClient`, + workers can obtain the local partitions of the global object. Each worker is responsible for + processing its local partitions. + + This pattern is commonly utilized in many computing engines that have been integrated with + vineyard, such as GraphScope and Presto. diff --git a/_sources/notes/key-concepts/io-drivers.rst.txt b/_sources/notes/key-concepts/io-drivers.rst.txt new file mode 100644 index 0000000000..78231f3415 --- /dev/null +++ b/_sources/notes/key-concepts/io-drivers.rst.txt @@ -0,0 +1,37 @@ +.. _divein-driver-label: + +I/O Drivers +=========== + +As we have shown in the getting-started, the ``open`` function in vineyard can open a local +file as a stream for consuming, and we notice that the path of the local file is headed +with the scheme ``file://``. + +Actually, vineyard supports several different types of data source, e.g., ``kafka://`` +for kafka topics. The functional methods to open different data sources as vineyard +streams are called ``drivers`` in vineyard. They are registered to ``open`` for +specific schemes, so that when ``open`` is invoked, it will dispatch the corresponding +driver to handle the specific data source according to the scheme of the path. + +The following sample code demonstrates the dispatching logic in ``open``, and the +registration examples. + +.. code:: python + + >>> @registerize + >>> def open(path, *args, **kwargs): + >>> scheme = urlparse(path).scheme + + >>> for reader in open._factory[scheme][::-1]: + >>> r = reader(path, *args, **kwargs) + >>> if r is not None: + >>> return r + >>> raise RuntimeError('Unable to find a proper IO driver for %s' % path) + >>> + >>> # different driver functions are registered as follows + >>> open.register('file', local_driver) + + +Most importantly, the registration design allows users to register their own drivers +to ``registerized`` vineyard methods using ``.register``, which prevents major revisions +on the processing code to fulfill customized computation requirements. diff --git a/_sources/notes/key-concepts/objects.rst.txt b/_sources/notes/key-concepts/objects.rst.txt new file mode 100644 index 0000000000..18b50ef411 --- /dev/null +++ b/_sources/notes/key-concepts/objects.rst.txt @@ -0,0 +1,279 @@ +.. _vineyard-objects: + +Objects +======= + +Vineyard represents various data types as vineyard objects. It employs a +metadata-payloads decoupled design, where an object in vineyard comprises: + +1. A collection of blobs containing the actual data payload; +2. A hierarchical meta tree that describes the data's type, layout, and properties. + +.. _metadata-and-payloads: + +Object = metadata + payloads +---------------------------- + +There are some examples that explain the basic idea of metadata and payload that +forms vineyard objects: + +- Blob: A blob is a pointer with a length that describes the size of the data, + + - metadata: + + - :code:`length` + + - payloads: + + - :code:`pointer`, the actual payload of the blob + +- Tensor: A tensor can be viewed as a blob that contains the actual data and several + metadata entries that describe the shape and type information, + + - metadata: + + - :code:`shape` + - :code:`dtype` + - :code:`data`, a member with type :code:`Blob` + + - payloads: + + - :code:`pointer` in the member :code:`data` + +- Dataframe: A dataframe is an ordered collection of tensors as its columns and each + column has a unique name, + + - metadata: + + - :code:`column_size` + - :code:`names`, a list of members with type :code:`string` + - :code:`columns`, a list of member with type :code:`Tensor` + + - payloads: + + - a set of :code:`pointer` in the member :code:`columns` (the member :code:`data` of + of those :code:`Tensor` s) + +From the example above, it is evident that objects naturally conform to a hierarchical +model, allowing complex data objects to be composed of simpler ones. Each object +consists of a set of blobs as the payload and a metadata tree that describes +the semantics and organization of those blobs. + +.. admonition:: An example for the object metadata: a dataframe with two columns where each + column is a tensor. + :class: admonition-details + + .. code:: json + + { + "__values_-key-0": "1", + "__values_-key-1": "\"a\"", + "__values_-size": 2, + "__values_-value-0": { + "buffer_": { + "id": "o800527ecdf05cff9", + "instance_id": 39, + "length": 0, + "nbytes": 0, + "transient": true, + "typename": "vineyard::Blob" + }, + "id": "o000527ecdffd95c4", + "instance_id": 39, + "nbytes": 400, + "partition_index_": "[]", + "shape_": "[100]", + "signature": 1451273207424436, + "transient": false, + "typename": "vineyard::Tensor", + "value_type_": "float" + }, + "__values_-value-1": { + "buffer_": { + "id": "o800527ecdeaf1015", + "instance_id": 39, + "length": 0, + "nbytes": 0, + "transient": true, + "typename": "vineyard::Blob" + }, + "id": "o000527ece12e4f0a", + "instance_id": 39, + "nbytes": 800, + "partition_index_": "[]", + "shape_": "[100]", + "signature": 1451273227452968, + "transient": false, + "typename": "vineyard::Tensor", + "value_type_": "double" + }, + "columns_": "[\"a\",1]", + "id": "o000527ece15d374c", + "instance_id": 39, + "nbytes": 1200, + "partition_index_column_": 0, + "partition_index_row_": 0, + "row_batch_index_": 0, + "signature": 1451273231074538, + "transient": false, + "typename": "vineyard::DataFrame" + } + +From the above example of object metadata, it is evident that an object is composed +of various sub-objects, forming a hierarchical data model. Each object consists of +a set of blobs and a metadata tree that describes the semantics of those blobs. + +.. tip:: + + Without the metadata, the set of blobs would merely be a collection of memory + pieces without any meaningful interpretation. + +Refer to :ref:`using-objects-python` for a demonstration of how to put Python objects +into vineyard and retrieve them using IPC clients. + +Separating metadata and payload +------------------------------- + +The decoupling of data payload and data layout in vineyard offers three key advantages: + +1. Payloads are stored locally within each vineyard instance, while metadata is shared + across all instances in the cluster. This significantly reduces the overhead of maintaining + consistency for distributed data. + +2. Vineyard objects become self-descriptive, as the metadata fully determines how + the object should be resolved. This not only ensures semantic consistency when + sharing vineyard objects between different systems and programming languages, + but also allows users to store complex data structures with high-level abstractions, such + as graphs in CSR format directly in vineyard, without the need for serialization/deserialization + every time the object is saved or loaded. + +3. This design enables the exploitation of data-aware scheduling techniques. For example, when processing + a graph in vineyard, we can easily access the metadata tree of the graph to determine the size of each + partitioned fragment without accessing the actual vertices and edges. As a result, + we can allocate precise amounts of computational resources for each fragment, leading to overall + performance improvements. + +Vineyard employs two design choices for the metadata and methods of its objects: + +1. A composable design for vineyard objects, which facilitates distributed data management; + +2. An extensible design for object methods, enabling flexible data sharing + between different computation systems with minimal additional development cost. + +Data model +---------- + +Composable +^^^^^^^^^^ + +The composition mechanism in vineyard is based on the hierarchical tree structure of +the metadata of its objects. The root metadata of a complex object stores references +to the root metadata of its components. By recursively traversing these references, +a complete metadata tree is constructed for the complex object. + +.. figure:: ../../images/vineyard_composable.jpg + :width: 75% + :alt: Vineyard objects are composable + + Vineyard objects are composable + +For instance, a distributed dataframe consists of partitioned dataframe chunks, while +a dataframe is composed of column vectors. Considering the decoupling design of payload +and layout in vineyard objects, the blobs are stored in the corresponding vineyard +instance's memory for each partition, and the metadata (e.g., chunk index, shape, +column data types) are stored in the key-value store behind the metadata service. + +To store a distributed graph, we first save the partitioned fragments in each vineyard +instance and share their metadata in the backend key-value store. Then, we can create +the distributed graph by generating the root metadata containing links to the root +metadata of the fragments in an efficient manner. + +.. _distributed-objects: + +Distributed objects +^^^^^^^^^^^^^^^^^^^ + +Vineyard is designed to store large objects across multiple nodes in a cluster, enabling +user programs to seamlessly interact with these objects as a single entity. Data is +sharded across multiple machines without replication. + +.. figure:: ../../images/vineyard_distributed_tensor.jpg + :alt: Distributed objects in vineyard + :width: 60% + + Distributed objects in vineyard + +For example, consider a "Tensor" object that contains billions of columns and rows, making +it too large to fit into a single machine. In such cases, the tensor can be split along +the index or column axis, with each vineyard node holding a subset of chunks. Vineyard +provides a logical view of the complete tensor, allowing distributed computation engines +like Mars and GraphScope to process the data structure as a whole. +.. TODO: add the collection APIs + +.. tip:: + + See also the concepts of *persistent objects* in the following subsection. Refer to + the following subsection for more information on the concept of *persistent objects*. + +Transient vs. Persistent +^^^^^^^^^^^^^^^^^^^^^^^^ + +As previously mentioned, vineyard objects' metadata and payloads are managed separately +by different components of the vineyard server. Payloads are designed to be shared with +computing engines using local memory mapping. However, metadata may need to be inspected +by clients connected to other vineyard instances, such as when forming a distributed object. +In this case, the distributed object consists of a set of chunks placed on different +vineyard instances. When retrieving the distributed objects from vineyard, computing engines +may need to inspect the metadata of non-local pieces to understand the distribution of the +entire dataset. + +This requirement implies that metadata must be globally synchronized and accessible from +clients connected to other vineyard instances. However, global synchronization is a costly +operation, and numerous small key-value pairs can significantly increase the burden on the +key-value store backend of our metadata services. To address this issue, we categorize +objects as transient or persistent. + +- **Transient objects** are designed for cases where the object is known not to be part of a + distributed object and will never need to be inspected by clients on other vineyard instances. + Transient objects are useful for short-lived immediate values within the progress of a + single computing engine. + +- **Persistent objects** are designed for cases where the object chunk will be used to form + a larger distributed object, and the metadata is needed when applications inspect the + distributed object. Persistent objects and distributed objects are commonly used to pass + intermediate data between two distributed engines. + +.. caution:: + + By default, objects are **transient**. We provide an API :code:`client.persist()` that + can explicitly persist the metadata of the target object to etcd, ensuring its visibility + by clients connected to other instances in the cluster. + +.. _builder-resolver: + +Builders and resolvers +^^^^^^^^^^^^^^^^^^^^^^ + +Vineyard utilizes an extensible registry mechanism to enable users to easily integrate their +data structures into the system. This design, which includes builders, resolvers, and drivers, +allows users to create, resolve, and share their data structures across different systems and +paradigms. Notably, even the core data structures and drivers in Vineyard follow this design. + +.. note:: + + **What is the registry mechanism?** + + The registry mechanism decouples methods from the definition of Vineyard data types. For + builders and resolvers, this means users can flexibly register different implementations + in various languages to build and resolve the same Vineyard data type. This enables data + sharing between different systems and paradigms and allows for native language optimizations. + + For drivers, the registry mechanism permits users to flexibly plug in functionality methods + in different languages for Vineyard data types, providing the necessary capabilities for + data types during the data analysis process. + + Moreover, the registered methods can be implemented and optimized according to specific + data analysis tasks, further enhancing efficiency. + +Refer to :ref:`define-python-types` and :ref:`define-cpp-types` for examples of how builders +and resolvers are implemented in Python and C++, respectively. diff --git a/_sources/notes/key-concepts/streams.rst.txt b/_sources/notes/key-concepts/streams.rst.txt new file mode 100644 index 0000000000..afa663367e --- /dev/null +++ b/_sources/notes/key-concepts/streams.rst.txt @@ -0,0 +1,122 @@ +.. _streams-in-vineyard: + +Streams in Vineyard +=================== + +Streams in Vineyard serve as an abstraction over the immutable data sharing storage, +facilitating seamless pipelining between computing engines. Similar to +`pipe `_, Vineyard's streams enable +efficient inter-engine communication while minimizing the overhead associated with +data serialization/deserialization and copying. + +A typical use case for streams in Vineyard involves one process continuously producing +data chunks (e.g., an IO reader) while another process performs scan computations +on the data (e.g., filtering and aggregation operations). A stream consists of a +sequence of immutable data chunks, produced by the former engine and consumed by the +latter engine. + +This section will explore the utilization of streams in Vineyard. + +Using streams +------------- + +We first import required packages: + +.. code:: python + + import threading + import time + from typing import List + + import numpy as np + import pandas as pd + + import vineyard + from vineyard.io.recordbatch import RecordBatchStream + +.. tip:: + + Vineyard has defined some built-in stream types, e.g., + :class:`vineyard.io.recordbatch.RecordBatchStream`. For other stream types, + you could refer to :ref:`python-api-streams`. + +Producer and consumer +--------------------- + +We define a producer that generates random dataframe chunks and inserts them +into the stream: + +.. code:: python + :caption: A producer of :code:`RecordBatchStream` + + def generate_random_dataframe(dtypes, size): + columns = dict() + for k, v in dtypes.items(): + columns[k] = np.random.random(size).astype(v) + return pd.DataFrame(columns) + + def producer(stream: RecordBatchStream, total_chunks, dtypes, produced: List): + writer = stream.writer + for idx in range(total_chunks): + time.sleep(idx) + chunk = generate_random_dataframe(dtypes, 2) # np.random.randint(10, 100)) + chunk_id = vineyard_client.put(chunk) + writer.append(chunk_id) + produced.append((chunk_id, chunk)) + writer.finish() + +Additionally, we create a consumer that retrieves the chunks from the stream in a +loop, continuing until it encounters a :code:`StopIteration` exception: + +.. code:: python + :caption: A consumer of :code:`RecordBatchStream` + + def consumer(stream: RecordBatchStream, total_chunks, produced: List): + reader = stream.reader + index = 0 + while True: + try: + chunk = reader.next() + print('reader receive chunk:', type(chunk), chunk) + pd.testing.assert_frame_equal(produced[index][1], chunk) + except StopIteration: + break + index += 1 + +Streams between processes +------------------------- + +Finally, we can test the producer and consumer using two threads: + +.. code:: python + :caption: Connect the producer and consumer threads using vineyard stream + + def test_recordbatch_stream(vineyard_client, total_chunks): + stream = RecordBatchStream.new(vineyard_client) + dtypes = { + 'a': np.dtype('int'), + 'b': np.dtype('float'), + 'c': np.dtype('bool'), + } + + client1 = vineyard_client.fork() + client2 = vineyard_client.fork() + stream1 = client1.get(stream.id) + stream2 = client2.get(stream.id) + + produced = [] + + thread1 = threading.Thread(target=consumer, args=(stream1, total_chunks, produced)) + thread1.start() + + thread2 = threading.Thread(target=producer, args=(stream2, total_chunks, dtypes, produced)) + thread2.start() + + thread1.join() + thread2.join() + + if __name__ == '__main__': + vineyard_client = vineyard.connect("/tmp/vineyard.sock") + test_recordbatch_stream(vineyard_client, total_chunks=10) + +For more detailed API about the streams, please refer to :ref:`python-api-streams`. diff --git a/_sources/notes/key-concepts/vcdl.rst.txt b/_sources/notes/key-concepts/vcdl.rst.txt new file mode 100644 index 0000000000..24683a28d7 --- /dev/null +++ b/_sources/notes/key-concepts/vcdl.rst.txt @@ -0,0 +1,40 @@ +.. _vcdl: + +Code Generation for Boilerplate +=============================== + +The process of sharing objects between engines involves two fundamental steps: defining +the data structure and establishing the protocol to represent the data type +as :ref:`vineyard-objects`. To alleviate the integration burden with custom data types, +Vineyard offers an auto-generation mechanism. + +This mechanism, known as **VCDL**, relies on the custom annotation :code:`[[shared]]` +applied to C++ classes. + +Consider the following C++ class :code:`Array` as an example: + +.. code:: c++ + + template + class [[vineyard]] Array { + public: + [[shared]] const T& operator[](size_t loc) const { return data()[loc]; } + [[shared]] size_t size() const { return size_; } + [[shared]] const T* data() const { + return reinterpret_cast(buffer_->data()); + } + + private: + [[shared]] size_t size_; + [[shared]] std::shared_ptr buffer_; + }; + +- When applied to classes: the class itself is identified as a shared vineyard + object, and a builder and resolver (see also :ref:`builder-resolver`) are + automatically synthesized. + +- When applied to data members: the data member is treated as a metadata + field or a sub-member. + +- When applied to method members: the method member is deemed + cross-language sharable, and FFI wrappers are automatically synthesized. diff --git a/_sources/notes/references.rst.txt b/_sources/notes/references.rst.txt new file mode 100644 index 0000000000..be42a8cc59 --- /dev/null +++ b/_sources/notes/references.rst.txt @@ -0,0 +1,62 @@ +API Reference +============== + +.. toctree:: + :maxdepth: 1 + :caption: TOC + :hidden: + + references/python-api.rst + references/cpp-api.rst + references/ctl.rst + +Vineyard offers a comprehensive suite of SDKs, including Python and C++ versions. +For detailed API references, please explore the following pages: + +.. panels:: + :header: text-center + :column: col-lg-12 p-2 + + .. link-button:: references/python-api + :type: ref + :text: Python + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + API reference for vineyard Python SDK. + + --- + + .. link-button:: references/cpp-api + :type: ref + :text: C++ + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + API reference for vineyard C++ SDK. + +In addition, the command-line tool `vineyard-ctl` is available to facilitate interactions +with a local :code:`vineyardd` instance, making inspection and debugging tasks more efficient. + +.. panels:: + :header: text-center + :column: col-lg-12 p-2 + + .. link-button:: references/ctl + :type: ref + :text: Vineyard CTL + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Reference for vineyard command line tools. + +All terms in the documentation site can use search from the following +indexing page: + +.. panels:: + :header: text-center + :column: col-lg-12 p-2 + + .. link-button:: genindex + :type: ref + :text: API Indexes + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Term indexes for the vineyard documentation. diff --git a/_sources/notes/references/cpp-api.rst.txt b/_sources/notes/references/cpp-api.rst.txt new file mode 100644 index 0000000000..e13bb7e647 --- /dev/null +++ b/_sources/notes/references/cpp-api.rst.txt @@ -0,0 +1,146 @@ +C++ API Reference +================= + +.. _cpp-api: + +.. default-domain:: cpp + +Objects +------- + +.. doxygentypedef:: vineyard::ObjectID + +.. doxygenclass:: vineyard::Object + :members: + :protected-members: + :undoc-members: + +.. doxygenclass:: vineyard::ObjectBuilder + :members: + :protected-members: + :undoc-members: + +.. doxygenclass:: vineyard::ObjectBase + :members: + :undoc-members: + +Metadata +-------- + +.. doxygenclass:: vineyard::ObjectMeta + :members: + :protected-members: + :undoc-members: + +Vineyard Clients +---------------- + +.. doxygenclass:: vineyard::ClientBase + :members: + :protected-members: + :undoc-members: + +.. doxygenclass:: vineyard::Client + :members: + :protected-members: + :undoc-members: + +.. doxygenclass:: vineyard::RPCClient + :members: + :protected-members: + :undoc-members: + +Vineyard Server +--------------- + +.. doxygenstruct:: vineyard::InstanceStatus + :members: + :undoc-members: + +Blob +---- + +.. doxygenclass:: vineyard::Blob + :members: + :undoc-members: + +.. doxygenclass:: vineyard::BlobWriter + :members: + :undoc-members: + +Stream +------ + +.. doxygenclass:: vineyard::ByteStream + :members: + :undoc-members: + +Basic Data Types +---------------- + +.. doxygenclass:: vineyard::Array + :members: + :undoc-members: + +.. doxygenclass:: vineyard::ArrayBuilder + :members: + :undoc-members: + +.. doxygenclass:: vineyard::Hashmap + :members: + :undoc-members: + +.. doxygenclass:: vineyard::HashmapBuilder + :members: + :undoc-members: + +.. doxygenclass:: vineyard::Tensor + :members: + :undoc-members: + +.. doxygenclass:: vineyard::TensorBuilder + :members: + :undoc-members: + +.. doxygenclass:: vineyard::DataFrame + :members: + :undoc-members: + +.. doxygenclass:: vineyard::DataFrameBuilder + :members: + :undoc-members: + +.. doxygenclass:: vineyard::Sequence + :members: + :undoc-members: + +.. doxygenclass:: vineyard::SequenceBuilder + :members: + :undoc-members: + +.. doxygenclass:: vineyard::Scalar + :members: + :undoc-members: + +.. doxygenclass:: vineyard::ScalarBuilder + :members: + :undoc-members: + +Distributed Data Types +---------------------- + +.. doxygenclass:: vineyard::GlobalTensor + :members: + :undoc-members: + +.. doxygenclass:: vineyard::GlobalTensorBuilder + :members: + :undoc-members: + +.. doxygenclass:: vineyard::GlobalDataFrame + :members: + :undoc-members: + +.. doxygenclass:: vineyard::GlobalDataFrameBuilder + :members: + :undoc-members: diff --git a/_sources/notes/references/ctl.rst.txt b/_sources/notes/references/ctl.rst.txt new file mode 100644 index 0000000000..d275ebd903 --- /dev/null +++ b/_sources/notes/references/ctl.rst.txt @@ -0,0 +1,285 @@ +Vineyard Cli +============ + +**vineyard-ctl**: A command-line tool for **vineyard**. + +Connect to vineyard +------------------- + ++ Via command-line: + + Options: + + + :code:`ipc_socket`: Socket location of connected vineyard server. + + :code:`rpc_host`: RPC HOST of the connected vineyard server. + + :code:`rpc_port`: RPC PORT of the connected vineyard server. + + :code:`rpc_endpoint`: RPC endpoint of the connected vineyard server. + + Example: + + .. code:: shell + + vineyard-ctl --ipc_socket /var/run/vineyard.sock + ++ Via vineyard configuration file: + + This will pick IPC or RPC values from the vineyard configuration file or + environment variables. + +Supported Commands +------------------ + ++ :code:`ls` ++ :code:`query` ++ :code:`head` ++ :code:`copy` ++ :code:`del` ++ :code:`stat` ++ :code:`put` ++ :code:`config` ++ :code:`migrate` ++ :code:`debug` ++ :code:`start` + +.. note:: + + .. code:: shell + + vineyard-ctl {command} + +:code:`ls` +^^^^^^^^^^ + +List vineyard objects. + +Options: + ++ :code:`pattern`: The pattern string that will be matched against the object’s typename. ++ :code:`regex`: The pattern string will be considered as a regex expression. ++ :code:`limit`: The limit to list. + +Example: + +.. code:: shell + + vineyard-ctl ls --pattern * --regex --limit 8 + +:code:`query` +^^^^^^^^^^^^^ + +Query a vineyard object. + +Options: + ++ :code:`object_id`: ID of the object to be fetched. ++ :code:`meta`: Metadata of the object (**Simple** or **JSON**). ++ :code:`metric`: Metric data of the object (**nbytes** or **signature** or **typename**). ++ :code:`exists`: Check if the object exists or not. ++ :code:`stdout`: Get object to stdout. ++ :code:`output_file`: Get object to file. ++ :code:`tree`: Get object lineage in tree-like style. ++ :code:`memory_status`: Get the memory used by the vineyard object. ++ :code:`detail`: Get detailed memory used by the vineyard object. + +Example: + +.. code:: shell + + vineyard-ctl query --object_id 00002ec13bc81226 --meta json --metric typename + +:code:`head` +^^^^^^^^^^^^ + +Print first n(limit) lines of a vineyard object. Currently supported for a pandas dataframe only. + +Options: + ++ :code:`object_id`: ID of the object to be printed. ++ :code:`limit`: Number of lines of the object to be printed. + +Example: + +.. code:: shell + + vineyard-ctl head --object_id 00002ec13bc81226 --limit 3 + +:code:`copy` +^^^^^^^^^^^^ + +Copy a vineyard object. + +Options: + ++ :code:`object_id`: ID of the object to be copied. ++ :code:`shallow`: Get a shallow copy of the object. ++ :code:`deep`: Get a deep copy of the object. + +Example: + +.. code:: shell + + vineyard-ctl copy --object_id 00002ec13bc81226 --shallow + +:code:`del` +^^^^^^^^^^^ + +Delete a vineyard object. + +Options: + ++ :code:`object_id`: ID of the object to be deleted. ++ :code:`regex_pattern`: Delete all the objects that match the regex pattern. ++ :code:`force`: Recursively delete even if the member object is also referred by others. ++ :code:`deep`: Deeply delete an object means we will deleting the members recursively. + +Example: + +.. code:: shell + + vineyard-ctl del --object_id 00002ec13bc81226 --force + +:code:`stat` +^^^^^^^^^^^^ + +Get the status of connected vineyard server. + +Options: + ++ :code:`instance_id`: Instance ID of vineyardd that the client is connected to. ++ :code:`deployment`: The deployment mode of the connected vineyardd cluster. ++ :code:`memory_usage`: Memory usage (in bytes) of current vineyardd instance. ++ :code:`memory_limit`: Memory limit (in bytes) of current vineyardd instance. ++ :code:`deferred_requests`: Number of waiting requests of current vineyardd instance. ++ :code:`ipc_connections`: Number of alive IPC connections on the current vineyardd instance. ++ :code:`rpc_connections`: Number of alive RPC connections on the current vineyardd instance. + +Example: + +.. code:: shell + + vineyard-ctl stat + +:code:`put` +^^^^^^^^^^^ + +Put a python value to vineyard. + +Options: + ++ :code:`value`: The python value you want to put to the vineyard server. ++ :code:`file`: The file you want to put to the vineyard server as a pandas dataframe. ++ :code:`sep`: Delimiter used in the file. ++ :code:`delimiter`: Delimiter used in the file. ++ :code:`header`: Row number to use as the column names. + +Example: + +.. code:: shell + + vineyard-ctl put --file example_csv_file.csv --sep , + +:code:`config` +^^^^^^^^^^^^^^ + +Edit configuration file. + +Options: + ++ :code:`ipc_socket_value`: The ipc_socket value to enter in the config file. ++ :code:`rpc_host_value`: The rpc_host value to enter in the config file. ++ :code:`rpc_port_value`: The rpc_port value to enter in the config file. ++ :code:`rpc_endpoint_value`: The rpc_endpoint value to enter in the config file. + +Example: + +.. code:: shell + + vineyard-ctl config --ipc_socket_value /var/run/vineyard.sock + +:code:`migrate` +^^^^^^^^^^^^^^^ + +Migrate a vineyard object. + +Options: + ++ :code:`ipc_socket_value`: The ipc_socket value for the second client. ++ :code:`rpc_host_value`: The rpc_host value for the second client. ++ :code:`rpc_port_value`: The rpc_port value for the second client. ++ :code:`rpc_endpoint_value`: The rpc_endpoint value for the second client. ++ :code:`object_id`: ID of the object to be migrated. ++ :code:`local`: Migrate the vineyard object local to local. ++ :code:`remote`: Migrate the vineyard object remote to local. + +Example: + +.. code:: shell + + vineyard-ctl migrate --ipc_socket_value /tmp/vineyard.sock --object_id 00002ec13bc81226 --remote + +:code:`debug` +^^^^^^^^^^^^^ + +Issue a debug request. + +Options: + ++ :code:`payload`: The payload that will be sent to the debug handler. + +Example: + +.. code:: shell + + vineyard-ctl debug --payload '{"instance_status":[], "memory_size":[]}' + +:code:`start` +^^^^^^^^^^^^^ + +Start vineyardd. + +Options: + ++ :code:`local`: start a local vineyard cluster. ++ :code:`distributed`: start a local vineyard cluster in a distributed fashion. ++ :code:`hosts`: A list of machines to launch vineyard server. ++ :code:`etcd_endpoints`: Launching vineyard using specified etcd endpoints. + If not specified, vineyard will launch its own etcd instance. ++ :code:`vineyardd_path`: Location of vineyard server program. If not specified, + vineyard will use its own bundled vineyardd binary. ++ :code:`size`: The memory size limit for vineyard’s shared memory. The memory size + can be a plain integer or as a fixed-point number using one of these suffixes: + :code:`E`, :code:`P`, :code:`T`, :code:`G`, :code:`M`, :code:`K`. You can also + use the power-of-two equivalents: :code:`Ei`, :code:`Pi`, :code:`Ti`, :code:`Gi`, + :code:`Mi`, :code:`Ki`. ++ :code:`socket`: The UNIX domain socket socket path that vineyard server will + bind and listen on. When the socket parameter is None, a random path under + temporary directory will be generated and used. ++ :code:`rpc_socket_port`: The port that vineyard will use to privode RPC service. ++ :code:`debug`: Whether to print debug logs. + +Example: + +.. code:: shell + + vineyard-ctl start --local + +Autocomplete +------------ + +Autocomplete for vineyard-ctl is only supported for the bash shell currently. + +Follow the following steps to enable autocomplete for vineyard-ctl on your system: + ++ Install :code:`argcomplete` via :code:`pip3`: :code:`pip3 install argcomplete`. ++ Copy the :code:`python/vineyard/cli.py` file to :code:`/usr/local/bin`. ++ Add :code:`eval "$(register-python-argcomplete cli.py)"` to :code:`~/.bashrc`. ++ Run :code:`source /etc/profile`. ++ Run :code:`source ~/.bashrc`. ++ Run :code:`activate-global-python-argcomplete` + +That is it. You're good to go. Autocomplete will be enabled working for vineyard-ctl. + +.. note:: + + In the bash shell, type :code:`vineyard-ctl sta` and press :code:`tab`, it will autocomplete + to :code:`vineyard-ctl start` diff --git a/_sources/notes/references/python-api.rst.txt b/_sources/notes/references/python-api.rst.txt new file mode 100644 index 0000000000..ed9193bf7c --- /dev/null +++ b/_sources/notes/references/python-api.rst.txt @@ -0,0 +1,128 @@ +Python API Reference +==================== + +.. _python-api: + +.. default-domain:: py + +.. currentmodule:: vineyard + +Objects +------- + +.. autoclass:: ObjectID + :special-members: + :members: + +.. autoclass:: Object + :members: + +.. autoclass:: ObjectBuilder + :members: + +Metadata +-------- + +.. autoclass:: ObjectMeta + :special-members: + :members: + +Vineyard client +--------------- + +.. autofunction:: connect + +.. autoclass:: IPCClient + :inherited-members: + :members: + +.. autoclass:: RPCClient + :inherited-members: + :members: + +Vineyard cluster +---------------- + +.. autoclass:: InstanceStatus + :special-members: + :members: + +Blob +---- + +.. autoclass:: Blob + :members: + +.. autoclass:: BlobBuilder + :members: + +.. autoclass:: RemoteBlob + :members: + +.. autoclass:: RemoteBlobBuilder + :members: + +Resolvers and builders +---------------------- + +.. autoclass:: vineyard.core.resolver.ResolverContext + :members: + +.. autofunction:: vineyard.core.resolver.get_current_resolvers +.. autofunction:: vineyard.core.resolver.resolver_context + +.. autoclass:: vineyard.core.builder.BuilderContext + :members: + +.. autofunction:: vineyard.core.builder.get_current_builders +.. autofunction:: vineyard.core.builder.builder_context + +.. autoclass:: vineyard.core.driver.DriverContext + :members: + +.. autofunction:: vineyard.core.driver.get_current_drivers +.. autofunction:: vineyard.core.driver.driver_context + +.. _shared-memory: + +Shared memory +------------- + +.. autoclass:: vineyard.shared_memory.SharedMemory + :members: + +.. autoclass:: vineyard.shared_memory.ShareableList + :members: + +.. _vineyard-python-deployment-api: + +Deployment +---------- + +.. autofunction:: vineyard.connect +.. autofunction:: vineyard.get_current_socket +.. autofunction:: vineyard.deploy.local.start_vineyardd +.. autofunction:: vineyard.deploy.distributed.start_vineyardd +.. autofunction:: vineyard.deploy.kubernetes.start_vineyardd +.. autofunction:: vineyard.deploy.kubernetes.delete_kubernetes_objects + +I/O Drivers +----------- + +.. autofunction:: vineyard.io.open +.. autofunction:: vineyard.io.read +.. autofunction:: vineyard.io.write + +.. _python-api-streams: + +Streams +------- + +.. autoclass:: vineyard.io.byte.ByteStream + :members: + +.. autoclass:: vineyard.io.dataframe.DataframeStream + :members: + +.. autoclass:: vineyard.io.recordbatch.RecordBatchStream + :members: diff --git a/_sources/tutorials/data-processing.rst.txt b/_sources/tutorials/data-processing.rst.txt new file mode 100644 index 0000000000..700226e66c --- /dev/null +++ b/_sources/tutorials/data-processing.rst.txt @@ -0,0 +1,59 @@ + +Data processing +=============== + +.. toctree:: + :maxdepth: 1 + :caption: TOC + :hidden: + + ./data-processing/using-objects-python.rst + ./data-processing/python-sharedmemory.rst + ./data-processing/distributed-learning.rst + ./data-processing/accelerate-data-sharing-in-kedro.rst + +In these comprehensive case studies, we demonstrate how to seamlessly integrate vineyard's +capabilities with existing data-intensive tasks. By incorporating vineyard into complex +workflows involving multiple computing engines, users can experience significant +improvements in both performance and ease of use. + +.. panels:: + :header: text-center + :column: col-lg-12 p-2 + + .. link-button:: ./data-processing/using-objects-python + :type: ref + :text: Python Objects + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Effortlessly share Python objects between processes using vineyard's intuitive and efficient approach. + + --- + + .. link-button:: ./data-processing/python-sharedmemory + :type: ref + :text: SharedMemory in Python + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Utilize vineyard as an elegant alternative to :code:`multiprocessing.shared_memory` in Python. + + --- + + .. link-button:: ./data-processing/distributed-learning + :type: ref + :text: Distributed Learning + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Discover how vineyard enhances distributed machine learning training workflows by + seamlessly integrating with various computing engines for improved efficiency and elegance. + + --- + + .. link-button:: ./data-processing/accelerate-data-sharing-in-kedro + :type: ref + :text: Accelerate Data Sharing in Kedro + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Vineyard serves as the :code:`DataSet` backend for Kedro pipelines, enabling + efficient data sharing between tasks without intrusive code modification, even + when the pipeline is deployed to Kubernetes. diff --git a/_sources/tutorials/data-processing/accelerate-data-sharing-in-kedro.rst.txt b/_sources/tutorials/data-processing/accelerate-data-sharing-in-kedro.rst.txt new file mode 100644 index 0000000000..a3ebe5a7eb --- /dev/null +++ b/_sources/tutorials/data-processing/accelerate-data-sharing-in-kedro.rst.txt @@ -0,0 +1,292 @@ +.. _accelerate-data-sharing-in-kedro: + +Accelerate Data Sharing in Kedro +================================ + +This is a tutorial that shows how Vineyard accelerate the intermediate data +sharing between tasks in Kedro pipelines using our +`vineyard-kedro `_ plugin, when data +scales and the pipeline are deployed on Kubernetes. + +.. note:: + + This tutorial is based on the `Developing and Learning MLOps at Home `_ project, + a tutorial about orchestrating a machine learning pipeline with Kedro. + +Prepare the Kubernetes cluster +------------------------------ + +To deploy Kedro pipelines on Kubernetes, you must have a kubernetes cluster. + +.. tip:: + + If you already have a K8s cluster, just skip this section and continue + on deploying. + +We recommend `kind v0.20.0 `_ to create a multi-node +Kubernetes cluster on your local machine as follows: + +.. code:: bash + + $ cat < + + - If you are working with Minio, you first need to expose the services + and then create the bucket: + + - Forward minio-artifacts service: + + .. code:: bash + + $ kubectl port-forward service/minio -n minio-dev 9000:9000 + + - Install the minio client: + + .. code:: bash + + $ wget https://dl.min.io/client/mc/release/linux-amd64/mc + $ chmod +x mc + $ sudo mv mc /usr/local/bin + + - Configure the minio client: + + .. code:: bash + + $ mc alias set minio http://localhost:9000 + Enter Access Key: + Enter Secret Key: + + - Finally, create the bucket :code:`minio-s3-benchmark-bucket`: + + .. code:: bash + + $ mc mb minio/minio-s3-benchmark-bucket + Bucket created successfully `minio/minio-s3-benchmark-bucket`. + +Prepare the Docker images +------------------------- + +1. Vineyard has delivered `a benchmark project `_ + to test Kedro pipelines on Vineyard and S3: + + .. code:: bash + + $ cd python/vineyard/contrib/kedro/benchmark/mlops + +2. Configure the credentials configurations of AWS S3: + + .. code:: bash + + $ cat conf/aws-s3/credentials.yml + benchmark_aws_s3: + client_kwargs: + aws_access_key_id: Your AWS/Minio Access Key ID + aws_secret_access_key: Your AWS/Minio Secret Access Key + region_name: Your AWS Region Name + +3. To deploy pipelines to Kubernetes, you first need to build the Docker image for the + benchmark project. + + To show how vineyard can accelerate the data sharing along with the dataset + scales, Docker images for different data size will be generated: + + - For running Kedro on vineyard: + + .. code:: bash + + $ make docker-build + + You will see Docker images for different data size are generated: + + .. code:: bash + + $ docker images | grep mlops + mlops-benchmark latest fceaeb5a6688 17 seconds ago 1.07GB + +4. To make those images available for your Kubernetes cluster, they need to be + pushed to your registry (or load to kind cluster if you setup your Kubernetes + cluster using kind): + + - Push to registry: + + .. code:: bash + + $ docker tag mlops-benchmark:latest /mlops-benchmark:latest + $ docker push /mlops-benchmark:latest + + - Load to kind cluster: + + .. code:: bash + + $ kind load docker-image mlops-benchmark:latest + +Deploy the Kedro Pipelines +-------------------------- + +1. Deploy the Kedro pipeline with vineyard for intermediate data sharing: + + .. code:: bash + + $ kubectl create namespace vineyard + $ for multiplier in 1 10 100 500; do \ + argo submit -n vineyard --watch argo-vineyard-benchmark.yml -p multiplier=${multiplier}; \ + done + +2. Similarly, using AWS S3 or Minio for intermediate data sharing: + + - Using AWS S3: + + .. code:: bash + + $ kubectl create namespace aws-s3 + # create the aws secrets from your ENV + $ kubectl create secret generic aws-secrets -n aws-s3 \ + --from-literal=access_key_id=$AWS_ACCESS_KEY_ID \ + --from-literal=secret_access_key=$AWS_SECRET_ACCESS_KEY + $ for multiplier in 1 10 100 500 1000 2000; do \ + argo submit -n aws-s3 --watch argo-aws-s3-benchmark.yml -p multiplier=${multiplier}; \ + done + + - Using `Cloudpickle dataset `_: + + .. code:: bash + + $ kubectl create namespace cloudpickle + # create the aws secrets from your ENV + $ kubectl create secret generic aws-secrets -n cloudpickle \ + --from-literal=access_key_id=$AWS_ACCESS_KEY_ID \ + --from-literal=secret_access_key=$AWS_SECRET_ACCESS_KEY + $ for multiplier in 1 10 100 500 1000 2000; do \ + argo submit -n cloudpickle --watch argo-cloudpickle-benchmark.yml -p multiplier=${multiplier}; \ + done + + - Using Minio: + + .. code:: bash + + $ kubectl create namespace minio-s3 + $ for multiplier in 1 10 100 500 1000 2000; do \ + argo submit -n minio-s3 --watch argo-minio-s3-benchmark.yml -p multiplier=${multiplier}; \ + done + +Performance +----------- + +After running the benchmark above on Kubernetes, we recorded each node's execution time from the logs +of the argo workflow and calculated the sum of all nodes as the following end-to-end execution time +for each data scale: + +========== ========= ======== ============== ========= +Data Scale Vineyard Minio S3 Cloudpickle S3 AWS S3 +========== ========= ======== ============== ========= +1 4.2s 4.3s 22.5s 16.9s +10 4.9s 5.5s 28.6s 23.3s +100 13.2s 20.3s 64.4s 74s +500 53.6s 84.5s 173.2s 267.9s +1000 109.8s 164.2s 322.7s 510.6s +2000 231.6s 335.9s 632.8s 1069.7s +========== ========= ======== ============== ========= + +We have the following observations from above comparison: + +- Vineyard can significantly accelerate the data sharing between tasks in Kedro pipelines, without the + need for any intrusive changes to the original Kedro pipelines; +- When data scales, the performance of Vineyard is more impressive, as the intermediate data sharing + cost becomes more dominant in end-to-end execution; +- Even compared with local Minio, Vineyard still outperforms it by a large margin, thanks to the ability + of Vineyard to avoid (de)serialization, file I/O and excessive memory copies. +- When using the Cloudpickle dataset(pickle + zstd), the performance is better than AWS S3, as the dataset + will be compressed before uploading to S3. diff --git a/_sources/tutorials/data-processing/distributed-learning.ipynb.txt b/_sources/tutorials/data-processing/distributed-learning.ipynb.txt new file mode 100644 index 0000000000..dd6c41a750 --- /dev/null +++ b/_sources/tutorials/data-processing/distributed-learning.ipynb.txt @@ -0,0 +1,536 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "Distributed Learning with Vineyard\n", + "==================================\n", + "\n", + "With the growth of data, distributed learning is becoming a must in real-world machine learning\n", + "applications, as the data size can easily exceed the memory limit of a single machine.\n", + "Thus, many distributed systems addressing different workloads are developed\n", + "and they share the same objective of extending users' single machine prototypes \n", + "to distributed settings with as few modifications to the code as possible.\n", + "\n", + "For example, **dask.dataframe** mimics the API of **pandas** which is the de-facto standard\n", + "library for single-machine structured data processing, so that users can apply their\n", + "pandas code for data preprocessing in the dask cluster with few modifications.\n", + "Similarly, **horovod** provides easy-to-use APIs for users to transfer their single-machine\n", + "code in machine learning frameworks (e.g., TensorFlow, PyTorch, MXNet) to the distributed settings\n", + "with only a few additional lines of code.\n", + "\n", + "However, when extending to distributed learning, the data sharing between libraries within the same\n", + "python process (e.g., pandas and tensorflow) becomes inter-process sharing between engines (e.g.,\n", + "dask and horovod), not to mention in the distributed fashion. Existing solutions using external\n", + "distributed file systems are less than optimal for the huge I/O overheads.\n", + "\n", + "Vineyard shares the same design principle with the aforementioned distributed systems, which aims to\n", + "provide efficient cross-engine data sharing with few modifications to the existing code.\n", + "Next, we demonstrate how to transfer a single-machine learning example in **keras** to\n", + "distributed learning with dask, horovod and Vineyard.\n", + "\n", + "An Example from Keras\n", + "---------------------\n", + "\n", + "This [example](https://keras.io/examples/structured_data/wide_deep_cross_networks/)\n", + "uses the Covertype dataset from the UCI Machine Learning Repository.\n", + "The task is to predict forest cover type from cartographic variables.\n", + "The dataset includes 506,011 instances with 12 input features:\n", + "10 numerical features and 2 categorical features.\n", + "Each instance is categorized into 1 of 7 classes.\n", + "\n", + "The solution contains three steps:\n", + "\n", + "1. preprocess the data in pandas to extract the 12 features and the label\n", + "2. store the preprocessed data in files\n", + "3. define and train the model in keras\n", + "\n", + "\n", + "Mapping the solution to distributed learning, we have:\n", + "\n", + "1. preprocess the data in dask.dataframe\n", + "2. share the preprocessed data using Vineyard\n", + "3. train the model in horovod.keras\n", + "\n", + "\n", + "We will walk through the code as follows.\n", + "\n", + "Setup\n", + "-------\n", + "\n", + "The distributed deployment of vineyard and dask is as follows: on each machine, we launch a vineyard daemon process to handle the local data storage on that machine; and we also launch a dask worker on that machine for the computation accordingly. In this notebook, we limit the machine number as 1 (i.e., the local machine) just for demonstration." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "import vineyard\n", + "import subprocess as sp\n", + "\n", + "# launch local vineyardd\n", + "client = vineyard.connect()\n", + "\n", + "# launch dask scheduler and worker\n", + "dask_scheduler = sp.Popen(['dask-scheduler', '--host', 'localhost'])\n", + "dask_worker = sp.Popen(['dask-worker', 'tcp://localhost:8786'])" + ], + "outputs": [], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Preprocessing the data\n", + "----------------------\n", + "\n", + "To read the data, we replace\n", + "**pd.read_csv** by **dd.read_csv**, which will automatically\n", + "read the data in parallel." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "import dask.dataframe as dd\n", + "raw_data = dd.read_csv('covtype.data', header=None)" + ], + "outputs": [], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Then we preprocess the data using the same code from the example,\n", + "except the replacement of **pd.concat** to **dd.concat** only." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "\"\"\"\n", + "The two categorical features in the dataset are binary-encoded.\n", + "We will convert this dataset representation to the typical representation, where each\n", + "categorical feature is represented as a single integer value.\n", + "\"\"\"\n", + "import warnings\n", + "warnings.filterwarnings('ignore')\n", + "\n", + "soil_type_values = [f\"soil_type_{idx+1}\" for idx in range(40)]\n", + "wilderness_area_values = [f\"area_type_{idx+1}\" for idx in range(4)]\n", + "\n", + "soil_type = raw_data.loc[:, 14:53].apply(\n", + " lambda x: soil_type_values[0::1][x.to_numpy().nonzero()[0][0]], axis=1\n", + ")\n", + "wilderness_area = raw_data.loc[:, 10:13].apply(\n", + " lambda x: wilderness_area_values[0::1][x.to_numpy().nonzero()[0][0]], axis=1\n", + ")\n", + "\n", + "CSV_HEADER = [\n", + " \"Elevation\",\n", + " \"Aspect\",\n", + " \"Slope\",\n", + " \"Horizontal_Distance_To_Hydrology\",\n", + " \"Vertical_Distance_To_Hydrology\",\n", + " \"Horizontal_Distance_To_Roadways\",\n", + " \"Hillshade_9am\",\n", + " \"Hillshade_Noon\",\n", + " \"Hillshade_3pm\",\n", + " \"Horizontal_Distance_To_Fire_Points\",\n", + " \"Wilderness_Area\",\n", + " \"Soil_Type\",\n", + " \"Cover_Type\",\n", + "]\n", + "\n", + "data = dd.concat(\n", + " [raw_data.loc[:, 0:9], wilderness_area, soil_type, raw_data.loc[:, 54]],\n", + " axis=1,\n", + " ignore_index=True,\n", + ")\n", + "data.columns = CSV_HEADER\n", + "\n", + "# Convert the target label indices into a range from 0 to 6 (there are 7 labels in total).\n", + "data[\"Cover_Type\"] = data[\"Cover_Type\"] - 1" + ], + "outputs": [], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Finally, instead of saving the preprocessed data into files, we store them in Vineyard.\n" + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "import vineyard\n", + "from vineyard.core.builder import builder_context\n", + "from vineyard.contrib.dask.dask import register_dask_types\n", + "\n", + "with builder_context() as builder:\n", + " register_dask_types(builder, None) # register dask builders\n", + " gdf_id = client.put(data, dask_scheduler='tcp://localhost:8786')\n", + " print(gdf_id)" + ], + "outputs": [], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "We saved the preprocessed data as a global dataframe\n", + "in Vineyard with the ObjectID above." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Training the model\n", + "------------------\n", + "\n", + "In the single machine solution from the example. A **get_dataset_from_csv** function \n", + "is defined to load the dataset from the files of the preprocessed data as follows:\n", + "```python\n", + "def get_dataset_from_csv(csv_file_path, batch_size, shuffle=False):\n", + "\n", + " dataset = tf.data.experimental.make_csv_dataset(\n", + " csv_file_path,\n", + " batch_size=batch_size,\n", + " column_names=CSV_HEADER,\n", + " column_defaults=COLUMN_DEFAULTS,\n", + " label_name=TARGET_FEATURE_NAME,\n", + " num_epochs=1,\n", + " header=True,\n", + " shuffle=shuffle,\n", + " )\n", + " return dataset.cache()\n", + "```\n", + "while in the training procedure, it loads the train_dataset and test_dataset\n", + "separately from two files as:\n", + "```python\n", + "def run_experiment(model):\n", + "\n", + " model.compile(\n", + " optimizer=keras.optimizers.Adam(learning_rate=learning_rate),\n", + " loss=keras.losses.SparseCategoricalCrossentropy(),\n", + " metrics=[keras.metrics.SparseCategoricalAccuracy()],\n", + " )\n", + "\n", + " train_dataset = get_dataset_from_csv(train_data_file, batch_size, shuffle=True)\n", + "\n", + " test_dataset = get_dataset_from_csv(test_data_file, batch_size)\n", + "\n", + " print(\"Start training the model...\")\n", + " history = model.fit(train_dataset, epochs=num_epochs)\n", + " print(\"Model training finished\")\n", + "\n", + " _, accuracy = model.evaluate(test_dataset, verbose=0)\n", + "\n", + " print(f\"Test accuracy: {round(accuracy * 100, 2)}%\")\n", + "```\n", + "In our solution, we provide a function to load dataset from the global dataframe\n", + "generated in the last step." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "from vineyard.core.resolver import resolver_context\n", + "from vineyard.contrib.ml.tensorflow import register_tf_types\n", + "\n", + "def get_dataset_from_vineyard(object_id, batch_size, shuffle=False):\n", + " with resolver_context() as resolver:\n", + " register_tf_types(None, resolver) # register tf resolvers\n", + " ds = vineyard.connect().get(object_id, label=TARGET_FEATURE_NAME) # specify the label column\n", + "\n", + " if shuffle:\n", + " ds = ds.shuffle(len(ds))\n", + "\n", + " len_test = int(len(ds) * 0.15)\n", + " test_dataset = ds.take(len_test).batch(batch_size)\n", + " train_dataset = ds.skip(len_test).batch(batch_size)\n", + "\n", + " return train_dataset, test_dataset" + ], + "outputs": [], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "And modify the training procedure with a few lines of horovod code." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "import horovod.keras as hvd\n", + "\n", + "def run_experiment(model):\n", + "\n", + " hvd.init()\n", + "\n", + " model.compile(\n", + " optimizer=hvd.DistributedOptimizer(keras.optimizers.Adam(learning_rate=learning_rate)),\n", + " loss=keras.losses.SparseCategoricalCrossentropy(),\n", + " metrics=[keras.metrics.SparseCategoricalAccuracy()],\n", + " )\n", + "\n", + " callbacks = [\n", + " # Horovod: broadcast initial variable states from rank 0 to all other processes.\n", + " # This is necessary to ensure consistent initialization of all workers when\n", + " # training is started with random weights or restored from a checkpoint.\n", + " hvd.callbacks.BroadcastGlobalVariablesCallback(0),\n", + " ]\n", + "\n", + " train_dataset, test_dataset = get_dataset_from_vineyard(gdf_id, batch_size, shuffle=True)\n", + "\n", + " print(\"Start training the model...\")\n", + " history = model.fit(train_dataset, epochs=num_epochs, callbacks=callbacks)\n", + " print(\"Model training finished\")\n", + "\n", + " _, accuracy = model.evaluate(test_dataset, verbose=0)\n", + "\n", + " print(f\"Test accuracy: {round(accuracy * 100, 2)}%\")" + ], + "outputs": [], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "All the other parts of training procedure are the same as the single machine solution." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "TARGET_FEATURE_NAME = \"Cover_Type\"\n", + "\n", + "TARGET_FEATURE_LABELS = [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"]\n", + "\n", + "NUMERIC_FEATURE_NAMES = [\n", + " \"Aspect\",\n", + " \"Elevation\",\n", + " \"Hillshade_3pm\",\n", + " \"Hillshade_9am\",\n", + " \"Hillshade_Noon\",\n", + " \"Horizontal_Distance_To_Fire_Points\",\n", + " \"Horizontal_Distance_To_Hydrology\",\n", + " \"Horizontal_Distance_To_Roadways\",\n", + " \"Slope\",\n", + " \"Vertical_Distance_To_Hydrology\",\n", + "]\n", + "\n", + "CATEGORICAL_FEATURES_WITH_VOCABULARY = {\n", + " \"Soil_Type\": soil_type_values,\n", + " \"Wilderness_Area\": wilderness_area_values,\n", + "}\n", + "\n", + "CATEGORICAL_FEATURE_NAMES = list(CATEGORICAL_FEATURES_WITH_VOCABULARY.keys())\n", + "\n", + "FEATURE_NAMES = NUMERIC_FEATURE_NAMES + CATEGORICAL_FEATURE_NAMES\n", + "\n", + "NUM_CLASSES = len(TARGET_FEATURE_LABELS)\n", + "\n", + "learning_rate = 0.001\n", + "dropout_rate = 0.1\n", + "batch_size = 265\n", + "num_epochs = 5\n", + "\n", + "hidden_units = [32, 32]\n", + "\n", + "\"\"\"\n", + "## Create model inputs\n", + "Now, define the inputs for the models as a dictionary, where the key is the feature name,\n", + "and the value is a `keras.layers.Input` tensor with the corresponding feature shape\n", + "and data type.\n", + "\"\"\"\n", + "import tensorflow as tf\n", + "\n", + "def create_model_inputs():\n", + " inputs = {}\n", + " for feature_name in FEATURE_NAMES:\n", + " if feature_name in NUMERIC_FEATURE_NAMES:\n", + " inputs[feature_name] = layers.Input(\n", + " name=feature_name, shape=(), dtype=tf.float32\n", + " )\n", + " else:\n", + " inputs[feature_name] = layers.Input(\n", + " name=feature_name, shape=(), dtype=tf.string\n", + " )\n", + " return inputs\n", + "\n", + "\n", + "\"\"\"\n", + "## Encode features\n", + "We create two representations of our input features: sparse and dense:\n", + "1. In the **sparse** representation, the categorical features are encoded with one-hot\n", + "encoding using the `CategoryEncoding` layer. This representation can be useful for the\n", + "model to *memorize* particular feature values to make certain predictions.\n", + "2. In the **dense** representation, the categorical features are encoded with\n", + "low-dimensional embeddings using the `Embedding` layer. This representation helps\n", + "the model to *generalize* well to unseen feature combinations.\n", + "\"\"\"\n", + "\n", + "\n", + "from tensorflow.keras.layers import StringLookup\n", + "\n", + "\n", + "def encode_inputs(inputs, use_embedding=False):\n", + " encoded_features = []\n", + " for feature_name in inputs:\n", + " if feature_name in CATEGORICAL_FEATURE_NAMES:\n", + " vocabulary = CATEGORICAL_FEATURES_WITH_VOCABULARY[feature_name]\n", + " # Create a lookup to convert string values to an integer indices.\n", + " # Since we are not using a mask token nor expecting any out of vocabulary\n", + " # (oov) token, we set mask_token to None and num_oov_indices to 0.\n", + " lookup = StringLookup(\n", + " vocabulary=vocabulary,\n", + " mask_token=None,\n", + " num_oov_indices=0,\n", + " output_mode=\"int\" if use_embedding else \"binary\",\n", + " )\n", + " if use_embedding:\n", + " # Convert the string input values into integer indices.\n", + " encoded_feature = lookup(inputs[feature_name])\n", + " embedding_dims = int(math.sqrt(len(vocabulary)))\n", + " # Create an embedding layer with the specified dimensions.\n", + " embedding = layers.Embedding(\n", + " input_dim=len(vocabulary), output_dim=embedding_dims\n", + " )\n", + " # Convert the index values to embedding representations.\n", + " encoded_feature = embedding(encoded_feature)\n", + " else:\n", + " # Convert the string input values into a one hot encoding.\n", + " encoded_feature = lookup(tf.expand_dims(inputs[feature_name], -1))\n", + " else:\n", + " # Use the numerical features as-is.\n", + " encoded_feature = tf.expand_dims(inputs[feature_name], -1)\n", + "\n", + " encoded_features.append(encoded_feature)\n", + "\n", + " all_features = layers.concatenate(encoded_features)\n", + " return all_features\n", + "\n", + "\n", + "\"\"\"\n", + "## Experiment 1: a baseline model\n", + "In the first experiment, let's create a multi-layer feed-forward network,\n", + "where the categorical features are one-hot encoded.\n", + "\"\"\"\n", + "from tensorflow import keras\n", + "from tensorflow.keras import layers\n", + "\n", + "def create_baseline_model():\n", + " inputs = create_model_inputs()\n", + " features = encode_inputs(inputs)\n", + "\n", + " for units in hidden_units:\n", + " features = layers.Dense(units)(features)\n", + " features = layers.BatchNormalization()(features)\n", + " features = layers.ReLU()(features)\n", + " features = layers.Dropout(dropout_rate)(features)\n", + "\n", + " outputs = layers.Dense(units=NUM_CLASSES, activation=\"softmax\")(features)\n", + " model = keras.Model(inputs=inputs, outputs=outputs)\n", + " return model\n", + "\n", + "\n", + "baseline_model = create_baseline_model()" + ], + "outputs": [], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Let's run it:" + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "run_experiment(baseline_model)" + ], + "outputs": [], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "We clear the environments in the end." + ], + "metadata": {} + }, + { + "cell_type": "code", + "execution_count": null, + "source": [ + "dask_worker.terminate()\n", + "dask_scheduler.terminate()\n", + "\n", + "vineyard.shutdown()" + ], + "outputs": [], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Finally, we can use **horovodrun** to run the above code distributedly in a cluster for distributed learning on big datasets." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Conclusion\n", + "----------\n", + "\n", + "From this example, we can see that with the help of Vineyard, users can easily extend\n", + "their single machine solutions to distributed learning using dedicated systems without\n", + "worrying about the cross-system data sharing issues." + ], + "metadata": {} + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/_sources/tutorials/data-processing/python-sharedmemory.rst.txt b/_sources/tutorials/data-processing/python-sharedmemory.rst.txt new file mode 100644 index 0000000000..4ff434e3c7 --- /dev/null +++ b/_sources/tutorials/data-processing/python-sharedmemory.rst.txt @@ -0,0 +1,42 @@ +:code:`multiprocessing.shared_memory` in Python +=============================================== + +Vineyard offers a shared memory interface through :class:`SharedMemory` and +:class:`ShareableList` classes, ensuring compatibility with Python's `multiprocessing.shared_memory`_. + +Utilize the shared memory interface as demonstrated below: + +.. code:: python + + >>> from vineyard import shared_memory + >>> value = shared_memory.ShareableList(client, [b"a", "bb", 1234, 56.78, True]) + >>> value + ShareableList([b'a', 'bb', 1234, 56.78, True], name='o8000000119aa10c0') + >>> value[4] = False + >>> value + ShareableList([b'a', 'bb', 1234, 56.78, False], name='o8000000119aa10c0') + +.. caution:: + + Please be aware that the semantics of Vineyard's :code:`shared_memory` differ slightly + from those of Python's multiprocessing module's :code:`shared_memory`. In Vineyard, + shared memory cannot be modified once it becomes visible to other clients. + +We have added a :code:`freeze` method to make such transformation happen: + +.. code:: python + + >>> value.freeze() + +After being frozen, the shared memory (aka. the :code:`ShareableList` in this case) +is available for other clients: + +.. code:: python + + >>> value1 = shared_memory.ShareableList(client, name=value.shm.name) + >>> value1 + ShareableList([b'a', 'bb', 1234, 56.78, False], name='o8000000119aa10c0') + +For more details, see :ref:`shared-memory`. + +.. _multiprocessing.shared_memory: https://docs.python.org/3/library/multiprocessing.shared_memory.html diff --git a/_sources/tutorials/data-processing/using-objects-python.rst.txt b/_sources/tutorials/data-processing/using-objects-python.rst.txt new file mode 100644 index 0000000000..4b41e053f1 --- /dev/null +++ b/_sources/tutorials/data-processing/using-objects-python.rst.txt @@ -0,0 +1,87 @@ +.. _using-objects-python: + +Sharing Python Objects with Vineyard +------------------------------------ + +As discussed in :ref:`vineyard-objects`, each object in Vineyard consists of two parts: + +1. The data payload, which is stored locally in the corresponding Vineyard instance +2. The hierarchical metadata, which is shared across the entire Vineyard cluster + +Specifically, a ``Blob`` represents the unit where the data payload resides within a +Vineyard instance. A blob object holds a segment of memory in the bulk store of the +Vineyard instance, allowing users to save their local buffer into a blob and later +retrieve the blob in another process using a zero-copy approach through memory mapping. + +.. code:: python + + >>> payload = b"Hello, World!" + >>> blob_id = client.put(payload) + >>> blob = client.get_object(blob_id) + >>> print(blob.typename, blob.size, blob) + +.. code:: console + + vineyard::Blob 28 Object <"o800000011cfa7040": vineyard::Blob> + +On the other hand, the hierarchical metadata of Vineyard objects is shared across +the entire cluster. In the following example, for the sake of simplicity, we +launch a Vineyard cluster consisting of two Vineyard instances on the same machine. +However, in real-world scenarios, these Vineyard instances would be distributed +across multiple machines within the cluster. + +.. code:: console + + $ python3 -m vineyard --socket /var/run/vineyard.sock1 + $ python3 -m vineyard --socket /var/run/vineyard.sock2 + +With this setup, we can create a distributed pair of arrays in Vineyard, where +the first array is stored in the first Vineyard instance listening to the IPC socket +``/var/run/vineyard.sock1``, and the second array is stored in the second instance +listening to the IPC socket ``/var/run/vineyard.sock2``. + +.. code:: python + + >>> import numpy as np + >>> import vineyard + >>> import vineyard.data.tensor + + >>> # build the first array in the first vineyard instance + >>> client1 = vineyard.connect('/var/run/vineyard.sock1') + >>> id1 = client1.put(np.zeros(8)) + >>> # persist the object to make it visible to form the global object + >>> client1.persist(id1) + + >>> # build the second array in the second vineyard instance + >>> client2 = vineyard.connect('/var/run/vineyard.sock2') + >>> id2 = client2.put(np.ones(4)) + >>> # persist the object to make it visible to form the global object + >>> client2.persist(id2) + + >>> # build the pair from client1 + >>> obj1 = client1.get_object(id1) + >>> obj2 = client2.get_object(id2) + >>> id_pair = client1.put((obj1, obj2)) + + >>> # get the pair object from client2 + >>> obj_pair = client2.get_object(id_pair) + >>> print(obj_pair.first.typename, obj_pair.first.size(), obj_pair.second.size()) + +.. code:: console + + vineyard::Array 8 4 + +.. code:: console + + >>> # get the pair value from client2 + >>> value_pair = client2.get(id_pair) + >>> print(value_pair) + +.. code:: console + + (None, [1, 1, 1, 1]) + +In this example, we can access the metadata of the pair object from ``client2`` +even though it was created by ``client1``. However, we cannot retrieve the payload +of the first element of the pair from ``client2`` because it is stored locally +in the first Vineyard instance. diff --git a/_sources/tutorials/extending.rst.txt b/_sources/tutorials/extending.rst.txt new file mode 100644 index 0000000000..4eab2b7188 --- /dev/null +++ b/_sources/tutorials/extending.rst.txt @@ -0,0 +1,37 @@ + +Extending vineyard +================== + +.. toctree:: + :maxdepth: 1 + :caption: TOC + :hidden: + + ./extending/define-datatypes-python.rst + ./extending/define-datatypes-cpp.rst + +Vineyard offers a collection of efficient data structures tailored for data-intensive tasks, +such as tensors, data frames, tables, and graphs. These data types can be easily extended +to accommodate custom requirements. By registering user-defined types in the vineyard type +registry, computing engines built on top of vineyard can instantly leverage the advantages +provided by these custom data structures. + +.. panels:: + :header: text-center + :column: col-lg-12 p-2 + + .. link-button:: ./extending/define-datatypes-python + :type: ref + :text: Define Python Types + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Craft builders and resolvers for custom Python data types. + + --- + + .. link-button:: ./extending/define-datatypes-cpp + :type: ref + :text: Define C++ Types + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Implement and register custom data types in C++ for seamless integration with vineyard's ecosystem. diff --git a/_sources/tutorials/extending/define-datatypes-cpp.rst.txt b/_sources/tutorials/extending/define-datatypes-cpp.rst.txt new file mode 100644 index 0000000000..2d2b0b1aa6 --- /dev/null +++ b/_sources/tutorials/extending/define-datatypes-cpp.rst.txt @@ -0,0 +1,312 @@ +.. _define-cpp-types: + +Defining Custom Data Types in C++ +================================= + +Vineyard provides an extensive set of efficient built-in data types in +its C++ SDK, such as :code:`Vector`, :code:`HashMap`, :code:`Tensor`, +:code:`DataFrame`, :code:`Table`, and :code:`Graph` (refer to :ref:`cpp-api`). +However, there may be situations where users need to develop their +own data structures and share the data efficiently with Vineyard. This +step-by-step tutorial guides you through the process of adding custom +C++ data types with ease. + +.. note:: + + This tutorial includes code snippets that could be auto-generated to + provide a clear understanding of the design internals and to help + developers grasp the overall functionality of the Vineyard client. + +``Object`` and ``ObjectBuilder`` +-------------------------------- + +Vineyard has a base class :code:`vineyard::Objects`, and a corresponding +base class :code:`Vineyard::ObjectBuilder` for builders as follows, + +.. code:: cpp + + class Object { + public: + static std::unique_ptr Create() { + ... + } + + virtual void Construct(const ObjectMeta& meta); + } + +and the builder + +.. code:: cpp + + class ObjectBuilder { + virtual Status Build(Client& client) override = 0; + + virtual std::shared_ptr _Seal(Client& client) = 0; + } + +Where the object is the base class for user-defined data types, and the +builders is responsible for placing the data into vineyard. + +Defining Your Custom Type +------------------------- + +Let's take the example of defining a custom `Vector` type. Essentially, +a `Vector` consists of a `vineyard::Blob` as its payload, along with +metadata such as `dtype` and `size`. + +The class definition for the `Vector` type typically appears as follows: + +.. code:: cpp + + template + class Vector { + private: + size_t size; + const T *data = nullptr; + public: + Vector(): size(0), data(nullptr) { + } + + Vector(const int size, const T *data): size(size), data(data) { + } + + size_t length() const { + return size; + } + + const T& operator[](size_t index) { + assert(index < size); + return data[index]; + } + }; + +Registering C++ Types +--------------------- + +First, we need to adapt the existing :code:`Vector` to become a Vineyard +:code:`Object`, + +.. code:: diff + + template + -class Vector { + +class Vector: public vineyard::Registered> { + private: + size_t size; + T *data = nullptr; + public: + + static std::unique_ptr Create() __attribute__((used)) { + + return std::static_pointer_cast( + + std::unique_ptr>{ + + new Vector()}); + + } + + + Vector(): size(0), data(nullptr) { + } + + Vector(const int size, const T *data): size(size), data(data) { + } + + ... + } + +Observe the two key modifications above: + ++ Inheriting from :code:`vineyard::Registered>`: + + :code:`vineyard::Registered` serves as a helper to generate static + initialization stubs, registering the data type :code:`T` with the type + resolving factory and associating the type :code:`T` with its typename. + The typename is an auto-generated, human-readable name for C++ types, e.g., + :code:`"Vector"` for :code:`Vector`. + ++ Implementing the zero-parameter static constructor :code:`Create()`: + + :code:`Create()` is a static function registered with the + resolving factory by the helper :code:`vineyard::Registered`. It is + used to construct an instance of type :code:`T` when retrieving objects + from Vineyard. + + The Vineyard client locates the static constructor using the :code:`typename` + found in the metadata of Vineyard objects stored in the daemon server. + +To retrieve the object :code:`Vector` from Vineyard's metadata, we need to +implement a `Construct` method as well. The :code:`Construct` method takes +a :code:`vineyard::ObjectMeta` as input and extracts metadata and +members from it to populate its own data members. The memory in the member +:code:`buffer` (a :code:`vineyard::Blob`) is shared using memory mapping, +eliminating the need for copying. + +.. code:: diff + + template + class Vector: public vineyard::Registered> { + public: + ... + + + void Construct(const ObjectMeta& meta) override { + + this->size = meta.GetKeyValue("size"); + + + + auto buffer = std::dynamic_pointer_cast(meta.GetMember("buffer")); + + this->data = reinterpret_cast(buffer->data()); + + } + + + ... + } + +Builder +------- + +Moving on to the builder section, the :code:`vineyard::ObjectBuilder` consists of two parts: + ++ :code:`Build()`: This method is responsible for storing the blobs of custom data + structures into Vineyard. + ++ :code:`_Seal()`: This method is responsible for generating the corresponding metadata + and inserting the metadata into Vineyard. + +For our :code:`Vector` type, let's first define a general vector builder: + +.. code:: cpp + + template + class VectorBuilder { + private: + std::unique_ptr buffer_builder; + std::size_t size; + T *data; + + public: + VectorBuilder(size_t size): size(size) { + data = static_cast(malloc(sizeof(T) * size)); + } + + T& operator[](size_t index) { + assert(index < size); + return data[index]; + } + }; + +The builder allocates the necessary memory based on the specified :code:`size` to accommodate +the elements and provides a `[]` operator to populate the data. + +Next, we adapt the above builder as a `ObjectBuilder` in Vineyard, + +.. code:: diff + + template + -class VectorBuilder { + +class VectorBuilder: public vineyard::ObjectBuilder { + private: + std::unique_ptr buffer_builder; + std::size_t size; + T *data; + + public: + VectorBuilder(size_t size): size(size) { + data = static_cast(malloc(sizeof(T) * size)); + } + + + Status Build(Client& client) override { + + RETURN_ON_ERROR(client.CreateBlob(size * sizeof(T), buffer_builder)); + + memcpy(buffer_builder->data(), data, size * sizeof(T)); + + return Status::OK(); + + } + + + + Status _Seal(Client& client, std::shared_ptr &object) override { + + RETURN_ON_ERROR(this->Build(client)); + + + + auto vec = std::make_shared>(); + object = vec; + + std::shared_ptr buffer_object; + + RETURN_ON_ERROR(this->buffer_builder->Seal(client, buffer_object)); + + auto buffer = std::dynamic_pointer_cast(buffer_object); + + vec->size = size; + + vec->data = reinterpret_cast(buffer->data()); + + + + vec->meta_.SetTypeName(vineyard::type_name>()); + + vec->meta_.SetNBytes(size * sizeof(T)); + + vec->meta_.AddKeyValue("size", size); + + vec->meta_.AddMember("buffer", buffer); + + return client.CreateMetaData(vec->meta_, vec->id_); + + } + + + T& operator[](size_t index) { + assert(index < size); + return data[index]; + } + }; + +To access private member fields and methods, the builder may need to be +added as a friend class of the original type declaration. + +.. note:: + + Since the builder requires direct access to the private data members of + :code:`Vector`, it is necessary to declare the builder as a friend class + of our vector type, + +.. code:: diff + + template + class Vector: public vineyard::Registered> { + + const T& operator[](size_t index) { + assert(index < size); + return data[index]; + } + + + + friend class VectorBuilder; + }; + +In the example above, you may notice that the builder and constructor contain numerous +boilerplate snippets. These can be auto-generated based on the layout of the class +:code:`Vector` through static analysis of the user's source code, streamlining +the process and enhancing readability. + +Utilizing Custom Data Types with Vineyard +----------------------------------------- + +At this point, we have successfully defined our custom data types and integrated them +with Vineyard. Now, we can demonstrate how to build these custom data types using the +Vineyard client and retrieve them for further processing. + +.. code:: cpp + + int main(int argc, char** argv) { + std::string ipc_socket = std::string(argv[1]); + + Client client; + VINEYARD_CHECK_OK(client.Connect(ipc_socket)); + LOG(INFO) << "Connected to IPCServer: " << ipc_socket; + + auto builder = VectorBuilder(3); + builder[0] = 1; + builder[1] = 2; + builder[2] = 3; + auto result = builder.Seal(client); + + auto vec = std::dynamic_pointer_cast>(client.GetObject(result->id())); + for (size_t index = 0; index < vec->length(); ++index) { + std::cout << "element at " << index << " is: " << (*vec)[index] << std::endl; + } + } + +Cross-Language Compatibility +---------------------------- + +Vineyard maintains consistent design principles across SDKs in various languages, +such as Java and Python. For an example of Vineyard objects and their builders in +Python, please refer to :ref:`builder-resolver`. + +As demonstrated in the example above, there is a significant amount of boilerplate +code involved in defining constructors and builders. To simplify the integration +with Vineyard, we are developing a code generator that will automatically produce +SDKs in different languages based on a C++-like Domain Specific Language (DSL). +Stay tuned for updates! + +For a sneak peek at how the code generator works, please refer to `array.vineyard-mod`_ +and `arrow.vineyard-mod`_. + +.. _array.vineyard-mod: https://github.com/v6d-io/v6d/blob/main/modules/basic/ds/array.vineyard-mod +.. _arrow.vineyard-mod: https://github.com/v6d-io/v6d/blob/main/modules/basic/ds/arrow.vineyard-mod diff --git a/_sources/tutorials/extending/define-datatypes-python.rst.txt b/_sources/tutorials/extending/define-datatypes-python.rst.txt new file mode 100644 index 0000000000..86045f9acc --- /dev/null +++ b/_sources/tutorials/extending/define-datatypes-python.rst.txt @@ -0,0 +1,169 @@ +.. _define-python-types: + +Define Data Types in Python +--------------------------- + +Objects +^^^^^^^ + +As discussed in :ref:`vineyard-objects`, each object in vineyard comprises two components: + +1. The data payload, which is stored locally within the corresponding vineyard instance +2. The hierarchical meta data, which is shared across the entire vineyard cluster + +Specifically, a ``Blob`` represents the unit where the data payload resides in a vineyard +instance. A blob object contains a segment of memory in the bulk store of the vineyard +instance, allowing users to save their local buffer into a blob and later retrieve the +blob in another process using a zero-copy approach through memory mapping. + +.. code:: python + + >>> payload = b"Hello, World!" + >>> blob_id = client.put(payload) + >>> blob = client.get_object(blob_id) + >>> print(blob.typename, blob.size, blob) + +.. code:: console + + vineyard::Blob 28 Object <"o800000011cfa7040": vineyard::Blob> + +On the other hand, vineyard objects' hierarchical meta data is shared across the entire +cluster. In the following example, for the sake of simplicity, we will launch a vineyard +cluster with two vineyard instances on the same machine. However, in real-world scenarios, +these vineyard instances would typically be distributed across multiple machines within +the cluster. + +.. code:: console + + $ python3 -m vineyard --socket /var/run/vineyard.sock1 + $ python3 -m vineyard --socket /var/run/vineyard.sock2 + +With this setup, we can create a distributed pair of arrays in vineyard, where the first +array is stored in the first vineyard instance (listening to ipc_socket at `/var/run/vineyard.sock1`), +and the second array is stored in the second instance (listening to ipc_socket at +`/var/run/vineyard.sock2`). + +.. code:: python + + >>> import numpy as np + >>> import vineyard + >>> import vineyard.data.tensor + + >>> # build the first array in the first vineyard instance + >>> client1 = vineyard.connect('/var/run/vineyard.sock1') + >>> id1 = client1.put(np.zeros(8)) + >>> # persist the object to make it visible to form the global object + >>> client1.persist(id1) + + >>> # build the second array in the second vineyard instance + >>> client2 = vineyard.connect('/var/run/vineyard.sock2') + >>> id2 = client2.put(np.ones(4)) + >>> # persist the object to make it visible to form the global object + >>> client2.persist(id2) + + >>> # build the pair from client1 + >>> obj1 = client1.get_object(id1) + >>> obj2 = client2.get_object(id2) + >>> id_pair = client1.put((obj1, obj2)) + + >>> # get the pair object from client2 + >>> obj_pair = client2.get_object(id_pair) + >>> print(obj_pair.first.typename, obj_pair.first.size(), obj_pair.second.size()) + +.. code:: console + + vineyard::Array 8 4 + +.. code:: console + + >>> # get the pair value from client2 + >>> value_pair = client2.get(id_pair) + >>> print(value_pair) + +.. code:: console + + (None, [1, 1, 1, 1]) + +In this example, we can access the metadata of the pair object from `client2` even +though it was created by `client1`. However, we cannot retrieve the payload of the +first element of the pair from `client2`, as it is stored locally within the first +vineyard instance. + +Creating Builders and Resolvers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As demonstrated in :ref:`builder-resolver`, vineyard enables users to register +builders and resolvers for constructing and resolving vineyard objects from/to +client-side data types based on specific computational requirements. + +For instance, if we use ``pyarrow`` types in our context, we can define the builder and +resolver for the conversion between ``vineyard::NumericArray`` and ``pyarrow.NumericArray`` +as follows: + +.. code:: python + + >>> def numeric_array_builder(client, array, builder): + >>> meta = ObjectMeta() + >>> meta['typename'] = 'vineyard::NumericArray<%s>' % array.type + >>> meta['length_'] = len(array) + >>> meta['null_count_'] = array.null_count + >>> meta['offset_'] = array.offset + >>> + >>> null_bitmap = buffer_builder(client, array.buffers()[0], builder) + >>> buffer = buffer_builder(client, array.buffers()[1], builder) + >>> + >>> meta.add_member('buffer_', buffer) + >>> meta.add_member('null_bitmap_', null_bitmap) + >>> meta['nbytes'] = array.nbytes + >>> return client.create_metadata(meta) + + >>> def numeric_array_resolver(obj): + >>> meta = obj.meta + >>> typename = obj.typename + >>> value_type = normalize_dtype(re.match(r'vineyard::NumericArray<([^>]+)>', typename).groups()[0]) + >>> dtype = pa.from_numpy_dtype(value_type) + >>> buffer = as_arrow_buffer(obj.member('buffer_')) + >>> null_bitmap = as_arrow_buffer(obj.member('null_bitmap_')) + >>> length = int(meta['length_']) + >>> null_count = int(meta['null_count_']) + >>> offset = int(meta['offset_']) + >>> return pa.lib.Array.from_buffers(dtype, length, [null_bitmap, buffer], null_count, offset) + +Finally, we register the builder and resolver for automatic building and resolving: +.. code:: python + + >>> builder_ctx.register(pa.NumericArray, numeric_array_builder) + >>> resolver_ctx.register('vineyard::NumericArray', numeric_array_resolver) + +In some cases, we may have multiple resolvers or builders for a specific type. +For instance, the `vineyard::Tensor` object can be resolved as either `numpy.ndarray` or +`xgboost::DMatrix`. To accommodate this, we could have: + +.. code:: python + + >>> resolver_ctx.register('vineyard::Tensor', numpy_resolver) + >>> resolver_ctx.register('vineyard::Tensor', xgboost_resolver) + +This flexibility enables seamless integration with various libraries and frameworks by +effectively handling different data types and their corresponding resolvers or builders. + +.. code:: python + + def xgboost_resolver(obj): + ... + + default_resolver_context.register('vineyard::Tensor', xgboost_resolver) + +at the same time. The stackable :code:`resolver_context` could help there, + +.. code:: python + + with resolver_context({'vineyard::Tensor', xgboost_resolver}): + ... + +Assuming the default context resolves `vineyard::Tensor` to `numpy.ndarray`, the +`with resolver_context` allows for temporary resolution of `vineyard::Tensor` to +`xgboost::DMatrix`. Upon exiting the context, the global environment reverts to +its default state. + +The `with resolver_context` can be nested for additional flexibility. diff --git a/_sources/tutorials/kubernetes.rst.txt b/_sources/tutorials/kubernetes.rst.txt new file mode 100644 index 0000000000..d689e590cd --- /dev/null +++ b/_sources/tutorials/kubernetes.rst.txt @@ -0,0 +1,37 @@ +Vineyard on Kubernetes +====================== + +.. toctree:: + :maxdepth: 1 + :caption: TOC + :hidden: + + ./kubernetes/using-vineyard-operator.rst + ./kubernetes/ml-pipeline-mars-pytorch.rst + ./kubernetes/data-sharing-with-vineyard-on-kubernetes.rst + +Vineyard can be seamlessly deployed on Kubernetes, managed by the :ref:`vineyard-operator`, +to enhance big-data workflows through its data-aware scheduling policy. This policy +orchestrates shared objects and routes jobs to where their input data resides. In the +following tutorials, you will learn how to deploy Vineyard and effectively integrate it +with Kubernetes. + +.. panels:: + :header: text-center + :column: col-lg-12 p-2 + + .. link-button:: ./kubernetes/using-vineyard-operator + :type: ref + :text: Vineyard operator + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + The Vineyard operator serves as the central component for seamless integration with Kubernetes. + + --- + + .. link-button:: ./kubernetes/ml-pipeline-mars-pytorch + :type: ref + :text: ML with Vineyard + :classes: btn-block stretched-link + ^^^^^^^^^^^^ + Vineyard functions as an efficient intermediate data storage solution for machine learning pipelines on Kubernetes. diff --git a/_sources/tutorials/kubernetes/data-sharing-with-vineyard-on-kubernetes.rst.txt b/_sources/tutorials/kubernetes/data-sharing-with-vineyard-on-kubernetes.rst.txt new file mode 100644 index 0000000000..55e73813d7 --- /dev/null +++ b/_sources/tutorials/kubernetes/data-sharing-with-vineyard-on-kubernetes.rst.txt @@ -0,0 +1,269 @@ +Data sharing with Vineyard on Kubernetes +======================================== + +If you want to share data between different workloads(pods or containers) on kubernetes, it's a good idea to +use vineyard as the data-sharing service. In this tutorial, we will show you how to +share data between different containers or pods on kubernetes step by step. + +.. figure:: ../../images/data_sharing_with_sidecar.jpg + :width: 75% + :alt: Data sharing between containers + + Data sharing between containers + +From the above figure, the `vineyardctl inject` command will inject vineyard container into the app pod and +the app containers will connect to the vineyard container to share the vineyard data. + +.. figure:: ../../images/data_sharing_with_deployment.jpg + :width: 75% + :alt: Data sharing on the vineyard deployment + + Data sharing on the vineyard deployment + +From the above figure, the `vineyardctl deploy vineyard-deployment` command will deploy a vineyard deployment +on the kubernetes cluster (default is 3 replicas) and the app pods will be scheduled to the vineyard deployment +to share the vineyard data via the command `vineyardctl schedule workload`. + +Prerequisites +------------- + +- A kubernetes cluster with version >= 1.25.10. +- Install the latest vineyardctl command line tool refer to `vineyardctl installation`_. + +Data sharing between different containers +----------------------------------------- + +In this section, we will show you how to share data between different containers on kubernetes. +Assuming you have a pod with two containers, one is a producer and the other is a consumer. +The producer will generate some data and write it to vineyard, and the consumer will read the data +from vineyard and do some computation. + +Save the following yaml as `pod.yaml`. + +.. code:: yaml + + $ cat << EOF >> pod.yaml + apiVersion: v1 + kind: Pod + metadata: + name: vineyard-producer-consumer + namespace: vineyard-test + spec: + containers: + - name: producer + image: python:3.10 + command: + - bash + - -c + - | + pip install vineyard numpy pandas; + cat << EOF >> producer.py + import vineyard; + import numpy as np; + import pandas as pd; + client = vineyard.connect(); + # put a pandas dataframe to vineyard + client.put(pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD')), persist=True, name="test_dataframe"); + # put a basic data unit to vineyard + client.put((1, 1.2345, 'xxxxabcd'), persist=True, name="test_basic_data_unit"); + client.close() + EOF + python producer.py; + sleep infinity; + - name: consumer + image: python:3.10 + command: + - bash + - -c + - | + # wait for the producer to finish + sleep 10; + pip install vineyard numpy pandas; + cat << EOF >> consumer.py + import vineyard; + client = vineyard.connect(); + # get the pandas dataframe from vineyard + print(client.get(name="test_dataframe").sum()) + # get the basic data unit from vineyard + print(client.get(name="test_basic_data_unit")) + client.close() + EOF + python consumer.py; + sleep infinity; + EOF + +Use the `vineyardctl` to inject vineyard into the pod and apply them to the kubernetes cluster +as follows. + +.. code:: bash + + # create the namespace + $ kubectl create ns vineyard-test + # get all injected resources + $ vineyardctl inject -f pod.yaml | kubectl apply -f - + pod/vineyard-sidecar-etcd-0 created + service/vineyard-sidecar-etcd-0 created + service/vineyard-sidecar-etcd-service created + service/vineyard-sidecar-rpc created + pod/vineyard-producer-consumer created + + +Then you can get the logs of the consumer containers as follows. + +.. code:: bash + + # get the logs of the consumer container + $ kubectl logs -f vineyard-producer-consumer -n test -c consumer + A -30.168469 + B -19.269489 + C 6.332533 + D -9.714950 + dtype: float64 + (1, 1.2345000505447388, 'xxxxabcd') + +Data sharing between different pods +----------------------------------- + +In this section, we will show you how to share data between different workloads on kubernetes. +You are supposed to create a vineyard deployment and then deploy the application pods on +the nodes where the vineyard deployment is running. + +Deploy the vineyard deployment (default is 3 replicas) as follows. + +.. code:: bash + + # create the namespace if not exists + $ kubectl create ns vineyard-test + # create the vineyard deployment + $ vineyardctl deploy vineyard-deployment --name vineyardd-sample -n vineyard-test + 2023-07-21T15:42:25.981+0800 INFO vineyard cluster deployed successfully + +Check the vineyard deployment status and the three vineyardd pods should run on the different nodes. + +.. code:: bash + + # check the pods status + $ kubectl get pod -lapp.vineyard.io/name=vineyardd-sample -n vineyard-test -owide + NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES + vineyardd-sample-5fd45fdd66-fq55z 1/1 Running 0 3m37s 10.244.1.17 kind-worker3 + vineyardd-sample-5fd45fdd66-qjr5c 1/1 Running 0 3m37s 10.244.3.35 kind-worker + vineyardd-sample-5fd45fdd66-ssqb7 1/1 Running 0 3m37s 10.244.2.29 kind-worker2 + vineyardd-sample-etcd-0 1/1 Running 0 3m53s 10.244.1.16 kind-worker3 + +Assume we have two pods, one is a producer and the other is a consumer. + +The producer yaml file is as follows. + +.. code:: bash + + $ cat << EOF >> producer.yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + name: producer + namespace: vineyard-test + spec: + selector: + matchLabels: + app: producer + replicas: 1 + template: + metadata: + labels: + app: producer + spec: + containers: + - name: producer + image: python:3.10 + command: + - bash + - -c + - | + pip install vineyard numpy pandas; + cat << EOF >> producer.py + import vineyard + import numpy as np + import pandas as pd + client = vineyard.connect() + client.put(pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD')), persist=True, name="test_dataframe") + client.put((1, 1.2345, 'xxxxabcd'), persist=True, name="test_basic_data_unit"); + client.close() + EOF + python producer.py; + sleep infinity; + EOF + +The consumer yaml file is as follows. + +.. code:: bash + + $ cat << EOF >> consumer.yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + name: consumer + namespace: vineyard-test + spec: + selector: + matchLabels: + app: consumer + replicas: 1 + template: + metadata: + labels: + app: consumer + spec: + containers: + - name: consumer + image: python:3.10 + command: + - bash + - -c + - | + pip install vineyard numpy pandas; + cat << EOF >> consumer.py + import vineyard + client = vineyard.connect() + dataframe_obj = client.get_name("test_dataframe") + print(client.get(dataframe_obj,fetch=True).sum()) + unit_obj = client.get_name("test_basic_data_unit") + print(client.get(unit_obj,fetch=True)) + client.close() + EOF + python consumer.py; + sleep infinity; + EOF + +Use the `vineyardctl` to schedule the two workloads on the vineyard cluster. + +.. code:: bash + + # schedule the producer workload to the vineyard cluster and apply it to the kubernetes cluster + $ vineyardctl schedule workload -f producer.yaml --vineyardd-name vineyardd-sample \ + --vineyardd-namespace vineyard-test -o yaml | kubectl apply -f - + deployment.apps/producer created + + # schedule the consumer workload to the vineyard cluster and apply it to the kubernetes cluster + $ vineyardctl schedule workload -f consumer.yaml --vineyardd-name vineyardd-sample \ + --vineyardd-namespace vineyard-test -o yaml | kubectl apply -f - + deployment.apps/consumer created + +Check the logs of the consumer pods as follows. + +.. code:: bash + + $ kubectl logs -f $(kubectl get pod -lapp=consumer -n vineyard-test -o jsonpath='{.items[0].metadata.name}') -n vineyard-test + A 11.587912 + B 12.059792 + C 4.863514 + D -2.682567 + dtype: float64 + (1, 1.2345000505447388, 'xxxxabcd') + +From the above example, we can see the code of the consumer is quiet different from the previous sidecar example. +As the consumer may be scheduled to different node from the producer with the default kubernetes scheduler, the client +should get the remote object id by name and then fetch it from other vineyard nodes. For more details, please refer to +the `vineyard objects`_. + +.. _vineyardctl installation: https://v6d.io/notes/developers/build-from-source.html#install-vineyardctl +.. _vineyard objects: https://v6d.io/notes/key-concepts/objects.html#transient-vs-persistent \ No newline at end of file diff --git a/_sources/tutorials/kubernetes/ml-pipeline-mars-pytorch.rst.txt b/_sources/tutorials/kubernetes/ml-pipeline-mars-pytorch.rst.txt new file mode 100644 index 0000000000..a1698103ed --- /dev/null +++ b/_sources/tutorials/kubernetes/ml-pipeline-mars-pytorch.rst.txt @@ -0,0 +1,264 @@ +Machine learning with Vineyard on Kubernetes +-------------------------------------------- + +In this demonstration, we will build a fraudulent transaction classifier for +fraudulent transaction data. The process consists of the following +three main steps: + +- :code:`prepare-data`: Utilize Vineyard to read and store data in a distributed manner. +- :code:`process-data`: Employ Mars to process the data across multiple nodes. +- :code:`train-data`: Use Pytorch to train the model on the distributed data. + +We have three tables: user table, product table, and transaction table. +The user and product tables primarily contain user and product IDs, along with +their respective ``Feature`` vectors. Each record in the transaction table indicates +a user purchasing a product, with a ``Fraud`` label identifying whether the +transaction is fraudulent. Additional features related to these transactions are also +stored in the transaction table. You can find the three tables in the `dataset repo`_. +Follow the steps below to reproduce the demonstration. First, create a vineyard cluster +with 3 worker nodes. + +.. code:: bash + + $ cd k8s && make install-vineyard + +.. admonition:: Expected output + :class: admonition-details + + .. code:: bash + + the kubeconfig path is /tmp/e2e-k8s.config + Creating the kind cluster with local registry + a16c878c5091c1e5c9eff0a1fca065665f47edb4c8c75408b3d33e22f0ec0d05 + Creating cluster "kind" ... + ✓ Ensuring node image (kindest/node:v1.24.0) 🖼 + ✓ Preparing nodes 📦 📦 📦 📦 + ✓ Writing configuration 📜 + ✓ Starting control-plane 🕹️ + ✓ Installing CNI 🔌 + ✓ Installing StorageClass 💾 + ✓ Joining worker nodes 🚜 + Set kubectl context to "kind-kind" + You can now use your cluster with: + + kubectl cluster-info --context kind-kind --kubeconfig /tmp/e2e-k8s.config + + Thanks for using kind! 😊 + configmap/local-registry-hosting created + Installing cert-manager... + namespace/cert-manager created + customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created + customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created + customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created + customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created + customresourcedefinition.apiextensions.k8s.io/issuers.cert-manager.io created + customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manager.io created + serviceaccount/cert-manager-cainjector created + serviceaccount/cert-manager created + serviceaccount/cert-manager-webhook created + configmap/cert-manager-webhook created + clusterrole.rbac.authorization.k8s.io/cert-manager-cainjector created + clusterrole.rbac.authorization.k8s.io/cert-manager-controller-issuers created + clusterrole.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers created + clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificates created + clusterrole.rbac.authorization.k8s.io/cert-manager-controller-orders created + clusterrole.rbac.authorization.k8s.io/cert-manager-controller-challenges created + clusterrole.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim created + clusterrole.rbac.authorization.k8s.io/cert-manager-view created + clusterrole.rbac.authorization.k8s.io/cert-manager-edit created + clusterrole.rbac.authorization.k8s.io/cert-manager-controller-approve:cert-manager-io created + clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificatesigningrequests created + clusterrole.rbac.authorization.k8s.io/cert-manager-webhook:subjectaccessreviews created + clusterrolebinding.rbac.authorization.k8s.io/cert-manager-cainjector created + clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-issuers created + clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers created + clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificates created + clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-orders created + clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-challenges created + clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim created + clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-approve:cert-manager-io created + clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificatesigningrequests created + clusterrolebinding.rbac.authorization.k8s.io/cert-manager-webhook:subjectaccessreviews created + role.rbac.authorization.k8s.io/cert-manager-cainjector:leaderelection created + role.rbac.authorization.k8s.io/cert-manager:leaderelection created + role.rbac.authorization.k8s.io/cert-manager-webhook:dynamic-serving created + rolebinding.rbac.authorization.k8s.io/cert-manager-cainjector:leaderelection created + rolebinding.rbac.authorization.k8s.io/cert-manager:leaderelection created + rolebinding.rbac.authorization.k8s.io/cert-manager-webhook:dynamic-serving created + service/cert-manager created + service/cert-manager-webhook created + deployment.apps/cert-manager-cainjector created + deployment.apps/cert-manager created + deployment.apps/cert-manager-webhook created + mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created + validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created + pod/cert-manager-5dd59d9d9b-k9hkm condition met + pod/cert-manager-cainjector-8696fc9f89-bmjzh condition met + pod/cert-manager-webhook-7d4b5b8c56-fvmc2 condition met + Cert-Manager ready. + Installing vineyard-operator... + The push refers to repository [localhost:5001/vineyard-operator] + c3a672704524: Pushed + b14a7037d2e7: Pushed + 8d7366c22fd8: Pushed + latest: digest: sha256:ea06c833351f19c5db28163406c55e2108676c27fdafea7652500c55ce333b9d size: 946 + make[1]: Entering directory '/opt/caoye/v6d/k8s' + go: creating new go.mod: module tmp + /home/gsbot/go/bin/controller-gen rbac:roleName=manager-role crd:maxDescLen=0 webhook paths="./..." output:crd:artifacts:config=config/crd/bases + cd config/manager && /usr/local/bin/kustomize edit set image controller=localhost:5001/vineyard-operator:latest + /usr/local/bin/kustomize build config/default | kubectl apply -f - + namespace/vineyard-system created + customresourcedefinition.apiextensions.k8s.io/backups.k8s.v6d.io created + customresourcedefinition.apiextensions.k8s.io/globalobjects.k8s.v6d.io created + customresourcedefinition.apiextensions.k8s.io/localobjects.k8s.v6d.io created + customresourcedefinition.apiextensions.k8s.io/operations.k8s.v6d.io created + customresourcedefinition.apiextensions.k8s.io/recovers.k8s.v6d.io created + customresourcedefinition.apiextensions.k8s.io/sidecars.k8s.v6d.io created + customresourcedefinition.apiextensions.k8s.io/vineyardds.k8s.v6d.io created + serviceaccount/vineyard-manager created + role.rbac.authorization.k8s.io/vineyard-leader-election-role created + clusterrole.rbac.authorization.k8s.io/vineyard-manager-role created + clusterrole.rbac.authorization.k8s.io/vineyard-metrics-reader created + clusterrole.rbac.authorization.k8s.io/vineyard-proxy-role created + clusterrole.rbac.authorization.k8s.io/vineyard-scheduler-plugin-role created + rolebinding.rbac.authorization.k8s.io/vineyard-leader-election-rolebinding created + clusterrolebinding.rbac.authorization.k8s.io/vineyard-kube-scheduler-rolebinding created + clusterrolebinding.rbac.authorization.k8s.io/vineyard-manager-rolebinding created + clusterrolebinding.rbac.authorization.k8s.io/vineyard-proxy-rolebinding created + clusterrolebinding.rbac.authorization.k8s.io/vineyard-scheduler-plugin-rolebinding created + clusterrolebinding.rbac.authorization.k8s.io/vineyard-scheduler-rolebinding created + clusterrolebinding.rbac.authorization.k8s.io/vineyard-volume-scheduler-rolebinding created + service/vineyard-controller-manager-metrics-service created + service/vineyard-webhook-service created + deployment.apps/vineyard-controller-manager created + certificate.cert-manager.io/vineyard-serving-cert created + issuer.cert-manager.io/vineyard-selfsigned-issuer created + mutatingwebhookconfiguration.admissionregistration.k8s.io/vineyard-mutating-webhook-configuration created + validatingwebhookconfiguration.admissionregistration.k8s.io/vineyard-validating-webhook-configuration created + make[1]: Leaving directory '/opt/caoye/v6d/k8s' + deployment.apps/vineyard-controller-manager condition met + Vineyard-Operator Ready + Installing vineyard cluster... + vineyardd.k8s.v6d.io/vineyardd-sample created + vineyardd.k8s.v6d.io/vineyardd-sample condition met + Vineyard cluster Ready + +Verify that all Vineyard pods are running. + +.. code:: bash + + $ KUBECONFIG=/tmp/e2e-k8s.config kubectl get pod -n vineyard-system + +.. admonition:: Expected output + :class: admonition-details + + .. code:: bash + + NAME READY STATUS RESTARTS AGE + etcd0 1/1 Running 0 68s + etcd1 1/1 Running 0 68s + etcd2 1/1 Running 0 68s + vineyard-controller-manager-7f569b57c5-46tgq 2/2 Running 0 92s + vineyardd-sample-6ffcb96cbc-gs2v9 1/1 Running 0 67s + vineyardd-sample-6ffcb96cbc-n59gg 1/1 Running 0 67s + vineyardd-sample-6ffcb96cbc-xwpzd 1/1 Running 0 67s + +First, let's prepare the dataset and download it into the kind worker nodes as follows. + +.. code:: bash + + $ worker=($(docker ps | grep kind-worker | awk -F ' ' '{print $1}')) + $ for c in ${worker[@]}; do \ + docker exec $c sh -c "\ + mkdir -p /datasets; \ + cd /datasets/; \ + curl -OL https://raw.githubusercontent.com/GraphScope/gstest/master/vineyard-mars-showcase-dataset/{item,txn,user}.csv" \ + done + +The `prepare-data` job primarily reads the datasets and distributes them across different +Vineyard nodes. For more information, please refer to the `prepare data code`_. To apply +the job, follow the steps below: + +.. note:: + + The `prepare-data` job needs to exec into the other pods. Therefore, you need to + create a service account and bind it to the role under the namespace. + Please make sure you can have permission to create the following role. + + .. code:: text + + - apiGroups: [""] + resources: ["pods", "pods/log", "pods/exec"] + verbs: ["get", "patch", "delete", "create", "watch", "list"] + +.. code:: bash + + $ kubectl create ns vineyard-job && \ + kubectl apply -f showcase/vineyard-mars-pytorch/prepare-data/resources && \ + kubectl wait job -n vineyard-job -l app=prepare-data --for condition=complete --timeout=1200s + +.. admonition:: Expected output + :class: admonition-details + + .. code:: bash + + namespace/vineyard-job created + clusterrolebinding.rbac.authorization.k8s.io/prepare-data-rolebinding created + clusterrole.rbac.authorization.k8s.io/prepare-data-role created + job.batch/prepare-data created + serviceaccount/prepare-data created + job.batch/prepare-data condition met + +.. note:: + + The `process-data` job needs to create a new namespace and deploy several kubernetes + resources in it. Please make sure you can have permission to create the following role. + + .. code:: text + + - apiGroups: [""] + resources: ["pods", "pods/exec", "pods/log", "endpoints", "services"] + verbs: ["get", "patch", "delete", "create", "watch", "list"] + - apiGroups: [""] + resources: ["namespaces"] + verbs: ["get", "create", "delete"] + - apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "list"] + - apiGroups: ["rbac.authorization.k8s.io"] + resources: ["roles", "rolebindings"] + verbs: ["patch", "get", "create", "delete"] + - apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["create"] + + Notice, the `process-data` job will require lots of permissions to deal + kubernetes resources, so please check the image of `process-data` job + if it is an official one. + +The `prepare-data` job creates numerous dataframes in Vineyard. To combine these dataframes, +we use the appropriate join method in `mars`_. For more details, refer to the `process data +code`_. Apply the `process-data` job as follows: + +.. code:: bash + + $ kubectl apply -f showcase/vineyard-mars-pytorch/process-data/resources && \ + kubectl wait job -n vineyard-job -l app=process-data --for condition=complete --timeout=1200s + +Finally, apply the `train-data` job to obtain the fraudulent transaction classifier. You can +also view the `train data code`_. + +.. code:: bash + + $ kubectl apply -f k8s/showcase/vineyard-mars-pytorch/train-data/resources && \ + kubectl wait pods -n vineyard-job -l app=train-data --for condition=Ready --timeout=1200s + +If any of the above steps fail, please refer to the `mars showcase e2e test`_ for further guidance. + + +.. _mars: https://github.com/mars-project/mars +.. _mars showcase e2e test: https://github.com/v6d-io/v6d/blob/main/k8s/test/e2e/mars-examples/e2e.yaml +.. _dataset repo: https://github.com/GraphScope/gstest/tree/master/vineyard-mars-showcase-dataset +.. _prepare data code: https://github.com/v6d-io/v6d/blob/main/k8s/examples/vineyard-mars-pytorch/prepare-data/prepare-data.py +.. _process data code: https://github.com/v6d-io/v6d/blob/main/k8s/examples/vineyard-mars-pytorch/process-data/process-data.py +.. _train data code: https://github.com/v6d-io/v6d/blob/main/k8s/examples/vineyard-mars-pytorch/train-data/train-data.py diff --git a/_sources/tutorials/kubernetes/using-vineyard-operator.rst.txt b/_sources/tutorials/kubernetes/using-vineyard-operator.rst.txt new file mode 100644 index 0000000000..fb7d0e4a82 --- /dev/null +++ b/_sources/tutorials/kubernetes/using-vineyard-operator.rst.txt @@ -0,0 +1,481 @@ +Use vineyard operator +===================== + +Vineyard operator has been designed to manage vineyard components within Kubernetes. +This tutorial provides a step-by-step guide on how to effectively utilize the vineyard +operator. For more details, please refer to :ref:`vineyard-operator`. + +Step 0: (optional) Initialize Kubernetes Cluster +------------------------------------------------ + +If you don't have a Kubernetes cluster readily available, we highly recommend using `kind`_ to +create one. Before setting up the Kubernetes cluster, please ensure you have the following +tools installed: + +- kubectl: version >= 1.19.2 +- kind: version >= 0.14.0 +- docker: version >= 0.19.0 + +Utilize kind (v0.14.0) to create a Kubernetes cluster consisting of 4 nodes (1 master node and 3 +worker nodes): + +.. code:: bash + + $ cat > kind-config.yaml < 114s v1.24.0 + kind-worker2 Ready 114s v1.24.0 + kind-worker3 Ready 114s v1.24.0 + +Step 1: Deploy the Vineyard Operator +------------------------------------- + +Create a dedicated namespace for the Vineyard Operator. + +.. code:: bash + + $ kubectl create namespace vineyard-system + +.. admonition:: Expected output + :class: admonition-details + + .. code:: bash + + namespace/vineyard-system created + +The operator needs a certificate created by cert-manager for webhook(https), +and the cert-manager is a sub chart of the vineyard operator chart. Also, the +Vineyard CRDs、Controllers、Webhooks and Scheduler are packaged by `helm`_, you could +deploy all resources as follows. + +.. note:: + + The vineyard operator needs permission to create several CRDs and kubernetes + resources, before deploying the vineyard operator, please ensure you can create + the `clusterrole`_. + +.. code:: bash + + $ helm repo add vineyard https://vineyard.oss-ap-southeast-1.aliyuncs.com/charts/ + +.. admonition:: Expected output + :class: admonition-details + + .. code:: bash + + "vineyard" has been added to your repositories + +Update the vineyard operator chart to the newest one. + +.. code:: bash + + $ helm repo update + +.. admonition:: Expected output + :class: admonition-details + + .. code:: bash + + Hang tight while we grab the latest from your chart repositories... + ...Successfully got an update from the "vineyard" chart repository + Update Complete. ⎈Happy Helming!⎈ + +Deploy the vineyard operator in the namespace ``vineyard-system``. + +.. code:: bash + + $ helm install vineyard-operator vineyard/vineyard-operator -n vineyard-system + +.. admonition:: Expected output + :class: admonition-details + + .. code:: bash + + NAME: vineyard-operator + LAST DEPLOYED: Wed Jan 4 16:41:45 2023 + NAMESPACE: vineyard-system + STATUS: deployed + REVISION: 1 + TEST SUITE: None + NOTES: + Thanks for installing VINEYARD-OPERATOR, release at namespace: vineyard-system, name: vineyard-operator. + + To learn more about the release, try: + + $ helm status vineyard-operator -n vineyard-system # get status of running vineyard operator + $ helm get all vineyard-operator -n vineyard-system # get all deployment yaml of vineyard operator + + To uninstall the release, try: + + $ helm uninstall vineyard-operator -n vineyard-system + +You could get all details about vineyard operator in the doc :ref:`vineyard-operator`, just have fun with vineyard operator! + +Check the status of all vineyard resources created by helm: + +.. code:: bash + + $ kubectl get all -n vineyard-system + +.. admonition:: Expected output + :class: admonition-details + + .. code:: bash + + NAME READY STATUS RESTARTS AGE + pod/vineyard-operator-cert-manager-cainjector-b865888cc-xj8x9 1/1 Running 0 2m30s + pod/vineyard-operator-cert-manager-d99dcb884-gq9j5 1/1 Running 0 2m30s + pod/vineyard-operator-cert-manager-webhook-5bc8fd5d48-vh4bg 1/1 Running 0 2m30s + pod/vineyard-operator-controller-manager-5bcbb75fb6-cfdpk 2/2 Running 0 2m30s + + NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + service/vineyard-operator-cert-manager ClusterIP 10.96.166.147 9402/TCP 2m30s + service/vineyard-operator-cert-manager-webhook ClusterIP 10.96.111.112 443/TCP 2m30s + service/vineyard-operator-controller-manager-metrics-service ClusterIP 10.96.153.134 8443/TCP 2m30s + service/vineyard-operator-webhook-service ClusterIP 10.96.9.101 443/TCP 2m30s + + NAME READY UP-TO-DATE AVAILABLE AGE + deployment.apps/vineyard-operator-cert-manager 1/1 1 1 2m30s + deployment.apps/vineyard-operator-cert-manager-cainjector 1/1 1 1 2m30s + deployment.apps/vineyard-operator-cert-manager-webhook 1/1 1 1 2m30s + deployment.apps/vineyard-operator-controller-manager 1/1 1 1 2m30s + + NAME DESIRED CURRENT READY AGE + replicaset.apps/vineyard-operator-cert-manager-cainjector-b865888cc 1 1 1 2m30s + replicaset.apps/vineyard-operator-cert-manager-d99dcb884 1 1 1 2m30s + replicaset.apps/vineyard-operator-cert-manager-webhook-5bc8fd5d48 1 1 1 2m30s + replicaset.apps/vineyard-operator-controller-manager-5bcbb75fb6 1 1 1 2m30s + +Step 2: Deploy a Vineyard Cluster +---------------------------------- + +After successfully installing the Vineyard operator as described in the previous step, +you can now proceed to deploy a Vineyard cluster. To create a cluster with two Vineyard +instances, simply create a `Vineyardd` Custom Resource (CR) as shown below. + +.. code:: bash + + $ cat <", + "value_type_": "float64", + "value_type_meta_": "", + "value_type_": "float64", + "value_type_meta_": "= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/_static/airflow_etl.jpg b/_static/airflow_etl.jpg new file mode 100644 index 0000000000..78842377dc Binary files /dev/null and b/_static/airflow_etl.jpg differ diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 0000000000..eeb0519a69 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,899 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} +dl.footnote > dt, +dl.citation > dt { + float: left; + margin-right: 0.5em; +} + +dl.footnote > dd, +dl.citation > dd { + margin-bottom: 0em; +} + +dl.footnote > dd:after, +dl.citation > dd:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} +dl.field-list > dt:after { + content: ":"; +} + + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/check-solid.svg b/_static/check-solid.svg new file mode 100644 index 0000000000..92fad4b5c0 --- /dev/null +++ b/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/_static/clipboard.min.js b/_static/clipboard.min.js new file mode 100644 index 0000000000..54b3c46381 --- /dev/null +++ b/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 \ No newline at end of file diff --git a/_static/cncf-small.png b/_static/cncf-small.png new file mode 100644 index 0000000000..27bdc98ff2 Binary files /dev/null and b/_static/cncf-small.png differ diff --git a/_static/cncf-tiny.png b/_static/cncf-tiny.png new file mode 100644 index 0000000000..2d9fe42414 Binary files /dev/null and b/_static/cncf-tiny.png differ diff --git a/_static/cncf.png b/_static/cncf.png new file mode 100644 index 0000000000..97796cba6c Binary files /dev/null and b/_static/cncf.png differ diff --git a/_static/copy-button.svg b/_static/copy-button.svg new file mode 100644 index 0000000000..9c074dae52 --- /dev/null +++ b/_static/copy-button.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/_static/copybutton.css b/_static/copybutton.css new file mode 100644 index 0000000000..f1916ec7d1 --- /dev/null +++ b/_static/copybutton.css @@ -0,0 +1,94 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +/* Show the copybutton */ +.highlight:hover button.copybtn, button.copybtn.success { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/_static/copybutton.js b/_static/copybutton.js new file mode 100644 index 0000000000..be65e437f9 --- /dev/null +++ b/_static/copybutton.js @@ -0,0 +1,248 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copier dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for a moment, then changes it back +// We want the timeout of our `success` class to be a bit shorter than the +// tooltip and icon change, so that we can hide the icon before changing back. +var timeoutIcon = 2000; +var timeoutSuccessClass = 1500; + +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + // Remove success a little bit sooner than we change the tooltip + // So that we can use CSS to hide the copybutton first + setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) + setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.notranslate:not(.prompt) div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/_static/copybutton_funcs.js b/_static/copybutton_funcs.js new file mode 100644 index 0000000000..dbe1aaad79 --- /dev/null +++ b/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/_static/css/brands.min.css b/_static/css/brands.min.css new file mode 100644 index 0000000000..714509e6f9 --- /dev/null +++ b/_static/css/brands.min.css @@ -0,0 +1,6 @@ +/*! + * Font Awesome Free 6.1.1 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2022 Fonticons, Inc. + */ +:host,:root{--fa-font-brands:normal 400 1em/1 "Font Awesome 6 Brands"}@font-face{font-family:"Font Awesome 6 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}.fa-brands,.fab{font-family:"Font Awesome 6 Brands";font-weight:400}.fa-42-group:before,.fa-innosoft:before{content:"\e080"}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-alipay:before{content:"\f642"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-amilia:before{content:"\f36d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-pay:before{content:"\f415"}.fa-artstation:before{content:"\f77a"}.fa-asymmetrik:before{content:"\f372"}.fa-atlassian:before{content:"\f77b"}.fa-audible:before{content:"\f373"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-aws:before{content:"\f375"}.fa-bandcamp:before{content:"\f2d5"}.fa-battle-net:before{content:"\f835"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bilibili:before{content:"\e3d9"}.fa-bimobject:before{content:"\f378"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bootstrap:before{content:"\f836"}.fa-bots:before{content:"\e340"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-buromobelexperte:before{content:"\f37f"}.fa-buy-n-large:before{content:"\f8a6"}.fa-buysellads:before{content:"\f20d"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-cloudflare:before{content:"\e07d"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cmplid:before{content:"\e360"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cotton-bureau:before{content:"\f89e"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-critical-role:before{content:"\f6c9"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dailymotion:before{content:"\e052"}.fa-dashcube:before{content:"\f210"}.fa-deezer:before{content:"\e077"}.fa-delicious:before{content:"\f1a5"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dhl:before{content:"\f790"}.fa-diaspora:before{content:"\f791"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-draft2digital:before{content:"\f396"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drupal:before{content:"\f1a9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edge-legacy:before{content:"\e078"}.fa-elementor:before{content:"\f430"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envira:before{content:"\f299"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-etsy:before{content:"\f2d7"}.fa-evernote:before{content:"\f839"}.fa-expeditedssl:before{content:"\f23e"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-figma:before{content:"\f799"}.fa-firefox:before{content:"\f269"}.fa-firefox-browser:before{content:"\e007"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-fly:before{content:"\f417"}.fa-font-awesome-flag:before,.fa-font-awesome-logo-full:before,.fa-font-awesome:before{content:"\f2b4"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-fulcrum:before{content:"\f50b"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-gofore:before{content:"\f3a7"}.fa-golang:before{content:"\e40f"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-pay:before{content:"\e079"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guilded:before{content:"\e07e"}.fa-gulp:before{content:"\f3ae"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hashnode:before{content:"\e499"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-hive:before{content:"\e07f"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-hotjar:before{content:"\f3b1"}.fa-houzz:before{content:"\f27c"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-ideal:before{content:"\e013"}.fa-imdb:before{content:"\f2d8"}.fa-instagram:before{content:"\f16d"}.fa-instagram-square:before{content:"\e055"}.fa-instalod:before{content:"\e081"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joomla:before{content:"\f1aa"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaggle:before{content:"\f5fa"}.fa-keybase:before{content:"\f4f5"}.fa-keycdn:before{content:"\f3ba"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-korvue:before{content:"\f42f"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-leanpub:before{content:"\f212"}.fa-less:before{content:"\f41d"}.fa-line:before{content:"\f3c0"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-mailchimp:before{content:"\f59e"}.fa-mandalorian:before{content:"\f50f"}.fa-markdown:before{content:"\f60f"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-mdb:before{content:"\f8ca"}.fa-medapps:before{content:"\f3c6"}.fa-medium-m:before,.fa-medium:before{content:"\f23a"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-mendeley:before{content:"\f7b3"}.fa-microblog:before{content:"\e01a"}.fa-microsoft:before{content:"\f3ca"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mixer:before{content:"\e056"}.fa-mizuni:before{content:"\f3cc"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-nfc-directional:before{content:"\e530"}.fa-nfc-symbol:before{content:"\e531"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-octopus-deploy:before{content:"\e082"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-old-republic:before{content:"\f510"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-orcid:before{content:"\f8d2"}.fa-osi:before{content:"\f41a"}.fa-padlet:before{content:"\e4a0"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-palfed:before{content:"\f3d8"}.fa-patreon:before{content:"\f3d9"}.fa-paypal:before{content:"\f1ed"}.fa-perbyte:before{content:"\e083"}.fa-periscope:before{content:"\f3da"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-square:before{content:"\e01e"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pix:before{content:"\e43a"}.fa-playstation:before{content:"\f3df"}.fa-product-hunt:before{content:"\f288"}.fa-pushed:before{content:"\f3e1"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-r-project:before{content:"\f4f7"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-renren:before{content:"\f18b"}.fa-replyd:before{content:"\f3e6"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-rev:before{content:"\f5b2"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-rust:before{content:"\e07a"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-schlix:before{content:"\f3ea"}.fa-screenpal:before{content:"\e570"}.fa-scribd:before{content:"\f28a"}.fa-searchengin:before{content:"\f3eb"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-servicestack:before{content:"\f3ec"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shopify:before{content:"\e057"}.fa-shopware:before{content:"\f5b5"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sith:before{content:"\f512"}.fa-sitrox:before{content:"\e44a"}.fa-sketch:before{content:"\f7c6"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack-hash:before,.fa-slack:before{content:"\f198"}.fa-slideshare:before{content:"\f1e7"}.fa-snapchat-ghost:before,.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-square:before{content:"\f2ad"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spotify:before{content:"\f1bc"}.fa-square-font-awesome:before{content:"\f425"}.fa-font-awesome-alt:before,.fa-square-font-awesome-stroke:before{content:"\f35c"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-sticker-mule:before{content:"\f3f7"}.fa-strava:before{content:"\f428"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-superpowers:before{content:"\f2dd"}.fa-supple:before{content:"\f3f9"}.fa-suse:before{content:"\f7d6"}.fa-swift:before{content:"\f8e1"}.fa-symfony:before{content:"\f83d"}.fa-teamspeak:before{content:"\f4f9"}.fa-telegram-plane:before,.fa-telegram:before{content:"\f2c6"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-the-red-yeti:before{content:"\f69d"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-think-peaks:before{content:"\f731"}.fa-tiktok:before{content:"\e07b"}.fa-trade-federation:before{content:"\f513"}.fa-trello:before{content:"\f181"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbraco:before{content:"\f8e8"}.fa-uncharted:before{content:"\e084"}.fa-uniregistry:before{content:"\f404"}.fa-unity:before{content:"\e049"}.fa-unsplash:before{content:"\e07c"}.fa-untappd:before{content:"\f405"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-vaadin:before{content:"\f408"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-viber:before{content:"\f409"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-vuejs:before{content:"\f41f"}.fa-watchman-monitoring:before{content:"\e087"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-whmcs:before{content:"\f40d"}.fa-wikipedia-w:before{content:"\f266"}.fa-windows:before{content:"\f17a"}.fa-wirsindhandwerk:before,.fa-wsh:before{content:"\e2d0"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wodu:before{content:"\e088"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"} \ No newline at end of file diff --git a/_static/css/custom.css b/_static/css/custom.css new file mode 100644 index 0000000000..42f56b2532 --- /dev/null +++ b/_static/css/custom.css @@ -0,0 +1,55 @@ +.fa.fa-2x { + font-size: 36px; +} + +/* Decrease the padding of button block in panels */ +div.card-body.card-body-less-padding { + padding: 0.25em; +} + +/* Disable theme toggle */ +div.theme-toggle-container.theme-toggle-content { + display: none; +} + +/* Proper distance at the bottom of TOC tree */ +.sidebar-container > .sidebar-sticky > .sidebar-scroll > .sidebar-tree { + padding-bottom: 1em; +} + +/* Admonition for drop-down like details component */ + +.admonition.admonition-details { + padding: 0 0 0 0; + margin: 0 auto; +} + +.admonition.admonition-details.active > :not(.admonition-title) { + display: inherit; +} + +.admonition.admonition-details > :not(.admonition-title) { + display: none; +} + +.admonition.admonition-details > p.admonition-title, p.topic-title { + margin: 0 0 0 0; +} + +.admonition.admonition-details > blockquote { + padding: 0; +} + +.admonition.admonition-details > blockquote > div > div[class^=highlight-] { + margin: 0; +} + +.admonition.admonition-details > blockquote > div > div[class^=table-wrapper] { + margin-top: 0; + margin-bottom: 0; + padding: 0 0 0 0; +} + +.admonition.admonition-details > blockquote > div > div[class^=table-wrapper] > table { + min-width: 100%; +} diff --git a/_static/css/index.css b/_static/css/index.css new file mode 100644 index 0000000000..bfeef1af4f --- /dev/null +++ b/_static/css/index.css @@ -0,0 +1,442 @@ +body { + font-family: "Lato", sans-serif; + margin: 0; +} + +/* nav { + position: sticky; + top: 0; + transition: background-color .25s; +} */ + +.list-style-none { + list-style: none; +} + +.padding-left-right-20 { + padding: 0 20px; +} + +nav i { + padding: 0 20px; +} + +h4 > i { + padding-right: 10px; +} + +p i { + padding-left: 6px; +} + +a { + text-decoration: none; +} + +.button { + border: none; + width: 120px; + height: 50px; + border-radius: 7px; + font-weight: 500; + font-size: 0.95rem; +} + +.button:hover { + cursor: pointer; +} + +.background-gradient-color { + background: linear-gradient( + 270deg, + rgba(35, 128, 242, 0.5) 15.55%, + rgba(35, 128, 242, 0) 99.31% + ), + rgba(49, 227, 222, 0.7); +} + +/* html:not([data-scroll='0']) { + .navigator.background-gradient-color { + background: #f5f5f5; + box-shadow: 0 0 .5em rgba(0, 0, 0, .5); + } +} */ + +.main-content { + max-width: max(70%, 1080px); +} + +.nav-link { + color: white; +} + +.nav-link:hover { + color: blue; +} + +.flex { + display: flex; +} + +.flex-column { + flex-direction: column; +} + +.align-items-center { + align-items: center; +} + +.vertical-align-center { + margin: 0 auto; +} + +.justify-content-space-around { + justify-content: space-around; +} + +.justify-content-space-between { + justify-content: space-between; +} + +.justify-content-center { + justify-content: center; +} + +.gap-sm { + gap: 20px; +} + +.navbar { + padding: 30px 3%; + margin: 0 auto; +} + +.logo { + width: 140px; + height: 40px; + object-fit: contain; +} + +.logo > a > img { + max-width: 100%; + max-height: 100%; +} + +.text-center { + text-align: center; +} + +.text-bold { + font-size: 1.1rem; + font-weight: 600; +} + +.text-underline { + text-decoration: underline; + text-decoration-thickness: 2px; + text-underline-offset: 10px; +} + +.text-white { + color: white; +} + +.text-black { + color: black; +} + +.padding-bottom-20 { + padding-bottom: 20px; +} + +.padding-bottom-10 { + padding-bottom: 10px; +} + +.btn-container { + display: flex; + gap: 15px; + margin-top: 30px; +} + +.btn-primary { + background-color: #2380f2; + color: white; +} + +.btn-secondary { + background-color: #f1f1f1; + color: #476581; +} + +.termynal { + margin-top: 30px; + text-align: left; +} + +.breaking-word-all { + word-break: break-all; +} + +.font-weight-300 { + font-weight: 300; +} + +.hero-container { + padding: 100px 3% 100px; +} + +.hero-text { + font-size: 3rem; + color: #f8f8f8; +} + +.hero-text-secondary { + width: 45%; + margin-top: -15px; + color: white; + font-weight: 300; + font-size: larger; +} + +.feature-section { + padding: 100px 3% 25px; + font-size: larger; +} + +.feature-section > .main-content { + margin: 0 auto; +} + +.feature-item { + width: 45%; +} + +.feature-item > p { + font-weight: 300; +} + +.feature-item-sm > h4 { + display: inline-block; + height: 1rem; +} + +.feature-item-sm > p { + font-weight: 100; +} + +.feature-item-sm > span { + margin: auto 1em 1em 0; + text-align: right; +} + +.feature-item-sm { + width: 18em; + height: 15em; + background-color: #ffffff; + padding: 0 0.5em 0 0.5em; + display: flex; + flex-direction: column; + border-radius: 0 1.25em 0 1.25em; +} + +.use-case-section { + background-color: ghostwhite; +} + +.banner { + padding: 120px 0px 70px; + font-weight: 500; + font-size: 1.5rem; + margin: 0 auto; +} + +.banner-link { + text-decoration: underline; + color: black; +} + +.footer { + padding: 50px 20%; + color: white; + background-color: black; + font-weight: 300; +} + +.footer-info-text { + font-size: 0.85rem; + padding-top: 10px; +} + +.footer-link-text { + color: white; + text-decoration: underline; +} + +.img-container { + width: 300px; + height: 100px; + object-fit: cover; + margin: 0 auto; +} + +.media-section { + display: flex; +} + +.navbar ul { + display: flex; +} + +#mobile-menu { + display: none; +} + +.text-wrapping { + overflow-wrap: break-word; + word-wrap: break-word; + -ms-word-break: break-all; + word-break: break-word; + -ms-hyphens: auto; + -moz-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +@media only screen and (max-width: 786px) { + .media-section { + display: none; + } + + #mobile-menu { + display: block; + } + + .menu-toggle { + justify-self: end; + } + + nav { + position: fixed; + width: 100vw; + } + + .navbar { + width: 90%; + margin: 0 auto; + } + + .navbar-linkss { + display: none; + } + + .menu-toggle, .bar { + display: block; + cursor: pointer; + } + + .menu-toggle .bar { + width: 25px; + height: 3px; + background-color: #3f3f3f; + margin: 5px auto; + -webkit-transition: all 0.3s ease-in-out; + -o-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; + } + + .navbar ul { + display: none; + } + + .nav-link-container { + display: flex; + flex-direction: column; + position: fixed; + justify-content: start; + top: 60px; + bottom: 0; + background-color: #fff; + width: 100vw; + height: calc(100% - 60px); + transform: translate(-12%); + text-align: center; + overflow: hidden; + } + + .navbar li { + padding: 25px; + } + + .navbar li:first-child { + margin-top: 50px; + } + + .navbar .nav-link { + color: black; + font-size: 1.3rem; + } + + #mobile-menu.is-active .bar:nth-child(2) { + opacity: 0; + } + + #mobile-menu.is-active .bar:nth-child(1) { + -webkit-transform: translateY(8px) rotate(45deg); + -ms-transform: translateY(8px) rotate(45deg); + -o-transform: translateY(8px) rotate(45deg); + transform: translateY(8px) rotate(45deg); + } + + #mobile-menu.is-active .bar:nth-child(3) { + -webkit-transform: translateY(-8px) rotate(-45deg); + -ms-transform: translateY(-8px) rotate(-45deg); + -o-transform: translateY(-8px) rotate(-45deg); + transform: translateY(-8px) rotate(-45deg); + } + + .hero-container { + width: 90%; + } + + .hero-text-secondary { + width: 70%; + } + + .footer { + padding: 50px 5%; + } + + .footer-container { + display: grid; + grid-template-columns: repeat(2, 1fr); + row-gap: 5px; + gap: 5px; + } + + .feature-container { + display: grid; + grid-template-columns: repeat(1, 1fr); + padding-bottom: 1em; + } + + .feature-section-mobile { + padding: 100px 3% 0px; + } + + .feature-section { + padding: 100px 3% 0px; + font-size: initial; + } + + .feature-item { + width: 80%; + margin: 0 auto; + } + + .feature-item-sm { + margin: 0 auto; + width: 80%; + height: auto; + } +} diff --git a/_static/css/panels.css b/_static/css/panels.css new file mode 100644 index 0000000000..5cf775f167 --- /dev/null +++ b/_static/css/panels.css @@ -0,0 +1,147 @@ +/* Referred and derived from https://github.com/flyteorg/furo/blob/main/src/furo/assets/styles/flyte.css */ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: bold; +} + +.caption-text { + font-size: 15px; + /* color: #696969; */ + color: #333333; +} + +div.sphinx-bs .card { + flex-direction: row; +} + +/* sphinx-panels custom styles */ +div.sphinx-bs .card-header { + border-bottom: none; + background-color: var(--color-background-primary); + display: flex; + align-items: center; + justify-content: left; + width: 28%; + float: left; +} + +.sphinx-bs .card-header:first-child { + border-radius: calc(0.25rem - 1px) 0 0 calc(0.25rem - 1px); +} + +div.sphinx-bs .card-header .sphinx-bs.btn, +div.sphinx-bs .card-body .sphinx-bs.btn, +div.sphinx-bs .card-header p.card-text { + font-size: 1rem; + text-decoration: none; + word-spacing: 2.5px; + color: var(--color-sidebar-link-text); +} + +div.sphinx-bs .card-header p.card-text a { + text-align: left; +} + +.sphinx-bs.btn:focus { + box-shadow: none; +} + +div.sphinx-bs .card-body { + width: 72%; + float: left; +} + +.sphinx-bs .card-body .fa { + color: var(--color-sidebar-link-text); +} + +.sphinx-bs .card-body:hover .fa { + color: var(--color-link--hover); +} + +.sphinx-bs .card-body .fa { + font-size: 2rem; +} + +div.sphinx-bs .card:hover { + box-shadow: none !important; + border-color: #cca9ff; +} + +div.sphinx-bs .card:hover .card-header { + background-color: #f2e9ff; + color: #fff; +} + +body[data-theme="dark"] div.sphinx-bs .card:hover { + border-color: #2a144a; +} + +body[data-theme="dark"] div.sphinx-bs .card:hover .card-header { + background-color: #2a144a; + color: #fff; +} + +/* make sure hover style is consistent if user prefers dark theme at OS level */ +@media (prefers-color-scheme: dark) { + body:not([data-theme="light"]) div.sphinx-bs .card:hover { + border-color: #2a144a; + } + body:not([data-theme="light"]) div.sphinx-bs .card:hover .card-header { + background-color: #2a144a; + color: #fff; + } +} + +div.sphinx-bs .card:hover .sphinx-bs.btn { + color: var(--color-link); +} + +div.sphinx-bs .card:hover .card-body .sphinx-bs.btn { + color: var(--color-link--hover); +} + +.getting-started-panels div.sphinx-bs .sphinx-bs.btn:hover { + border-color: var(--color-link); + background-color: #9d68e4; + color: #ffffff; +} + +div.sphinx-bs .card { + background-color: var(--color-background-secondary); + border: 1px solid var(--color-background-border); +} + +.center-card-content p { + margin: auto !important; +} + +.sphinx-tabs { + padding-top: 10px; +} + +.sphinx-tabs-tab { + color: var(--color-link); +} + +/* sphinx tabs */ +.sphinx-tabs-tab[aria-selected="true"] { + background-color: var(--color-background-secondary); + border: 1px solid var(--color-background-border); + border-bottom: 1px solid var(--color-background-secondary); +} + +.sphinx-tabs-panel { + border: 1px solid var(--color-background-border); + background: var(--color-background-secondary); + border-top: 0; +} + +[role="tablist"] { + border-bottom: 1px solid var(--color-background-border); +} diff --git a/_static/css/termynal.css b/_static/css/termynal.css new file mode 100644 index 0000000000..76a7d02cf2 --- /dev/null +++ b/_static/css/termynal.css @@ -0,0 +1,101 @@ +/** + * termynal.js + * + * @author Ines Montani + * @version 0.0.1 + * @license MIT + */ + + :root { + --color-bg: #252a33; + --color-text: #eee; + --color-text-subtle: #a2a2a2; +} + +[data-termynal] { + width: 750px; + max-width: 100%; + background: var(--color-bg); + color: var(--color-text); + font-size: 18px; + font-family: 'Fira Mono', Consolas, Menlo, Monaco, 'Courier New', Courier, monospace; + border-radius: 4px; + padding: 75px 45px 35px; + position: relative; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +[data-termynal]:before { + content: ''; + position: absolute; + top: 15px; + left: 15px; + display: inline-block; + width: 15px; + height: 15px; + border-radius: 50%; + /* A little hack to display the window buttons in one pseudo element. */ + background: #d9515d; + -webkit-box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930; + box-shadow: 25px 0 0 #f4c025, 50px 0 0 #3ec930; +} + +[data-termynal]:after { + content: 'bash'; + position: absolute; + color: var(--color-text-subtle); + top: 5px; + left: 0; + width: 100%; + text-align: center; +} + +[data-ty] { + display: block; + line-height: 2; +} + +[data-ty]:before { + /* Set up defaults and ensure empty lines are displayed. */ + content: ''; + display: inline-block; + vertical-align: middle; +} + +[data-ty="input"]:before, +[data-ty-prompt]:before { + margin-right: 0.75em; + color: var(--color-text-subtle); +} + +[data-ty="input"]:before { + content: '$'; +} + +[data-ty][data-ty-prompt]:before { + content: attr(data-ty-prompt); +} + +[data-ty-cursor]:after { + content: attr(data-ty-cursor); + font-family: monospace; + margin-left: 0.5em; + -webkit-animation: blink 1s infinite; + animation: blink 1s infinite; +} + + +/* Cursor animation */ + +@-webkit-keyframes blink { + 50% { + opacity: 0; + } +} + +@keyframes blink { + 50% { + opacity: 0; + } +} diff --git a/_static/css/v4-shims.min.css b/_static/css/v4-shims.min.css new file mode 100644 index 0000000000..f742adcbe9 --- /dev/null +++ b/_static/css/v4-shims.min.css @@ -0,0 +1,6 @@ +/*! + * Font Awesome Free 6.1.1 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2022 Fonticons, Inc. + */ +.fa.fa-glass:before{content:"\f000"}.fa.fa-envelope-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-envelope-o:before{content:"\f0e0"}.fa.fa-star-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-star-o:before{content:"\f005"}.fa.fa-close:before,.fa.fa-remove:before{content:"\f00d"}.fa.fa-gear:before{content:"\f013"}.fa.fa-trash-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-trash-o:before{content:"\f2ed"}.fa.fa-home:before{content:"\f015"}.fa.fa-file-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-o:before{content:"\f15b"}.fa.fa-clock-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-clock-o:before{content:"\f017"}.fa.fa-arrow-circle-o-down{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-arrow-circle-o-down:before{content:"\f358"}.fa.fa-arrow-circle-o-up{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-arrow-circle-o-up:before{content:"\f35b"}.fa.fa-play-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-play-circle-o:before{content:"\f144"}.fa.fa-repeat:before,.fa.fa-rotate-right:before{content:"\f01e"}.fa.fa-refresh:before{content:"\f021"}.fa.fa-list-alt{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-list-alt:before{content:"\f022"}.fa.fa-dedent:before{content:"\f03b"}.fa.fa-video-camera:before{content:"\f03d"}.fa.fa-picture-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-picture-o:before{content:"\f03e"}.fa.fa-photo{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-photo:before{content:"\f03e"}.fa.fa-image{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-image:before{content:"\f03e"}.fa.fa-map-marker:before{content:"\f3c5"}.fa.fa-pencil-square-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-pencil-square-o:before{content:"\f044"}.fa.fa-edit{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-edit:before{content:"\f044"}.fa.fa-share-square-o:before{content:"\f14d"}.fa.fa-check-square-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-check-square-o:before{content:"\f14a"}.fa.fa-arrows:before{content:"\f0b2"}.fa.fa-times-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-times-circle-o:before{content:"\f057"}.fa.fa-check-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-check-circle-o:before{content:"\f058"}.fa.fa-mail-forward:before{content:"\f064"}.fa.fa-expand:before{content:"\f424"}.fa.fa-compress:before{content:"\f422"}.fa.fa-eye,.fa.fa-eye-slash{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-warning:before{content:"\f071"}.fa.fa-calendar:before{content:"\f073"}.fa.fa-arrows-v:before{content:"\f338"}.fa.fa-arrows-h:before{content:"\f337"}.fa.fa-bar-chart-o:before,.fa.fa-bar-chart:before{content:"\e0e3"}.fa.fa-facebook-square,.fa.fa-twitter-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-gears:before{content:"\f085"}.fa.fa-thumbs-o-up{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-thumbs-o-up:before{content:"\f164"}.fa.fa-thumbs-o-down{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-thumbs-o-down:before{content:"\f165"}.fa.fa-heart-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-heart-o:before{content:"\f004"}.fa.fa-sign-out:before{content:"\f2f5"}.fa.fa-linkedin-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-linkedin-square:before{content:"\f08c"}.fa.fa-thumb-tack:before{content:"\f08d"}.fa.fa-external-link:before{content:"\f35d"}.fa.fa-sign-in:before{content:"\f2f6"}.fa.fa-github-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-lemon-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-lemon-o:before{content:"\f094"}.fa.fa-square-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-square-o:before{content:"\f0c8"}.fa.fa-bookmark-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-bookmark-o:before{content:"\f02e"}.fa.fa-facebook,.fa.fa-twitter{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-facebook:before{content:"\f39e"}.fa.fa-facebook-f{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-facebook-f:before{content:"\f39e"}.fa.fa-github{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-credit-card{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-feed:before{content:"\f09e"}.fa.fa-hdd-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hdd-o:before{content:"\f0a0"}.fa.fa-hand-o-right{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-o-right:before{content:"\f0a4"}.fa.fa-hand-o-left{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-o-left:before{content:"\f0a5"}.fa.fa-hand-o-up{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-o-up:before{content:"\f0a6"}.fa.fa-hand-o-down{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-o-down:before{content:"\f0a7"}.fa.fa-globe:before{content:"\f57d"}.fa.fa-tasks:before{content:"\f828"}.fa.fa-arrows-alt:before{content:"\f31e"}.fa.fa-group:before{content:"\f0c0"}.fa.fa-chain:before{content:"\f0c1"}.fa.fa-cut:before{content:"\f0c4"}.fa.fa-files-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-files-o:before{content:"\f0c5"}.fa.fa-floppy-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-floppy-o:before{content:"\f0c7"}.fa.fa-save{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-save:before{content:"\f0c7"}.fa.fa-navicon:before,.fa.fa-reorder:before{content:"\f0c9"}.fa.fa-magic:before{content:"\e2ca"}.fa.fa-google-plus,.fa.fa-google-plus-square,.fa.fa-pinterest,.fa.fa-pinterest-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-google-plus:before{content:"\f0d5"}.fa.fa-money:before{content:"\f3d1"}.fa.fa-unsorted:before{content:"\f0dc"}.fa.fa-sort-desc:before{content:"\f0dd"}.fa.fa-sort-asc:before{content:"\f0de"}.fa.fa-linkedin{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-linkedin:before{content:"\f0e1"}.fa.fa-rotate-left:before{content:"\f0e2"}.fa.fa-legal:before{content:"\f0e3"}.fa.fa-dashboard:before,.fa.fa-tachometer:before{content:"\f625"}.fa.fa-comment-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-comment-o:before{content:"\f075"}.fa.fa-comments-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-comments-o:before{content:"\f086"}.fa.fa-flash:before{content:"\f0e7"}.fa.fa-clipboard:before{content:"\f0ea"}.fa.fa-lightbulb-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-lightbulb-o:before{content:"\f0eb"}.fa.fa-exchange:before{content:"\f362"}.fa.fa-cloud-download:before{content:"\f0ed"}.fa.fa-cloud-upload:before{content:"\f0ee"}.fa.fa-bell-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-bell-o:before{content:"\f0f3"}.fa.fa-cutlery:before{content:"\f2e7"}.fa.fa-file-text-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-text-o:before{content:"\f15c"}.fa.fa-building-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-building-o:before{content:"\f1ad"}.fa.fa-hospital-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hospital-o:before{content:"\f0f8"}.fa.fa-tablet:before{content:"\f3fa"}.fa.fa-mobile-phone:before,.fa.fa-mobile:before{content:"\f3cd"}.fa.fa-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-circle-o:before{content:"\f111"}.fa.fa-mail-reply:before{content:"\f3e5"}.fa.fa-github-alt{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-folder-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-folder-o:before{content:"\f07b"}.fa.fa-folder-open-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-folder-open-o:before{content:"\f07c"}.fa.fa-smile-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-smile-o:before{content:"\f118"}.fa.fa-frown-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-frown-o:before{content:"\f119"}.fa.fa-meh-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-meh-o:before{content:"\f11a"}.fa.fa-keyboard-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-keyboard-o:before{content:"\f11c"}.fa.fa-flag-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-flag-o:before{content:"\f024"}.fa.fa-mail-reply-all:before{content:"\f122"}.fa.fa-star-half-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-star-half-o:before{content:"\f5c0"}.fa.fa-star-half-empty{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-star-half-empty:before{content:"\f5c0"}.fa.fa-star-half-full{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-star-half-full:before{content:"\f5c0"}.fa.fa-code-fork:before{content:"\f126"}.fa.fa-chain-broken:before,.fa.fa-unlink:before{content:"\f127"}.fa.fa-calendar-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-calendar-o:before{content:"\f133"}.fa.fa-css3,.fa.fa-html5,.fa.fa-maxcdn{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-unlock-alt:before{content:"\f09c"}.fa.fa-minus-square-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-minus-square-o:before{content:"\f146"}.fa.fa-level-up:before{content:"\f3bf"}.fa.fa-level-down:before{content:"\f3be"}.fa.fa-pencil-square:before{content:"\f14b"}.fa.fa-external-link-square:before{content:"\f360"}.fa.fa-compass{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-caret-square-o-down{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-caret-square-o-down:before{content:"\f150"}.fa.fa-toggle-down{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-toggle-down:before{content:"\f150"}.fa.fa-caret-square-o-up{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-caret-square-o-up:before{content:"\f151"}.fa.fa-toggle-up{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-toggle-up:before{content:"\f151"}.fa.fa-caret-square-o-right{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-caret-square-o-right:before{content:"\f152"}.fa.fa-toggle-right{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-toggle-right:before{content:"\f152"}.fa.fa-eur:before,.fa.fa-euro:before{content:"\f153"}.fa.fa-gbp:before{content:"\f154"}.fa.fa-dollar:before,.fa.fa-usd:before{content:"\24"}.fa.fa-inr:before,.fa.fa-rupee:before{content:"\e1bc"}.fa.fa-cny:before,.fa.fa-jpy:before,.fa.fa-rmb:before,.fa.fa-yen:before{content:"\f157"}.fa.fa-rouble:before,.fa.fa-rub:before,.fa.fa-ruble:before{content:"\f158"}.fa.fa-krw:before,.fa.fa-won:before{content:"\f159"}.fa.fa-bitcoin,.fa.fa-btc{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-bitcoin:before{content:"\f15a"}.fa.fa-file-text:before{content:"\f15c"}.fa.fa-sort-alpha-asc:before{content:"\f15d"}.fa.fa-sort-alpha-desc:before{content:"\f881"}.fa.fa-sort-amount-asc:before{content:"\f884"}.fa.fa-sort-amount-desc:before{content:"\f160"}.fa.fa-sort-numeric-asc:before{content:"\f162"}.fa.fa-sort-numeric-desc:before{content:"\f886"}.fa.fa-xing,.fa.fa-xing-square,.fa.fa-youtube,.fa.fa-youtube-play,.fa.fa-youtube-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-youtube-play:before{content:"\f167"}.fa.fa-adn,.fa.fa-bitbucket,.fa.fa-bitbucket-square,.fa.fa-dropbox,.fa.fa-flickr,.fa.fa-instagram,.fa.fa-stack-overflow{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-bitbucket-square:before{content:"\f171"}.fa.fa-tumblr,.fa.fa-tumblr-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-long-arrow-down:before{content:"\f309"}.fa.fa-long-arrow-up:before{content:"\f30c"}.fa.fa-long-arrow-left:before{content:"\f30a"}.fa.fa-long-arrow-right:before{content:"\f30b"}.fa.fa-android,.fa.fa-apple,.fa.fa-dribbble,.fa.fa-foursquare,.fa.fa-gittip,.fa.fa-gratipay,.fa.fa-linux,.fa.fa-skype,.fa.fa-trello,.fa.fa-windows{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-gittip:before{content:"\f184"}.fa.fa-sun-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-sun-o:before{content:"\f185"}.fa.fa-moon-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-moon-o:before{content:"\f186"}.fa.fa-pagelines,.fa.fa-renren,.fa.fa-stack-exchange,.fa.fa-vk,.fa.fa-weibo{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-arrow-circle-o-right{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-arrow-circle-o-right:before{content:"\f35a"}.fa.fa-arrow-circle-o-left{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-arrow-circle-o-left:before{content:"\f359"}.fa.fa-caret-square-o-left{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-caret-square-o-left:before{content:"\f191"}.fa.fa-toggle-left{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-toggle-left:before{content:"\f191"}.fa.fa-dot-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-dot-circle-o:before{content:"\f192"}.fa.fa-vimeo-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-try:before,.fa.fa-turkish-lira:before{content:"\e2bb"}.fa.fa-plus-square-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-plus-square-o:before{content:"\f0fe"}.fa.fa-openid,.fa.fa-slack,.fa.fa-wordpress{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-bank:before,.fa.fa-institution:before{content:"\f19c"}.fa.fa-mortar-board:before{content:"\f19d"}.fa.fa-behance,.fa.fa-behance-square,.fa.fa-delicious,.fa.fa-digg,.fa.fa-drupal,.fa.fa-google,.fa.fa-joomla,.fa.fa-pied-piper-alt,.fa.fa-pied-piper-pp,.fa.fa-reddit,.fa.fa-reddit-square,.fa.fa-steam,.fa.fa-steam-square,.fa.fa-stumbleupon,.fa.fa-stumbleupon-circle,.fa.fa-yahoo{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-automobile:before{content:"\f1b9"}.fa.fa-cab:before{content:"\f1ba"}.fa.fa-deviantart,.fa.fa-soundcloud,.fa.fa-spotify{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-file-pdf-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-pdf-o:before{content:"\f1c1"}.fa.fa-file-word-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-word-o:before{content:"\f1c2"}.fa.fa-file-excel-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-excel-o:before{content:"\f1c3"}.fa.fa-file-powerpoint-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-powerpoint-o:before{content:"\f1c4"}.fa.fa-file-image-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-image-o:before{content:"\f1c5"}.fa.fa-file-photo-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-photo-o:before{content:"\f1c5"}.fa.fa-file-picture-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-picture-o:before{content:"\f1c5"}.fa.fa-file-archive-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-archive-o:before{content:"\f1c6"}.fa.fa-file-zip-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-zip-o:before{content:"\f1c6"}.fa.fa-file-audio-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-audio-o:before{content:"\f1c7"}.fa.fa-file-sound-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-sound-o:before{content:"\f1c7"}.fa.fa-file-video-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-video-o:before{content:"\f1c8"}.fa.fa-file-movie-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-movie-o:before{content:"\f1c8"}.fa.fa-file-code-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-code-o:before{content:"\f1c9"}.fa.fa-codepen,.fa.fa-jsfiddle,.fa.fa-vine{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-life-bouy:before,.fa.fa-life-buoy:before,.fa.fa-life-saver:before,.fa.fa-support:before{content:"\f1cd"}.fa.fa-circle-o-notch:before{content:"\f1ce"}.fa.fa-ra,.fa.fa-rebel{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-ra:before{content:"\f1d0"}.fa.fa-resistance{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-resistance:before{content:"\f1d0"}.fa.fa-empire,.fa.fa-ge{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-ge:before{content:"\f1d1"}.fa.fa-git,.fa.fa-git-square,.fa.fa-hacker-news,.fa.fa-y-combinator-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-y-combinator-square:before{content:"\f1d4"}.fa.fa-yc-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-yc-square:before{content:"\f1d4"}.fa.fa-qq,.fa.fa-tencent-weibo,.fa.fa-wechat,.fa.fa-weixin{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-wechat:before{content:"\f1d7"}.fa.fa-send:before{content:"\f1d8"}.fa.fa-paper-plane-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-paper-plane-o:before{content:"\f1d8"}.fa.fa-send-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-send-o:before{content:"\f1d8"}.fa.fa-circle-thin{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-circle-thin:before{content:"\f111"}.fa.fa-header:before{content:"\f1dc"}.fa.fa-futbol-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-futbol-o:before{content:"\f1e3"}.fa.fa-soccer-ball-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-soccer-ball-o:before{content:"\f1e3"}.fa.fa-slideshare,.fa.fa-twitch,.fa.fa-yelp{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-newspaper-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-newspaper-o:before{content:"\f1ea"}.fa.fa-cc-amex,.fa.fa-cc-discover,.fa.fa-cc-mastercard,.fa.fa-cc-paypal,.fa.fa-cc-stripe,.fa.fa-cc-visa,.fa.fa-google-wallet,.fa.fa-paypal{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-bell-slash-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-bell-slash-o:before{content:"\f1f6"}.fa.fa-trash:before{content:"\f2ed"}.fa.fa-copyright{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-eyedropper:before{content:"\f1fb"}.fa.fa-area-chart:before{content:"\f1fe"}.fa.fa-pie-chart:before{content:"\f200"}.fa.fa-line-chart:before{content:"\f201"}.fa.fa-angellist,.fa.fa-ioxhost,.fa.fa-lastfm,.fa.fa-lastfm-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-cc{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-cc:before{content:"\f20a"}.fa.fa-ils:before,.fa.fa-shekel:before,.fa.fa-sheqel:before{content:"\f20b"}.fa.fa-buysellads,.fa.fa-connectdevelop,.fa.fa-dashcube,.fa.fa-forumbee,.fa.fa-leanpub,.fa.fa-sellsy,.fa.fa-shirtsinbulk,.fa.fa-simplybuilt,.fa.fa-skyatlas{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-diamond{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-diamond:before{content:"\f3a5"}.fa.fa-intersex:before,.fa.fa-transgender:before{content:"\f224"}.fa.fa-transgender-alt:before{content:"\f225"}.fa.fa-facebook-official{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-facebook-official:before{content:"\f09a"}.fa.fa-pinterest-p,.fa.fa-whatsapp{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-hotel:before{content:"\f236"}.fa.fa-medium,.fa.fa-viacoin,.fa.fa-y-combinator,.fa.fa-yc{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-yc:before{content:"\f23b"}.fa.fa-expeditedssl,.fa.fa-opencart,.fa.fa-optin-monster{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-battery-4:before,.fa.fa-battery:before{content:"\f240"}.fa.fa-battery-3:before{content:"\f241"}.fa.fa-battery-2:before{content:"\f242"}.fa.fa-battery-1:before{content:"\f243"}.fa.fa-battery-0:before{content:"\f244"}.fa.fa-object-group,.fa.fa-object-ungroup,.fa.fa-sticky-note-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-sticky-note-o:before{content:"\f249"}.fa.fa-cc-diners-club,.fa.fa-cc-jcb{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-clone{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hourglass-o:before{content:"\f252"}.fa.fa-hourglass-1:before{content:"\f251"}.fa.fa-hourglass-2:before,.fa.fa-hourglass-half:before{content:"\f254"}.fa.fa-hourglass-3:before{content:"\f253"}.fa.fa-hand-rock-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-rock-o:before{content:"\f255"}.fa.fa-hand-grab-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-grab-o:before{content:"\f255"}.fa.fa-hand-paper-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-paper-o:before{content:"\f256"}.fa.fa-hand-stop-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-stop-o:before{content:"\f256"}.fa.fa-hand-scissors-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-scissors-o:before{content:"\f257"}.fa.fa-hand-lizard-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-lizard-o:before{content:"\f258"}.fa.fa-hand-spock-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-spock-o:before{content:"\f259"}.fa.fa-hand-pointer-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-pointer-o:before{content:"\f25a"}.fa.fa-hand-peace-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-peace-o:before{content:"\f25b"}.fa.fa-registered{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-chrome,.fa.fa-creative-commons,.fa.fa-firefox,.fa.fa-get-pocket,.fa.fa-gg,.fa.fa-gg-circle,.fa.fa-internet-explorer,.fa.fa-odnoklassniki,.fa.fa-odnoklassniki-square,.fa.fa-opera,.fa.fa-safari,.fa.fa-wikipedia-w{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-television:before{content:"\f26c"}.fa.fa-500px,.fa.fa-amazon,.fa.fa-contao{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-calendar-plus-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-calendar-plus-o:before{content:"\f271"}.fa.fa-calendar-minus-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-calendar-minus-o:before{content:"\f272"}.fa.fa-calendar-times-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-calendar-times-o:before{content:"\f273"}.fa.fa-calendar-check-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-calendar-check-o:before{content:"\f274"}.fa.fa-map-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-map-o:before{content:"\f279"}.fa.fa-commenting:before{content:"\f4ad"}.fa.fa-commenting-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-commenting-o:before{content:"\f4ad"}.fa.fa-houzz,.fa.fa-vimeo{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-vimeo:before{content:"\f27d"}.fa.fa-black-tie,.fa.fa-edge,.fa.fa-fonticons,.fa.fa-reddit-alien{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-credit-card-alt:before{content:"\f09d"}.fa.fa-codiepie,.fa.fa-fort-awesome,.fa.fa-mixcloud,.fa.fa-modx,.fa.fa-product-hunt,.fa.fa-scribd,.fa.fa-usb{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-pause-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-pause-circle-o:before{content:"\f28b"}.fa.fa-stop-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-stop-circle-o:before{content:"\f28d"}.fa.fa-bluetooth,.fa.fa-bluetooth-b,.fa.fa-envira,.fa.fa-gitlab,.fa.fa-wheelchair-alt,.fa.fa-wpbeginner,.fa.fa-wpforms{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-wheelchair-alt:before{content:"\f368"}.fa.fa-question-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-question-circle-o:before{content:"\f059"}.fa.fa-volume-control-phone:before{content:"\f2a0"}.fa.fa-asl-interpreting:before{content:"\f2a3"}.fa.fa-deafness:before,.fa.fa-hard-of-hearing:before{content:"\f2a4"}.fa.fa-glide,.fa.fa-glide-g{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-signing:before{content:"\f2a7"}.fa.fa-snapchat,.fa.fa-snapchat-ghost,.fa.fa-viadeo,.fa.fa-viadeo-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-snapchat-ghost:before{content:"\f2ab"}.fa.fa-first-order,.fa.fa-google-plus-official,.fa.fa-pied-piper,.fa.fa-snapchat-square,.fa.fa-themeisle,.fa.fa-yoast{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-google-plus-official:before{content:"\f2b3"}.fa.fa-google-plus-circle{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-google-plus-circle:before{content:"\f2b3"}.fa.fa-fa,.fa.fa-font-awesome{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-fa:before{content:"\f2b4"}.fa.fa-handshake-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-handshake-o:before{content:"\f2b5"}.fa.fa-envelope-open-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-envelope-open-o:before{content:"\f2b6"}.fa.fa-linode{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-address-book-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-address-book-o:before{content:"\f2b9"}.fa.fa-vcard:before{content:"\f2bb"}.fa.fa-address-card-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-address-card-o:before{content:"\f2bb"}.fa.fa-vcard-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-vcard-o:before{content:"\f2bb"}.fa.fa-user-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-user-circle-o:before{content:"\f2bd"}.fa.fa-user-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-user-o:before{content:"\f007"}.fa.fa-id-badge{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-drivers-license:before{content:"\f2c2"}.fa.fa-id-card-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-id-card-o:before{content:"\f2c2"}.fa.fa-drivers-license-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-drivers-license-o:before{content:"\f2c2"}.fa.fa-free-code-camp,.fa.fa-quora,.fa.fa-telegram{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-thermometer-4:before,.fa.fa-thermometer:before{content:"\f2c7"}.fa.fa-thermometer-3:before{content:"\f2c8"}.fa.fa-thermometer-2:before{content:"\f2c9"}.fa.fa-thermometer-1:before{content:"\f2ca"}.fa.fa-thermometer-0:before{content:"\f2cb"}.fa.fa-bathtub:before,.fa.fa-s15:before{content:"\f2cd"}.fa.fa-window-maximize,.fa.fa-window-restore{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-times-rectangle:before{content:"\f410"}.fa.fa-window-close-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-window-close-o:before{content:"\f410"}.fa.fa-times-rectangle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-times-rectangle-o:before{content:"\f410"}.fa.fa-bandcamp,.fa.fa-eercast,.fa.fa-etsy,.fa.fa-grav,.fa.fa-imdb,.fa.fa-ravelry{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-eercast:before{content:"\f2da"}.fa.fa-snowflake-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-snowflake-o:before{content:"\f2dc"}.fa.fa-meetup,.fa.fa-superpowers,.fa.fa-wpexplorer{font-family:"Font Awesome 6 Brands";font-weight:400} \ No newline at end of file diff --git a/_static/dask-tf.jpg b/_static/dask-tf.jpg new file mode 100644 index 0000000000..e33dddd526 Binary files /dev/null and b/_static/dask-tf.jpg differ diff --git a/_static/data_sharing_with_deployment.jpg b/_static/data_sharing_with_deployment.jpg new file mode 100644 index 0000000000..7053b4875e Binary files /dev/null and b/_static/data_sharing_with_deployment.jpg differ diff --git a/_static/data_sharing_with_sidecar.jpg b/_static/data_sharing_with_sidecar.jpg new file mode 100644 index 0000000000..99f6b909ac Binary files /dev/null and b/_static/data_sharing_with_sidecar.jpg differ diff --git a/_static/debug.css b/_static/debug.css new file mode 100644 index 0000000000..74d4aec33e --- /dev/null +++ b/_static/debug.css @@ -0,0 +1,69 @@ +/* + This CSS file should be overridden by the theme authors. It's + meant for debugging and developing the skeleton that this theme provides. +*/ +body { + font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, + "Apple Color Emoji", "Segoe UI Emoji"; + background: lavender; +} +.sb-announcement { + background: rgb(131, 131, 131); +} +.sb-announcement__inner { + background: black; + color: white; +} +.sb-header { + background: lightskyblue; +} +.sb-header__inner { + background: royalblue; + color: white; +} +.sb-header-secondary { + background: lightcyan; +} +.sb-header-secondary__inner { + background: cornflowerblue; + color: white; +} +.sb-sidebar-primary { + background: lightgreen; +} +.sb-main { + background: blanchedalmond; +} +.sb-main__inner { + background: antiquewhite; +} +.sb-header-article { + background: lightsteelblue; +} +.sb-article-container { + background: snow; +} +.sb-article-main { + background: white; +} +.sb-footer-article { + background: lightpink; +} +.sb-sidebar-secondary { + background: lightgoldenrodyellow; +} +.sb-footer-content { + background: plum; +} +.sb-footer-content__inner { + background: palevioletred; +} +.sb-footer { + background: pink; +} +.sb-footer__inner { + background: salmon; +} +.sb-article { + background: white; +} diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 0000000000..527b876ca6 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 0000000000..902bb33589 --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,14 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: true, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 0000000000..a858a410e4 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/fraud-detection-job.jpg b/_static/fraud-detection-job.jpg new file mode 100644 index 0000000000..34005ee5a7 Binary files /dev/null and b/_static/fraud-detection-job.jpg differ diff --git a/_static/jquery-3.6.0.js b/_static/jquery-3.6.0.js new file mode 100644 index 0000000000..fc6c299b73 --- /dev/null +++ b/_static/jquery-3.6.0.js @@ -0,0 +1,10881 @@ +/*! + * jQuery JavaScript Library v3.6.0 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2021-03-02T17:08Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.6.0", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.6 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2021-02-16 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +} +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the primary Deferred + primary = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + primary.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( primary.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return primary.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); + } + + return primary.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + + // Support: Chrome 86+ + // In Chrome, if an element having a focusout handler is blurred by + // clicking outside of it, it invokes the handler synchronously. If + // that handler calls `.remove()` on the element, the data is cleared, + // leaving `result` undefined. We need to guard against this. + return result && result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + which: true +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + // Suppress native focus or blur as it's already being fired + // in leverageNative. + _default: function() { + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + // + // Support: Firefox 70+ + // Only Firefox includes border widths + // in computed dimensions. (gh-4529) + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; + tr.style.cssText = "border:1px solid"; + + // Support: Chrome 86+ + // Height set through cssText does not get applied. + // Computed height then comes back as 0. + tr.style.height = "1px"; + trChild.style.height = "9px"; + + // Support: Android 8 Chrome 86+ + // In our bodyBackground.html iframe, + // display for all div elements is set to "inline", + // which causes a problem only in Android 8 Chrome 86. + // Ensuring the div is display: block + // gets around this issue. + trChild.style.display = "block"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + + parseInt( trStyle.borderTopWidth, 10 ) + + parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml, parserErrorElem; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) {} + + parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; + if ( !xml || parserErrorElem ) { + jQuery.error( "Invalid XML: " + ( + parserErrorElem ? + jQuery.map( parserErrorElem.childNodes, function( el ) { + return el.textContent; + } ).join( "\n" ) : + data + ) ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ).filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ).map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + +originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script but not if jsonp + if ( !isSuccess && + jQuery.inArray( "script", s.dataTypes ) > -1 && + jQuery.inArray( "json", s.dataTypes ) < 0 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+Vineyard: an in-memory immutable data manager +

an in-memory immutable data manager#

+
+

PyPI FAQ Discussion Slack License ACM DL

+
+

Why bother?#

+

Sharing intermediate data between systems in modern big data and AI workflows +can be challenging, often causing significant bottlenecks in such jobs. Let’s +consider the following fraud detection pipeline:

+
+A real-life fraud detection job +

A real-life fraud detection job#

+
+

From the pipeline, we observed:

+
    +
  1. Users usually prefer to program with dedicated computing systems for different tasks in the +same applications, such as SQL and Python.

    +

    Integrating a new computing system into production environments demands high technical +effort to align with existing production environments in terms of I/O, failover, etc.

    +
  2. +
  3. Data could be polymorphic. Non-relational data, such as tensors, dataframes (in Pandas) and +graphs/networks (in GraphScope) are becoming increasingly prevalent. Tables and SQL may +not be the best way to store, exchange, or process them.

    +

    Transforming the data back and forth between different systems as “tables” could +result in a significant overhead.

    +
  4. +
  5. Saving/loading the data to/from the external storage requires numerous memory copies and +incurs high IO costs.

  6. +
+
+
+

What is Vineyard?#

+

Vineyard (v6d) is an in-memory immutable data manager that offers out-of-the-box high-level +abstraction and zero-copy sharing for distributed data in big data tasks, such as +graph analytics (e.g., GraphScope), numerical computing (e.g., Mars), and machine learning.

+
+

Features#

+
+

Efficient data sharing#

+

Vineyard shares immutable data across different systems using shared memory without extra overheads, +eliminating the overhead of serialization/deserialization and IO when exchanging immutable +data between systems.

+
+
+

Out-of-the-box data abstraction#

+

Vineyard defines a metadata-payload separated data model to capture the payload commonalities and +method commonalities between sharable objects in different programming languages and different +computing systems in a unified way.

+

The Code Generation for Boilerplate (Vineyard Component Description Language) is specifically designed to annotate +sharable members and methods, enabling automatic generation of boilerplate code for minimal +integration effort.

+
+
+

Pluggable I/O routines#

+

In many big data analytical tasks, a substantial portion of the workload consists of boilerplate +routines that are unrelated to the core computation. These routines include various IO adapters, +data partition strategies, and migration jobs. Due to different data structure abstractions across +systems, these routines are often not easily reusable, leading to increased complexity and redundancy.

+

Vineyard provides common manipulation routines for immutable data as drivers, which extend +the capabilities of data structures by registering appropriate drivers. This enables out-of-the-box +reuse of boilerplate components across diverse computation jobs.

+
+
+

Data orchestration on Kubernetes#

+

Vineyard provides efficient distributed data sharing in cloud-native environments by embracing +cloud-native big data processing. Kubernetes helps Vineyard leverage the scale-in/out and +scheduling abilities of Kubernetes.

+
+
+
+

Use cases#

+
+
+
+
+
+

Object manager

+

Put and get arbitrary objects using Vineyard, in a zero-copy way!

+
+
+
+
+
+
+

Cross-system sharing

+

Share large objects across computing systems.

+
+
+
+
+
+
+

Data orchestration

+

Vineyard coordinates the flow of objects and jobs on Kubernetes based on data-aware scheduling.

+
+
+
+
+
+
+
+
+

Get started now!#

+
+
+
+
+ +
+

Get started with Vineyard.

+
+
+
+
+
+ +
+

Deploy Vineyard on Kubernetes and accelerate big-data analytical workflows on cloud-native +infrastructures.

+
+
+
+
+
+ +
+

Explore use cases and tutorials where Vineyard can bring added value.

+
+
+
+
+
+ +
+

Get involved and become part of the Vineyard community.

+
+
+
+
+
+
+

FAQ

+
+
+

Frequently asked questions and discussions during the adoption of Vineyard.

+
+
+
+
+
+
+
+

Read the Paper#

+ +

Vineyard is a CNCF sandbox project and is made successful by its community.

+Vineyard is a CNCF sandbox project +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/genindex.html b/genindex.html new file mode 100644 index 0000000000..d5d2e8b0f3 --- /dev/null +++ b/genindex.html @@ -0,0 +1,1801 @@ + + + + + + + Index - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+ +
+

Index

+
_ | A | B | C | D | E | F | G | I | L | M | N | O | P | R | S | T | U | V | W
+
+
+

_

+ + + +
+
+ +
+

A

+ + + +
+
+ +
+

B

+ + + +
+
+ +
+

C

+ + + +
+
+ +
+

D

+ + + +
+
+ +
+

E

+ + + +
+
+ +
+

F

+ + + +
+
+ +
+

G

+ + + +
+
+ +
+

I

+ + + +
+
+ +
+

L

+ + + +
+
+ +
+

M

+ + + +
+
+ +
+

N

+ + + +
+
+ +
+

O

+ + + +
+
+ +
+

P

+ + + +
+
+ +
+

R

+ + + +
+
+ +
+

S

+ + + +
+
+ +
+

T

+ + +
+
+ +
+

U

+ + +
+
+ +
+

V

+ + + +
+
+ +
+

W

+ + +
+
+ + +
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000000..34b7d67ae5 --- /dev/null +++ b/index.html @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + Vineyard: an In-Memory Data Manager for Data-Intensive Analytics + + + +
+
+

+ Vineyard: an In-Memory Data Manager for Data-Intensive Analytics +

+

+ An innovative cloud-native in-memory immutable data manager that offers + out-of-the-box high-level abstractions and zero-copy in-memory sharing + for distributed data in various big data tasks. +

+ +
+ pip install vineyard + + Successfully installed vineyard + python + client = vineyard.connect() + object_id = client.put('Hello, vineyard!') + client.get(object_id) + 'Hello, vineyard!' +
+
+
+
+
+
+

Efficient data sharing

+

+ Vineyard shares immutable data across different systems using shared + memory without extra overheads, eliminating the overhead of + serialization and deserialization. +

+

Learn More

+
+
+

+ Out-of-the-box data abstraction +

+

+ Vineyard defines a metadata-payload separated data model to capture + the payload commonalities and method commonalities between sharable + objects. +

+

Learn More

+
+
+
+
+

+ Pluggable I/O + routines +

+

+ Vineyard provides common manipulation routines for immutable data as + drivers, which extend the capabilities of data structures by + registering appropriate drivers. +

+

Learn More

+
+
+

+ Data orchestration on + Kubernetes +

+

+ Vineyard provides efficient distributed data sharing in cloud-native + environments by embracing cloud-native big data processing. +

+

Learn More

+
+
+
+
+

Use Cases

+
+
+

Object store for all

+

+ Putting and getting arbitrary objects using Vineyard, in a zero-copy way! +

+ Learn More +
+
+

Data sharing in Kedro pipelines

+

Sharing intermediate data between tasks in Kedro pipelines.

+ Learn More +
+
+

Data processing for machine learning

+

+ Sharing large objects between different systems in data preprocessing pipelines in machine learning applications. +

+ Learn More +
+
+

Data sharing on Kubernetes

+

+ Coordinating the flow of objects and jobs on Kubernetes + with the data-aware scheduler plugin. +

+ Learn More +
+
+
+ + + + + + + + + + \ No newline at end of file diff --git a/notes/architecture.html b/notes/architecture.html new file mode 100644 index 0000000000..5c023aaf2c --- /dev/null +++ b/notes/architecture.html @@ -0,0 +1,639 @@ + + + + + + + + + + + + + + + + + + + Architecture - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Architecture#

+
+

Overview#

+

The following figure illustrates the architecture of Vineyard.

+
+Architecture of Vineyard +

Architecture of Vineyard#

+
+
+

Server side#

+

On the server (daemon) side (i.e., the aforementioned Vineyard instance), there are +three primary components:

+
    +
  1. The shared memory is the memory space in Vineyard that is shared with Vineyard +clients via the UNIX domain socket through memory mapping.

    +

    As previously mentioned, the partitions of the distributed data reside in the +shared memory of the corresponding Vineyard instance in the cluster.

    +
  2. +
  3. The metadata manager is responsible for managing the metadata of the data stored +in Vineyard.

    +

    The metadata manager maintains the metadata (structures, layouts, and properties) of +the data to provide high-level abstractions (e.g., graphs, tensors, dataframes). +The metadata managers in a Vineyard cluster communicate with each other through +the backend key-value store, such as etcd server, to ensure the consistency of the +distributed data stored in Vineyard.

    +
  4. +
  5. The IPC/RPC servers manage the IPC/RPC connections from Vineyard +clients for data sharing.

    +

    Specifically, the client can obtain the metadata of the data stored in Vineyard through +both IPC and RPC connections. However, to access the data partition, the client must connect +to the Vineyard instance via the UNIX domain socket, as the data +sharing occurs through the system call of memory mapping, which requires the client to be on +the same machine as the Vineyard instance.

    +
  6. +
+
+
+

Client side#

+

On the client side, the core component is the Vineyard client. The client side +includes both low-level APIs for accessing Vineyard instances in a precise +manner and high-level APIs for data structure sharing, manipulation, and +routine reuse (e.g., I/O drivers). More specifically,

+
    +
  1. The IPC client communicates with local Vineyard instances by connecting +to the UNIX domain socket.

    +

    The IPC client is used to establish an IPC connection between the Vineyard server and +the client, enabling memory-sharing (by mmap and transferring the file descriptor) +between the Vineyard server and the computing engines.

    +
  2. +
  3. The RPC client communicates with remote Vineyard instances by connecting +to the TCP port that the Vineyard daemon is bound to.

    +

    Unlike the IPC client, the RPC doesn’t allow memory-sharing between processes +but is useful for retrieving the metadata of objects in the Vineyard cluster.

    +
  4. +
  5. The builders and resolvers for out-of-the-box high-level data abstractions +offer a convenient way for applications to consume objects in Vineyard and +produce result objects into Vineyard.

    +

    The builders and resolvers adopt an extensible design where users can register +their own builders and resolvers for their newly defined data types, as well as +new builders and resolvers that build ad-hoc engine-specific data structures +as Vineyard objects and wrap Vineyard objects as engine-specific data types +at a low cost.

    +

    The builders, resolvers, and the registry are part of the language-specific +SDKs of Vineyard. Currently, Python and C++ are officially supported, and the Rust +and Go SDKs are under heavy development.

    +
  6. +
  7. The pluggable drivers assign specific functionalities to certain types of data +in Vineyard.

    +

    In particular, I/O drivers synchronize with external storages such as databases and file +systems to read data into and write data from Vineyard, while partition and +re-partition drivers reorganize the distributed graphs stored in Vineyard to +balance the workload.

    +
    +

    Note

    +

    The drivers typically employ the low-level APIs for precise operations.

    +
    +
  8. +
  9. Object migration is the mechanism implemented on the client side to +migrate objects between Vineyard instances in a cluster. Object migration +is usually needed when the computing engines cannot be scheduled to co-locate +with the data required by the jobs.

    +

    Object migration is implemented on the client side as a process pair where the +sender and receiver are both connected to (different) Vineyard instances and +communicate with each other using TCP to move objects between Vineyard instances. +We don’t put the object migration on the server side to decouple the functionalities +and allow users to register a more efficient object migration implemented on +their own deployment infrastructures, e.g.,leveraging RDMA and other high-performance +network technologies.

    +
  10. +
+
+
+
+

Core features#

+
+

Zero-cost in-memory data sharing#

+

Vineyard provides zero-cost data sharing through memory-mapping, as data objects +in Vineyard are immutable. When an object is created, we allocate blobs in +Vineyard to store the data payload. On the other hand, when retrieving the object, +we map the blob from the Vineyard instance into the application process using +inter-process memory mapping techniques, ensuring that no memory copy is involved +in sharing the data payload.

+
+
+

Distributed data sharing in big data tasks#

+

By examining the practices of big data tasks such as numeric computing, machine learning, +and graph analysis, we have identified four key properties of the data involved:

+
    +
  • Distributed and each partitioned fragment usually fits into memory;

  • +
  • Immutable, i.e., never modified after creation;

  • +
  • With complex structure, e.g., graph in CSR format;

  • +
  • Required to share between different computation systems and programming languages.

  • +
+

Vineyard is designed to address these challenges with:

+
    +
  • Composable design for Vineyard objects;

  • +
  • Immutable zero-cost in-memory data sharing via memory mapping;

  • +
  • Out-of-the-box high-level data abstraction for complex data structures;

  • +
  • Extensible design for builder/resolver/driver, enabling flexible cross-system and +cross-language data sharing.

  • +
+

In general, Vineyard’s design choices are fully determined by addressing +the difficulties in handling large-scale distributed data in practice.

+
+
+

Out-of-the-box high-level data abstraction#

+

Vineyard objects are stored with structures and high-level abstractions. +For instance, a graph with CSR format in Vineyard stores the index along with +the vertices and edges, enabling operations like edge iteration based on the +index. This means users don’t have to implement the index-building +function and edge iterators themselves, which is often required in +existing big data practices.

+
+
+

Convenient data integration#

+

The extensible design of builder/resolver/driver allows for convenient extension +of existing Vineyard objects to different programming languages. Moreover, +with codegen tools in Vineyard, users can easily transplant their +data structures into Vineyard with only a few annotations.

+
+
+

Data orchestration in a Python notebook#

+

Using Vineyard as the common data orchestration engine throughout the end-to-end +big data processing, users can hold large-scale distributed data as variables +of Vineyard objects in Python. As long as the computation modules +involved provide Python APIs, users can write down the entire processing +pipeline in a Python notebook. By running the Python script, users can +manage trillions of data and different computation systems in the background +distributedly across the cluster.

+
+
+
+

Non-goals and limitations#

+
+

NO mutable objects#

+

Once a Vineyard object is created and sealed in the Vineyard instance, it +becomes immutable and can NOT be modified anymore. Thus, Vineyard is not +suitable for use as a data cache to store mutable data that changes +rapidly along the processing pipeline.

+
+
+

NO instant remote data accessing#

+

The partitions of distributed data are stored distributedly in corresponding +Vineyard instances of the cluster. Only the client on the same machine can access +the data partition. In order to access a remote partition, data migration APIs of +Vineyard can be invoked to trigger the migration process, but not for instant accessing.

+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/cloud-native/deploy-kubernetes.html b/notes/cloud-native/deploy-kubernetes.html new file mode 100644 index 0000000000..27af8d22e3 --- /dev/null +++ b/notes/cloud-native/deploy-kubernetes.html @@ -0,0 +1,645 @@ + + + + + + + + + + + + + + + + + + + Deploy on Kubernetes - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Deploy on Kubernetes#

+

Vineyard is managed by the Vineyard Operator on Kubernetes.

+
+

Install vineyard-operator#

+

There are two recommended methods for installing the vineyard operator: using Helm (preferred) or +installing directly from the source code.

+
+

Note

+

Prior to installing the vineyard operator, ensure that you have a Kubernetes cluster and kubectl +installed. In this guide, we will use kind to create a cluster.

+
+

Before proceeding with the vineyard installation, it is essential to install cert-manager, as it is required +by the webhook components within the vineyard operator:

+ +
+

Option #2: Install form source code#

+
    +
  1. Clone the vineyard repo:

    +
    $ git clone https://github.com/v6d-io/v6d.git
    +
    +
    +
  2. +
  3. Build the vineyard operator’s Docker image:

    +
    $ cd k8s
    +$ make -C k8s docker-build
    +
    +
    +
    +

    Caution

    +

    With kind, you need to first import the image into the kind cluster:

    +
    $ kind load docker-image vineyardcloudnative/vineyard-operator:latest
    +
    +
    +
    +
  4. +
  5. Install the cert-manager

    +
    $ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.yaml
    +
    +
    +
    +

    Note

    +

    Please wait the cert-manager for a while until it is ready before installing the +vineyard operator.

    +
    +
  6. +
  7. Next, deploy the vineyard operator:

    +
    $ make -C k8s deploy
    +
    +
    +
  8. +
+
+
+

Wait vineyard-operator ready#

+

Once the operator is installed, its deployment can be checked using kubectl:

+
$ kubectl get all -n vineyard-system
+
+
+
+

Expected output

+
+
NAME                                               READY   STATUS    RESTARTS   AGE
+pod/vineyard-controller-manager-5c6f4bc454-8xm8q   2/2     Running   0          62m
+
+NAME                                                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
+service/vineyard-controller-manager-metrics-service   ClusterIP   10.96.240.173   <none>        8443/TCP   62m
+service/vineyard-webhook-service                      ClusterIP   10.96.41.132    <none>        443/TCP    62m
+
+NAME                                          READY   UP-TO-DATE   AVAILABLE   AGE
+deployment.apps/vineyard-controller-manager   1/1     1            1           62m
+
+NAME                                                     DESIRED   CURRENT   READY   AGE
+replicaset.apps/vineyard-controller-manager-5c6f4bc454   1         1         1       62m
+
+
+
+
+
+
+
+

Create vineyard cluster#

+

Once the vineyard operator becomes ready, you can create a vineyard cluster by creating a +Vineyardd CRD. The following is an example of creating a vineyard cluster with 3 daemon +replicas:

+
$ cat <<EOF | kubectl apply -f -
+apiVersion: k8s.v6d.io/v1alpha1
+kind: Vineyardd
+metadata:
+  name: vineyardd-sample
+  # don't use default namespace
+  namespace: vineyard-system
+spec:
+  replicas: 3
+  service:
+    type: ClusterIP
+    port: 9600
+  vineyard:
+    image: vineyardcloudnative/vineyardd:alpine-latest
+    imagePullPolicy: IfNotPresent
+EOF
+
+
+

The vineyard-operator efficiently creates the necessary dependencies, such as etcd, and establishes a +Deployment for a 3-replica vineyard server configuration. Once the setup is complete, you can +conveniently inspect the components created and managed by the vineyard operator using the kubectl +command.

+
$ kubectl get all -n vineyard-system
+
+
+
+

Expected output

+
+
NAME                                               READY   STATUS    RESTARTS   AGE
+pod/etcd0                                          1/1     Running   0          48s
+pod/etcd1                                          1/1     Running   0          48s
+pod/etcd2                                          1/1     Running   0          48s
+pod/vineyard-controller-manager-5c6f4bc454-8xm8q   2/2     Running   0          72s
+pod/vineyardd-sample-5cc797668f-9ggr9              1/1     Running   0          48s
+pod/vineyardd-sample-5cc797668f-nhw7p              1/1     Running   0          48s
+pod/vineyardd-sample-5cc797668f-r56h7              1/1     Running   0          48s
+
+NAME                                                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
+service/etcd-for-vineyard                             ClusterIP   10.96.174.41    <none>        2379/TCP            48s
+service/etcd0                                         ClusterIP   10.96.128.87    <none>        2379/TCP,2380/TCP   48s
+service/etcd1                                         ClusterIP   10.96.72.116    <none>        2379/TCP,2380/TCP   48s
+service/etcd2                                         ClusterIP   10.96.99.182    <none>        2379/TCP,2380/TCP   48s
+service/vineyard-controller-manager-metrics-service   ClusterIP   10.96.240.173   <none>        8443/TCP            72s
+service/vineyard-webhook-service                      ClusterIP   10.96.41.132    <none>        443/TCP             72s
+service/vineyardd-sample-rpc                          ClusterIP   10.96.102.183   <none>        9600/TCP            48s
+
+NAME                                          READY   UP-TO-DATE   AVAILABLE   AGE
+deployment.apps/vineyard-controller-manager   1/1     1            1           72s
+deployment.apps/vineyardd-sample              3/3     3            3           48s
+
+NAME                                                     DESIRED   CURRENT   READY   AGE
+replicaset.apps/vineyard-controller-manager-5c6f4bc454   1         1         1       72s
+replicaset.apps/vineyardd-sample-5cc797668f              3         3         3       48s
+
+
+
+
+
+
+

References#

+

In addition to deploying and managing the vineyard cluster, the operator plays a crucial role in scheduling +workloads on vineyard. This optimizes data sharing between tasks in workflows and triggers necessary data +movement or transformation tasks. Detailed references and examples can be found in vineyard-operator.

+

To simplify interactions with vineyard on Kubernetes, we offer a command-line tool, vineyardctl, which +automates much of the boilerplate configuration required when deploying workflows with vineyard on Kubernetes.

+
+
+
+
+ +
+

Vineyard operator manages vineyard cluster and orchestrates shared objects on Kubernetes.

+
+
+
+
+
+ +
+

vineyardctl is the command-line tool for working with the Vineyard Operator.

+
+
+
+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/cloud-native/vineyard-operator.html b/notes/cloud-native/vineyard-operator.html new file mode 100644 index 0000000000..cc4baba2d5 --- /dev/null +++ b/notes/cloud-native/vineyard-operator.html @@ -0,0 +1,2530 @@ + + + + + + + + + + + + + + + + + + + Vineyard Operator - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Vineyard Operator#

+
+

Architecture#

+

The following figure demonstrates the architecture of vineyard operator.

+
+Architecture of vineyard operator +

Architecture of vineyard operator#

+
+
+
+

Create a vineyard Cluster#

+

After successfully installing the vineyard operator (refer to Deploy on Kubernetes +for installation details), you can effortlessly create a vineyard cluster by utilizing +the Vineyardd CRD. The following example demonstrates the creation of a vineyard +cluster with 3 daemon replicas:

+
+

Note

+

The namespace of the vineyard cluster must be the same as the namespace of the +vineyard operator, as the vineyard cluster will use the vineyard operator’s +service account.

+
+
$ cat <<EOF | kubectl apply -f -
+apiVersion: k8s.v6d.io/v1alpha1
+kind: Vineyardd
+metadata:
+  name: vineyardd-sample
+  # use the same namespace as the vineyard operator
+  namespace: vineyard-system
+EOF
+
+
+

The vineyard-operator orchestrates the creation of a deployment for the required metadata +service backend (etcd), sets up appropriate services, and ultimately establishes a +deployment for 3-replica vineyard servers. Upon successful deployment, the following +components will be created and managed by the vineyard operator:

+
$ kubectl get all -n vineyard-system
+
+
+
+

Expected output

+
+
NAME                                               READY   STATUS    RESTARTS   AGE
+pod/etcd0                                          1/1     Running   0          48s
+pod/etcd1                                          1/1     Running   0          48s
+pod/etcd2                                          1/1     Running   0          48s
+pod/vineyard-controller-manager-5c6f4bc454-8xm8q   2/2     Running   0          72s
+pod/vineyardd-sample-5cc797668f-9ggr9              1/1     Running   0          48s
+pod/vineyardd-sample-5cc797668f-nhw7p              1/1     Running   0          48s
+pod/vineyardd-sample-5cc797668f-r56h7              1/1     Running   0          48s
+
+NAME                                                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)             AGE
+service/etcd-for-vineyard                             ClusterIP   10.96.174.41    <none>        2379/TCP            48s
+service/etcd0                                         ClusterIP   10.96.128.87    <none>        2379/TCP,2380/TCP   48s
+service/etcd1                                         ClusterIP   10.96.72.116    <none>        2379/TCP,2380/TCP   48s
+service/etcd2                                         ClusterIP   10.96.99.182    <none>        2379/TCP,2380/TCP   48s
+service/vineyard-controller-manager-metrics-service   ClusterIP   10.96.240.173   <none>        8443/TCP            72s
+service/vineyard-webhook-service                      ClusterIP   10.96.41.132    <none>        443/TCP             72s
+service/vineyardd-sample-rpc                          ClusterIP   10.96.102.183   <none>        9600/TCP            48s
+
+NAME                                          READY   UP-TO-DATE   AVAILABLE   AGE
+deployment.apps/vineyard-controller-manager   1/1     1            1           72s
+deployment.apps/vineyardd-sample              3/3     3            3           48s
+
+NAME                                                     DESIRED   CURRENT   READY   AGE
+replicaset.apps/vineyard-controller-manager-5c6f4bc454   1         1         1       72s
+replicaset.apps/vineyardd-sample-5cc797668f              3         3         3       48s
+
+
+
+
+

The detailed configuration entries for creating a vineyard cluster are listed as follows,

+
+

Vineyardd Configurations

+
+
+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Option Name

Type

Description

Default Value

replicas

int

The replicas of vineyardd.

3

+
etcdReplicas
+
+

int

The etcd replicas of vineyard

1

+
vineyard.
+
image
+
+

string

The image name of vineyardd container.

+
“vineyardcloudnative/
+
vineyardd:latest”
+
+
+
vineyard.
+
imagePullPolicy
+
+

string

The image pull policy of vineyardd image.

nil

+
vineyard.
+
syncCRDs
+
+

bool

Synchronize CRDs when persisting objects

true

+
vineyard.
+
socket
+
+

string

The ipc socket file of vineyardd.

nil

+
vineyard.
+
size
+
+

string

The shared memory size for vineyardd.

nil

+
vineyard.
+
reserveMemory
+
+

bool

Reserving enough physical memory pages for vineyardd.

false

+
vineyard.
+
streamThreshold
+
+

int64

The memory threshold of streams +(percentage of total memory)

nil

+
vineyard.
+
spill.
+
Name
+
+

string

The name of the spill config, +if set we’ll enable the spill module.

nil

+
vineyard.
+
spill.
+
path
+
+

string

The path of spilling.

nil

+
vineyard.
+
spill.
+
spillLowerRate
+
+

string

The low watermark of spilling memory.

nil

+
vineyard.
+
spill.
+
spillUpperRate
+
+

string

The high watermark of triggering spilling.

nil

+
vineyard.
+
spill.
+
persistent
+
VolumeSpec
+
+
+
corev1.
+
Persistent
+
VolumeSpec
+
+

The PV of the spilling for persistent storage.

nil

+
vineyard.
+
spill.
+
persistent
+
VolumeClaimSpec
+
+
+
corev1.
+
Persistent
+
VolumeClaimSpec
+
+

The PVC of the spilling for the persistent storage.

nil

+
vineyard.
+
env
+
+

[]corev1.EnvVar

The environment of vineyardd.

nil

+
vineyard.
+
env
+
+

[]corev1.EnvVar

The environment of vineyardd.

nil

+
pluginImage.
+
backupImage
+
+

string

The image of backup operation

“ghcr.io/v6d-io/v6d/backup-job”

+
pluginImage.
+
recoverImage
+
+

string

The image of recover operation

“ghcr.io/v6d-io/v6d/recover-job”

+
pluginImage.
+
daskRepartitionImage
+
+

string

The image of dask repartition operation

“ghcr.io/v6d-io/v6d/dask-repartition”

+
pluginImage.
+
localAssemblyImage
+
+

string

The image of local assembly operation

“ghcr.io/v6d-io/v6d/local-assembly”

+
pluginImage.
+
distributedAssemblyImage
+
+

string

The image of distributed assembly operation

“ghcr.io/v6d-io/v6d/distributed-assembly”

+
metric.
+
image
+
+

string

The image name of metric.

nil

+
metric.
+
imagePullPolicy
+
+

string

The image pull policy of metric.

nil

+
service.
+
type
+
+

string

The service type of vineyardd service.

nil

+
service.
+
port
+
+

int

The service port of vineyardd service

nil

+
volume.
+
pvcName
+
+

string

The pvc name of vineyard socket.

nil

+
volume.
+
mountPath
+
+

string

The mount path of pvc.

nil

+
+
+
+
+
+

Installing vineyard as sidecar#

+

Vineyard can be seamlessly integrated as a sidecar container within a pod. We offer the Sidecar +Custom Resource Definition (CRD) for configuring and managing the sidecar container. The Sidecar +CRD shares many similarities with the Vineyardd CRD, and the following list presents all +available configurations.

+
+

Sidecar Configurations

+
+
+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Option Name

Type

Description

Default Value

selector

string

The label selector of your app workload. Use ‘=’ to separate key and value.

“”

replicas

int

The replicas of your workload that needs to injected with vineyard sidecar.

0

+
vineyard.
+
image
+
+

string

The image name of vineyard sidecar container.

+
“vineyardcloudnative/
+
vineyardd:latest”
+
+
+
vineyard.
+
imagePullPolicy
+
+

string

The image pull policy of vineyard sidecar image.

nil

+
vineyard.
+
syncCRDs
+
+

bool

Synchronize CRDs when persisting objects

true

+
vineyard.
+
socket
+
+

string

The ipc socket file of vineyard sidecar.

nil

+
vineyard.
+
size
+
+

string

The shared memory size for vineyard sidecar.

nil

+
vineyard.
+
reserveMemory
+
+

bool

Reserving enough physical memory pages for vineyardd.

false

+
vineyard.
+
streamThreshold
+
+

int64

The memory threshold of streams +(percentage of total memory)

nil

+
vineyard.
+
spill.
+
Name
+
+

string

The name of the spill config, +if set we’ll enable the spill module.

nil

+
vineyard.
+
spill.
+
path
+
+

string

The path of spilling.

nil

+
vineyard.
+
spill.
+
spillLowerRate
+
+

string

The low watermark of spilling memory.

nil

+
vineyard.
+
spill.
+
spillUpperRate
+
+

string

The high watermark of triggering spilling.

nil

+
vineyard.
+
spill.
+
persistent
+
VolumeSpec
+
+
+
corev1.
+
Persistent
+
VolumeSpec
+
+

The PV of the spilling for persistent storage.

nil

+
vineyard.
+
spill.
+
persistent
+
VolumeClaimSpec
+
+
+
corev1.
+
Persistent
+
VolumeClaimSpec
+
+

The PVC of the spilling for the persistent storage.

nil

+
vineyard.
+
env
+
+

[]corev1.EnvVar

The environment of vineyard sidecar.

nil

+
vineyard.
+
memory
+
+

string

The requested memory of vineyard sidecar container.

“”

+
vineyard.
+
cpu
+
+

string

The requested cpu of vineyard sidecar container.

“”

+
metric.
+
enable
+
+

bool

Enable the metrics in vineyard sidecar.

false

+
metric.
+
image
+
+

string

The image name of metric.

nil

+
metric.
+
imagePullPolicy
+
+

string

The image pull policy of metric.

nil

+
service.
+
type
+
+

string

The service type of vineyard sidecar service.

nil

+
service.
+
port
+
+

int

The service port of vineyard sidecar service

nil

+
volume.
+
pvcName
+
+

string

The pvc name of vineyard socket.

nil

+
volume.
+
mountPath
+
+

string

The mount path of pvc.

nil

+
+
+
+

Besides, We provide some labels and annotations to help users to use the sidecar in vineyard operator. +The following are all labels that we provide:

+
+ + +++++ + + + + + + + + + + + + + + + + +
Sidecar Configurations#

Name

Yaml Fields

Description

“sidecar.v6d.io/enabled”

labels

Enable the sidecar.

“sidecar.v6d.io/name”

annotations

The name of sidecar cr. If the name is default, the default sidecar cr will be created.

+
+

There are two methods to install vineyard as a sidecar:

+
    +
  • Utilize the default sidecar configuration. Users should add two annotations, +sidecar.v6d.io/enabled: true and sidecar.v6d.io/name: default, to their app’s YAML. +This will create a default sidecar Custom Resource (CR) for observation.

  • +
  • Employ the custom sidecar configuration. Users must first create a custom sidecar CR, +such as sidecar-demo, and then add two annotations, sidecar.v6d.io/enabled: true and +sidecar.v6d.io/name: sidecar-demo, to their app’s YAML.

  • +
+

The following example demonstrates how to install vineyard as a sidecar container within a +pod. First, install the vineyard operator according to the previous steps, and then create +a namespace with the specific label sidecar-injection: enabled to enable the sidecar.

+
$ kubectl create namespace vineyard-job
+$ kubectl label namespace vineyard-job sidecar-injection=enabled
+
+
+

Next, use the following YAML to inject the default sidecar into the pod.

+
+

Note

+

Please configure the command field of your app container to be in the format +[“/bin/sh” or “/bin/bash”, “-c”, (your app command)]. After injecting the vineyard +sidecar, the command field will be modified to [“/bin/sh” or “/bin/bash”, “-c”, +while [ ! -e /var/run/vineyard.sock ]; do sleep 1; done;” + (your app command)] to +ensure that the vineyard sidecar is ready before the app container starts.

+
+
$ cat <<EOF | kubectl apply -f -
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: job-deployment-with-default-sidecar
+  namespace: vineyard-job
+spec:
+  selector:
+    matchLabels:
+      app: job-deployment-with-default-sidecar
+  replicas: 2
+  template:
+    metadata:
+      annotations:
+        sidecar.v6d.io/name: "default"
+      labels:
+        app: job-deployment-with-default-sidecar
+        sidecar.v6d.io/enabled: "true"
+    spec:
+      containers:
+      - name: job
+        image: ghcr.io/v6d-io/v6d/sidecar-job
+        imagePullPolicy: IfNotPresent
+        command: ["/bin/sh", "-c", "python3 /job.py"]
+        env:
+        - name: JOB_NAME
+          value: v6d-workflow-demo-job
+EOF
+
+
+

Next, you could see the sidecar container injected into the pod.

+
# get the default sidecar cr
+$ kubectl get sidecar app-job-deployment-with-default-sidecar-default-sidecar -n vineyard-job -o yaml
+apiVersion: k8s.v6d.io/v1alpha1
+kind: Sidecar
+metadata:
+  # the default sidecar's name is your label selector + "-default-sidecar"
+  name: app-job-deployment-with-default-sidecar-default-sidecar
+  namespace: vineyard-job
+spec:
+  metric:
+    enable: false
+    image: vineyardcloudnative/vineyard-grok-exporter:latest
+    imagePullPolicy: IfNotPresent
+  replicas: 2
+  selector: app=job-deployment-with-default-sidecar
+  service:
+    port: 9600
+    selector: rpc.vineyardd.v6d.io/rpc=vineyard-rpc
+    type: ClusterIP
+  vineyard:
+    image: vineyardcloudnative/vineyardd:latest
+    imagePullPolicy: IfNotPresent
+    size: ""
+    socket: /var/run/vineyard.sock
+    spill:
+      name: ""
+      path: ""
+      persistentVolumeClaimSpec:
+        resources: {}
+      persistentVolumeSpec: {}
+      spillLowerRate: "0.3"
+      spillUpperRate: "0.8"
+    streamThreshold: 80
+    syncCRDs: true
+# get the injected Pod, here we only show the important part of the Pod
+$ kubectl get pod -l app=job-deployment-with-default-sidecar -n vineyard-job -o yaml
+apiVersion: v1
+kind: Pod
+metadata:
+  name: job-deployment-with-default-sidecar-55664458f8-h4jzk
+  namespace: vineyard-job
+spec:
+  containers:
+  - command:
+    - /bin/sh
+    - -c
+    - while [ ! -e /var/run/vineyard.sock ]; do sleep 1; done;python3 /job.py
+    env:
+    - name: JOB_NAME
+      value: v6d-workflow-demo-job
+    image: ghcr.io/v6d-io/v6d/sidecar-job
+    imagePullPolicy: IfNotPresent
+    name: job
+    volumeMounts:
+    - mountPath: /var/run
+      name: vineyard-socket
+  - command:
+    - /bin/bash
+    - -c
+    - |
+      /usr/bin/wait-for-it.sh -t 60 etcd-for-vineyard.vineyard-job.svc.cluster.local:2379;
+      sleep 1; /usr/local/bin/vineyardd --sync_crds true --socket /var/run/vineyard.sock
+      --stream_threshold 80 --etcd_cmd etcd --etcd_prefix /vineyard
+      --etcd_endpoint http://etcd-for-vineyard:2379
+    env:
+    - name: VINEYARDD_UID
+      value: 7b0c2ec8-49f3-4f8f-9e5f-8576a4dc4321
+    - name: VINEYARDD_NAME
+      value: app-job-deployment-with-default-sidecar-default-sidecar
+    - name: VINEYARDD_NAMESPACE
+      value: vineyard-job
+    image: vineyardcloudnative/vineyardd:latest
+    imagePullPolicy: IfNotPresent
+    name: vineyard-sidecar
+    ports:
+    - containerPort: 9600
+      name: vineyard-rpc
+      protocol: TCP
+    volumeMounts:
+    - mountPath: /var/run
+      name: vineyard-socket
+  volumes:
+  - emptyDir: {}
+    name: vineyard-socket
+# get the number of injected sidecar
+$ kubectl get sidecar -A
+NAMESPACE      NAME                                                      CURRENT   DESIRED
+vineyard-job   app-job-deployment-with-default-sidecar-default-sidecar   2         2
+
+
+

If you don’t want to use the default sidecar configuration, you could create a custom +sidecar cr as follows:

+
+

Note

+

Please make sure your custom sidecar cr is created before deploying your app workload +and keep the same namespace with your app workload.

+
+
$ cat <<EOF | kubectl apply -f -
+apiVersion: k8s.v6d.io/v1alpha1
+kind: Sidecar
+metadata:
+  name: sidecar-sample
+  namespace: vineyard-job
+spec:
+  replicas: 2
+  selector: app=job-deployment-with-custom-sidecar
+  vineyard:
+    socket: /var/run/vineyard.sock
+    size: 1024Mi
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: job-deployment-with-custom-sidecar
+  namespace: vineyard-job
+spec:
+  selector:
+    matchLabels:
+      app: job-deployment-with-custom-sidecar
+  replicas: 2
+  template:
+    metadata:
+      annotations:
+        sidecar.v6d.io/name: "sidecar-sample"
+      labels:
+        app: job-deployment-with-custom-sidecar
+        sidecar.v6d.io/enabled: "true"
+    spec:
+      containers:
+      - name: job
+        image: ghcr.io/v6d-io/v6d/sidecar-job
+        imagePullPolicy: IfNotPresent
+        command: ["/bin/sh", "-c", "python3 /job.py"]
+        env:
+        - name: JOB_NAME
+          value: v6d-workflow-demo-job
+EOF
+
+
+

For more details about how to use the sidecar, please refer to the sidecar e2e test for +more inspiration.

+
+
+

Objects in Vineyard#

+

Vineyard objects are exposed to the Kubernetes control panel as Custom Resource Definitions (CRDs). +In vineyard, objects are abstracted as global objects and local objects (refer to Objects), +which are represented by the GlobalObject and LocalObject CRDs in the vineyard operator:

+
+

GlobalObject#

+

The GlobalObject custom resource definition (CRD) declaratively defines a global object +within a vineyard cluster. It contains the following fields:

+
+

GlobalObject Properties

+
+
+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Option Name

Type

Description

Default Value

id

string

The id of globalobject.

nil

name

string

The name of globalobject, the same as id.

nil

signature

string

The signature of the globalobject.

nil

typename

string

The typename of globalobject, +including the vineyard’s core type

nil

members

[]string

The signatures of all localobjects +contained in the globalobject

300

metadata

string

The same as typename

nil

+
+
+
+

In general, the GlobalObjects are created as intermediate objects when deploying +users’ applications. You could get them as follows.

+
$ kubectl get globalobjects -A
+NAMESPACE         NAME                ID                  NAME   SIGNATURE           TYPENAME
+vineyard-system   o001bcbcea406acd0   o001bcbcea406acd0          s001bcbcea4069f60   vineyard::GlobalDataFrame
+vineyard-system   o001bcc19dbfc9c34   o001bcc19dbfc9c34          s001bcc19dbfc8d7a   vineyard::GlobalDataFrame
+
+
+
+
+

LocalObject#

+

The LocalObject custom resource definition (CRD) declaratively defines the local object +in a Kubernetes cluster, it contains the following fields:

+
+

LocalObject Properties

+
+
+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Option Name

Type

Description

Default Value

id

string

The id of localobject.

nil

name

string

The name of localobject, the same as id.

nil

signature

string

The signature of localobjects

nil

typename

string

The typename of localobjects, +including the vineyard’s core type

nil

instance_id

int

The instance id created by vineyard daemon server

nil

hostname

string

The hostname of localobjects locations

nil

metadata

string

The same as typename

nil

+
+
+
+

The LocalObjects are also intermediate objects just like the GlobalObjects, and you could +get them as follows.

+
$ kubectl get localobjects -A
+
+
+
+

Expected output

+
+
NAMESPACE         NAME                ID                  NAME   SIGNATURE           TYPENAME              INSTANCE   HOSTNAME
+vineyard-system   o001bcbce202ab390   o001bcbce202ab390          s001bcbce202aa6f6   vineyard::DataFrame   0          kind-worker2
+vineyard-system   o001bcbce21d273e4   o001bcbce21d273e4          s001bcbce21d269c2   vineyard::DataFrame   1          kind-worker
+vineyard-system   o001bcbce24606f6a   o001bcbce24606f6a          s001bcbce246067fc   vineyard::DataFrame   2          kind-worker3
+
+
+
+
+
+
+
+

Vineyard Scheduler#

+

The Vineyard operator includes a scheduler plugin designed to efficiently schedule workloads +on Vineyard by placing them as close as possible to their input data, thereby reducing data +migration costs. The Vineyard scheduler plugin is developed based on the Kubernetes Scheduling +Framework, and its overall scheduling strategy can be summarized as follows:

+
    +
  • All Vineyard workloads can only be deployed on nodes where the Vineyard daemon server is +present.

  • +
  • If a workload does not depend on any other workload, it will be scheduled using a +round-robin approach. For example, if a workload has 3 replicas and there are 3 nodes +with Vineyard daemon servers, the first replica will be scheduled on the first node, the +second replica on the second node, and so on.

  • +
  • If a workload depends on other workloads, it will be scheduled using a best-effort policy. +Assuming a workload produces N chunks during its lifecycle, and there are M nodes with +Vineyard daemon servers, the best-effort policy will attempt to make the next workload +consume M/N: chunks. For instance, imagine a workload produces 12 chunks with the +following distribution:

    +
    node1: 0-8
    +node2: 9-11
    +node3: 12
    +
    +
    +

    The next workload has 3 replicas, and the best-effort policy will schedule it as follows:

    +
    replica1 -> node1 (consume 0-3 chunks)
    +replica2 -> node1 (consume 4-7 chunks)
    +replica3 -> node2 (consume 9-11 chunks, the other chunks will be migrated to the node)
    +
    +
    +
  • +
+
+

Utilizing the Vineyard Scheduler#

+

The Vineyard scheduler is integrated into the Vineyard operator and deployed alongside it. +This scheduler plugin relies on specific annotations and labels to provide necessary input +information. The required configurations are listed below in a clear and comprehensive manner:

+
+

Scheduler Plugin Configurations

+
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + +

Name

Yaml Fields

Description

“scheduling.k8s.v6d.io/required”

annotations

All jobs required by the job. If there are +more than two tasks, use the concatenator ‘.’ +to concatenate them into a string. +E.g. job1.job2.job3. +If there is no required jobs, set none.

“scheduling.k8s.v6d.io/vineyardd”

labels

The name or namespaced name of vineyardd. e.g., +vineyard-sample or +vineyard-system/vineyard-sample.

“scheduling.k8s.v6d.io/job “”

labels

The job name.

“schedulerName”

spec

The vineyard scheduler’s name, and the +default value is vineyard-scheduler.

+
+
+
+

In this section, we will demonstrate a comprehensive example of utilizing the Vineyard +scheduler. To begin, ensure that the Vineyard operator and Vineyard daemon server are +installed by following the steps outlined earlier. Then, proceed to deploy workflow-job1 +as shown below.

+
$ kubectl create ns vineyard-job
+
+
+
$ cat <<EOF | kubectl apply -f -
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: v6d-workflow-demo-job1-deployment
+  namespace: vineyard-job
+spec:
+  selector:
+    matchLabels:
+      app: v6d-workflow-demo-job1
+  replicas: 2
+  template:
+    metadata:
+      labels:
+        app: v6d-workflow-demo-job1
+        # vineyardd's name
+        scheduling.k8s.v6d.io/vineyardd-namespace: vineyard-system
+        scheduling.k8s.v6d.io/vineyardd: vineyardd-sample
+        # job name
+        scheduling.k8s.v6d.io/job: v6d-workflow-demo-job1
+    spec:
+      # vineyard scheduler name
+      schedulerName: vineyard-scheduler
+      containers:
+      - name: job1
+        image: ghcr.io/v6d-io/v6d/workflow-job1
+        # please set the JOB_NAME env, it will be used by vineyard scheduler
+        env:
+        - name: JOB_NAME
+          value: v6d-workflow-demo-job1
+        imagePullPolicy: IfNotPresent
+        volumeMounts:
+        - mountPath: /var/run
+          name: vineyard-sock
+      volumes:
+      - name: vineyard-sock
+        hostPath:
+          path: /var/run/vineyard-kubernetes/vineyard-system/vineyardd-sample
+EOF
+
+
+

We can see the created job and the objects produced by it:

+
$ kubectl get all -n vineyard-job
+NAME                                                     READY   STATUS    RESTARTS   AGE
+pod/v6d-workflow-demo-job1-deployment-6f479d695b-698xb   1/1     Running   0          3m16s
+pod/v6d-workflow-demo-job1-deployment-6f479d695b-7zrw6   1/1     Running   0          3m16s
+
+NAME                                                READY   UP-TO-DATE   AVAILABLE   AGE
+deployment.apps/v6d-workflow-demo-job1-deployment   2/2     2            2           3m16s
+
+NAME                                                           DESIRED   CURRENT   READY   AGE
+replicaset.apps/v6d-workflow-demo-job1-deployment-6f479d695b   2         2         2       3m16s
+
+$ kubectl get globalobjects -n vineyard-system
+NAME                ID                  NAME   SIGNATURE           TYPENAME
+o001c87014cf03c70   o001c87014cf03c70          s001c87014cf03262   vineyard::Sequence
+o001c8729e49e06b8   o001c8729e49e06b8          s001c8729e49dfbb4   vineyard::Sequence
+
+$ kubectl get localobjects -n vineyard-system
+NAME                ID                  NAME   SIGNATURE           TYPENAME                  INSTANCE   HOSTNAME
+o001c87014ca81924   o001c87014ca81924          s001c87014ca80acc   vineyard::Tensor<int64>   1          kind-worker2
+o001c8729e4590626   o001c8729e4590626          s001c8729e458f47a   vineyard::Tensor<int64>   2          kind-worker3
+
+# when a job is scheduled, the scheduler will create a configmap to record the globalobject id
+# that the next job will consume.
+$ kubectl get configmap v6d-workflow-demo-job1 -n vineyard-job -o yaml
+apiVersion: v1
+data:
+  kind-worker3: o001c8729e4590626
+  v6d-workflow-demo-job1: o001c8729e49e06b8
+kind: ConfigMap
+...
+
+
+

Then deploy the workflow-job2 as follows.

+
$ cat <<EOF | kubectl apply -f -
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: v6d-workflow-demo-job2-deployment
+  namespace: vineyard-job
+spec:
+  selector:
+    matchLabels:
+      app: v6d-workflow-demo-job2
+replicas: 3
+template:
+  metadata:
+    annotations:
+      # required jobs
+      scheduling.k8s.v6d.io/required: v6d-workflow-demo-job1
+    labels:
+      app: v6d-workflow-demo-job2
+      # vineyardd's name
+      scheduling.k8s.v6d.io/vineyardd-namespace: vineyard-system
+      scheduling.k8s.v6d.io/vineyardd: vineyardd-sample
+      # job name
+      scheduling.k8s.v6d.io/job: v6d-workflow-demo-job2
+    spec:
+      # vineyard scheduler name
+      schedulerName: vineyard-scheduler
+      containers:
+      - name: job2
+        image: ghcr.io/v6d-io/v6d/workflow-job2
+        imagePullPolicy: IfNotPresent
+        env:
+        - name: JOB_NAME
+          value: v6d-workflow-demo-job2
+        # pass node name to the environment
+        - name: NODENAME
+          valueFrom:
+            fieldRef:
+              fieldPath: spec.nodeName
+        # Notice, vineyard operator will create a configmap to pass the global object id produced by the previous job.
+        # Please set the configMapRef, it's name is the same as the job name.
+        envFrom:
+          - configMapRef:
+              name: v6d-workflow-demo-job1
+        volumeMounts:
+        - mountPath: /var/run
+          name: vineyard-sock
+      volumes:
+      - name: vineyard-sock
+        hostPath:
+          path: /var/run/vineyard-kubernetes/vineyard-system/vineyardd-sample
+EOF
+
+
+

Now you can see that both jobs have been scheduled and become running:

+
$ kubectl get all -n vineyard-job
+
+
+
+

Expected output

+
+
NAME                                                     READY   STATUS    RESTARTS      AGE
+pod/v6d-workflow-demo-job1-deployment-6f479d695b-698xb   1/1     Running   0             8m12s
+pod/v6d-workflow-demo-job1-deployment-6f479d695b-7zrw6   1/1     Running   0             8m12s
+pod/v6d-workflow-demo-job2-deployment-b5b58cbdc-4s7b2    1/1     Running   0             6m24s
+pod/v6d-workflow-demo-job2-deployment-b5b58cbdc-cd5v2    1/1     Running   0             6m24s
+pod/v6d-workflow-demo-job2-deployment-b5b58cbdc-n6zvm    1/1     Running   0             6m24s
+
+NAME                                                READY   UP-TO-DATE   AVAILABLE   AGE
+deployment.apps/v6d-workflow-demo-job1-deployment   2/2     2            2           8m12s
+deployment.apps/v6d-workflow-demo-job2-deployment   3/3     3            3           6m24s
+
+NAME                                                           DESIRED   CURRENT   READY   AGE
+replicaset.apps/v6d-workflow-demo-job1-deployment-6f479d695b   2         2         2       8m12s
+replicaset.apps/v6d-workflow-demo-job2-deployment-b5b58cbdc    3         3         3       6m24s
+
+
+
+
+

The above is the process of running the workload based on the vineyard scheduler, and it’s same +as the workflow e2e test. What’s more, you could refer to the +workflow demo to dig into what happens in the container.

+
+
+
+

Operations and drivers#

+

The Operation custom resource definition (CRD) elegantly defines the configurable +pluggable drivers, primarily assembly and repartition, within a Kubernetes cluster. +It encompasses the following fields:

+
+

Operation Configurations

+
+
+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Option Name

Type

Description

Default Value

name

string

The name of vineyard pluggable drivers, +including assembly and repartition.

nil

type

string

the type of operation. For assembly, +it mainly contains local (for localobject) and +distributed (for globalobject). For repartition, +it contains dask (object built in dask).

nil

require

string

The required job’s name of the operation.

nil

target

string

The target job’s name of the operation.

nil

timeoutSeconds

string

The timeout of the operation.

300

+
+
+
+

The Operation Custom Resource (CR) is created by the vineyard scheduler while scheduling vineyard jobs. +You can retrieve the created Operation CRs as follows:

+
$ kubectl get operation -A
+NAMESPACE      NAME                                    OPERATION     TYPE   STATE
+vineyard-job   dask-repartition-job2-bbf596bf4-985vc   repartition   dask
+
+
+

Currently, the vineyard operator includes three pluggable drivers: checkpoint, assembly, and +repartition. The following sections provide a brief introduction to each of these drivers.

+
+

Checkpoint#

+

Vineyard currently supports two types of checkpoint drivers:

+
    +
  1. Active checkpoint - Serialization: Users can store data in temporary or persistent storage +for checkpoint purposes using the API (vineyard.io.serialize/deserialize). Note that the +serialization process is triggered by the user within the application image, and the volume is +also created by the user. Therefore, it is not managed by the vineyard operator.

  2. +
  3. Passive checkpoint - Spill: Vineyard now supports spilling data from memory to storage +when the data size exceeds the available memory capacity. There are two watermarks for memory +spilling: the low watermark and the high watermark. When the data size surpasses the high watermark, +vineyardd will spill the excess data to storage until it reaches the low watermark.

  4. +
+
+

Triggering a checkpoint job#

+

Now, the checkpoint driver (Spill) is configured within the vineyardd Custom Resource +Definition (CRD). To create a default vineyardd daemon server with the spill mechanism enabled, +use the following YAML file:

+
+

Note

+

The spill mechanism supports temporary storage (HostPath) and persistent storage +(PersistentVolume)

+
+
$ cat <<EOF | kubectl apply -f -
+apiVersion: k8s.v6d.io/v1alpha1
+kind: Vineyardd
+metadata:
+  name: vineyardd-sample
+  # use the same namespace as the vineyard operator
+  namespace: vineyard-system
+spec:
+  vineyard:
+    # spill configuration
+    spill:
+      name: spill-path
+      # please make sure the path exists
+      path: /var/vineyard/spill
+      spillLowerRate: "0.3"
+      spillUpperRate: "0.8"
+      persistentVolumeSpec:
+        storageClassName: manual
+        capacity:
+          storage: 1Gi
+        accessModes:
+          - ReadWriteOnce
+        hostPath:
+          path: /var/vineyard/spill
+      persistentVolumeClaimSpec:
+        storageClassName: manual
+        accessModes:
+          - ReadWriteOnce
+        resources:
+          requests:
+            storage: 512Mi
+EOF
+
+
+

For a comprehensive understanding of the checkpoint mechanism in the vineyard operator, +please refer to the checkpoint examples. Additionally, the serialize e2e test and +the spill e2e test can provide valuable insights on how to effectively utilize the +checkpoint mechanism within a workflow.

+
+
+
+

Assembly#

+

In real-world scenarios, workloads often involve various computing engines. Some of these +engines support stream types to accelerate data processing, while others do not. To ensure +the seamless operation of the workload, an assembly mechanism is required to convert the +stream type into a chunk type. This conversion enables subsequent computing engines that +do not support stream types to read the metadata generated by the previous engine.

+
+

Triggering an assembly job#

+

To reduce the load on the Kubernetes API Server, we offer a namespace selector for assembly. +The assembly driver will only be applied to namespaces with the specific label +operation-injection: enabled. Therefore, ensure that the application’s namespace has +this label before using the assembly mechanism.

+

We provide several labels to assist users in utilizing the assembly mechanism in the +vineyard operator. The following are the available labels:

+
+

Assembly Drivers Configurations

+
+
+ +++++ + + + + + + + + + + + + + + + + +

Name

Yaml Fields

Description

“assembly.v6d.io/enabled”

labels

If the job needs an assembly operation +before deploying it, then set true.

“assembly.v6d.io/type”

labels

There are two types in assembly operation, +local only for localobject(stream on the same node), +distributed for globalobject(stream on different nodes).

+
+
+
+

In this example, we demonstrate how to utilize the assembly mechanism in the +vineyard operator. We have a workflow consisting of two workloads: the first +workload processes a stream, and the second workload processes a chunk. The +assembly mechanism is used to convert the stream output from the first workload +into a chunk format that can be consumed by the second workload. The following +YAML file represents the assembly workload1:

+
+

Note

+

Ensure that the vineyard operator and vineyardd are installed before +executing the following YAML file.

+
+
$ kubectl create namespace vineyard-job
+
+
+
$ cat <<EOF | kubectl apply -f -
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: assembly-job1
+  namespace: vineyard-job
+spec:
+  selector:
+    matchLabels:
+      app: assembly-job1
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: assembly-job1
+        # this label represents the vineyardd's name that need to be used
+        scheduling.k8s.v6d.io/vineyardd-namespace: vineyard-system
+        scheduling.k8s.v6d.io/vineyardd: vineyardd-sample
+        scheduling.k8s.v6d.io/job: assembly-job1
+    spec:
+      schedulerName: vineyard-scheduler
+      containers:
+        - name: assembly-job1
+          image: ghcr.io/v6d-io/v6d/assembly-job1
+          env:
+            - name: JOB_NAME
+              value: assembly-job1
+          imagePullPolicy: IfNotPresent
+          volumeMounts:
+            - mountPath: /var/run
+              name: vineyard-sock
+      volumes:
+        - name: vineyard-sock
+          hostPath:
+            path: /var/run/vineyard-kubernetes/vineyard-system/vineyardd-sample
+EOF
+# we can get the localobjects produced by the first workload, it's a stream type.
+$ kubectl get localobjects -n vineyard-system
+NAME                ID                  NAME   SIGNATURE           TYPENAME                      INSTANCE   HOSTNAME
+o001d1b280049b146   o001d1b280049b146          s001d1b280049a4d4   vineyard::RecordBatchStream   0          kind-worker2
+
+
+

From the output above, it is evident that the localobjects generated by the first +workload are of the stream type. Next, we will deploy the second workload utilizing +the assembly mechanism. The following YAML file represents the assembly workload2:

+
# remember label the namespace with the label `operation-injection: enabled` to
+# enable pluggable drivers.
+$ kubectl label namespace vineyard-job operation-injection=enabled
+
+
+
$ cat <<EOF | kubectl apply -f -
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: assembly-job2
+  namespace: vineyard-job
+spec:
+  selector:
+    matchLabels:
+      app: assembly-job2
+  replicas: 1
+  template:
+    metadata:
+      annotations:
+        scheduling.k8s.v6d.io/required: assembly-job1
+      labels:
+        app: assembly-job2
+        assembly.v6d.io/enabled: "true"
+        assembly.v6d.io/type: "local"
+        # this label represents the vineyardd's name that need to be used
+        scheduling.k8s.v6d.io/vineyardd-namespace: vineyard-system
+        scheduling.k8s.v6d.io/vineyardd: vineyardd-sample
+        scheduling.k8s.v6d.io/job: assembly-job2
+    spec:
+      schedulerName: vineyard-scheduler
+      containers:
+        - name: assembly-job2
+          image: ghcr.io/v6d-io/v6d/assembly-job2
+          env:
+            - name: JOB_NAME
+              value: assembly-job2
+            - name: REQUIRED_JOB_NAME
+              value: assembly-job1
+          envFrom:
+          - configMapRef:
+              name: assembly-job1
+          imagePullPolicy: IfNotPresent
+          volumeMounts:
+            - mountPath: /var/run
+              name: vineyard-sock
+      volumes:
+        - name: vineyard-sock
+          hostPath:
+            path: /var/run/vineyard-kubernetes/vineyard-system/vineyardd-sample
+EOF
+
+
+

Upon deploying the second workload, it remains in a pending state. This indicates that the scheduler +has identified the need for an assembly operation, and consequently, the corresponding assembly +operation Custom Resource (CR) will be created.

+
# get all workloads, the job2 is pending as it needs an assembly operation.
+$ kubectl get pod -n vineyard-job
+NAME                             READY   STATUS    RESTARTS   AGE
+assembly-job1-86c99c995f-nzns8   1/1     Running   0          2m
+assembly-job2-646b78f494-cvz2w   0/1     Pending   0          53s
+
+# the assembly operation CR is created by the scheduler.
+$ kubectl get operation -A
+NAMESPACE      NAME                             OPERATION   TYPE    STATE
+vineyard-job   assembly-job2-646b78f494-cvz2w   assembly    local
+
+
+

During the assembly operation, the Operation Controller will create a job to run assembly +operation. We can get the objects produced by the job.

+
# get the assembly operation job
+$ kubectl get job -n vineyard-job
+NAMESPACE      NAME                         COMPLETIONS   DURATION   AGE
+vineyard-job   assemble-o001d1b280049b146   1/1           26s        119s
+# get the pod
+$ kubectl get pod -n vineyard-job
+NAME                               READY   STATUS      RESTARTS   AGE
+assemble-o001d1b280049b146-fzws7   0/1     Completed   0          5m55s
+assembly-job1-86c99c995f-nzns8     1/1     Running     0          4m
+assembly-job2-646b78f494-cvz2w     0/1     Pending     0          5m
+
+# get the localobjects produced by the job
+$ kubectl get localobjects -l k8s.v6d.io/created-podname=assemble-o001d1b280049b146-fzws7 -n vineyard-system
+NAME                ID                  NAME   SIGNATURE           TYPENAME              INSTANCE   HOSTNAME
+o001d1b56f0ec01f8   o001d1b56f0ec01f8          s001d1b56f0ebf578   vineyard::DataFrame   0          kind-worker2
+o001d1b5707c74e62   o001d1b5707c74e62          s001d1b5707c742e0   vineyard::DataFrame   0          kind-worker2
+o001d1b571f47cfe2   o001d1b571f47cfe2          s001d1b571f47c3c0   vineyard::DataFrame   0          kind-worker2
+o001d1b5736a6fd6c   o001d1b5736a6fd6c          s001d1b5736a6f1cc   vineyard::DataFrame   0          kind-worker2
+o001d1b574d9b94ae   o001d1b574d9b94ae          s001d1b574d9b8a9e   vineyard::DataFrame   0          kind-worker2
+o001d1b5765629cbc   o001d1b5765629cbc          s001d1b57656290a8   vineyard::DataFrame   0          kind-worker2
+o001d1b57809911ce   o001d1b57809911ce          s001d1b57809904e0   vineyard::DataFrame   0          kind-worker2
+o001d1b5797a9f958   o001d1b5797a9f958          s001d1b5797a9ee82   vineyard::DataFrame   0          kind-worker2
+o001d1b57add9581c   o001d1b57add9581c          s001d1b57add94e62   vineyard::DataFrame   0          kind-worker2
+o001d1b57c53875ae   o001d1b57c53875ae          s001d1b57c5386a22   vineyard::DataFrame   0          kind-worker2
+
+# get the globalobjects produced by the job
+$ kubectl get globalobjects -l k8s.v6d.io/created-podname=assemble-o001d1b280049b146-fzws7 -n vineyard-system
+NAME                ID                  NAME   SIGNATURE           TYPENAME
+o001d1b57dc2c74ee   o001d1b57dc2c74ee          s001d1b57dc2c6a4a   vineyard::Sequence
+
+
+

Each stream will be transformed into a globalobject. To make the second workload obtain the +globalobject generated by the assembly operation, the vineyard scheduler will create a configmap +to store the globalobject id as follows.

+
$ kubectl get configmap assembly-job1 -n vineyard-job -o yaml
+apiVersion: v1
+data:
+  assembly-job1: o001d1b57dc2c74ee
+kind: ConfigMap
+...
+
+
+

Upon completion of the assembly operation, the scheduler will reschedule the second workload, +allowing it to be successfully deployed as shown below:

+
$ kubectl get pod -n vineyard-job
+NAME                               READY   STATUS      RESTARTS   AGE
+assemble-o001d1b280049b146-fzws7   0/1     Completed   0          9m55s
+assembly-job1-86c99c995f-nzns8     1/1     Running     0          8m
+assembly-job2-646b78f494-cvz2w     1/1     Running     0          9m
+
+
+

The assembly operation process is demonstrated in the local assembly e2e test. For more +details, please refer to the assembly demo and local assembly operation.

+

Additionally, we also support distributed assembly operation. You can explore the +distributed assembly e2e test for further insights.

+
+
+
+

Repartitioning#

+

Repartitioning is a mechanism that adjusts the distribution of data across the Vineyard +cluster. It is particularly useful when the number of workers cannot accommodate the required +number of partitions. For example, if a workload creates 4 partitions, but the subsequent +workload has only 3 workers, the repartitioning mechanism will redistribute the partitions +from 4 to 3, allowing the next workload to function as expected. Currently, the Vineyard +operator supports repartitioning based on dask.

+
+

Initiating a Repartition Job#

+

For workloads based on Dask, we provide several annotations and labels to help users +utilize the repartitioning mechanism in the Vineyard operator. The following list contains +all the labels and annotations we offer:

+
+

Dask Repartition Drivers Configurations

+
+
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Name

Yaml Fields

Description

“scheduling.k8s.v6d.io/dask-scheduler”

annotations

The service of dask scheduler.

“scheduling.k8s.v6d.io/dask-worker-selector”

annotations

The label selector of dask worker pod.

“repartition.v6d.io/enabled”

labels

Enable the repartition.

“repartition.v6d.io/type”

labels

The type of repartition, at present, +only support dask.

“scheduling.k8s.v6d.io/replicas”

labels

The replicas of the workload.

+
+
+
+

The following is a demo of repartition based on dask. At first, we create a dask cluster +with 3 workers.

+
+

Note

+

Please make sure you have installed the vineyard operator and vineyardd before +running the following yaml file.

+
+
# install dask scheduler and dask worker.
+$ helm repo add dask https://helm.dask.org/
+$ helm repo update
+
+
+
# the dask-worker's image is built with vineyard, please refer
+# https://github.com/v6d-io/v6d/blob/main/k8s/test/e2e/repartition-demo/Dockerfile.dask-worker-with-vineyard.
+$ cat <<EOF | helm install dask-cluster dask/dask --values -
+scheduler:
+  image:
+    tag: "2022.8.1"
+
+jupyter:
+  enabled: false
+
+worker:
+  # worker numbers
+  replicas: 3
+  image:
+    repository: ghcr.io/v6d-io/v6d/dask-worker-with-vineyard
+    tag: latest
+  env:
+    - name: VINEYARD_IPC_SOCKET
+      value: /var/run/vineyard.sock
+    - name: VINEYARD_RPC_SOCKET
+      value: vineyardd-sample-rpc.vineyard-system:9600
+  mounts:
+    volumes:
+      - name: vineyard-sock
+        hostPath:
+          path: /var/run/vineyard-kubernetes/vineyard-system/vineyardd-sample
+    volumeMounts:
+      - mountPath: /var/run
+        name: vineyard-sock
+EOF
+
+
+

Deploy the repartition workload1 as follows:

+
$ kubectl create namespace vineyard-job
+
+
+
$ cat <<EOF | kubectl apply -f -
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: dask-repartition-job1
+  namespace: vineyard-job
+spec:
+  selector:
+    matchLabels:
+      app: dask-repartition-job1
+  replicas: 1
+  template:
+    metadata:
+      annotations:
+        scheduling.k8s.v6d.io/dask-scheduler: "tcp://my-release-dask-scheduler.default:8786"
+        # use ',' to separate the different labels here
+        scheduling.k8s.v6d.io/dask-worker-selector: "app:dask,component:worker"
+      labels:
+        app: dask-repartition-job1
+        repartition.v6d.io/type: "dask"
+        scheduling.k8s.v6d.io/replicas: "1"
+        # this label represents the vineyardd's name that need to be used
+        scheduling.k8s.v6d.io/vineyardd-namespace: vineyard-system
+        scheduling.k8s.v6d.io/vineyardd: vineyardd-sample
+        scheduling.k8s.v6d.io/job: dask-repartition-job1
+    spec:
+      schedulerName: vineyard-scheduler
+      containers:
+      - name: dask-repartition-job1
+        image: ghcr.io/v6d-io/v6d/dask-repartition-job1
+        imagePullPolicy: IfNotPresent
+        env:
+        - name: JOB_NAME
+          value: dask-repartition-job1
+        - name: DASK_SCHEDULER
+          value: tcp://my-release-dask-scheduler.default:8786
+        volumeMounts:
+        - mountPath: /var/run
+          name: vineyard-sock
+      volumes:
+      - name: vineyard-sock
+        hostPath:
+          path: /var/run/vineyard-kubernetes/vineyard-system/vineyardd-sample
+EOF
+
+
+

The first workload will create 4 partitions (each partition as a localobject):

+
$ kubectl get globalobjects -n vineyard-system
+NAME                ID                  NAME   SIGNATURE           TYPENAME
+o001d2a6ae6c6e2e8   o001d2a6ae6c6e2e8          s001d2a6ae6c6d4f4   vineyard::GlobalDataFrame
+$ kubectl get localobjects -n vineyard-system
+NAME                ID                  NAME   SIGNATURE           TYPENAME              INSTANCE   HOSTNAME
+o001d2a6a6483ac44   o001d2a6a6483ac44          s001d2a6a6483a3ce   vineyard::DataFrame   1          kind-worker3
+o001d2a6a64a29cf4   o001d2a6a64a29cf4          s001d2a6a64a28f2e   vineyard::DataFrame   0          kind-worker
+o001d2a6a66709f20   o001d2a6a66709f20          s001d2a6a667092a2   vineyard::DataFrame   2          kind-worker2
+o001d2a6ace0f6e30   o001d2a6ace0f6e30          s001d2a6ace0f65b8   vineyard::DataFrame   2          kind-worker2
+
+
+

Deploy the repartition workload2 as follows:

+
$ kubectl label namespace vineyard-job operation-injection=enabled
+
+
+
$ cat <<EOF | kubectl apply -f -
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: dask-repartition-job2
+  namespace: vineyard-job
+spec:
+  selector:
+    matchLabels:
+      app: dask-repartition-job2
+  replicas: 1
+  template:
+    metadata:
+      annotations:
+        scheduling.k8s.v6d.io/required: "dask-repartition-job1"
+        scheduling.k8s.v6d.io/dask-scheduler: "tcp://my-release-dask-scheduler.default:8786"
+        # use ',' to separate the different labels here
+        scheduling.k8s.v6d.io/dask-worker-selector: "app:dask,component:worker"
+      labels:
+        app: dask-repartition-job2
+        repartition.v6d.io/enabled: "true"
+        repartition.v6d.io/type: "dask"
+        scheduling.k8s.v6d.io/replicas: "1"
+        # this label represents the vineyardd's name that need to be used
+        scheduling.k8s.v6d.io/vineyardd-namespace: vineyard-system
+        scheduling.k8s.v6d.io/vineyardd: vineyardd-sample
+        scheduling.k8s.v6d.io/job: dask-repartition-job2
+    spec:
+      schedulerName: vineyard-scheduler
+      containers:
+      - name: dask-repartition-job2
+        image: ghcr.io/v6d-io/v6d/dask-repartition-job2
+        imagePullPolicy: IfNotPresent
+        env:
+        - name: JOB_NAME
+          value: dask-repartition-job2
+        - name: DASK_SCHEDULER
+          value: tcp://my-release-dask-scheduler.default:8786
+        - name: REQUIRED_JOB_NAME
+          value: dask-repartition-job1
+        envFrom:
+        - configMapRef:
+            name: dask-repartition-job1
+        volumeMounts:
+        - mountPath: /var/run
+          name: vineyard-sock
+      volumes:
+      - name: vineyard-sock
+        hostPath:
+          path: /var/run/vineyard-kubernetes/vineyard-system/vineyardd-sample
+EOF
+
+
+

The second workload waits for the repartition operation to finish:

+
# check all workloads
+$ kubectl get pod -n vineyard-job
+NAME                                     READY   STATUS    RESTARTS   AGE
+dask-repartition-job1-5dbfc54997-7kghk   1/1     Running   0          92s
+dask-repartition-job2-bbf596bf4-cvrt2    0/1     Pending   0          49s
+
+# check the repartition operation
+$ kubectl get operation -A
+NAMESPACE      NAME                                    OPERATION     TYPE   STATE
+vineyard-job   dask-repartition-job2-bbf596bf4-cvrt2   repartition   dask
+
+# check the job
+$ kubectl get job -n vineyard-job
+NAME                            COMPLETIONS   DURATION   AGE
+repartition-o001d2a6ae6c6e2e8   0/1           8s         8s
+
+
+

After the repartition job finishes, the second workload will be scheduled:

+
# check all workloads
+$ kubectl get pod -n vineyard-job
+NAME                                     READY   STATUS      RESTARTS   AGE
+dask-repartition-job1-5dbfc54997-7kghk   1/1     Running     0          5m43s
+dask-repartition-job2-bbf596bf4-cvrt2    0/1     Pending     0          4m30s
+repartition-o001d2a6ae6c6e2e8-79wcm      0/1     Completed   0          3m30s
+
+# check the repartition operation
+# as the second workload only has 1 replica, the repartition operation will repartitioned
+# the global object into 1 partition
+$ kubectl get globalobjects -n vineyard-system
+NAME                ID                  NAME   SIGNATURE           TYPENAME
+o001d2ab523e3fbd0   o001d2ab523e3fbd0          s001d2ab523e3f0e6   vineyard::GlobalDataFrame
+
+# the repartition operation will create a new local object(only 1 partition)
+$ kubectl get localobjects -n vineyard-system
+NAMESPACE         NAME                ID                  NAME   SIGNATURE           TYPENAME              INSTANCE   HOSTNAME
+vineyard-system   o001d2dc18d72a47e   o001d2dc18d72a47e          s001d2dc18d729ab6   vineyard::DataFrame   2          kind-worker2
+
+
+

The whole workflow can be found in dask repartition e2e test. What’s more, +please refer the repartition directory to get more details.

+
+
+
+
+

Failover mechanism of vineyard cluster#

+

If you want to back up data for the current vineyard cluster, you can create a Backup CR to +perform a backup operation. As the Backup CR will use the default service account of the +namespace the vineyard operator is deployed, you need to set up the same namespace as +the vineyard operator. The main fields are described as follows.

+
+

Backup Configurations

+
+
+ ++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Option Name

Type

Description

Default Value

vineyarddName

string

The name of vineyardd cluster.

nil

vineyarddNamespace

string

The namespace of vineyardd cluster.

nil

objectIDs

[]string

The object IDs that need to be backed up. +If it is empty, all objects will be backed up.

nil

backupPath

string

The path of backup data

nil

persistentVolumeSpec

corev1.PersistentVolumeSpec

The PersistentVolumeSpec of the backup data

nil

persistentVolumeClaimSpec

corev1.PersistentVolumeClaimSpec

The PersistentVolumeClaimSpec of the backup data

nil

+
+
+
+

After data backup, you can create a Recover CR to restore a certain vineyard backup data. +Its fields are as follows.

+
+

Recover Configurations

+
+
+ ++++++ + + + + + + + + + + + + + + + + + + + +

Option Name

Type

Description

Default Value

backupName

string

The name of a backup.

nil

backupNamespace

string

The namespace of a backup.

nil

+
+
+
+

Next, we will show how to use the failover mechanism in vineyard operator. Assuming that +we have a vineyard cluster that contains some objects, then we create a backup cr to back +up the data. The following is the yaml file of the backup:

+
+

Note

+

Please make sure you have installed the vineyard operator and vineyardd before +running the following yaml file.

+
+
$ cat <<EOF | kubectl apply -f -
+apiVersion: k8s.v6d.io/v1alpha1
+kind: Backup
+metadata:
+  name: backup-sample
+  namespace: vineyard-system
+spec:
+  vineyarddName: vineyardd-sample
+  vineyarddNamespace: vineyard-system
+  backupPath: /var/vineyard/dump
+  persistentVolumeSpec:
+    storageClassName: manual
+    capacity:
+      storage: 1Gi
+    accessModes:
+      - ReadWriteOnce
+    hostPath:
+      path: /var/vineyard/dump
+  persistentVolumeClaimSpec:
+    storageClassName: manual
+    accessModes:
+      - ReadWriteOnce
+    resources:
+      requests:
+        storage: 1Gi
+EOF
+
+
+

Assuming that the vineyard cluster crashes at some point, we create Recover CR to +restore the data in the vineyard cluster, and the recover yaml file is as follows:

+
$ cat <<EOF | kubectl apply -f -
+apiVersion: k8s.v6d.io/v1alpha1
+kind: Recover
+metadata:
+  name: recover-sample
+  namespace: vineyard-system
+spec:
+  backupName: backup-sample
+  backupNamespace: vineyard-system
+EOF
+
+
+

Then you could get the Recover’s status to get the mapping relationship between the +object ID during backup and the object ID during recovery as follows:

+
$ kubectl get recover -A
+NAMESPACE            NAME             MAPPING                                                                                                                     STATE
+vineyard-system      recover-sample   {"o000ef92379fd8850":"o000ef9ea5189718d","o000ef9237a3a5432":"o000ef9eb5d26ad5e","o000ef97a8289973f":"o000ef9ed586ef1d3"}   Succeed
+
+
+

If you want to get more details about the failover mechanism of vineyard cluster, please refer +the failover e2e test.

+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/cloud-native/vineyardctl.html b/notes/cloud-native/vineyardctl.html new file mode 100644 index 0000000000..dc6b36f903 --- /dev/null +++ b/notes/cloud-native/vineyardctl.html @@ -0,0 +1,2559 @@ + + + + + + + + + + + + + + + + + + + vineyardctl - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

vineyardctl#

+

vineyardctl is the command-line tool for interact with the Vineyard Operator.

+
+

Synopsis#

+

vineyardctl is the command-line tool for working with the +Vineyard Operator. It supports creating, deleting and checking +status of Vineyard Operator. It also supports managing the +vineyard relevant components such as vineyardd and pluggable +drivers.

+

SEE ALSO

+ +
+
+

Options#

+
      --create-namespace    create the namespace if it does not exist, default false
+  -j, --dump-usage          Dump usage in JSON
+  -g, --gen-doc             Generate reference docs, e.g., "./cmd/README.md"
+  -h, --help                help for vineyardctl
+      --kubeconfig string   kubeconfig path for the kubernetes cluster (default "$HOME/.kube/config")
+  -n, --namespace string    the namespace for operation (default "vineyard-system")
+      --verbose             print verbose log, default false
+  -v, --version             version for vineyardctl
+      --wait                wait for the kubernetes resource to be ready, default true (default true)
+
+
+
+
+

vineyardctl create#

+

Create a vineyard jobs on kubernetes

+

SEE ALSO

+ +
+

Examples#

+
  # create the backup job on kubernetes
+  vineyardctl create backup --vineyardd-name vineyardd-sample --vineyardd-namespace vineyard-system
+
+  # create the recover job on kubernetes
+  vineyardctl create recover --backup-name vineyardd-sample -n vineyard-system
+
+  # create the operation job on kubernetes
+  vineyardctl create operation --name assembly \
+    --type local \
+    --require job1 \
+    --target job2 \
+    --timeoutSeconds 600
+
+
+
+
+

Options#

+
  -h, --help   help for create
+
+
+
+
+
+

vineyardctl create backup#

+

Create a backup cr to backup the current vineyard cluster on kubernetes

+
+

Synopsis#

+

Backup the current vineyard cluster on kubernetes. You could +backup all objects of the current vineyard cluster quickly. +For persistent storage, you could specify the pv spec and pv +spec.

+

Notice, the command is used to create a backup cr for the +vineyard operator and you must deploy the vineyard operator +and vineyard cluster before using it.

+
vineyardctl create backup [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # create a backup cr for the vineyard cluster on kubernetes
+  # you could define the pv and pvc spec from json string as follows
+  vineyardctl create backup \
+    --vineyardd-name vineyardd-sample \
+    --vineyardd-namespace vineyard-system  \
+    --limit 1000 \
+    --path /var/vineyard/dump  \
+    --pv-pvc-spec '{
+      "pv-spec": {
+        "capacity": {
+          "storage": "1Gi"
+        },
+        "accessModes": [
+          "ReadWriteOnce"
+        ],
+        "storageClassName": "manual",
+        "hostPath": {
+          "path": "/var/vineyard/dump"
+        }
+      },
+      "pvc-spec": {
+        "storageClassName": "manual",
+        "accessModes": [
+          "ReadWriteOnce"
+        ],
+        "resources": {
+          "requests": {
+          "storage": "1Gi"
+          }
+        }
+      }
+      }'
+
+  # create a backup cr for the vineyard cluster on kubernetes
+  # you could define the pv and pvc spec from yaml string as follows
+  vineyardctl create backup \
+    --vineyardd-name vineyardd-sample \
+    --vineyardd-namespace vineyard-system  \
+    --limit 1000 --path /var/vineyard/dump  \
+    --pv-pvc-spec  \
+    '
+    pv-spec:
+    capacity:
+    storage: 1Gi
+    accessModes:
+    - ReadWriteOnce
+    storageClassName: manual
+    hostPath:
+    path: "/var/vineyard/dump"
+    pvc-spec:
+    storageClassName: manual
+    accessModes:
+    - ReadWriteOnce
+    resources:
+    requests:
+    storage: 1Gi
+    '
+
+  # create a backup cr for the vineyard cluster on kubernetes
+  # you could define the pv and pvc spec from json file as follows
+  # also you could use yaml file instead of json file
+  cat pv-pvc.json | vineyardctl create backup \
+    --vineyardd-name vineyardd-sample \
+    --vineyardd-namespace vineyard-system  \
+    --limit 1000 --path /var/vineyard/dump  \
+    -
+
+
+
+
+

Options#

+
      --backup-name string           the name of backup job (default "vineyard-backup")
+  -h, --help                         help for backup
+      --objectIDs strings            the specific objects to be backed up
+      --path string                  the path of the backup data
+      --pv-pvc-spec string           the PersistentVolume and PersistentVolumeClaim of the backup data
+      --vineyardd-name string        the name of vineyardd
+      --vineyardd-namespace string   the namespace of vineyardd
+
+
+
+
+
+

vineyardctl create operation#

+

Insert an operation in a workflow based on vineyard cluster

+
+

Synopsis#

+

Insert an operation in a workflow based on vineyard cluster. +You could create a assembly or repartition operation in a +workflow. Usually, the operation should be created between +the workloads: job1 -> operation -> job2.

+
vineyardctl create operation [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # create a local assembly operation between job1 and job2
+  vineyardctl create operation --name assembly \
+    --type local \
+    --require job1 \
+    --target job2 \
+    --timeoutSeconds 600
+
+  # create a distributed assembly operation between job1 and job2
+  vineyardctl create operation --name assembly \
+    --type distributed \
+    --require job1 \
+    --target job2 \
+    --timeoutSeconds 600
+
+  # create a dask repartition operation between job1 and job2
+  vineyardctl create operation --name repartition \
+    --type dask \
+    --require job1 \
+    --target job2 \
+    --timeoutSeconds 600
+
+
+
+
+

Options#

+
  -h, --help                 help for operation
+      --kind string          the kind of operation, including "assembly" and "repartition"
+      --name string          the name of operation
+      --require string       the job that need an operation to be executed
+      --target string        the job that need to be executed before this operation
+      --timeoutSeconds int   the timeout seconds of operation (default 600)
+      --type string          the type of operation: for assembly, it can be "local" or "distributed"; for repartition, it can be "dask"
+
+
+
+
+
+

vineyardctl create recover#

+

Create a recover cr to recover the current vineyard cluster on kubernetes

+
+

Synopsis#

+

Recover the current vineyard cluster on kubernetes. You could +recover all objects from a backup of vineyard cluster. Usually, +the recover crd should be created in the same namespace of +the backup job.

+

Notice, the command is used to create a recover cr for the +vineyard operator and you must deploy the vineyard operator +and vineyard cluster before using it.

+
vineyardctl create recover [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # create a recover cr for a backup job in the same namespace
+  vineyardctl create recover --backup-name vineyardd-sample -n vineyard-system
+
+
+
+
+

Options#

+
      --backup-name string    the name of backup job (default "vineyard-backup")
+  -h, --help                  help for recover
+      --recover-name string   the name of recover job (default "vineyard-recover")
+
+
+
+
+
+

vineyardctl delete#

+

Delete the vineyard components from kubernetes

+

SEE ALSO

+ +
+

Examples#

+
  # delete the default vineyard cluster on kubernetes
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config delete
+
+  # delete the default vineyard operator on kubernetes
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config delete operator
+
+  # delete the default cert-manager on kubernetes
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config delete cert-manager
+
+  # delete the default vineyardd on kubernetes
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config delete vineyardd
+
+
+
+
+

Options#

+
  -h, --help   help for delete
+
+
+
+
+
+

vineyardctl delete backup#

+

Delete the backup job on kubernetes

+
+

Synopsis#

+

Delete the backup job on kubernetes.

+
vineyardctl delete backup [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # delete the default backup job
+  vineyardctl delete backup
+
+
+
+
+

Options#

+
      --backup-name string   the name of backup job (default "vineyard-backup")
+  -h, --help                 help for backup
+
+
+
+
+
+

vineyardctl delete cert-manager#

+

Delete the cert-manager on kubernetes

+
+

Synopsis#

+

Delete the cert-manager in the cert-manager namespace. +The default version of cert-manager is v1.9.1.

+
vineyardctl delete cert-manager [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # delete the default version(v1.9.1) of cert-manager
+  vineyardctl --kubeconfig $HOME/.kube/config delete cert-manager
+
+
+
+
+

Options#

+
  -h, --help   help for cert-manager
+
+
+
+
+
+

vineyardctl delete operation#

+

Delete the operation from kubernetes

+
vineyardctl delete operation [flags]
+
+
+

SEE ALSO

+ +
+

Examples#

+
  # delete the operation named "assembly-test" in the "vineyard-system" namespace
+  vineyardctl delete operation --name assembly-test
+
+
+
+
+

Options#

+
  -h, --help          help for operation
+      --name string   the name of operation
+
+
+
+
+
+

vineyardctl delete operator#

+

Delete the vineyard operator from kubernetes

+
vineyardctl delete operator [flags]
+
+
+

SEE ALSO

+ +
+

Examples#

+
  # delete the default vineyard operator in the vineyard-system namespace
+  vineyardctl delete operator
+  
+  # delete the vineyard operator in a specific namespace
+  vineyardctl delete operator -n <namespace>
+
+
+
+
+

Options#

+
  -h, --help   help for operator
+
+
+
+
+
+

vineyardctl delete recover#

+

Delete the recover job from kubernetes

+
vineyardctl delete recover [flags]
+
+
+

SEE ALSO

+ +
+

Examples#

+
  # delete the default recover job on kubernetes
+  vineyardctl delete recover
+
+
+
+
+

Options#

+
  -h, --help                  help for recover
+      --recover-name string   the name of recover job (default "vineyard-recover")
+
+
+
+
+
+

vineyardctl delete vineyard-cluster#

+

Delete the vineyard cluster from kubernetes

+
vineyardctl delete vineyard-cluster [flags]
+
+
+

SEE ALSO

+ +
+

Examples#

+
  # delete the default vineyard cluster on kubernetes
+  vineyardctl delete vineyard-cluster
+
+
+
+
+

Options#

+
  -h, --help   help for vineyard-cluster
+
+
+
+
+
+

vineyardctl delete vineyard-deployment#

+

delete vineyard-deployment will delete the vineyard deployment without vineyard operator

+
vineyardctl delete vineyard-deployment [flags]
+
+
+

SEE ALSO

+ +
+

Examples#

+
  # delete the default vineyard deployment in the vineyard-system namespace
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config delete vineyard-deployment
+
+  # delete the vineyard deployment with specific name in the vineyard-system namespace
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config delete vineyard-deployment \
+    --name vineyardd-0
+
+
+
+
+

Options#

+
  -h, --help          help for vineyard-deployment
+      --name string   the name of vineyardd (default "vineyardd-sample")
+
+
+
+
+
+

vineyardctl delete vineyardd#

+

Delete the vineyardd cluster from kubernetes

+
vineyardctl delete vineyardd [flags]
+
+
+

SEE ALSO

+ +
+

Examples#

+
  # delete the default vineyardd cluster(vineyardd-sample) in the default namespace
+  vineyardctl delete vineyardd
+
+  # delete the specific vineyardd cluster in the vineyard-system namespace
+  vineyardctl -n vineyard-system delete vineyardd --name vineyardd-test
+
+
+
+
+

Options#

+
  -h, --help          help for vineyardd
+      --name string   the name of vineyardd (default "vineyardd-sample")
+
+
+
+
+
+

vineyardctl deploy#

+

Deploy the vineyard components on kubernetes

+

SEE ALSO

+ +
+

Examples#

+
  # deploy the default vineyard cluster on kubernetes
+  vineyardctl --kubeconfig $HOME/.kube/config deploy vineyard-cluster
+
+  # deploy the vineyard operator on kubernetes
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy operator
+
+  # deploy the cert-manager on kubernetes
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy cert-manager
+
+  # deploy the vineyardd on kubernetes
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy vineyardd
+
+
+
+
+

Options#

+
  -h, --help   help for deploy
+
+
+
+
+
+

vineyardctl deploy backup-job#

+

Deploy a backup job of vineyard cluster on kubernetes

+
+

Synopsis#

+

Deploy the backup job for the vineyard cluster on kubernetes, +which will backup all objects of the current vineyard cluster +quickly. For persistent storage, you could specify the pv spec +and pv spec and the related pv and pvc will be created automatically. +Also, you could also specify the existing pv and pvc name to use

+
vineyardctl deploy backup-job [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # deploy a backup job for all vineyard objects of the vineyard
+  # cluster on kubernetes and you could define the pv and pvc
+  # spec from json string as follows
+  vineyardctl deploy backup-job \
+    --vineyard-deployment-name vineyardd-sample \
+    --vineyard-deployment-namespace vineyard-system  \
+    --path /var/vineyard/dump  \
+    --pv-pvc-spec '{
+      "pv-spec": {
+        "capacity": {
+          "storage": "1Gi"
+        },
+        "accessModes": [
+          "ReadWriteOnce"
+        ],
+        "storageClassName": "manual",
+        "hostPath": {
+          "path": "/var/vineyard/dump"
+        }
+      },
+      "pvc-spec": {
+        "storageClassName": "manual",
+        "accessModes": [
+          "ReadWriteOnce"
+        ],
+        "resources": {
+          "requests": {
+          "storage": "1Gi"
+          }
+        }
+      }
+      }'
+
+  # deploy a backup job for the vineyard cluster on kubernetes
+  # you could define the pv and pvc spec from yaml string as follows
+  vineyardctl deploy backup-job \
+    --vineyard-deployment-name vineyardd-sample \
+    --vineyard-deployment-namespace vineyard-system  \
+    --path /var/vineyard/dump  \
+    --pv-pvc-spec  \
+    '
+    pv-spec:
+    capacity:
+      storage: 1Gi
+    accessModes:
+    - ReadWriteOnce
+    storageClassName: manual
+    hostPath:
+      path: "/var/vineyard/dump"
+    pvc-spec:
+    storageClassName: manual
+    accessModes:
+    - ReadWriteOnce
+    resources:
+      requests:
+      storage: 1Gi
+    '
+
+  # deploy a backup job for specific vineyard objects of the vineyard
+  # cluster on kubernetes.
+  cat pv-pvc.json | vineyardctl deploy backup-job \
+    --vineyard-deployment-name vineyardd-sample \
+    --vineyard-deployment-namespace vineyard-system  \
+    --objectIDs "o000018d29207fd01,o000018d80d264010"  \
+    --path /var/vineyard/dump
+    
+  # Assume you have already deployed a pvc named "pvc-sample", you
+  # could use them as the backend storage for the backup job as follows
+  vineyardctl deploy backup-job \
+    --vineyard-deployment-name vineyardd-sample \
+    --vineyard-deployment-namespace vineyard-system  \
+    --path /var/vineyard/dump  \
+    --pvc-name pvc-sample
+  
+  # The namespace to deploy the backup and recover job must be the same
+  # as the vineyard cluster namespace.
+  # Assume the vineyard cluster is deployed in the namespace "test", you
+  # could deploy the backup job as follows
+  vineyardctl deploy backup-job \
+    --vineyard-deployment-name vineyardd-sample \
+    --vineyard-deployment-namespace test  \
+    --namespace test  \
+    --path /var/vineyard/dump  \
+    --pvc-name pvc-sample
+
+
+
+
+

Options#

+
      --backup-name string                     the name of backup job (default "vineyard-backup")
+  -h, --help                                   help for backup-job
+      --objectIDs strings                      the specific objects to be backed up
+      --path string                            the path of the backup data
+      --pv-pvc-spec string                     the PersistentVolume and PersistentVolumeClaim of the backup data
+      --pvc-name string                        the name of an existing PersistentVolumeClaim
+      --vineyard-deployment-name string        the name of vineyard deployment
+      --vineyard-deployment-namespace string   the namespace of vineyard deployment
+
+
+
+
+
+

vineyardctl deploy cert-manager#

+

Deploy the cert-manager on kubernetes

+
+

Synopsis#

+

Deploy the cert-manager in the cert-manager namespace. The default +version of cert-manager is v1.9.1.

+
vineyardctl deploy cert-manager [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # install the default version(v1.9.1) in the cert-manager namespace
+  # wait for the cert-manager to be ready(default option)
+  vineyardctl --kubeconfig $HOME/.kube/config deploy cert-manager
+
+  # install the default version(v1.9.1) in the cert-manager namespace
+  # not to wait for the cert-manager to be ready, but we does not recommend
+  # to do this, because there may be errors caused by the cert-manager
+  # not ready
+  vineyardctl --kubeconfig $HOME/.kube/config deploy cert-manager \
+    --wait=false
+
+
+
+
+

Options#

+
  -h, --help   help for cert-manager
+
+
+
+
+
+

vineyardctl deploy operator#

+

Deploy the vineyard operator on kubernetes

+
+

Synopsis#

+

Deploy the vineyard operator on kubernetes.

+
vineyardctl deploy operator [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # deploy the vineyard operator on the 'vineyard-system' namespace
+  vineyardctl deploy operator
+  
+  # deploy the vineyard operator on the existing namespace
+  vineyardctl deploy operator -n my-custom-namespace
+  
+  # deploy the vineyard operator on the new namespace
+  vineyardctl deploy operator -n a-new-namespace-name --create-namespace
+
+
+
+
+

Options#

+
  -h, --help   help for operator
+
+
+
+
+
+

vineyardctl deploy recover-job#

+

Deploy a recover job to recover a backup of current vineyard cluster on kubernetes

+
+

Synopsis#

+

Deploy the recover job for vineyard cluster on kubernetes, which +will recover all objects from a backup of vineyard cluster. Usually, +the recover job should be created in the same namespace of +the backup job.

+
vineyardctl deploy recover-job [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # Deploy a recover job for the vineyard deployment in the same namespace.
+  # After the recover job finished, the command will create a kubernetes
+  # configmap named [recover-name]+"-mapping-table" that contains the
+  # mapping table from the old vineyard objects to the new ones.
+  #
+  # If you create the recover job as follows, you can get the mapping table via
+  # "kubectl get configmap vineyard-recover-mapping-table -n vineyard-system -o yaml"
+  # the left column is the old object id, and the right column is the new object id.
+  vineyardctl deploy recover-job \
+  --vineyard-deployment-name vineyardd-sample \
+  --vineyard-deployment-namespace vineyard-system  \
+  --recover-path /var/vineyard/dump \
+  --pvc-name vineyard-backup
+
+
+
+
+

Options#

+
  -h, --help                                   help for recover-job
+      --pvc-name string                        the name of an existing PersistentVolumeClaim
+      --recover-name string                    the name of recover job (default "vineyard-recover")
+      --recover-path string                    the path of recover job
+      --vineyard-deployment-name string        the name of vineyard deployment
+      --vineyard-deployment-namespace string   the namespace of vineyard deployment
+
+
+
+
+
+

vineyardctl deploy vineyard-cluster#

+

Deploy the vineyard cluster from kubernetes

+
vineyardctl deploy vineyard-cluster [flags]
+
+
+

SEE ALSO

+ +
+

Examples#

+
  # deploy the default vineyard cluster on kubernetes
+  vineyardctl deploy vineyard-cluster
+
+
+
+
+

Options#

+
  -h, --help   help for vineyard-cluster
+
+
+
+
+
+

vineyardctl deploy vineyard-deployment#

+

DeployVineyardDeployment builds and deploy the yaml file of vineyardd without vineyard operator

+
+

Synopsis#

+

Builds and deploy the yaml file of vineyardd the vineyardd +without vineyard operator. You could deploy a customized +vineyardd from stdin or file.

+
vineyardctl deploy vineyard-deployment [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # deploy the default vineyard deployment on kubernetes
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config \
+  deploy vineyard-deployment
+
+  # deploy the vineyard deployment with customized image
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config \
+  deploy vineyard-deployment --image vineyardcloudnative/vineyardd:v0.12.2
+
+
+
+
+

Options#

+
      --etcd.replicas int                             the number of etcd replicas in a vineyard cluster (default 1)
+  -f, --file string                                   the path of vineyardd
+  -h, --help                                          help for vineyard-deployment
+      --name string                                   the name of vineyardd (default "vineyardd-sample")
+      --owner-references string                       The owner reference of all vineyard deployment resources
+      --pluginImage.backupImage string                the backup image of vineyardd (default "ghcr.io/v6d-io/v6d/backup-job")
+      --pluginImage.daskRepartitionImage string       the dask repartition image of vineyardd workflow (default "ghcr.io/v6d-io/v6d/dask-repartition")
+      --pluginImage.distributedAssemblyImage string   the distributed image of vineyard workflow (default "ghcr.io/v6d-io/v6d/distributed-assembly")
+      --pluginImage.localAssemblyImage string         the local assembly image of vineyardd workflow (default "ghcr.io/v6d-io/v6d/local-assembly")
+      --pluginImage.recoverImage string               the recover image of vineyardd (default "ghcr.io/v6d-io/v6d/recover-job")
+      --replicas int                                  the number of vineyardd replicas (default 3)
+      --vineyardd.cpu string                          the cpu requests and limits of vineyard container
+      --vineyardd.envs strings                        The environment variables of vineyardd
+      --vineyardd.image string                        the image of vineyardd (default "vineyardcloudnative/vineyardd:latest")
+      --vineyardd.imagePullPolicy string              the imagePullPolicy of vineyardd (default "IfNotPresent")
+      --vineyardd.memory string                       the memory requests and limits of vineyard container
+      --vineyardd.metric.enable                       enable metrics of vineyardd
+      --vineyardd.metric.image string                 the metic image of vineyardd (default "vineyardcloudnative/vineyard-grok-exporter:latest")
+      --vineyardd.metric.imagePullPolicy string       the imagePullPolicy of the metric image (default "IfNotPresent")
+      --vineyardd.reserve_memory                      Reserving enough physical memory pages for vineyardd
+      --vineyardd.service.port int                    the service port of vineyard service (default 9600)
+      --vineyardd.service.type string                 the service type of vineyard service (default "ClusterIP")
+      --vineyardd.size string                         The size of vineyardd. You can use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. Defaults "", means not limited
+      --vineyardd.socket string                       The directory on host for the IPC socket file. The namespace and name will be replaced with your vineyard config (default "/var/run/vineyard-kubernetes/{{.Namespace}}/{{.Name}}")
+      --vineyardd.spill.config string                 If you want to enable the spill mechanism, please set the name of spill config
+      --vineyardd.spill.path string                   The path of spill config
+      --vineyardd.spill.pv-pvc-spec string            the json string of the persistent volume and persistent volume claim
+      --vineyardd.spill.spillLowerRate string         The low watermark of spilling memory (default "0.3")
+      --vineyardd.spill.spillUpperRate string         The high watermark of spilling memory (default "0.8")
+      --vineyardd.streamThreshold int                 memory threshold of streams (percentage of total memory) (default 80)
+      --vineyardd.syncCRDs                            enable metrics of vineyardd (default true)
+      --vineyardd.volume.mountPath string             Set the mount path for the pvc
+      --vineyardd.volume.pvcname string               Set the pvc name for storing the vineyard objects persistently
+
+
+
+
+
+

vineyardctl deploy vineyardd#

+

Deploy the vineyardd on kubernetes

+
+

Synopsis#

+

Deploy the vineyardd on kubernetes. You could deploy a +customized vineyardd from stdin or file.

+
vineyardctl deploy vineyardd [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # deploy the default vineyard on kubernetes
+  # wait for the vineyardd to be ready(default option)
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy vineyardd
+
+  # not to wait for the vineyardd to be ready
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy vineyardd \
+    --wait=false
+
+  # deploy the vineyardd from a yaml file
+  vineyardctl --kubeconfig $HOME/.kube/config deploy vineyardd --file vineyardd.yaml
+
+  # deploy the vineyardd with customized image
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy vineyardd \
+    --image vineyardd:v0.12.2
+
+  # deploy the vineyardd with spill mechanism on persistent storage from json string
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy vineyardd \
+    --vineyardd.spill.config spill-path \
+    --vineyardd.spill.path /var/vineyard/spill \
+    --vineyardd.spill.pv-pvc-spec '{
+      "pv-spec": {
+        "capacity": {
+          "storage": "1Gi"
+        },
+        "accessModes": [
+          "ReadWriteOnce"
+        ],
+        "storageClassName": "manual",
+        "hostPath": {
+          "path": "/var/vineyard/spill"
+        }
+      },
+      "pvc-spec": {
+        "storageClassName": "manual",
+        "accessModes": [
+          "ReadWriteOnce"
+        ],
+        "resources": {
+          "requests": {
+          "storage": "512Mi"
+          }
+        }
+      }
+    }'
+
+  # deploy the vineyardd with spill mechanism on persistent storage from yaml string
+  vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy vineyardd \
+    --vineyardd.spill.config spill-path \
+    --vineyardd.spill.path /var/vineyard/spill \
+    --vineyardd.spill.pv-pvc-spec \
+    '
+    pv-spec:
+      capacity:
+      storage: 1Gi
+      accessModes:
+      - ReadWriteOnce
+      storageClassName: manual
+      hostPath:
+      path: "/var/vineyard/spill"
+    pvc-spec:
+      storageClassName: manual
+      accessModes:
+      - ReadWriteOnce
+      resources:
+      requests:
+        storage: 512Mi
+    '
+
+# deploy the vineyardd with spill mechanism on persistent storage from json file
+  # also you could use the yaml file
+  cat pv-pvc.json | vineyardctl -n vineyard-system --kubeconfig $HOME/.kube/config deploy vineyardd \
+    --vineyardd.spill.config spill-path \
+    --vineyardd.spill.path /var/vineyard/spill \
+    -
+
+
+
+
+

Options#

+
      --etcd.replicas int                             the number of etcd replicas in a vineyard cluster (default 1)
+  -f, --file string                                   the path of vineyardd
+  -h, --help                                          help for vineyardd
+      --name string                                   the name of vineyardd (default "vineyardd-sample")
+      --pluginImage.backupImage string                the backup image of vineyardd (default "ghcr.io/v6d-io/v6d/backup-job")
+      --pluginImage.daskRepartitionImage string       the dask repartition image of vineyardd workflow (default "ghcr.io/v6d-io/v6d/dask-repartition")
+      --pluginImage.distributedAssemblyImage string   the distributed image of vineyard workflow (default "ghcr.io/v6d-io/v6d/distributed-assembly")
+      --pluginImage.localAssemblyImage string         the local assembly image of vineyardd workflow (default "ghcr.io/v6d-io/v6d/local-assembly")
+      --pluginImage.recoverImage string               the recover image of vineyardd (default "ghcr.io/v6d-io/v6d/recover-job")
+      --replicas int                                  the number of vineyardd replicas (default 3)
+      --vineyardd.cpu string                          the cpu requests and limits of vineyard container
+      --vineyardd.envs strings                        The environment variables of vineyardd
+      --vineyardd.image string                        the image of vineyardd (default "vineyardcloudnative/vineyardd:latest")
+      --vineyardd.imagePullPolicy string              the imagePullPolicy of vineyardd (default "IfNotPresent")
+      --vineyardd.memory string                       the memory requests and limits of vineyard container
+      --vineyardd.metric.enable                       enable metrics of vineyardd
+      --vineyardd.metric.image string                 the metic image of vineyardd (default "vineyardcloudnative/vineyard-grok-exporter:latest")
+      --vineyardd.metric.imagePullPolicy string       the imagePullPolicy of the metric image (default "IfNotPresent")
+      --vineyardd.reserve_memory                      Reserving enough physical memory pages for vineyardd
+      --vineyardd.service.port int                    the service port of vineyard service (default 9600)
+      --vineyardd.service.type string                 the service type of vineyard service (default "ClusterIP")
+      --vineyardd.size string                         The size of vineyardd. You can use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. Defaults "", means not limited
+      --vineyardd.socket string                       The directory on host for the IPC socket file. The namespace and name will be replaced with your vineyard config (default "/var/run/vineyard-kubernetes/{{.Namespace}}/{{.Name}}")
+      --vineyardd.spill.config string                 If you want to enable the spill mechanism, please set the name of spill config
+      --vineyardd.spill.path string                   The path of spill config
+      --vineyardd.spill.pv-pvc-spec string            the json string of the persistent volume and persistent volume claim
+      --vineyardd.spill.spillLowerRate string         The low watermark of spilling memory (default "0.3")
+      --vineyardd.spill.spillUpperRate string         The high watermark of spilling memory (default "0.8")
+      --vineyardd.streamThreshold int                 memory threshold of streams (percentage of total memory) (default 80)
+      --vineyardd.syncCRDs                            enable metrics of vineyardd (default true)
+      --vineyardd.volume.mountPath string             Set the mount path for the pvc
+      --vineyardd.volume.pvcname string               Set the pvc name for storing the vineyard objects persistently
+
+
+
+
+
+

vineyardctl get#

+

Get vineyard objects, metadatas, blobs or cluster-info

+

SEE ALSO

+ +
+

Examples#

+
  # Connect the vineyardd deployment with IPC client
+  # Get the cluster info and output as table
+  vineyardctl get cluster-info --deployment-name vineyardd-sample -n vineyard-system
+
+
+
+
+

Options#

+
  -h, --help   help for get
+
+
+
+
+
+

vineyardctl get cluster-info#

+

Get vineyard cluster info

+
+

Synopsis#

+

Get vineyard cluster info, including +the instanceId, hostName, node name and so on.

+
vineyardctl get cluster-info [flags]
+
+
+

SEE ALSO

+
    +
  • vineyardctl get - Get vineyard objects, metadatas, blobs or cluster-info

  • +
+
+
+

Examples#

+
  # Get the cluster info of vineyard deployment and output as table
+  vineyardctl get cluster-info --deployment-name vineyardd-sample -n vineyard-system
+
+  # Get the cluster info of vineyard deployment and output as json
+  vineyardctl get cluster-info --deployment-name vineyardd-sample -n vineyard-system -o json
+  
+  # Get the cluster info via IPC socket
+  vineyardctl get cluster-info --ipc-socket /var/run/vineyard.sock
+
+
+
+
+

Options#

+
      --deployment-name string   the name of vineyard deployment
+  -o, --format string            the output format, support table or json, default is table (default "table")
+      --forward-port int         the forward port of vineyard deployment (default 9600)
+  -h, --help                     help for cluster-info
+      --ipc-socket string        vineyard IPC socket path
+      --port int                 the port of vineyard deployment (default 9600)
+      --rpc-socket string        vineyard RPC socket path
+
+
+
+
+
+

vineyardctl inject#

+

Inject the vineyard sidecar container into a workload

+
+

Synopsis#

+

Inject the vineyard sidecar container into a workload. You can +input a workload yaml or a workload json and then get the injected +workload and some etcd manifests from the output. The workload can +be a pod or a deployment or a statefulset, etc.

+

The output is a set of manifests that includes the injected workload, +the rpc service, the etcd service and the etcd cluster(e.g. several +pods and services).

+

If you have a pod yaml:

+
apiVersion: v1
+kind: Pod
+metadata:
+  name: python
+spec:
+  containers:
+  - name: python
+    image: python:3.10
+    command: ["python", "-c", "import time; time.sleep(100000)"]
+
+
+

Then, you can use the following command to inject the vineyard sidecar

+

$ vineyardctl inject -f pod.yaml

+

After running the command, the output is as follows:

+
apiVersion: v1
+kind: Pod
+metadata:
+  labels:
+    app.vineyard.io/name: vineyard-sidecar
+    app.vineyard.io/role: etcd
+    etcd_node: vineyard-sidecar-etcd-0
+  name: vineyard-sidecar-etcd-0
+  namespace: null
+  ownerReferences: []
+spec:
+  containers:
+  - command:
+    - etcd
+    - --name
+    - vineyard-sidecar-etcd-0
+    - --initial-advertise-peer-urls
+    - http://vineyard-sidecar-etcd-0:2380
+    - --advertise-client-urls
+    - http://vineyard-sidecar-etcd-0:2379
+    - --listen-peer-urls
+    - http://0.0.0.0:2380
+    - --listen-client-urls
+    - http://0.0.0.0:2379
+    - --initial-cluster
+    - vineyard-sidecar-etcd-0=http://vineyard-sidecar-etcd-0:2380
+    - --initial-cluster-state
+    - new
+    image: vineyardcloudnative/vineyardd:latest
+    name: etcd
+    ports:
+    - containerPort: 2379
+      name: client
+      protocol: TCP
+    - containerPort: 2380
+      name: server
+      protocol: TCP
+  restartPolicy: Always
+---
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    etcd_node: vineyard-sidecar-etcd-0
+  name: vineyard-sidecar-etcd-0
+  namespace: null
+  ownerReferences: []
+spec:
+  ports:
+  - name: client
+    port: 2379
+    protocol: TCP
+    targetPort: 2379
+  - name: server
+    port: 2380
+    protocol: TCP
+    targetPort: 2380
+  selector:
+    app.vineyard.io/role: etcd
+    etcd_node: vineyard-sidecar-etcd-0
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: vineyard-sidecar-etcd-service
+  namespace: null
+  ownerReferences: []
+spec:
+  ports:
+  - name: vineyard-sidecar-etcd-for-vineyard-port
+    port: 2379
+    protocol: TCP
+    targetPort: 2379
+  selector:
+    app.vineyard.io/name: vineyard-sidecar
+    app.vineyard.io/role: etcd
+---
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    app.vineyard.io/name: vineyard-sidecar
+  name: vineyard-sidecar-rpc
+  namespace: null
+  ownerReferences: []
+spec:
+  ports:
+  - name: vineyard-rpc
+    port: 9600
+    protocol: TCP
+  selector:
+    app.vineyard.io/name: vineyard-sidecar
+    app.vineyard.io/role: vineyardd
+  type: ClusterIP
+---
+apiVersion: v1
+kind: Pod
+metadata:
+  creationTimestamp: null
+  labels:
+    app.vineyard.io/name: vineyard-sidecar
+    app.vineyard.io/role: vineyardd
+  name: python
+  ownerReferences: []
+spec:
+  containers:
+  - command:
+    - python
+    - -c
+    - while [ ! -e /var/run/vineyard.sock ]; do sleep 1; done;import time; time.sleep(100000)
+    env:
+    - name: VINEYARD_IPC_SOCKET
+      value: /var/run/vineyard.sock
+    image: python:3.10
+    name: python
+    resources: {}
+    volumeMounts:
+    - mountPath: /var/run
+      name: vineyard-socket
+  - command:
+    - /bin/bash
+    - -c
+    - |
+      /usr/bin/wait-for-it.sh -t 60 vineyard-sidecar-etcd-service..svc.cluster.local:2379; \
+      sleep 1; /usr/local/bin/vineyardd --sync_crds true --socket /var/run/vineyard.sock --size \
+      --stream_threshold 80 --etcd_cmd etcd --etcd_prefix /vineyard --etcd_endpoint http://vineyard-sidecar-etcd-service:2379
+    env:
+    - name: VINEYARDD_UID
+      value: null
+    - name: VINEYARDD_NAME
+      value: vineyard-sidecar
+    - name: VINEYARDD_NAMESPACE
+      value: null
+    image: vineyardcloudnative/vineyardd:latest
+    imagePullPolicy: IfNotPresent
+    name: vineyard-sidecar
+    ports:
+    - containerPort: 9600
+      name: vineyard-rpc
+      protocol: TCP
+    resources:
+      limits: null
+      requests: null
+    volumeMounts:
+    - mountPath: /var/run
+      name: vineyard-socket
+  volumes:
+  - emptyDir: {}
+    name: vineyard-socket
+status: {}
+
+
+

Next, we will introduce a simple example to show the injection with +the apply-resources flag.

+

Assume you have the following workload yaml:

+
apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: nginx-deployment
+    # Notice, you must set the namespace here
+  namespace: vineyard-job
+spec:
+  selector:
+    matchLabels:
+      app: nginx
+  template:
+    metadata:
+      labels:
+        app: nginx
+    spec:
+      containers:
+      - name: nginx
+        image: nginx:1.14.2
+        ports:
+        - containerPort: 80
+
+
+

Then, you can use the following command to inject the vineyard sidecar +which means that all resources will be created during the injection except +the workload itself. The workload should be created by users.

+

$ vineyardctl inject -f workload.yaml –apply-resources

+

After running the command, the main output(removed some unnecessary fields) +is as follows:

+
apiVersion: apps/v1
+kind: Deployment
+metadata:
+  creationTimestamp: null
+  name: nginx-deployment
+  namespace: vineyard-job
+spec:
+  selector:
+    matchLabels:
+      app: nginx
+template:
+  metadata:
+  labels:
+    app: nginx
+    # the default sidecar name is vineyard-sidecar
+    app.vineyard.io/name: vineyard-sidecar
+  spec:
+    containers:
+    - command: null
+      image: nginx:1.14.2
+      name: nginx
+      ports:
+      - containerPort: 80
+      volumeMounts:
+      - mountPath: /var/run
+        name: vineyard-socket
+    - command:
+      - /bin/bash
+      - -c
+      - |
+        /usr/bin/wait-for-it.sh -t 60 vineyard-sidecar-etcd-service.vineyard-job.svc.cluster.local:2379; \
+        sleep 1; /usr/local/bin/vineyardd --sync_crds true --socket /var/run/vineyard.sock \
+        --stream_threshold 80 --etcd_cmd etcd --etcd_prefix /vineyard \
+        --etcd_endpoint http://vineyard-sidecar-etcd-service:2379
+      env:
+      - name: VINEYARDD_UID
+        value: null
+      - name: VINEYARDD_NAME
+        value: vineyard-sidecar
+      - name: VINEYARDD_NAMESPACE
+        value: vineyard-job
+      image: vineyardcloudnative/vineyardd:latest
+      imagePullPolicy: IfNotPresent
+      name: vineyard-sidecar
+      ports:
+      - containerPort: 9600
+        name: vineyard-rpc
+        protocol: TCP
+      volumeMounts:
+      - mountPath: /var/run
+        name: vineyard-socket
+    volumes:
+    - emptyDir: {}
+      name: vineyard-socket
+
+
+

The sidecar template can be accessed from the following link: +https://github.com/v6d-io/v6d/blob/main/k8s/pkg/templates/sidecar/injection-template.yaml +also you can get some inspiration from the doc link: +https://v6d.io/notes/cloud-native/vineyard-operator.html#installing-vineyard-as-sidecar

+
vineyardctl inject [flags]
+
+
+

SEE ALSO

+
    +
  • vineyardctl - vineyardctl is the command-line tool for interact with the Vineyard Operator.

  • +
+
+
+

Examples#

+
  # use json format to output the injected workload
+  # notice that the output is a json string of all manifests
+  # it looks like:
+  # {
+  #   "workload": "workload json string",
+  #   "rpc_service": "rpc service json string",
+  #   "etcd_service": "etcd service json string",
+  #   "etcd_internal_service": [
+  #     "etcd internal service json string 1",
+  #     "etcd internal service json string 2",
+  #     "etcd internal service json string 3"
+  #   ],
+  #   "etcd_pod": [
+  #     "etcd pod json string 1",
+  #     "etcd pod json string 2",
+  #     "etcd pod json string 3"
+  #   ]
+  # }
+  vineyardctl inject -f workload.yaml -o json
+
+  # inject the default vineyard sidecar container into a workload
+  # output all injected manifests and then deploy them
+  vineyardctl inject -f workload.yaml | kubectl apply -f -
+
+  # if you only want to get the injected workload yaml rather than
+  # all manifests that includes the etcd cluster and the rpc service,
+  # you can enable the apply-resources and then the manifests will be
+  # created during the injection, finally you will get the injected
+  # workload yaml
+  vineyardctl inject -f workload.yaml --apply-resources
+
+
+
+
+

Options#

+
      --apply-resources                         Whether to apply the resources including the etcd cluster and the rpc service if you enable this flag, the etcd cluster and the rpc service will be created during the injection
+      --etcd-replicas int                       The number of etcd replicas (default 1)
+  -f, --file string                             The yaml of workload
+  -h, --help                                    help for inject
+      --name string                             The name of sidecar (default "vineyard-sidecar")
+  -o, --output string                           The output format of the command, support yaml and json (default "yaml")
+      --owner-references string                 The owner reference of all injectied resources
+      --resource string                         The resource of workload
+      --sidecar.cpu string                      the cpu requests and limits of vineyard container
+      --sidecar.envs strings                    The environment variables of vineyardd
+      --sidecar.image string                    the image of vineyardd (default "vineyardcloudnative/vineyardd:latest")
+      --sidecar.imagePullPolicy string          the imagePullPolicy of vineyardd (default "IfNotPresent")
+      --sidecar.memory string                   the memory requests and limits of vineyard container
+      --sidecar.metric.enable                   enable metrics of vineyardd
+      --sidecar.metric.image string             the metic image of vineyardd (default "vineyardcloudnative/vineyard-grok-exporter:latest")
+      --sidecar.metric.imagePullPolicy string   the imagePullPolicy of the metric image (default "IfNotPresent")
+      --sidecar.reserve_memory                  Reserving enough physical memory pages for vineyardd
+      --sidecar.service.port int                the service port of vineyard service (default 9600)
+      --sidecar.service.type string             the service type of vineyard service (default "ClusterIP")
+      --sidecar.size string                     The size of vineyardd. You can use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. Defaults "", means not limited
+      --sidecar.socket string                   The directory on host for the IPC socket file. The namespace and name will be replaced with your vineyard config (default "/var/run/vineyard-kubernetes/{{.Namespace}}/{{.Name}}")
+      --sidecar.spill.config string             If you want to enable the spill mechanism, please set the name of spill config
+      --sidecar.spill.path string               The path of spill config
+      --sidecar.spill.pv-pvc-spec string        the json string of the persistent volume and persistent volume claim
+      --sidecar.spill.spillLowerRate string     The low watermark of spilling memory (default "0.3")
+      --sidecar.spill.spillUpperRate string     The high watermark of spilling memory (default "0.8")
+      --sidecar.streamThreshold int             memory threshold of streams (percentage of total memory) (default 80)
+      --sidecar.syncCRDs                        enable metrics of vineyardd (default true)
+      --sidecar.volume.mountPath string         Set the mount path for the pvc
+      --sidecar.volume.pvcname string           Set the pvc name for storing the vineyard objects persistently
+
+
+
+
+
+

vineyardctl ls#

+

List vineyard objects, metadatas or blobs

+

SEE ALSO

+ +
+

Examples#

+
  # Connect the vineyardd server with IPC client
+  # List the vineyard objects no more than 10
+  vineyardctl ls objects --limit 10 --ipc-socket /var/run/vineyard.sock
+
+  # List the vineyard blobs no more than 10
+  vineyardctl ls blobs --limit 10 --ipc-socket /var/run/vineyard.sock
+
+  # List the vineyard objects with the specified pattern
+  vineyardctl ls objects --pattern "vineyard::Tensor<.*>" --regex --ipc-socket /var/run/vineyard.sock
+
+  # Connect the vineyardd server with RPC client
+  # List the vineyard metadatas no more than 1000
+  vineyardctl ls metadatas --rpc-socket 127.0.0.1:9600 --limit 1000
+
+  # Connect the vineyard deployment with PRC client
+  # List the vineyard objects no more than 1000
+  vineyardctl ls objects --deployment-name vineyardd-sample -n vineyard-system
+
+
+
+
+

Options#

+
  -h, --help   help for ls
+
+
+
+
+
+

vineyardctl ls blobs#

+

List vineyard blobs

+
+

Synopsis#

+

List vineyard blobs and only support IPC socket. +If you don’t specify the ipc socket every time, you can set it as the +environment variable VINEYARD_IPC_SOCKET.

+
vineyardctl ls blobs [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # List no more than 10 vineyard blobs
+  vineyardctl ls blobs --limit 10 --ipc-socket /var/run/vineyard.sock
+
+  # List no more than 1000 vineyard blobs
+  vineyardctl ls blobs --ipc-socket /var/run/vineyard.sock --limit 1000
+  
+  # List vineyard blobs with the name matching
+  vineyardctl ls blobs --pattern "vineyard::Tensor<.*>" --regex --ipc-socket /var/run/vineyard.sock
+  
+  # List vineyard blobs with the regex pattern
+  vineyardctl ls blobs --pattern "*DataFrame*" --ipc-socket /var/run/vineyard.sock
+  
+  # If you set the environment variable VINEYARD_IPC_SOCKET
+  # you can use the following command to list vineyard blobs
+  vineyardctl ls blobs --limit 1000
+
+
+
+
+

Options#

+
      --deployment-name string   the name of vineyard deployment
+  -o, --format string            the output format, support table or json, default is table (default "table")
+      --forward-port int         the forward port of vineyard deployment (default 9600)
+  -h, --help                     help for blobs
+      --ipc-socket string        vineyard IPC socket path
+  -l, --limit int                maximum number of objects to return (default 5)
+      --port int                 the port of vineyard deployment (default 9600)
+      --rpc-socket string        vineyard RPC socket path
+
+
+
+
+
+

vineyardctl ls metadatas#

+

List vineyard metadatas

+
+

Synopsis#

+

List vineyard metadatas and support IPC socket, +RPC socket and vineyard deployment. If you don’t specify the ipc socket or rpc socket +every time, you can set it as the environment variable VINEYARD_IPC_SOCKET or +VINEYARD_RPC_SOCKET.

+
vineyardctl ls metadatas [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # List no more than 10 vineyard metadatas
+  vineyardctl ls metadatas --limit 10 --ipc-socket /var/run/vineyard.sock
+  
+  # List no more than 1000 vineyard metadatas
+  vineyardctl ls metadatas --rpc-socket 127.0.0.1:9600 --limit 1000
+  
+  # List vineyard metadatas with the name matching the regex pattern
+  vineyardctl ls metadatas --pattern "vineyard::Blob" --ipc-socket /var/run/vineyard.sock
+
+  # List vineyard metadatas of the vineyard deployment
+  vineyardctl ls metadatas --deployment-name vineyardd-sample -n vineyard-system --limit 1000
+  
+  # List vineyard metadatas sorted by the instance id
+  vineyardctl ls metadatas --sorted-key instance_id --limit 1000 --ipc-socket /var/run/vineyard.sock
+
+  # List vineyard metadatas sorted by the type and print the output as json format
+  vineyardctl ls metadatas --sorted-key type --limit 1000 --format json --ipc-socket /var/run/vineyard.sock
+
+
+
+
+

Options#

+
      --deployment-name string   the name of vineyard deployment
+  -o, --format string            the output format, support table or json, default is table (default "table")
+      --forward-port int         the forward port of vineyard deployment (default 9600)
+  -h, --help                     help for metadatas
+      --ipc-socket string        vineyard IPC socket path
+  -l, --limit int                maximum number of objects to return (default 5)
+  -p, --pattern string           string that will be matched against the object’s typenames (default "*")
+      --port int                 the port of vineyard deployment (default 9600)
+  -r, --regex                    regex pattern to match the object’s typenames
+      --rpc-socket string        vineyard RPC socket path
+  -k, --sorted-key string        key to sort the objects, support:
+                                 - id: object id, the default value.
+                                 - typename: object typename, e.g. tensor, dataframe, etc.
+                                 - type: object type, e.g. global, local, etc.
+                                 - instance_id: object instance id. (default "id")
+
+
+
+
+
+

vineyardctl ls objects#

+

List vineyard objects

+
+

Synopsis#

+

List vineyard objects and support IPC socket, +RPC socket and vineyard deployment. If you don’t specify the ipc socket or rpc socket +every time, you can set it as the environment variable VINEYARD_IPC_SOCKET or +VINEYARD_RPC_SOCKET.

+
vineyardctl ls objects [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # List no more than 10 vineyard objects
+  vineyardctl ls objects --limit 10 --ipc-socket /var/run/vineyard.sock
+
+  # List any vineyard objects and no more than 1000 objects
+  vineyardctl ls objects --pattern "*" --ipc-socket /var/run/vineyard.sock --limit 1000
+
+  # List vineyard objects with the name matching the regex pattern
+  vineyardctl ls objects --pattern "vineyard::Tensor<.*>" --regex --ipc-socket /var/run/vineyard.sock
+
+  # List vineyard objects and output as json format
+  vineyardctl ls objects --format json --ipc-socket /var/run/vineyard.sock
+
+  # List vineyard objects sorted by the typename
+  vineyardctl ls objects --sorted-key typename --limit 1000 --ipc-socket /var/run/vineyard.sock
+
+
+
+
+

Options#

+
      --deployment-name string   the name of vineyard deployment
+  -o, --format string            the output format, support table or json, default is table (default "table")
+      --forward-port int         the forward port of vineyard deployment (default 9600)
+  -h, --help                     help for objects
+      --ipc-socket string        vineyard IPC socket path
+  -l, --limit int                maximum number of objects to return (default 5)
+  -p, --pattern string           string that will be matched against the object’s typenames (default "*")
+      --port int                 the port of vineyard deployment (default 9600)
+  -r, --regex                    regex pattern to match the object’s typenames
+      --rpc-socket string        vineyard RPC socket path
+  -k, --sorted-key string        key to sort the objects, support:
+                                 - id: object id, the default value.
+                                 - typename: object typename, e.g. tensor, dataframe, etc.
+                                 - type: object type, e.g. global, local, etc.
+                                 - instance_id: object instance id. (default "id")
+
+
+
+
+
+

vineyardctl manager#

+

Start the manager of vineyard operator

+
vineyardctl manager [flags]
+
+
+

SEE ALSO

+
    +
  • vineyardctl - vineyardctl is the command-line tool for interact with the Vineyard Operator.

  • +
+
+

Examples#

+
  # start the manager of vineyard operator with default configuration
+  # (Enable the controller, webhooks and scheduler)
+  vineyardctl manager
+
+  # start the manager of vineyard operator without webhooks
+  vineyardctl manager --enable-webhook=false
+
+  # start the manager of vineyard operator without scheduler
+  vineyardctl manager --enable-scheduler=false
+
+  # only start the controller
+  vineyardctl manager --enable-webhook=false --enable-scheduler=false
+
+
+
+
+

Options#

+
      --enable-scheduler                   Enable scheduler for controller manager. (default true)
+      --enable-webhook                     Enable webhook for controller manager. (default true)
+      --health-probe-bind-address string   The address the probe endpoint binds to. (default ":8081")
+  -h, --help                               help for manager
+      --leader-elect                       Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.
+      --metrics-bind-address string        The address the metric endpoint binds to. (default "127.0.0.1:8080")
+      --scheduler-config-file string       The location of scheduler plugin's configuration file. (default "/etc/kubernetes/scheduler.yaml")
+
+
+
+
+
+

vineyardctl schedule#

+

Schedule a workload or a workflow to existing vineyard cluster.

+

SEE ALSO

+ +
+

Examples#

+
  # Schedule a workload to a vineyard cluster
+  # it will add PodAffinity to the workload
+  vineyardctl schedule workload --resource '{kubernetes workload json string}'
+
+  # schedule a workflow to the vineyard cluster
+  # it will use the best-effort scheduling strategy
+  vineyardctl schedule workflow --file workflow.yaml
+
+
+
+
+

Options#

+
  -h, --help   help for schedule
+
+
+
+
+
+

vineyardctl schedule workflow#

+

Schedule a workflow based on the vineyard cluster

+
+

Synopsis#

+

Schedule a workflow based on the vineyard cluster. +It will apply the workflow to kubernetes cluster and deploy the workload +of the workflow on the vineyard cluster with the best-fit strategy.

+
vineyardctl schedule workflow [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # schedule a workflow to the vineyard cluster with the best-fit strategy
+  vineyardctl schedule workflow --file workflow.yaml
+  
+  # schedule a workflow without CRD installed
+  # Notice, it only works for the workflow built by pods
+  vineyardctl schedule workflow --file pod-workflow.yaml --without-crd
+
+
+
+
+

Options#

+
  -f, --file string   the path of workflow file
+  -h, --help          help for workflow
+      --without-crd   whether the CRD(especially for GlobalObject and LocalObject) is installed
+
+
+
+
+
+

vineyardctl schedule workload#

+

Schedule the workload to a vineyard cluster

+
+

Synopsis#

+

Schedule the workload to a vineyard cluster. +It will add the podAffinity to the workload so that the workload +will be scheduled to the vineyard cluster. Besides, if the workload +does not have the socket volumeMount and volume, it will add one.

+

Assume you have the following workload yaml:

+
apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: python-client
+  # Notice, you must set the namespace here
+  namespace: vineyard-job
+spec:
+  selector:
+    matchLabels:
+      app: python
+  template:
+    metadata:
+      labels:
+        app: python
+    spec:
+      containers:
+      - name: python
+        image: python:3.10
+        command: ["python", "-c", "import time; time.sleep(100000)"]
+
+
+

Then you can run the following command to add the podAffinity and socket volume +to the workload yaml:

+

$ vineyard schedule workload -f workload.yaml -o yaml

+

After that, you will get the following workload yaml:

+
apiVersion: apps/v1
+kind: Deployment
+metadata:
+  creationTimestamp: null
+  name: python-client
+  namespace: vineyard-job
+spec:
+  selector:
+    matchLabels:
+      app: python
+  strategy: {}
+  template:
+   metadata:
+      creationTimestamp: null
+      labels:
+        app: python
+    spec:
+      affinity:
+        podAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+          - labelSelector:
+              matchExpressions:
+              - key: app.kubernetes.io/instance
+                operator: In
+                values:
+                - vineyard-system-vineyardd-sample
+            namespaces:
+            - vineyard-system
+            topologyKey: kubernetes.io/hostname
+
+      containers:
+      - command:
+        - python
+        - -c
+        - import time; time.sleep(100000)
+        env:
+        - name: VINEYARD_IPC_SOCKET
+          value: /var/run/vineyard.sock
+        image: python:3.10
+        name: python
+        resources: {}
+        volumeMounts:
+        - mountPath: /var/run
+          name: vineyard-socket
+      volumes:
+      - hostPath:
+          path: /var/run/vineyard-kubernetes/vineyard-system/vineyardd-sample
+        name: vineyard-socket
+
+
+
vineyardctl schedule workload [flags]
+
+
+

SEE ALSO

+ +
+
+

Examples#

+
  # Add the podAffinity to the workload yaml
+  vineyardctl schedule workload -f workload.yaml \
+  --vineyardd-name vineyardd-sample \
+  --vineyardd-namespace vineyard-system
+
+  # Add the podAffinity to the workload for the specific vineyard cluster
+  vineyardctl schedule workload --resource '{
+    "apiVersion": "apps/v1",
+    "kind": "Deployment",
+    "metadata": {
+      "name": "web-server"
+    },
+    "spec": {
+      "selector": {
+      "matchLabels": {
+        "app": "web-store"
+      }
+      },
+      "replicas": 3,
+      "template": {
+      "metadata": {
+        "labels": {
+        "app": "web-store"
+        }
+      },
+      "spec": {
+        "affinity": {
+        "podAntiAffinity": {
+          "requiredDuringSchedulingIgnoredDuringExecution": [
+          {
+            "labelSelector": {
+            "matchExpressions": [
+              {
+              "key": "app",
+              "operator": "In",
+              "values": [
+                "web-store"
+              ]
+              }
+            ]
+            },
+            "topologyKey": "kubernetes.io/hostname"
+          }
+          ]
+        },
+        "podAffinity": {
+          "requiredDuringSchedulingIgnoredDuringExecution": [
+          {
+            "labelSelector": {
+            "matchExpressions": [
+              {
+              "key": "app",
+              "operator": "In",
+              "values": [
+                "store"
+              ]
+              }
+            ]
+            },
+            "topologyKey": "kubernetes.io/hostname"
+          }
+          ]
+        }
+        },
+        "containers": [
+        {
+          "name": "web-app",
+          "image": "nginx:1.16-alpine"
+        }
+        ]
+      }
+      }
+    }
+    }' \
+    --vineyardd-name vineyardd-sample \
+    --vineyardd-namespace vineyard-system
+
+
+
+
+

Options#

+
  -f, --file string                  the file path of workload
+  -h, --help                         help for workload
+  -o, --output string                the output format for vineyardctl schedule workload command (default "json")
+      --resource string              the json string of kubernetes workload
+      --vineyardd-name string        the namespace of vineyard cluster (default "vineyardd-sample")
+      --vineyardd-namespace string   the namespace of vineyard cluster (default "vineyard-system")
+
+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/developers.html b/notes/developers.html new file mode 100644 index 0000000000..7f6da4233c --- /dev/null +++ b/notes/developers.html @@ -0,0 +1,506 @@ + + + + + + + + + + + + + + + + + + + Getting Involved - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Getting Involved#

+
+
+

Vineyard is an open-source project that was accepted into the CNCF sandbox in April 2021. +It has been successfully developed and maintained by the open-source community. We are +committed to engaging community members to help us improve Vineyard. You will find our +community welcoming and responsive by joining our Github discussions or Slack channel:

+
+
+
+ +
+
+
+
+

Slack

+

+
+
+
+
+
+

To modify the Vineyard source code, you will need to set up the development environment +and build the project from source. Follow the instructions below:

+
+
+ +
+
+

If you encounter any issues during your journey with Vineyard, you may find solutions in:

+
+
+
+ +
+
+ +
+
+
+

We also have a public roadmap that outlines our future goals and highlights our ongoing efforts:

+
+
+
+
+ +
+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/developers/build-from-source.html b/notes/developers/build-from-source.html new file mode 100644 index 0000000000..bf732b996a --- /dev/null +++ b/notes/developers/build-from-source.html @@ -0,0 +1,625 @@ + + + + + + + + + + + + + + + + + + + Building from source - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Building from source#

+
+

Install vineyard#

+

Vineyard is distributed as a python package +and can be easily installed with pip:

+
pip3 install vineyard
+
+
+
+
+

Install etcd#

+

Vineyard is based on etcd, please refer the doc to install it.

+
+
+

Install from source#

+

Vineyard is open source on Github: https://github.com/v6d-io/v6d. +You can obtain the source code using git:

+
git clone https://github.com/v6d-io/v6d
+cd v6d
+git submodule update --init
+
+
+
+

Prepare dependencies#

+

Vineyard can be built and deployed on common Unix-like systems. Vineyard has been +fully tests with C++ compilers that supports C++ 14.

+
+

Dependencies#

+

Vineyard requires the following software as dependencies to build and run:

+
    +
  • apache-arrow >= 3.0.0

  • +
  • gflags

  • +
  • glog

  • +
  • boost

  • +
  • mpi, for the graph data structure module

  • +
+

If you want to build the vineyard server, the following additional libraries are needed:

+
    +
  • protobuf

  • +
  • grpc

  • +
+

And the following python packages are required:

+
    +
  • libclang

    +

    Can be installed using pip

    +
    pip3 install libclang
    +
    +
    +
  • +
+
+
+

Install on Ubuntu (or Debian)#

+

Vineyard has been fully tested on Ubuntu 20.04. The dependencies can be installed by

+
apt-get install -y ca-certificates \
+                   cmake \
+                   doxygen \
+                   libboost-all-dev \
+                   libcurl4-openssl-dev \
+                   libgflags-dev \
+                   libgoogle-glog-dev \
+                   libgrpc-dev \
+                   libgrpc++-dev \
+                   libmpich-dev \
+                   libprotobuf-dev \
+                   libssl-dev \
+                   libunwind-dev \
+                   libz-dev \
+                   protobuf-compiler-grpc \
+                   python3-pip \
+                   wget
+
+
+

Then install the apache-arrow (see also https://arrow.apache.org/install):

+
wget https://apache.jfrog.io/artifactory/arrow/$(lsb_release --id --short | tr 'A-Z' 'a-z')/apache-arrow-apt-source-latest-$(lsb_release --codename --short).deb \
+    -O /tmp/apache-arrow-apt-source-latest-$(lsb_release --codename --short).deb
+apt install -y -V /tmp/apache-arrow-apt-source-latest-$(lsb_release --codename --short).deb
+apt update -y
+apt install -y libarrow-dev
+
+
+
+
+

Dependencies on MacOS#

+

Vineyard has been tested on MacOS as well, the dependencies can be installed using brew:

+
brew install apache-arrow boost gflags glog grpc protobuf llvm mpich openssl zlib autoconf
+
+
+
+
+
+

Building vineyard#

+

After the required dependencies are installed, you do an out-of-source build using CMake:

+
+

Tip

+

We recommend to use the brew installed LLVM as the compiler for building vineyard on MacOS, +which can be accomplished by setting the environment variable CC and CXX:

+
export CC=$(brew --prefix llvm)/bin/clang
+export CXX=$(brew --prefix llvm)/bin/clang++
+
+
+
+
mkdir build
+cd build
+cmake ..
+make -j$(nproc)
+sudo make install  # optionally
+
+
+

You will see vineyard server binary under the bin directory, and static or shared linked +libraries will be placed under the lib-shared folder.

+
+
+

Building python wheels#

+

After building the vineyard library successfully, you can package an install wheel distribution by

+
python3 setup.py bdist_wheel
+
+
+
+
+
+

Install vineyardctl#

+

Vineyardctl is available on the Github release page, you can download the binary as follows:

+
export LATEST_TAG=$(curl -s "https://api.github.com/repos/v6d-io/v6d/tags" | jq -r '.[0].name')
+export OS=$(uname -s | tr '[:upper:]' '[:lower:]')
+export ARCH=${$(uname -m)/x86_64/amd64}
+curl -Lo vineyardctl https://github.com/v6d-io/v6d/releases/download/$LATEST_TAG/vineyardctl-$LATEST_TAG-$OS-$ARCH
+chmod +x vineyardctl
+sudo mv vineyardctl /usr/local/bin/
+
+
+
+
+

Building the documentation#

+

Vineyard documentation is organized and generated by sphinx. There are other packages that +help us build the documentation, which can be easily installed using pip:

+
pip3 install -r requirements.txt -r requirements-dev.txt
+
+
+

Once installed, you could go to the docs/ directory and build the documentation by

+
cd docs/  # skip if you are already there
+make html
+
+
+
+
+

Building on various platforms#

+

Vineyard is continuously tested on various platforms and you may find building and installation steps +from our CI:

+ +
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/developers/contributing.html b/notes/developers/contributing.html new file mode 100644 index 0000000000..39872e5773 --- /dev/null +++ b/notes/developers/contributing.html @@ -0,0 +1,664 @@ + + + + + + + + + + + + + + + + + + + Contributing to vineyard - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Contributing to vineyard#

+

Vineyard is the product of a dedicated team of software engineers and +researchers. We warmly welcome contributions from the open-source community to +enhance and refine this project!

+

Vineyard is licensed under the Apache License 2.0.

+
+

Install development dependencies#

+

Vineyard requires the following C++ packages for development:

+
    +
  • apache-arrow >= 0.17.1

  • +
  • gflags

  • +
  • glog

  • +
  • boost

  • +
  • protobuf

  • +
  • grpc

  • +
+

and the following python packages that can be easily installed using pip:

+
    +
  • libclang

  • +
  • parsec

  • +
+
+
+

Developing Vineyard Using Docker#

+

To streamline the dependency installation process, we offer a pre-built Docker +image containing all necessary requirements. You can find this image at +vineyardcloudnative/vineyard-dev.

+
docker pull vineyardcloudnative/vineyard-dev:latest
+
+
+
+
+

Build the source#

+

You can do an out-of-source build using CMake:

+
mkdir build
+cd build
+cmake ..
+make -j$(nproc)
+
+
+

The vineyardd target will be generated under the bin directory.

+

You may find building and installation instructions for other platforms from our CI:

+ +
+
+

Running Unit Tests#

+

Vineyard incorporates a comprehensive set of unit tests within its continuous integration +process. To build these test cases, execute the following command:

+
cd build
+make vineyard_tests -j$(nproc)
+
+
+

Before running the test cases, ensure that etcd is properly installed by executing +brew install etcd on macOS or pip3 install etcd_distro on Linux distributions.

+

A dedicated script is provided to set up the required environments and execute the test cases:

+
./test/runner.py --help
+usage: runner.py [-h] [--with-cpp] [--with-python] [--with-io] [--with-deployment] [--with-migration] [--with-contrib] [--tests [TESTS [TESTS ...]]]
+
+optional arguments:
+  -h, --help            show this help message and exit
+  --with-cpp            Whether to run C++ tests
+  --with-python         Whether to run python tests
+  --with-io             Whether to run IO adaptors tests
+  --with-deployment     Whether to run deployment and scaling in/out tests
+  --with-migration      Whether to run object migration tests
+  --with-contrib        Whether to run python contrib tests
+  --tests [TESTS [TESTS ...]]
+                        Specify tests cases ro run
+
+
+

As shown above, you could run C++ unittests by

+
./test/runner --with-cpp
+
+
+

You could only run specified test case as well:

+
./test/runner --with-cpp --tests array_test dataframe_test
+
+
+
+
+

Documentation#

+

Vineyard’s documentation is generated using Doxygen and Sphinx. To build the +documentation locally, navigate to the docs/ directory and execute the +following commands:

+
cd docs/
+make html
+
+
+

Upon successful completion, the HTML documentation will be available under the +docs/_build/html directory:

+
open _build/html/index.html
+
+
+

For the most up-to-date version of the documentation, visit https://v6d.io.

+

Vineyard offers comprehensive documentation that delves into the design and +implementation details of the project. The documentation adheres to the syntax +conventions of Doxygen and Sphinx markup. If you identify areas for improvement +or wish to contribute, feel free to submit a pull request. We appreciate your +enthusiasm and support!

+
+
+

Reporting Bugs#

+

Vineyard is hosted on GitHub and utilizes GitHub issues as its bug tracker. +If you encounter any issues or unexpected behavior while using Vineyard, please file an issue.

+

Before creating a new bug report, we recommend that you first search among existing +Vineyard bugs to check if the issue has already been addressed.

+

When submitting a new bug report, kindly provide essential information regarding your +problem in the description, such as the operating system version, Vineyard version, +and any relevant system configurations. This will greatly assist us in diagnosing +and resolving the issue.

+
+
+

Submitting Pull Requests#

+

We greatly appreciate contributions from the community, including bug fixes and new +features. To submit a pull request to Vineyard, please follow the guidelines in this +section:

+
+

Install Pre-commit#

+

Vineyard uses pre-commit to prevent accidental inclusion of secrets in the Git +repository. To install pre-commit, run:

+
pip3 install pre-commit
+
+
+

Next, configure the necessary pre-commit hooks with:

+
pre-commit install
+
+
+
+
+

Sign Off Your Commits#

+

Vineyard has enabled the DCO, which requires you to sign-off your commits included +in pull requests. Git provides a -s command line option to sign-off your +commit automatically:

+
git commit -s -m 'This is my commit message'
+
+
+
+
+

Code Formatting#

+

Vineyard adheres to the Google C++ Style Guide. When submitting patches, please format +your code using clang-format with the Makefile command make vineyard_clformat, and +ensure your code complies with the cpplint convention using the CMakefile command +make vineyard_cpplint.

+
+
+

Open a Pull Request#

+

When opening issues or submitting pull requests, please prefix the pull request title +with the issue number and the type of patch (BUGFIX or FEATURE) in brackets. For +example, [BUGFIX-1234] Fix crash in sealing vector to vineyard or [FEATURE-2345] +Support seamless operability with PyTorch's tensors.

+
+
+

Git Workflow for Newcomers#

+

Generally, you do NOT need to rebase your pull requests unless there are merge conflicts +with the main branch. If GitHub indicates “Can’t automatically merge” on your pull +request, you will be asked to rebase your pull request on top of the latest main branch +using the following commands:

+
    +
  • First, rebase to the most recent main:

    +
    git remote add upstream https://github.com/v6d-io/v6d.git
    +git fetch upstream
    +git rebase upstream/main
    +
    +
    +
  • +
  • If Git shows conflicts, such as in conflict.cpp,you need to: +- Manually modify the file to resolve the conflicts +- After resolving, mark it as resolved by

    +
    git add conflict.cpp
    +
    +
    +
  • +
  • Then, continue rebasing with:

    +
    git rebase --continue
    +
    +
    +
  • +
  • Finally, push to your fork, and the pull request will be updated:

    +
    git push --force
    +
    +
    +
  • +
+
+
+
+

Creating a Release#

+

The Vineyard Python package is built using the manylinux1 environment. To create +a release version, we utilize Docker for a consistent and reliable build process. +The base image’s details can be found in the docker/pypa/Dockerfile.manylinux1 file.

+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/developers/faq.html b/notes/developers/faq.html new file mode 100644 index 0000000000..e3e6447658 --- /dev/null +++ b/notes/developers/faq.html @@ -0,0 +1,560 @@ + + + + + + + + + + + + + + + + + + + Frequently Asked Questions - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Frequently Asked Questions#

+

This FAQ page compiles questions frequently asked by our end users to provide +informative and concise answers. If the following sections do not address your +concerns, please feel free to open an issue or post it to discussions.

+
    +
  1. What are the objects in vineyard?

  2. +
+
+

A global object is composed of multiple local objects distributed across the cluster, +with each local object stored in a single vineyard daemon (ensuring that a local object +can always fit into the memory of a single machine).

+

These local objects represent partitions of the global object (e.g., partitioned dataframes +within a large dataframe, graph fragments within a vast graph). Generally, a global object +serves as an abstraction for the input or output of a parallel-processing workload, while +a local object corresponds to the input or output of an individual worker within that workload.

+
+
    +
  1. Can multiple readers access the same data simultaneously in vineyard?

  2. +
+
+

Absolutely. Vineyard stores objects as immutable entities, which are shared +among readers’ processes through memory mapping. This ensures safe and concurrent +access to objects by multiple readers without any conflicts.

+
+
    +
  1. How can I launch a cluster with multiple vineyardd instances?

  2. +
+
+

A vineyard daemon server represents a single vineyard instance within a vineyard cluster. To +initiate a vineyard cluster, simply start the vineyardd process on all the +machines within the cluster, ensuring that these vineyard instances can register with +the same etcd_endpoint. The default value for etcd_endpoint is +http://127.0.0.1:2379, and if the etcd servers are not already running on the cluster, +vineyard will automatically launch the etcd_endpoint.

+

For additional parameter settings, refer to the help documentation by running +python3 -m vineyard --help.

+
+
    +
  1. Is Kubernetes a necessity for vineyard?

  2. +
+
+

No, Kubernetes is not a necessity for vineyard. However, deploying vineyard on Kubernetes +allows users to benefit from the flexible resource management offered by cloud-native +deployments for their application workloads. Additionally, the scheduler plugin assists +in co-locating worker pods with the data for improved data-work alignment.

+
+
    +
  1. How does vineyard achieve IPC and memory sharing (i.e., zero-copy sharing) on Kubernetes?

  2. +
+
+

Inter-process memory sharing can be challenging in Kubernetes, but it is achievable. When +deployed on Kubernetes, vineyard exposes its UNIX-domain socket as a PersistentVolume. +This volume can be mounted into the job’s pod, allowing the socket to be used for IPC +connections to the vineyard daemon. Memory sharing is accomplished by mounting a volume of +medium Memory into both the vineyard daemon’s pod and the job’s pod.

+
+
    +
  1. How does vineyard’s stream differ from similar systems, such as Kafka?

  2. +
+
+

Vineyard’s stream is an abstraction of a sequence of objects, where each object typically +represents a small portion of the entire object (e.g., a mini-batch of a tensor). This +abstraction is designed to support cross-engine pipelining between consecutive workers in +a data analytics pipeline (e.g., a dataframe engine generating training data while the +subsequent machine learning engine consumes the data and trains the model simultaneously).

+

The primary distinction between vineyard’s stream and traditional stream frameworks like +Kafka is that data in vineyard’s stream is still abstracted as (high-level) objects and +can be consumed in a zero-copy manner, similar to normal objects in vineyard. In contrast, +Kafka is designed for stream processing applications and abstracts data as (low-level) +messages. Utilizing Kafka in the aforementioned scenario would still incur (de)serialization +and memory copy costs.

+
+
    +
  1. Does vineyard support accessing remote objects?

  2. +
+
+

Yes, vineyard’s RPC client can access the metadata of an object, regardless of whether +the object is local or remote. This capability enables users and internal operators to +examine essential information (e.g., chunk axis, size) about an object, assisting in +decision-making processes related to object management (e.g., determining the need for +repartitioning, planning the next workload).

+
+
    +
  1. How does migration work in vineyard? Is it automatically triggered?

  2. +
+
+

Consider a scenario where workload A produces a global object O, and the subsequent +workload B consumes O as input. In a Kubernetes cluster with multiple hosts (e.g., +h1, h2, h3, h4), if A has two worker pods on h1 and h2, the local objects +(i.e., O1 and O2) of O are stored on h1 and h2, respectively.

+

If the two worker pods of B (i.e., B1 and B2) are placed on h1 and h3, B1 +can access O1 locally via memory mapping. However, B2 (on h3) cannot access O2 +since it resides on h2. In this situation, a utility program distributed with vineyard +in the initContainer of B2 triggers the migration of O2 from h2 to h3, +enabling pod B2 to access O2 locally.

+

Although data migration incurs a cost, the scheduler plugin has been developed to +prioritize h2 when launching B2, minimizing the need for migration whenever possible.

+
+
    +
  1. What’s the minimal Kubernetes version requirement for vineyard operator?

  2. +
+
+

At present, we only test the vineyard operator based on Kubernetes 1.24.0. +So we highly recommend using Kubernetes 1.24.0 or above.

+
+
    +
  1. Why the vineyard operator can’t be deployed on Kubernetes?

  2. +
+
+

If you use the helm to deploy the vineyard operator, you may find the vineyard operator +can’t be deployed successfully after a long time. In this case, you should check whether +the command contains the flag –wait. If so, you should remove the flag –wait and +try to install the operator again.

+
+
    +
  1. How to connect to the vineyard cluster deployed by the vineyard operator?

  2. +
+
+

There are two ways to connect to the vineyard cluster deployed by the vineyard operator:

+
    +
  • Through IPC. Create a pod with the specific labels so that the pod can be scheduled +to the node where the vineyard cluster is deployed.

  • +
  • Through RPC. Connect to the vineyard cluster through the RPC service exposed by the +vineyard operator. You could refer to the guide for more details.

  • +
+
+
    +
  1. Is there a way to install the vineyard cluster on Kubernetes quickly?

  2. +
+
+

To reduce the complexity of the installation, we provide a command line tool +to install the vineyard cluster on Kubernetes quickly.

+
+
+ +
+
+
+ + + + +
+ + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/developers/roadmap.html b/notes/developers/roadmap.html new file mode 100644 index 0000000000..f771cd05a0 --- /dev/null +++ b/notes/developers/roadmap.html @@ -0,0 +1,578 @@ + + + + + + + + + + + + + + + + + + + Roadmap - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Roadmap#

+

Vineyard aims to serve as an open-source in-memory immutable data manager. We +cut a major release once a year, a minor release for about every two months, +and a patch release every one or two weeks.

+

The roadmap for major vineyard releases are listed as follows:

+
+

v0.8.0#

+

Vineyard v0.8.0 will deliver the first implementation of the following +important features and will be hopefully release in the later Aug, 2022:

+
    +
  • Filesystem view of vineyard objects: vineyard objects can be accessed like +files on a filesystem in a high-performance fashion. Such a feature would +greatly ease the integration of computing processes with vineyard.

  • +
  • Copy-on-realloc and data lineage: the mutation support would be extended +from blobs to general objects with a carefully concurrency-control design.

  • +
  • Transparent object spilling: objects in vineyard can be spilled to disk +when they are too large to fit in memory.

  • +
  • Sharing GPU memory between processes of different compute engines: we are +working on shared memory on devices to enable boarder applications that +can benefit from the shared vineyard store, especially for deep learning +frameworks and GNN frameworks.

  • +
+
+
+

v0.7.0#

+

Vineyard v0.7.0 will be released in later July, 2022. Vineyard v0.7.0 will +introduces the following experimental features to ease the integration of +various kinds of workloads with Vineyard:

+
    +
  • Limited mutation support on blobs: starts from vineyard v0.7.0, unsealed +blobs can be get by other clients with an unsafe flag to ease the +integration of some online storage engines.

  • +
  • Limited support for remote data accessing using the RPC client: vineyard +v0.7.0 will bring the feature about creating and accessing remote blobs +using the RPC client. It would be greatly helpful for some specific deployment +and the cost of remote data sourcing to vineyard is tolerable.

  • +
+
+
+

v0.6.0#

+

We plan to release the v0.6.0 version before tne end of June, 2022. The v0.6.0 +release will include the following enhancement:

+
    +
  • Better compatibility on various platforms (e.g., CentOS and ArchLinux), and process +platform-specific features like LD_LIBRARY_PATH and libunwind dependency +carefully.

  • +
  • Ensure the backwards compatibility with various third-party integrations, e.g., +apache-airflow.

  • +
  • Vineyard v0.6.0 will be available from homebrew.

  • +
+
+
+

v0.5.0#

+

We plan to release the first preliminary version for the Rust SDK and Go SDK +in vineyard v0.5.0, that is expected to be delivered in later May, 2022.

+

In vineyard v0.5.0, we will investigate the opportunity about code generation +based on the metadata of vineyard objects, i.e., we could generate the data +structure definition based on the structure of metadata in runtime (for Python) +and in compile time (even maybe in runtime) for C++ and Rust.

+

The integration with Kubernetes (especially the CSI part) will be another key +improvement for v0.5.0.

+

Further details about release for v0.5.0 will be added later.

+
+
+

v0.4.0#

+

The release of vineyard v0.4.0, will be hopefully released before April, 2022, will +be a follow-up bugfix releases after v0.3.0. The version v0.4.0 makes the +kubernetes related components better.

+
    +
  • Improve the robustness of the scheduler plugin.

  • +
  • Refine the definition of CRDs.

  • +
  • Distribute the vineyard operator to artifact hub as a chart, to make it available for more users.

  • +
+
+
+

v0.3.0#

+

We plan to release v0.3.0 by the end of 2021. vineyard v0.3.0 will be the first major +stable releases with fully kubernetes support, which will include:

+
    +
  • A stable CRD definition for LocalObject and GlobalObject to represents vineyard objects +as kubernetes resources.

  • +
  • A full-features scheduler plugin for kubernetes, as well as a custom controller that manages +objects (custom resources) in vineyard cluster.

  • +
  • A refined version of Helm integration.

  • +
  • Application-aware far memory will be included in v0.3.0 as an experimental feature.

  • +
+
+
+

v0.2.0#

+

Vineyard v0.2.0 will address the issue about Python ecosystem compatibility, I/O, and +the kubernetes integration. Vineyard v0.2.0 will take about half of a year with several bugfix +release to testing the design and APIs to reach a stable stable state.

+
    +
  • Vineyard v0.2.0 will support any filesystem-spec-compatible data source/sink as well as file +format.

  • +
  • Vineyard v0.2.0 will support Python ecosystem (especially numpy and pandas) better.

  • +
  • Vineyard v0.2.0 will include basic Helm integration for deploying on Kubernetes as a DaemonSet.

  • +
  • A prototype of scheduler plugin to do data locality scheduling will be included into vineyard v0.2.0 +to demonstrates the capability about co-scheduling job and data in kubernetes brought by vineyard.

  • +
  • Match the criterion of CNCF sandbox project.

  • +
+
+
+

v0.1.0#

+

Vineyard v0.1.0 is the first release after open source. This version includes:

+
    +
  • Complete functionality for both server and client.

  • +
  • Complete Python SDK.

  • +
  • User-friendly package distribution on pypi (for python SDK) and on dockerhub (for vineyardd server).

  • +
+
+
+

Release Notes#

+

For more details about what changes happened for every version, please refer to +our releases notes as well.

+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/developers/troubleshooting.html b/notes/developers/troubleshooting.html new file mode 100644 index 0000000000..e71c27e5d0 --- /dev/null +++ b/notes/developers/troubleshooting.html @@ -0,0 +1,505 @@ + + + + + + + + + + + + + + + + + + + Troubleshooting - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Troubleshooting#

+

This page provides guidance for addressing common issues that may arise when +working with Vineyard.

+
+

Vineyard Fails to Start#

+
    +
  1. Improper Etcd Configuration

    +
    +

    If you encounter the following error when sending requests to Vineyard:

    +
    Etcd error: etcdserver: too many operations in txn request, error code: 3
    +
    +
    +

    This indicates that your Etcd configuration is not set up correctly and does not support +more than 128 operations within a single transaction. To resolve this issue, check your Etcd +startup parameters and increase the --max-txn-ops value, for example, to 102400.

    +
    +
  2. +
  3. bind: Permission Denied Error When Launching vineyardd

    +
    +

    The Vineyard server uses a UNIX-domain socket for IPC connections and memory sharing with clients. +By default, the UNIX-domain socket is located at /var/run/vineyard.sock, which typically +requires root permission.

    +

    To launch vineyardd, you can either:

    +
      +
    • Run the vineyardd command with sudo,

    • +
    • Or, specify a different location for the UNIX-domain socket that does not require root permission +using the --socket command line argument, e.g., +.. code:: bash

      +
      +

      python3 -m vineyard –socket=/tmp/vineyard.sock

      +
      +
    • +
    +
    +
  4. +
+
+
+

Vineyard Issues on Kubernetes#

+
    +
  1. Etcd Pod Resource Limitations in Kubernetes Deployment

    +
    +

    We have observed that etcd performance may degrade when a Vineyard client persists a large +object, particularly in Kubernetes deployments where the CPU cores of the etcd pod are limited by +cgroups. In such cases, users should increase the CPU resources allocated to the etcd pod. For +more information on etcd tuning, please refer to the Hardware recommendations section in the etcd documentation.

    +
    +
  2. +
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/getting-started.html b/notes/getting-started.html new file mode 100644 index 0000000000..a1b7d4ecbe --- /dev/null +++ b/notes/getting-started.html @@ -0,0 +1,673 @@ + + + + + + + + + + + + + + + + + + + Getting Started - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Getting Started#

+
+

Installing vineyard#

+

Vineyard is distributed as a Python package and can be effortlessly installed using pip:

+
$ pip3 install vineyard
+
+
+
+
+

Launching vineyard server#

+
$ python3 -m vineyard
+
+
+

A vineyard daemon server will be launched with default settings. By default, /var/run/vineyard.sock +will be used by vineyardd to listen for incoming IPC connections.

+

To stop the running vineyardd instance, simply press Ctrl-C in the terminal.

+
+

Tip

+

If you encounter errors like cannot launch vineyardd on '/var/run/vineyard.sock': +Permission denied,, it means you don’t have the permission to create a UNIX-domain +socket at /var/run/vineyard.sock. You can either:

+
    +
  • Run vineyard as root, using sudo:

    +
    $ sudo -E python3 -m vineyard
    +
    +
    +
  • +
  • Or, change the socket path to a writable location with the --socket command +line option:

    +
    $ python3 -m vineyard --socket /tmp/vineyard.sock
    +
    +
    +
  • +
+
+
+
+

Connecting to vineyard#

+

Once launched, you can call vineyard.connect with the socket name to initiate a vineyard client +from Python:

+
>>> import vineyard
+>>> client = vineyard.connect('/var/run/vineyard.sock')
+
+
+
+
+

Storing and Retrieving Python Objects#

+

Vineyard is designed as an in-memory object store and offers two high-level APIs put and +get for creating and accessing shared objects, enabling seamless interoperability with the Python +ecosystem. The former returns a vineyard.ObjectID upon success, which can be used +to retrieve shared objects from vineyard using the latter.

+

In the following example, we use client.put() to build a vineyard object from the numpy +ndarray arr, which returns the object_id - a unique identifier in vineyard representing +the object. Given the object_id, we can obtain a shared-memory object from vineyard with the +client.get() method.

+
>>> import numpy as np
+>>>
+>>> object_id = client.put(np.random.rand(2, 4))
+>>> object_id
+o0015c78883eddf1c
+>>>
+>>> shared_array = client.get(object_id)
+>>> shared_array
+ndarray([[0.39736989, 0.38047846, 0.01948815, 0.38332264],
+         [0.61671189, 0.48903213, 0.03875045, 0.5873005 ]])
+
+
+
+

Note

+

shared_array does not allocate extra memory in the Python process; instead, it shares memory +with the vineyard server via mmap in a zero-copy process.

+
+

The sharable objects can be complex and nested. Like numpy ndarray, the pandas dataframe df can +be seamlessly stored in vineyard and retrieved with the .put() and .get() methods as follows:

+
>>> import pandas as pd
+>>>
+>>> df = pd.DataFrame({'u': [0, 0, 1, 2, 2, 3],
+>>>                    'v': [1, 2, 3, 3, 4, 4],
+>>>                    'weight': [1.5, 3.2, 4.7, 0.3, 0.8, 2.5]})
+>>> object_id = client.put(df)
+>>>
+>>> shared_dataframe = client.get(object_id)
+>>> shared_dataframe
+   u  v  weight
+0  0  1     1.5
+1  0  2     3.2
+2  1  3     4.7
+3  2  3     0.3
+4  2  4     0.8
+5  3  4     2.5
+
+
+

Under the hood, vineyard implements a builder/resolver mechanism to represent arbitrary +data structures as vineyard objects and resolve them back to native values in the corresponding +programming languages and computing systems. See also I/O Drivers for more information.

+
+
+

Sharing objects between tasks#

+

Vineyard is designed for sharing intermediate data between tasks. The following example +demonstrates how a dataframe can be passed between two processes using vineyard, namely +the producer and consumer in the example below:

+
import multiprocessing as mp
+import vineyard
+
+import numpy as np
+import pandas as pd
+
+socket = '/var/run/vineyard.sock'
+
+def produce(name):
+   client = vineyard.connect(socket)
+   client.put(pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD')),
+              persist=True, name=name)
+
+def consume(name):
+   client = vineyard.connect(socket)
+   print(client.get(name=name).sum())
+
+if __name__ == '__main__':
+   name = 'dataset'
+
+   producer = mp.Process(target=produce, args=(name,))
+   producer.start()
+   consumer = mp.Process(target=consume, args=(name,))
+   consumer.start()
+
+   producer.join()
+   consumer.join()
+
+
+

Running the code above, you should see the following output:

+
A   -4.529080
+B   -2.969152
+C   -7.067356
+D    4.003676
+dtype: float64
+
+
+
+
+

Next steps#

+

Beyond the core functionality of sharing objects between tasks, vineyard also provides:

+
    +
  • Distributed objects and stream abstraction over immutable chunks;

  • +
  • An IDL (Code Generation for Boilerplate) that helps integrate vineyard with other systems at minimal cost;

  • +
  • A mechanism of pluggable drivers for various tasks that serve as the glue +between the core compute engine and the external world, e.g., data sources, data +sinks;

  • +
  • Integration with Kubernetes for sharing between tasks in workflows deployed +on cloud-native infrastructures.

  • +
+
+
+
+
+ +
+

Overview of vineyard.

+
+
+
+
+
+

Learn more about vineyard’s key concepts from the following user guides:

+
+
+
+
+
+

Vineyard Objects

+

Explore the design of the object model in vineyard.

+
+
+
+
+
+
+

VCDL

+

Discover how vineyard integrates with other computing systems.

+
+
+
+
+
+
+

I/O Drivers

+

Understand the design and implementation of pluggable routines for I/O, repartition, +migration, and more.

+
+
+
+
+
+

Vineyard is a natural fit for cloud-native computing, where it can be deployed and +managed by the vineyard operator, providing data-aware scheduling for data analytical +workflows to achieve efficient data sharing on Kubernetes. More details about vineyard +on Kubernetes can be found here:

+
+
+
+
+ +
+

Deploy vineyard on Kubernetes and accelerate your big-data workflows.

+
+
+
+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/integration-bigdata.html b/notes/integration-bigdata.html new file mode 100644 index 0000000000..5920beafb8 --- /dev/null +++ b/notes/integration-bigdata.html @@ -0,0 +1,465 @@ + + + + + + + + + + + + + + + + + + + Big-data on Vineyard - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Big-data on Vineyard#

+
+
+

Vineyard serves as a powerful data-sharing engine, seamlessly integrating with +a variety of big-data computing platforms. This includes machine learning +frameworks and the distributed data processing engine, Dask.

+
+
+
+
+ +
+

Executing machine learning workflows on top of vineyard.

+
+
+
+
+
+
+

Dask

+
+
+

Using vineyard as the data source / sink of dask computations.

+
+
+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/integration-orchestration.html b/notes/integration-orchestration.html new file mode 100644 index 0000000000..e322b0f06d --- /dev/null +++ b/notes/integration-orchestration.html @@ -0,0 +1,477 @@ + + + + + + + + + + + + + + + + + + + Workflow orchestration - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Workflow orchestration#

+
+
+

Vineyard seamlessly integrates with the workflow orchestration engines, e.g., +Apache Airflow and Kedro, enabling users to effortlessly incorporate Vineyard +into their workflows for enhanced performance.

+

Moreover, the Airflow integration empowers users to work with large Python objects +featuring complex data types (e.g., pandas.DataFrame) at minimal cost, while +eliminating the need for cumbersome pickle.dump/loads operations.

+
+
+
+
+ +
+

Airflow uses vineyard as the XCom backend to efficiently handle complex data in Python.

+
+
+
+
+
+

The Kedro integration enables users to easily share large data objects across +nodes in a pipeline and eliminates the high cost of (de)serialization and I/O +compared with alternatives like AWS S3 or Minio, without the need to modify +the pipeline code intrusively, and provides seamless user experience when scaling +pipelines to Kubernetes.

+
+
+
+
+
+

Kedro

+
+
+

Kedro uses vineyard as a DataSet implementation for efficient intermediate data sharing.

+
+
+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/integration/airflow.html b/notes/integration/airflow.html new file mode 100644 index 0000000000..1e165947d9 --- /dev/null +++ b/notes/integration/airflow.html @@ -0,0 +1,657 @@ + + + + + + + + + + + + + + + + + + + Airflow on Vineyard - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Airflow on Vineyard#

+

Big data analytical pipelines often involve various types of workloads, each +requiring a dedicated computing system to complete the task. Intermediate +data flows between tasks in the pipeline, and the additional cost of transferring data +accounts for a significant portion of the end-to-end performance in real-world deployments, +making optimization a challenging task.

+

Integrating Vineyard with Airflow presents opportunities to alleviate this problem.

+
+

Introducing Airflow#

+

Airflow is a platform that enables users to programmatically author, schedule, and +monitor workflows. Users organize tasks in a Directed Acyclic Graph (DAG), and the +Airflow scheduler executes the tasks on workflows while adhering to the specified +dependencies.

+

Consider the following ETL workflow as an example 1,

+
@dag(schedule_interval=None, start_date=days_ago(2), tags=['example'])
+def tutorial_taskflow_api_etl():
+    @task()
+    def extract():
+        data_string = '{"1001": 301.27, "1002": 433.21, "1003": 502.22}'
+
+        order_data_dict = json.loads(data_string)
+        return order_data_dict
+
+    @task(multiple_outputs=True)
+    def transform(order_data_dict: dict):
+        return {"total_order_value": total_order_value}
+
+    @task()
+    def load(total_order_value: float):
+        print(f"Total order value is: {total_order_value:.2f}")
+
+    order_data = extract()
+    order_summary = transform(order_data)
+
+
+tutorial_etl_dag = tutorial_taskflow_api_etl()
+
+
+

It forms the following DAG, including three individual tasks as the nodes, and +runs the tasks sequentially based on their data This forms a DAG, including +three individual tasks as nodes, and edges between nodes that describe the +data dependency relations. The Airflow scheduler runs the tasks sequentially +based on their data dependencies.dependencies. Airflow ETL Workflow

+
+
+

Airflow on Vineyard#

+
+

The Rationale for Airflow on Vineyard#

+

Airflow excels at defining and orchestrating complex workflows. However, managing +data flow within the pipeline remains a challenge. Airflow relies on database +backends such as SQLite, MySQL, and PostgreSQL to store intermediate data between +tasks. In real-world scenarios, large-scale data, such as large tensors, dataframes, +and distributed graphs, cannot fit into these databases. As a result, external +storage systems like HDFS and S3 are used to store intermediate data, with only +an identifier stored in the database.

+

Utilizing external storage systems to share intermediate data among tasks in big +data analytical pipelines incurs performance costs due to data copying, +serialization/deserialization, and network data transfer.

+

Vineyard is designed to efficiently share intermediate in-memory data for big data +analytical pipelines, making it a natural fit for workloads on Airflow.

+
+
+

How Vineyard Enhances Airflow#

+

Airflow allows users to register an external XCom backend, which is precisely +what Vineyard is designed for.

+

Vineyard serves as an XCom backend for Airflow workers, enabling the transfer of +large-scale data objects between tasks without relying on Airflow’s database backend +or external storage systems like HDFS. The Vineyard XCom backend also handles object +migration when the required inputs are not located where the task is scheduled to +execute.

+

Vineyard’s XCom backend achieves its functionality by injecting hooks into the +processes of saving values to the backend and fetching values from the backend, +as described below:

+
class VineyardXCom(BaseXCom):
+
+    @staticmethod
+    def serialize_value(value: Any):
+        """ Store the value to vineyard server, and serialized the result
+            Object ID to save it into the backend database later.
+        """
+
+    @staticmethod
+    def deserialize_value(result: "XCom") -> Any:
+        """ Obtain the Object ID after deserialization, and fetching the
+            underlying value from vineyard.
+
+            This value is resolved from vineyard objects in a zero-copy
+            fashion.
+        """
+
+
+
+
+

Addressing Distributed Deployment Challenges#

+

Airflow supports parallel task execution across multiple workers to efficiently +process complex workflows. In a distributed deployment (using the CeleryExecutor), +tasks sharing intermediate data might be scheduled on different workers, necessitating +remote data access.

+

Vineyard seamlessly handles object migration for various data types. In the XCom backend, +when the IPC client encounters remote objects, it triggers a migration action to move +the objects to the local worker, ensuring input data is readily available before task +execution.

+

This transparent object migration simplifies complex data operations and movement, +allowing data scientists to focus on computational logic when developing big data +applications on Airflow.

+
+
+
+

Running Vineyard + Airflow#

+

Users can try Airflow provider for Vineyard by the following steps:

+
    +
  1. Install required packages:

    +
    pip3 install airflow-provider-vineyard
    +
    +
    +
  2. +
  3. Configure Vineyard locally

    +

    The vineyard server can be easier launched locally with the following command:

    +
    python -m vineyard --socket=/tmp/vineyard.sock
    +
    +
    +

    See also our documentation about launching vineyard.

    +
  4. +
  5. Configure Airflow to use the vineyard XCom backend by specifying the environment +variable

    +
    export AIRFLOW__CORE__XCOM_BACKEND=vineyard.contrib.airflow.xcom.VineyardXCom
    +
    +
    +

    and configure the location of UNIX-domain IPC socket for vineyard client by

    +
    export AIRFLOW__VINEYARD__IPC_SOCKET=/tmp/vineyard.sock
    +
    +
    +

    or

    +
    export VINEYARD_IPC_SOCKET=/tmp/vineyard.sock
    +
    +
    +
  6. +
  7. Launching your airflow scheduler and workers, and run the following DAG as example,

    +
    import numpy as np
    +import pandas as pd
    +
    +from airflow.decorators import dag, task
    +from airflow.utils.dates import days_ago
    +
    +default_args = {
    +    'owner': 'airflow',
    +}
    +
    +@dag(default_args=default_args, schedule_interval=None, start_date=days_ago(2), tags=['example'])
    +def taskflow_etl_pandas():
    +    @task()
    +    def extract():
    +        order_data_dict = pd.DataFrame({
    +            'a': np.random.rand(100000),
    +            'b': np.random.rand(100000),
    +        })
    +        return order_data_dict
    +
    +    @task(multiple_outputs=True)
    +    def transform(order_data_dict: dict):
    +        return {"total_order_value": order_data_dict["a"].sum()}
    +
    +    @task()
    +    def load(total_order_value: float):
    +        print(f"Total order value is: {total_order_value:.2f}")
    +
    +    order_data = extract()
    +    order_summary = transform(order_data)
    +    load(order_summary["total_order_value"])
    +
    +taskflow_etl_pandas_dag = taskflow_etl_pandas()
    +
    +
    +
  8. +
+

In the example above, the extract and transform tasks share a pandas.DataFrame as +intermediate data. This presents a challenge, as the DataFrame cannot be pickled, and when +dealing with large data, it cannot fit into the backend databases of Airflow.

+

This example is adapted from the Airflow documentation. For more information, refer to the +Tutorial on the Taskflow API.

+
+
+

Further Ahead#

+

The Airflow provider for Vineyard, currently in its experimental stage, demonstrates +significant potential for efficiently and flexibly sharing large-scale intermediate data +in big data analytical workflows within Airflow.

+

The Airflow community is actively working to enhance support for modern big data and AI +applications. We believe that the integration of Vineyard, Airflow, and other cloud-native +infrastructures can provide a more effective and efficient solution for data scientists.

+
+
1
+

See: https://airflow.apache.org/docs/apache-airflow/stable/tutorial_taskflow_api.html

+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/integration/dask.html b/notes/integration/dask.html new file mode 100644 index 0000000000..a083ab9125 --- /dev/null +++ b/notes/integration/dask.html @@ -0,0 +1,587 @@ + + + + + + + + + + + + + + + + + + + Dask on Vineyard - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Dask on Vineyard#

+

The integration with Dask enables dask.array and dask.dataframe to be seamlessly persisted in +and retrieved from Vineyard. In the following sections, we demonstrate how Vineyard simplifies +the implementation of an example that utilizes Dask for data preprocessing and TensorFlow for +distributed learning, as previously showcased in the blog.

+
+

The Deployment#

+Dask Tensorflow Workflow +

As illustrated in the figure above, we employ two machines for the distributed tasks for +demonstration purposes. The Vineyard daemon processes are launched on both machines, along +with the Dask workers. The Dask scheduler is initiated on the first machine, where we also +run the Dask preprocessing program in the first step, as the Dask scheduler manages the +distribution of computation tasks among its workers.

+

In the second step, we execute the training program on both machines with different TF_CONFIG +settings. For details on configuring the setup, please refer to the documentation.

+
+
+

Preprocessing in Dask#

+

In this step, we load the mnist data and duplicate it to simulate the parallel processing as same as the blog.

+
from vineyard.core.builder import builder_context
+from vineyard.contrib.dask.dask import dask_context
+
+def dask_preprocess(dask_scheduler):
+    def get_mnist():
+        (x_train, y_train), _ = tf.keras.datasets.mnist.load_data()
+        # The `x` arrays are in uint8 and have values in the [0, 255] range.
+        # You need to convert them to float64 with values in the [0, 1] range.
+        x_train = x_train / np.float64(255)
+        y_train = y_train.astype(np.int64)
+        return pd.DataFrame({'x': list(x_train), 'y': y_train})
+
+    with dask_context():
+        datasets = [delayed(get_mnist)() for i in range(20)]
+        dfs = [dd.from_delayed(ds) for ds in datasets]
+        gdf = dd.concat(dfs)
+        gdf_id = vineyard.connect().put(gdf, dask_scheduler=dask_scheduler)
+
+        return gdf_id
+
+
+

Here the returned gdf_id is the ObjectID of a vineyard::GlobalDataFrame +which consists of 20 partitions (10 partitions on each machine).

+
+
+

Training in Tensorflow#

+

In this step, we use the preprocessed data gdf_id to train a model distributedly +in keras of Tensorflow.

+
from vineyard.contrib.ml.tensorflow import register_tf_types
+from vineyard.core.resolver import resolver_context
+
+def mnist_dataset(gdf_id, batch_size):
+    with resolver_context() as resolver:
+        # register the resolver for tensorflow Dataset to the resolver_context
+        register_tf_types(None, resolver)
+        train_datasets = vineyard.connect().get(gdf_id, data='x', label='y')
+        train_datasets = train_datasets.repeat().batch(batch_size)
+
+        options = tf.data.Options()
+        options.experimental_distribute.auto_shard_policy = tf.data.experimental.AutoShardPolicy.OFF
+        train_datasets_no_auto_shard = train_datasets.with_options(options)
+        return train_datasets_no_auto_shard
+
+def build_and_compile_cnn_model():
+    model = tf.keras.Sequential([
+        tf.keras.layers.InputLayer(input_shape=(28, 28)),
+        tf.keras.layers.Reshape(target_shape=(28, 28, 1)),
+        tf.keras.layers.Conv2D(32, 3, activation='relu'),
+        tf.keras.layers.Flatten(),
+        tf.keras.layers.Dense(128, activation='relu'),
+        tf.keras.layers.Dense(10)
+    ])
+    model.compile(
+        loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
+        optimizer=tf.keras.optimizers.SGD(learning_rate=0.001),
+        metrics=['accuracy'])
+    return model
+
+def train(gdf_id):
+    per_worker_batch_size = 64
+    strategy = tf.distribute.MultiWorkerMirroredStrategy()
+    train_dataset = mnist_dataset(gdf_id, per_worker_batch_size)
+
+    with strategy.scope():
+    multi_worker_model = mnist.build_and_compile_cnn_model()
+
+    multi_worker_model.fit(train_dataset, epochs=3, steps_per_epoch=70)
+
+
+

To utilize the preprocessed data, we first register the resolvers capable of resolving a +vineyard::GlobalDataFrame distributed across multiple workers within the resolver_context. +Subsequently, we can directly obtain the tf.data.Dataset from Vineyard using the get +method.

+
+

Note

+

It is essential to specify the column names for the data and label, as they were set in +the previous step.

+
+
+
+

Transfer Learning#

+

In this section, we demonstrate how the dask-vineyard integration can be effectively utilized +in transfer learning scenarios. Transfer learning is a technique where a pre-trained deep +learning model is used to compute features for downstream models. Storing these features in +memory is advantageous, as it eliminates the need to recompute features or incur significant +I/O costs by repeatedly reading them from disk. We will refer to the featurization example +and use the tf_flowers dataset as a dask.array. We will employ the pre-trained ResNet50 +model to generate features and subsequently store them in Vineyard. The resulting global +tensor in Vineyard will consist of 8 partitions, each containing 400 data slots.

+
def get_images(idx, num):
+    paths = list(Path("flower_photos").rglob("*.jpg"))[idx::num]
+    data = []
+    for p in paths:
+        with open(p,'rb') as f:
+          img = Image.open(io.BytesIO(f.read())).resize([224, 224])
+          arr = preprocess_input(img_to_array(img))
+          data.append(arr)
+    return np.array(data)
+
+def featurize(v, block_id=None):
+    model = ResNet50(include_top=False)
+    preds = model.predict(np.stack(v))
+    return preds.reshape(400, 100352)
+
+imgs = [da.from_delayed(delayed(get_images)(i,8), shape=(400, 244, 244, 3), dtype='float') for i in range(8)]
+imgs = da.concatenate(imgs, axis=0)
+res = imgs.map_blocks(featurize, chunks=(400,100352), drop_axis=[2,3], dtype=float)
+global_tensor_id = vineyard.connect().put(res, dask_scheduler=dask_scheduler)
+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/integration/kedro.html b/notes/integration/kedro.html new file mode 100644 index 0000000000..406f0f2b24 --- /dev/null +++ b/notes/integration/kedro.html @@ -0,0 +1,695 @@ + + + + + + + + + + + + + + + + + + + Kedro Vineyard Plugin - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Kedro Vineyard Plugin#

+

The Kedro vineyard plugin contains components (e.g., DataSet and Runner) +to share intermediate data among nodes in Kedro pipelines using vineyard.

+
+

Kedro on Vineyard#

+

Vineyard works as the DataSet provider for kedro workers to allow transferring +large-scale data objects between tasks that cannot be efficiently serialized and +is not suitable for pickle, without involving external storage systems like +AWS S3 (or Minio as an alternative). The Kedro vineyard plugin handles object migration +as well when the required inputs are not located where the task is scheduled to execute.

+
+
+

Requirements#

+

The following packages are needed to run Kedro on vineyard,

+
    +
  • kedro >= 0.18

  • +
  • vineyard >= 0.14.5

  • +
+
+
+

Configuration#

+
    +
  1. Install required packages:

    +
    pip3 install vineyard-kedro
    +
    +
    +
  2. +
  3. Configure Vineyard locally

    +

    The vineyard server can be easier launched locally with the following command:

    +
    python3 -m vineyard --socket=/tmp/vineyard.sock
    +
    +
    +

    See also our documentation about Launching Vineyard.

    +
  4. +
  5. Configure the environment variable to tell Kedro vineyard plugin how to connect to the +vineyardd server:

    +
    export VINEYARD_IPC_SOCKET=/tmp/vineyard.sock
    +
    +
    +
  6. +
+
+
+

Usage#

+

After installing the dependencies and preparing the vineyard server, you can execute the +Kedro workflows as usual and benefits from vineyard for intermediate data sharing.

+

We take the Iris example as an example,

+
$ kedro new --starter=pandas-iris
+
+
+

The nodes in this pipeline look like

+
def split_data(
+    data: pd.DataFrame, parameters: Dict[str, Any]
+) -> Tuple[pd.DataFrame, pd.DataFrame, pd.Series, pd.Series]:
+    data_train = data.sample(
+        frac=parameters["train_fraction"], random_state=parameters["random_state"]
+    )
+    data_test = data.drop(data_train.index)
+
+    X_train = data_train.drop(columns=parameters["target_column"])
+    X_test = data_test.drop(columns=parameters["target_column"])
+    y_train = data_train[parameters["target_column"]]
+    y_test = data_test[parameters["target_column"]]
+
+    return X_train, X_test, y_train, y_test
+
+
+def make_predictions(
+    X_train: pd.DataFrame, X_test: pd.DataFrame, y_train: pd.Series
+) -> pd.Series:
+    X_train_numpy = X_train.to_numpy()
+    X_test_numpy = X_test.to_numpy()
+
+    squared_distances = np.sum(
+        (X_train_numpy[:, None, :] - X_test_numpy[None, :, :]) ** 2, axis=-1
+    )
+    nearest_neighbour = squared_distances.argmin(axis=0)
+    y_pred = y_train.iloc[nearest_neighbour]
+    y_pred.index = X_test.index
+
+    return y_pred
+
+
+

You can see that the intermediate data between split_data and make_predictions is some pandas +dataframes and series.

+

Try running the pipeline without vineyard,

+
$ cd iris
+$ kedro run
+[05/25/23 11:38:56] INFO     Kedro project iris                                                                                       session.py:355
+[05/25/23 11:38:57] INFO     Loading data from 'example_iris_data' (CSVDataSet)...                                               data_catalog.py:343
+                    INFO     Loading data from 'parameters' (MemoryDataSet)...                                                   data_catalog.py:343
+                    INFO     Running node: split: split_data([example_iris_data,parameters]) -> [X_train,X_test,y_train,y_test]          node.py:329
+                    INFO     Saving data to 'X_train' (MemoryDataSet)...                                                         data_catalog.py:382
+                    INFO     Saving data to 'X_test' (MemoryDataSet)...                                                          data_catalog.py:382
+                    INFO     Saving data to 'y_train' (MemoryDataSet)...                                                         data_catalog.py:382
+                    INFO     Saving data to 'y_test' (MemoryDataSet)...                                                          data_catalog.py:382
+                    INFO     Completed 1 out of 3 tasks                                                                      sequential_runner.py:85
+                    INFO     Loading data from 'X_train' (MemoryDataSet)...                                                      data_catalog.py:343
+                    INFO     Loading data from 'X_test' (MemoryDataSet)...                                                       data_catalog.py:343
+                    INFO     Loading data from 'y_train' (MemoryDataSet)...                                                      data_catalog.py:343
+                    INFO     Running node: make_predictions: make_predictions([X_train,X_test,y_train]) -> [y_pred]                      node.py:329
+...
+
+
+

You can see that the intermediate data is shared with memory. When kedro is deploy to a cluster, e.g., +to argo workflow, the MemoryDataSet is not applicable anymore and you will need to setup the +AWS S3 or Minio service and sharing those intermediate data as CSV files.

+
X_train:
+  type: pandas.CSVDataSet
+  filepath: s3://testing/data/02_intermediate/X_train.csv
+  credentials: minio
+
+X_test:
+  type: pandas.CSVDataSet
+  filepath: s3://testing/data/02_intermediate/X_test.csv
+  credentials: minio
+
+y_train:
+  type: pandas.CSVDataSet
+  filepath: s3://testing/data/02_intermediate/y_train.csv
+  credentials: minio
+
+
+

It might be inefficient for pickling pandas dataframes when data become larger. With the kedro +vineyard plugin, you can run the pipeline with vineyard as the intermediate data medium by

+
$ kedro run --runner vineyard.contrib.kedro.runner.SequentialRunner
+[05/25/23 11:45:34] INFO     Kedro project iris                                                                                       session.py:355
+                    INFO     Loading data from 'example_iris_data' (CSVDataSet)...                                               data_catalog.py:343
+                    INFO     Loading data from 'parameters' (MemoryDataSet)...                                                   data_catalog.py:343
+                    INFO     Running node: split: split_data([example_iris_data,parameters]) -> [X_train,X_test,y_train,y_test]          node.py:329
+                    INFO     Saving data to 'X_train' (VineyardDataSet)...                                                       data_catalog.py:382
+                    INFO     Saving data to 'X_test' (VineyardDataSet)...                                                        data_catalog.py:382
+                    INFO     Saving data to 'y_train' (VineyardDataSet)...                                                       data_catalog.py:382
+                    INFO     Saving data to 'y_test' (VineyardDataSet)...                                                        data_catalog.py:382
+                    INFO     Loading data from 'X_train' (VineyardDataSet)...                                                    data_catalog.py:343
+                    INFO     Loading data from 'X_test' (VineyardDataSet)...                                                     data_catalog.py:343
+                    INFO     Loading data from 'y_train' (VineyardDataSet)...                                                    data_catalog.py:343
+                    INFO     Running node: make_predictions: make_predictions([X_train,X_test,y_train]) -> [y_pred]                      node.py:329
+...
+
+
+

Without any modification to your pipeline code, you can see that the intermediate data is shared +with vineyard using the VineyardDataSet and no longer suffers from the overhead of (de)serialization +and the I/O cost between external AWS S3 or Minio services.

+

Like kedro catalog create, the Kedro vineyard plugin provides a command-line interface to generate +the catalog configuration for given pipeline, which will rewrite the unspecified intermediate data +to VineyardDataSet, e.g.,

+
$ kedro vineyard catalog create -p __default__
+
+
+

You will get

+
X_test:
+  ds_name: X_test
+  type: vineyard.contrib.kedro.io.dataset.VineyardDataSet
+X_train:
+  ds_name: X_train
+  type: vineyard.contrib.kedro.io.dataset.VineyardDataSet
+y_pred:
+  ds_name: y_pred
+  type: vineyard.contrib.kedro.io.dataset.VineyardDataSet
+y_test:
+  ds_name: y_test
+  type: vineyard.contrib.kedro.io.dataset.VineyardDataSet
+y_train:
+  ds_name: y_train
+  type: vineyard.contrib.kedro.io.dataset.VineyardDataSet
+
+
+
+
+

Deploy to Kubernetes#

+

When the pipeline scales to Kubernetes, the interaction with the Kedro vineyard plugin is +still simple and non-intrusive. The plugin provides tools to prepare the docker image and +generate Argo workflow specification file for the Kedro pipeline. Next, we’ll demonstrate +how to deploy pipelines to Kubernetes while leverage Vineyard for efficient intermediate +sharing between tasks step-by-step.

+
    +
  1. Prepare the vineyard cluster (see also Deploy on Kubernetes):

    +
    # export your kubeconfig path here
    +$ export KUBECONFIG=/path/to/your/kubeconfig
    +
    +# install the vineyard operator
    +$ go run k8s/cmd/main.go deploy vineyard-cluster --create-namespace
    +
    +
    +
  2. +
  3. Install the argo server:

    +
    # install the argo server
    +$ kubectl create namespace argo
    +$ kubectl apply -n argo -f https://github.com/argoproj/argo-workflows/releases/download/v3.4.8/install.yaml
    +
    +
    +
  4. +
  5. Generate the iris demo project from the official template:

    +
    $ kedro new --starter=pandas-iris
    +
    +
    +
  6. +
  7. Build the Docker image for this iris demo project:

    +
    # walk to the iris demo root directory
    +$ cd iris
    +$ kedro vineyard docker build
    +
    +
    +

    A Docker image named iris will be built successfully. The docker image +need to be pushed to your image registry, or loaded to the kind/minikube cluster, to be +available in Kubernetes.

    +
    $ docker images | grep iris
    +iris   latest   3c92da8241c6   About a minute ago   690MB
    +
    +
    +
  8. +
  9. Next, generate the Argo workflow YAML file from the iris demo project:

    +
    $ kedro vineyard argo generate -i iris
    +
    +# check the generated Argo workflow YAML file, you can see the Argo workflow YAML file named `iris.yaml`
    +# is generated successfully.
    +$ ls -l argo-iris.yml
    +-rw-rw-r-- 1 root root 3685 Jun 12 23:55 argo-iris.yml
    +
    +
    +
  10. +
  11. Finally, submit the Argo workflow to Kubernetes:

    +
    $ argo submit -n argo argo-iris.yml
    +
    +
    +

    You can interact with the Argo workflow using the argo command-line tool, e.g.,

    +
    $ argo list workflows -n argo
    +NAME         STATUS      AGE   DURATION   PRIORITY   MESSAGE
    +iris-sg6qf   Succeeded   18m   30s        0
    +
    +
    +
  12. +
+

We have prepared a benchmark to evaluate the performance gain brought by vineyard for data +sharing when data scales, for more details, please refer to this report.

+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/integration/ml.html b/notes/integration/ml.html new file mode 100644 index 0000000000..bcf2bb80fe --- /dev/null +++ b/notes/integration/ml.html @@ -0,0 +1,733 @@ + + + + + + + + + + + + + + + + + + + Machine Learning with Vineyard - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Machine Learning with Vineyard#

+

Vineyard-ML: A Vineyard package that integrates Machine Learning Frameworks to Vineyard.

+
+

TensorFlow#

+
+

Using Numpy Data#

+
>>> import tensorflow as tf
+>>> from vineyard.contrib.ml import tensorflow
+>>> dataset = tf.data.Dataset.from_tensor_slices((data, label))
+>>> data_id = vineyard_client.put(dataset)
+>>> vin_data = vineyard_client.get(data_id)
+
+
+

Vineyard supports the tf.data.Dataset. The vin_data will be a shared-memory object +from the vineyard.

+
+
+

Using Dataframe#

+
>>> import pandas as pd
+>>> df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [5, 6, 7, 8], 'target': [1.0, 2.0, 3.0, 4.0]})
+>>> label = df.pop('target')
+>>> dataset = tf.data.Dataset.from_tensor_slices((dict(df), label))
+>>> data_id = vineyard_client.put(dataset)
+>>> vin_data = vineyard_client.get(data_id)
+
+
+

Wrap the dataframe with tf.data.Dataset. This enables the use of feature columns as a +bridge to map from the columns in Pandas Dataframe to features in Dataset. The +dataset should return a dictionary of column names (from the dataframe) that maps +to column values. The dataset should only contain numerical data.

+
+
+

Using RecordBatch of Pyarrow#

+
>>> import pyarrow as pa
+>>> arrays = [pa.array([1, 2, 3, 4]), pa.array([3.0, 4.0, 5.0, 6.0]), pa.array([0, 1, 0, 1])]
+>>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'f1', 'label'])
+>>> data_id = vineyard_client.put(batch)
+>>> vin_data = vineyard_client.get(data_id)
+
+
+

Vineyard supports direct integration of RecordBatch. The vin_data object will +be a TensorFlow Dataset, i.e. tf.data.Dataset. Here the label row should be named as label.

+
+
+

Using Tables of Pyarrow#

+
>>> arrays = [pa.array([1, 2, 3, 4]), pa.array([3.0, 4.0, 5.0, 6.0]), pa.array([0, 1, 0, 1])]
+>>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'f1', 'label'])
+>>> batches = [batch]*3
+>>> table = pa.Table.from_batches(batches)
+>>> data_id = vineyard_client.put(table)
+>>> vin_data = vineyard_client.get(data_id)
+
+
+

Vineyard supports direct integration of Tables as well. Here, the vin_data +object will be of type TensorFlow Dataset, i.e. tf.data.Dataset. Here the label row +should be named as label.

+
+
+
+

PyTorch#

+
+

Using Numpy Data#

+

Vineyard supports Custom Datasets inherited from the PyTorch Dataset.

+
>>> import torch
+>>> from vineyard.contrib.ml import pytorch
+>>> data_id = vineyard_client.put(dataset, typename='Tensor')
+>>> vin_data = vineyard_client.get(data_id)
+
+
+

The dataset object should be an object of the type CustomDataset class which is inherited +from torch.utils.data.Dataset class. Adding the typename as Tensor is important. +The vin_data will be of type torch.utils.data.TensorDataset.

+
+
+

Using Dataframe#

+
>>> df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [5, 6, 7, 8], 'c': [1.0, 2.0, 3.0, 4.0]})
+>>> label = torch.tensor(df['c'].values.astype(np.float32))
+>>> data = torch.tensor(df.drop('c', axis=1).values.astype(np.float32))
+>>> dataset = torch.utils.data.TensorDataset(data, label)
+>>> data_id = vineyard_client.put(dataset, typename='Dataframe', cols=['a', 'b', 'c'], label='c')
+>>> vin_data = vineyard_client.get(data_id, label='c)
+
+
+

While using the PyTorch form of the dataframe with vineyard, it is important to mention +the typename as Dataframe, a list of column names in cols and the label +name in label tag. The vin_data will be of the form TensorDataset with +the label as mentioned with the label tag. If no value is passed to the label tag +vineyard will consider the default value which is the value of label passed in while +calling the put method

+
+
+

Using RecordBatch of Pyarrow#

+
>>> import pyarrow as pa
+>>> arrays = [pa.array([1, 2, 3, 4]), pa.array([3.0, 4.0, 5.0, 6.0]), pa.array([0, 1, 0, 1])]
+>>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'f1', 'f2'])
+>>> data_id = vineyard_client.put(batch)
+>>> vin_data = vineyard_client.get(data_id, label='f2')
+
+
+

The vin_data will be of the form TensorDataset with the label as mentioned +with the label tag. In this case it is important to mention the label tag.

+
+
+

Using Tables of Pyarrow#

+
>>> arrays = [pa.array([1, 2, 3, 4]), pa.array([3.0, 4.0, 5.0, 6.0]), pa.array([0, 1, 0, 1])]
+>>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'f1', 'f2'])
+>>> batches = [batch]*3
+>>> table = pa.Table.from_batches(batches)
+>>> data_id = vineyard_client.put(table)
+>>> vin_data = vineyard_client.get(data_id, label='f2')
+
+
+

The vin_data object will be of the form TensorDataset with the label as mentioned +with the label tag. In this case, it is important to mention the label tag.

+
+
+
+

MxNet#

+
+

Using Numpy Data#

+

Vineyard supports Array Datasets from the gluon.data of MxNet.

+
>>> import mxnet as mx
+>>> from vineyard.contrib.ml import mxnet
+>>> dataset = mx.gluon.data.ArrayDataset((data, label))
+>>> data_id = vineyard_client.put(dataset, typename='Tensor')
+>>> vin_data = vineyard_client.get(data_id)
+
+
+

The dataset object should be an object of the type ArrayDataset from mxnet.gluon.data +class. Here, Adding the typename as Tensor is important. The vin_data will be +of type mxnet.gluon.data.ArrayDataset.

+
+
+

Using Dataframe#

+
>>> df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [5, 6, 7, 8], 'c': [1.0, 2.0, 3.0, 4.0]})
+>>> label = df['c'].values.astype(np.float32)
+>>> data = df.drop('c', axis=1).values.astype(np.float32)
+>>> dataset = mx.gluon.data.ArrayDataset((data, label))
+>>> data_id = vineyard_client.put(dataset, typename='Dataframe', cols=['a', 'b', 'c'], label='c')
+>>> vin_data = vineyard_client.get(data_id, label='c)
+
+
+

While using the MxNet form of the dataframe with vineyard, it is important to mention +the typename as Dataframe, a list of column names in cols and the label +name in label tag. The vin_data will be of the form ArrayDataset with +the label as mentioned with the label tag. If no value is passed to the label tag +vineyard will consider the default value which is the value of label passed in while +calling the put method

+
+
+

Using RecordBatch of Pyarrow#

+
>>> import pyarrow as pa
+>>> arrays = [pa.array([1, 2, 3, 4]), pa.array([3.0, 4.0, 5.0, 6.0]), pa.array([0, 1, 0, 1])]
+>>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'f1', 'f2'])
+>>> data_id = vineyard_client.put(batch)
+>>> vin_data = vineyard_client.get(data_id, label='f2')
+
+
+

The vin_data will be of the form ArrayDataset with the label as mentioned +with the label tag. In this case, it is important to mention the label tag.

+
+
+

Using Tables of Pyarrow#

+
>>> arrays = [pa.array([1, 2, 3, 4]), pa.array([3.0, 4.0, 5.0, 6.0]), pa.array([0, 1, 0, 1])]
+>>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'f1', 'f2'])
+>>> batches = [batch]*3
+>>> table = pa.Table.from_batches(batches)
+>>> data_id = vineyard_client.put(table)
+>>> vin_data = vineyard_client.get(data_id, label='f2')
+
+
+

The vin_data object will be of the form ArrayDataset with the label as mentioned +with the label tag. In this case, it is important to mention the label tag.

+
+
+
+

XGBoost#

+

Vineyard supports resolving XGBoost::DMatrix from various kinds of vineyard data types.

+
+

From Vineyard::Tensor#

+
>>> arr = np.random.rand(4, 5)
+>>> vin_tensor_id = vineyard_client.put(arr)
+>>> dmatrix = vineyard_client.get(vin_tensor_id)
+
+
+

The dmatrix will be a DMatrix instance with the same shape (4, 5) resolved from the Vineyard::Tensor +object with the id vin_tensor_id.

+
+
+

From Vineyard::DataFrame#

+
>>> df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [5, 6, 7, 8], 'c': [1.0, 2.0, 3.0, 4.0]})
+>>> vin_df_id = vineyard_client.put(df)
+>>> dmatrix = vineyard_client.get(vin_df_id, label='a')
+
+
+

The dmatrix will be a DMatrix instance with shape of (4, 2) and feature_names of ['b', 'c']. +While the label of dmatrix is the values of column a.

+

Sometimes the dataframe is a complex data structure and only one column will be used as the features. +We support this case by providing the data kwarg.

+
>>> df = pd.DataFrame({'a': [1, 2, 3, 4],
+>>>                    'b': [[5, 1.0, 4], [6, 2.0, 3], [7, 3.0, 2], [8, 9.0, 1]]})
+>>> vin_df_id = vineyard_client.put(df)
+>>> dmatrix = vineyard_client.get(vin_df_id, data='b', label='a')
+
+
+

The dmatrix will have the shape of (4, 3) corresponding to the values of column b. +While the label is the values of column a.

+
+
+

From Vineyard::RecordBatch#

+
>>> import pyarrow as pa
+>>> arrays = [pa.array([1, 2, 3, 4]), pa.array([3.0, 4.0, 5.0, 6.0]), pa.array([0, 1, 0, 1])]
+>>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'f1', 'target'])
+>>> vin_rb_id = vineyard_client.put(batch)
+>>> dmatrix = vineyard_client.get(vin_rb_id, label='target')
+
+
+

The dmatrix will have the shape of (4, 2) and feature_names of ['f0', 'f1']. +While the label is the values of column target.

+
+
+

From Vineyard::Table#

+
>>> arrays = [pa.array([1, 2]), pa.array([0, 1]), pa.array([0.1, 0.2])]
+>>> batch = pa.RecordBatch.from_arrays(arrays, ['f0', 'label', 'f2'])
+>>> batches = [batch] * 3
+>>> table = pa.Table.from_batches(batches)
+>>> vin_tab_id = vineyard_client.put(table)
+>>> dmatrix = vineyard_client.get(vin_tab_id, label='label')
+
+
+

The dmatrix will have the shape of (6, 2) and feature_names of ['f0', 'f2']. +While the label is the values of column label.

+
+
+
+

Nvidia-DALI#

+

Vineyard supports integration of Dali Pipelines.

+
>>> from nvidia.dali import pipeline_def
+>>> pipeline = pipe(device_id=device_id, num_threads=num_threads, batch_size=batch_size)
+>>> pipeline.build()
+>>> pipe_out = pipeline.run()
+>>> data_id = vineyard_client.put(pipe_out)
+>>> vin_pipe = vineyard_client.get(data_id)
+
+
+

In this case, the pipe is a pipeline_def function. The data received after executing pipe.run() can +be stored into vineyard. The Pipeline should only return two values, namely data and label. The return +type of the data and label values should be of type TensorList. The vin_pipe object will be the +output of a simple in-built pipeline after executing the pipeline.build() and pipeline.run(). It will +simply return two values of type Pipeline.

+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/integration/ray.html b/notes/integration/ray.html new file mode 100644 index 0000000000..5445708597 --- /dev/null +++ b/notes/integration/ray.html @@ -0,0 +1,398 @@ + + + + + + + + + + + + + + + + + Ray on Vineyard - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Ray on Vineyard#

+
+ +
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/key-concepts.html b/notes/key-concepts.html new file mode 100644 index 0000000000..0761e94800 --- /dev/null +++ b/notes/key-concepts.html @@ -0,0 +1,526 @@ + + + + + + + + + + + + + + + + + + + Key Concepts - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Key Concepts#

+
+
+

The User Guide section offers an in-depth understanding of vineyard’s design +and implementation. It covers detailed environment setup instructions, the +architecture, and the core features within the vineyard engine.

+

Additional information on vineyard’s internals will be provided soon.

+
+

Tip

+

If you are new to vineyard, we recommend starting with the +Getting Started page for a smoother +introduction.

+
+
+

Concepts#

+
+
+
+
+ +
+

The design space of vineyard objects.

+
+
+
+
+
+ +
+

VCDL and how to integration vineyard with computing systems.

+
+
+
+
+
+ +
+

The approaches that can be used to access various kinds of objects stored in +vineyard.

+
+
+
+
+
+ +
+

The stream abstraction upon the immutable data sharing storage and its usages.

+
+
+
+
+
+ +
+

Design and implementation of the builtin I/O drivers that eases the integration +of computing engines to existing infrastructure.

+
+
+
+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/key-concepts/data-accessing.html b/notes/key-concepts/data-accessing.html new file mode 100644 index 0000000000..5c33dc7178 --- /dev/null +++ b/notes/key-concepts/data-accessing.html @@ -0,0 +1,747 @@ + + + + + + + + + + + + + + + + + + + Data Accessing - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Data Accessing#

+

Vineyard is designed to support distributed object sharing and offers both IPCClient +and RPCClient for efficient data access. This section will guide you through various +methods of accessing objects within vineyard. For more information on vineyard object +basics, please refer to Object = metadata + payloads and Distributed objects.

+
+

IPCClient vs. RPCClient#

+

As depicted in the above figure, data is partitioned across different vineyard +instances. The concept of zero-copy sharing was explained in Architecture. +Memory mapping is only available for clients on the same instance, while metadata +is globally synchronized and accessible from clients connected to instances on other hosts.

+

Vineyard provides two clients to support IPC and RPC scenarios:

+
    +
  • IPC Client

    +
      +
    • Can only connect to instances deployed on the same host.

    • +
    • Offers full support for local data access. Accessing local blobs is enabled +by zero-copy memory mapping.

    • +
    +
  • +
  • RPC Client

    +
      +
    • Can connect to any instance with an enabled RPC endpoint.

    • +
    • Provides limited support for remote data access. Creating and fetching remote +blobs incurs considerable network transfer overhead.

    • +
    +
  • +
+
+

Local vs. Remote#

+

Distributed shared objects are typically partitioned, with each vineyard instance managing +some chunks of the entire object. As shown in Distributed objects, a GlobalTensor +is partitioned into three chunks, and each instance holds one chunk of type Tensor.

+

From the perspective of computing engines, distributed computing engines launch +workers on vineyard instances. Each worker connects to the co-located local instance and +is responsible for processing chunks in that local instance. For example, when starting a Dask +cluster on a vineyard cluster as illustrated in the picture above, each Dask worker is responsible +for executing computations on its local chunks. Some computing tasks require communication between +workers, such as aggregation. In these cases, the communication is performed by the computing +engine itself (in this case, the Dask cluster).

+
+

Tip

+

We assume that the computing engines built upon vineyard are responsible for scheduling +tasks based on their awareness of the underlying data partitioning within the vineyard +cluster.

+

This design is well-suited for commonly-used modern computing engines,such as GraphScope, +Spark, Presto, Dask, Mars, and Ray.

+
+
+
+
+

Local Objects#

+

Creating and accessing local objects in vineyard can be easily achieved using put and get methods (see +vineyard.IPCClient.put() and vineyard.IPCClient.get()).

+
+
Effortlessly create and access local objects using put and get#
+
 >>> import pandas as pd
+ >>> import vineyard
+ >>> import numpy as np
+ >>>
+ >>> vineyard_ipc_client = vineyard.connect("/tmp/vineyard.sock")
+ >>>
+ >>> df = pd.DataFrame(np.random.rand(10, 2))
+ >>>
+ >>> # put object into vineyard
+ >>> r = vineyard_ipc_client.put(df)
+ >>> r, type(r)
+ (o00053008257020f8, vineyard._C.ObjectID)
+ >>>
+ >>> # get object from vineyard using object id
+ >>> data = vineyard_ipc_client.get(r)
+ >>> data
+           0         1
+ 0  0.534487  0.261941
+ 1  0.901056  0.441583
+ 2  0.687568  0.671564
+ ...
+
+
+
+

Vineyard provides low-level APIs to operate on metadatas and raw blobs as well.

+
+

Accessing metadatas#

+

The method vineyard.IPCClient.get_meta() can be used to inspect metadata in the +vineyard cluster, which returns a vineyard.ObjectMeta value:

+
+
Accessing metadata in vineyard#
+
 >>> meta = vineyard_ipc_client.get_meta(r)
+ >>> meta.id
+ o00053008257020f8
+ >>> meta.instance_id
+ 0
+ >>> meta.typename
+ 'vineyard::DataFrame'
+ >>> meta
+ {
+     "instance_id": 0,
+     "nbytes": 0,
+     "signature": 1460186430481176,
+     "transient": true,
+     "typename": "vineyard::DataFrame"
+     "__values_-value-0": {
+         "global": false,
+         "id": "o0005300822f54d1c",
+         "instance_id": 0,
+         "nbytes": 80,
+         "order_": "\"F\"",
+         "shape_": "[10]",
+         "signature": 1460186388165810,
+         "transient": true,
+         "typename": "vineyard::Tensor<double>",
+         "value_type_": "float64",
+         "value_type_meta_": "<f8"
+         "buffer_": {
+             "id": "o8005300822d858df",
+             "typename": "vineyard::Blob"
+             ...
+
+
+
+
+
+

Using blobs#

+

Vineyard offers low-level APIs for creating and accessing local blobs with enhanced efficiency:

+ +
+
Creating local blobs#
+
 >>> import vineyard
+ >>> vineyard_ipc_client = vineyard.connect("/tmp/vineyard.sock")
+ >>>
+ >>> # mock a data
+ >>> payload = b'abcdefgh1234567890uvwxyz'
+ >>>
+ >>> # create a blob builder
+ >>> buffer_builder = vineyard_ipc_client.create_blob(len(payload))
+ >>>
+ >>> # copy the mocked data into the builder
+ >>> buffer_builder.copy(0, payload)
+ >>>
+ >>> # seal the builder then we will get a blob
+ >>> blob = buffer_builder.seal(vineyard_ipc_client)
+
+
+
+
+
Accessing local blobs#
+
 >>> # get the blob from vineyard using object id
+ >>> blob = vineyard_ipc_client.get_blob(blob.id)
+ >>> blob, type(blob)
+ (Object <"o800532e4ab1f2087": vineyard::Blob>, vineyard._C.Blob)
+ >>>
+ >>> # inspect the value
+ >>> bytes(memoryview(blob))
+ b'abcdefgh1234567890uvwxyz'
+
+
+
+
+
+
+

Remote Objects#

+

The RPC client enables inspection of remote object metadata and facilitates operations on blobs +within the remote cluster, while taking into account the associated network transfer costs.

+
+

Inspecting metadata#

+

The method vineyard.RPCClient.get_meta() allows you to access object metadata in a similar +manner to vineyard.IPCClient.get_meta(), but with the added capability of connecting to a +remote instance.

+
+
Metadata accessing using RPCClient#
+
 >>> import vineyard
+ >>> vineyard_rpc_client = vineyard.connect("localhost", 9600)
+ >>>
+ >>> # the `r` from the above "Local Objects" section
+ >>> meta = vineyard_rpc_client.get_meta(r)
+ >>> meta.id
+ o00053008257020f8
+ >>> meta.instance_id
+ 0
+ >>> meta.typename
+ 'vineyard::DataFrame'
+
+
+
+
+
+

Using remote blobs#

+

However, due to the absence of memory sharing between hosts, zero-copy data sharing is not feasible when +connecting to a vineyard instance that is not deployed on the same host as the client. Transferring data +over the network incurs significant costs, and vineyard requires users to explicitly issue a migrate +command to move data from the remote instance to the local instance. For more details, please refer to +Object Migration in Vineyard.

+

For added convenience, we also provide APIs to fetch remote blobs to the local client by transferring +payloads over the network.

+ +
+

Warning

+

Note that the remote in the above APIs means the blob will be transferred using +TCP network. For large blobs, it implies a significant cost of time.

+
+
+
Creating remote blobs#
+
 >>> import vineyard
+ >>> vineyard_rpc_client = vineyard.connect("localhost", 9600)
+ >>>
+ >>> # mock a data
+ >>> payload = b'abcdefgh1234567890uvwxyz'
+ >>>
+ >>> # create an empty blob builder
+ >>> remote_buffer_builder = vineyard.RemoteBlobBuilder(len(payload))
+ >>>
+ >>> # copy the mocked data into the builder
+ >>> remote_buffer_builder.copy(0, payload)
+ >>>
+ >>> # create the remote blob using the RPCClient, with the `remote_buffer_builder` as argument
+ >>> remote_blob_id = vineyard_rpc_client.create_remote_blob(remote_buffer_builder)
+
+
+
+
+
Accessing remote blobs#
+
 >>> # get the remote blob from vineyard using object id
+ >>> remote_blob = vineyard_rpc_client.get_remote_blob(remote_blob_id)
+ >>> remote_blob, type(remote_blob)
+ (<vineyard._C.RemoteBlob at 0x142204870>, vineyard._C.RemoteBlob)
+ >>>
+ >>> # inspect the value of remote blob
+ >>> bytes(memoryview(remote_blob))
+ b'abcdefgh1234567890uvwxyz'
+
+
+
+
+

Warning

+

The APIs for creating blobs in vineyard.IPCClient and vineyard.RPCClient +have subtle differences. The vineyard.IPCClient.create_blob() method first allocates +a shared memory buffer to create an empty blob builder, allowing the user to fill the buffer +and then seal it. In contrast, the vineyard.RPCClient.create_remote_blob() method +creates a remote blob builder on-the-fly, enabling the user to fill the buffer and subsequently +use the client API to send the remote_buffer_builder to the remote instance.

+
+
+
+
+

Utilizing Distributed Objects#

+

In the illustration at the beginning of this section, we demonstrate that vineyard is capable of sharing +distributed objects partitioned across multiple hosts. Accessing these distributed objects +in vineyard can be achieved through two distinct approaches:

+
    +
  • Inspecting metadata using the RPCClient:

    +

    The metadata of global objects can be examined using the vineyard.RPCClient. This allows +computing engines to understand the distribution of partitions of global tensors using the +RPCClient, and subsequently schedule jobs over those chunks based on the distribution information.

    +

    Mars employs this method to consume distributed tensors and dataframes in vineyard.

    +
  • +
  • Accessing local partitions of global objects using the IPCClient:

    +

    Another prevalent pattern for accessing shared global objects involves launching a worker on each +instance where the global object is partitioned. Then, using the vineyard.IPCClient, +workers can obtain the local partitions of the global object. Each worker is responsible for +processing its local partitions.

    +

    This pattern is commonly utilized in many computing engines that have been integrated with +vineyard, such as GraphScope and Presto.

    +
  • +
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/key-concepts/io-drivers.html b/notes/key-concepts/io-drivers.html new file mode 100644 index 0000000000..1c6063e5f9 --- /dev/null +++ b/notes/key-concepts/io-drivers.html @@ -0,0 +1,463 @@ + + + + + + + + + + + + + + + + + + + I/O Drivers - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

I/O Drivers#

+

As we have shown in the getting-started, the open function in vineyard can open a local +file as a stream for consuming, and we notice that the path of the local file is headed +with the scheme file://.

+

Actually, vineyard supports several different types of data source, e.g., kafka:// +for kafka topics. The functional methods to open different data sources as vineyard +streams are called drivers in vineyard. They are registered to open for +specific schemes, so that when open is invoked, it will dispatch the corresponding +driver to handle the specific data source according to the scheme of the path.

+

The following sample code demonstrates the dispatching logic in open, and the +registration examples.

+
>>> @registerize
+>>> def open(path, *args, **kwargs):
+>>>     scheme = urlparse(path).scheme
+
+>>>     for reader in open._factory[scheme][::-1]:
+>>>         r = reader(path, *args, **kwargs)
+>>>         if r is not None:
+>>>             return r
+>>>     raise RuntimeError('Unable to find a proper IO driver for %s' % path)
+>>>
+>>> # different driver functions are registered as follows
+>>> open.register('file', local_driver)
+
+
+

Most importantly, the registration design allows users to register their own drivers +to registerized vineyard methods using .register, which prevents major revisions +on the processing code to fulfill customized computation requirements.

+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/key-concepts/objects.html b/notes/key-concepts/objects.html new file mode 100644 index 0000000000..ce9abe9661 --- /dev/null +++ b/notes/key-concepts/objects.html @@ -0,0 +1,722 @@ + + + + + + + + + + + + + + + + + + + Objects - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Objects#

+

Vineyard represents various data types as vineyard objects. It employs a +metadata-payloads decoupled design, where an object in vineyard comprises:

+
    +
  1. A collection of blobs containing the actual data payload;

  2. +
  3. A hierarchical meta tree that describes the data’s type, layout, and properties.

  4. +
+
+

Object = metadata + payloads#

+

There are some examples that explain the basic idea of metadata and payload that +forms vineyard objects:

+
    +
  • Blob: A blob is a pointer with a length that describes the size of the data,

    +
      +
    • metadata:

      +
        +
      • length

      • +
      +
    • +
    • payloads:

      +
        +
      • pointer, the actual payload of the blob

      • +
      +
    • +
    +
  • +
  • Tensor: A tensor can be viewed as a blob that contains the actual data and several +metadata entries that describe the shape and type information,

    +
      +
    • metadata:

      +
        +
      • shape

      • +
      • dtype

      • +
      • data, a member with type Blob

      • +
      +
    • +
    • payloads:

      +
        +
      • pointer in the member data

      • +
      +
    • +
    +
  • +
  • Dataframe: A dataframe is an ordered collection of tensors as its columns and each +column has a unique name,

    +
      +
    • metadata:

      +
        +
      • column_size

      • +
      • names, a list of members with type string

      • +
      • columns, a list of member with type Tensor

      • +
      +
    • +
    • payloads:

      +
        +
      • a set of pointer in the member columns (the member data of +of those Tensor s)

      • +
      +
    • +
    +
  • +
+

From the example above, it is evident that objects naturally conform to a hierarchical +model, allowing complex data objects to be composed of simpler ones. Each object +consists of a set of blobs as the payload and a metadata tree that describes +the semantics and organization of those blobs.

+
+

An example for the object metadata: a dataframe with two columns where each + column is a tensor.

+
{
+    "__values_-key-0": "1",
+    "__values_-key-1": "\"a\"",
+    "__values_-size": 2,
+    "__values_-value-0": {
+        "buffer_": {
+            "id": "o800527ecdf05cff9",
+            "instance_id": 39,
+            "length": 0,
+            "nbytes": 0,
+            "transient": true,
+            "typename": "vineyard::Blob"
+        },
+        "id": "o000527ecdffd95c4",
+        "instance_id": 39,
+        "nbytes": 400,
+        "partition_index_": "[]",
+        "shape_": "[100]",
+        "signature": 1451273207424436,
+        "transient": false,
+        "typename": "vineyard::Tensor<float>",
+        "value_type_": "float"
+    },
+    "__values_-value-1": {
+        "buffer_": {
+            "id": "o800527ecdeaf1015",
+            "instance_id": 39,
+            "length": 0,
+            "nbytes": 0,
+            "transient": true,
+            "typename": "vineyard::Blob"
+        },
+        "id": "o000527ece12e4f0a",
+        "instance_id": 39,
+        "nbytes": 800,
+        "partition_index_": "[]",
+        "shape_": "[100]",
+        "signature": 1451273227452968,
+        "transient": false,
+        "typename": "vineyard::Tensor<double>",
+        "value_type_": "double"
+    },
+    "columns_": "[\"a\",1]",
+    "id": "o000527ece15d374c",
+    "instance_id": 39,
+    "nbytes": 1200,
+    "partition_index_column_": 0,
+    "partition_index_row_": 0,
+    "row_batch_index_": 0,
+    "signature": 1451273231074538,
+    "transient": false,
+    "typename": "vineyard::DataFrame"
+}
+
+
+
+

From the above example of object metadata, it is evident that an object is composed +of various sub-objects, forming a hierarchical data model. Each object consists of +a set of blobs and a metadata tree that describes the semantics of those blobs.

+
+

Tip

+

Without the metadata, the set of blobs would merely be a collection of memory +pieces without any meaningful interpretation.

+
+

Refer to Sharing Python Objects with Vineyard for a demonstration of how to put Python objects +into vineyard and retrieve them using IPC clients.

+
+
+

Separating metadata and payload#

+

The decoupling of data payload and data layout in vineyard offers three key advantages:

+
    +
  1. Payloads are stored locally within each vineyard instance, while metadata is shared +across all instances in the cluster. This significantly reduces the overhead of maintaining +consistency for distributed data.

  2. +
  3. Vineyard objects become self-descriptive, as the metadata fully determines how +the object should be resolved. This not only ensures semantic consistency when +sharing vineyard objects between different systems and programming languages, +but also allows users to store complex data structures with high-level abstractions, such +as graphs in CSR format directly in vineyard, without the need for serialization/deserialization +every time the object is saved or loaded.

  4. +
  5. This design enables the exploitation of data-aware scheduling techniques. For example, when processing +a graph in vineyard, we can easily access the metadata tree of the graph to determine the size of each +partitioned fragment without accessing the actual vertices and edges. As a result, +we can allocate precise amounts of computational resources for each fragment, leading to overall +performance improvements.

  6. +
+

Vineyard employs two design choices for the metadata and methods of its objects:

+
    +
  1. A composable design for vineyard objects, which facilitates distributed data management;

  2. +
  3. An extensible design for object methods, enabling flexible data sharing +between different computation systems with minimal additional development cost.

  4. +
+
+
+

Data model#

+
+

Composable#

+

The composition mechanism in vineyard is based on the hierarchical tree structure of +the metadata of its objects. The root metadata of a complex object stores references +to the root metadata of its components. By recursively traversing these references, +a complete metadata tree is constructed for the complex object.

+
+Vineyard objects are composable +

Vineyard objects are composable#

+
+

For instance, a distributed dataframe consists of partitioned dataframe chunks, while +a dataframe is composed of column vectors. Considering the decoupling design of payload +and layout in vineyard objects, the blobs are stored in the corresponding vineyard +instance’s memory for each partition, and the metadata (e.g., chunk index, shape, +column data types) are stored in the key-value store behind the metadata service.

+

To store a distributed graph, we first save the partitioned fragments in each vineyard +instance and share their metadata in the backend key-value store. Then, we can create +the distributed graph by generating the root metadata containing links to the root +metadata of the fragments in an efficient manner.

+
+
+

Distributed objects#

+

Vineyard is designed to store large objects across multiple nodes in a cluster, enabling +user programs to seamlessly interact with these objects as a single entity. Data is +sharded across multiple machines without replication.

+
+Distributed objects in vineyard +

Distributed objects in vineyard#

+
+

For example, consider a “Tensor” object that contains billions of columns and rows, making +it too large to fit into a single machine. In such cases, the tensor can be split along +the index or column axis, with each vineyard node holding a subset of chunks. Vineyard +provides a logical view of the complete tensor, allowing distributed computation engines +like Mars and GraphScope to process the data structure as a whole. +.. TODO: add the collection APIs

+
+

Tip

+

See also the concepts of persistent objects in the following subsection. Refer to +the following subsection for more information on the concept of persistent objects.

+
+
+
+

Transient vs. Persistent#

+

As previously mentioned, vineyard objects’ metadata and payloads are managed separately +by different components of the vineyard server. Payloads are designed to be shared with +computing engines using local memory mapping. However, metadata may need to be inspected +by clients connected to other vineyard instances, such as when forming a distributed object. +In this case, the distributed object consists of a set of chunks placed on different +vineyard instances. When retrieving the distributed objects from vineyard, computing engines +may need to inspect the metadata of non-local pieces to understand the distribution of the +entire dataset.

+

This requirement implies that metadata must be globally synchronized and accessible from +clients connected to other vineyard instances. However, global synchronization is a costly +operation, and numerous small key-value pairs can significantly increase the burden on the +key-value store backend of our metadata services. To address this issue, we categorize +objects as transient or persistent.

+
    +
  • Transient objects are designed for cases where the object is known not to be part of a +distributed object and will never need to be inspected by clients on other vineyard instances. +Transient objects are useful for short-lived immediate values within the progress of a +single computing engine.

  • +
  • Persistent objects are designed for cases where the object chunk will be used to form +a larger distributed object, and the metadata is needed when applications inspect the +distributed object. Persistent objects and distributed objects are commonly used to pass +intermediate data between two distributed engines.

  • +
+
+

Caution

+

By default, objects are transient. We provide an API client.persist() that +can explicitly persist the metadata of the target object to etcd, ensuring its visibility +by clients connected to other instances in the cluster.

+
+
+
+

Builders and resolvers#

+

Vineyard utilizes an extensible registry mechanism to enable users to easily integrate their +data structures into the system. This design, which includes builders, resolvers, and drivers, +allows users to create, resolve, and share their data structures across different systems and +paradigms. Notably, even the core data structures and drivers in Vineyard follow this design.

+
+

Note

+

What is the registry mechanism?

+

The registry mechanism decouples methods from the definition of Vineyard data types. For +builders and resolvers, this means users can flexibly register different implementations +in various languages to build and resolve the same Vineyard data type. This enables data +sharing between different systems and paradigms and allows for native language optimizations.

+

For drivers, the registry mechanism permits users to flexibly plug in functionality methods +in different languages for Vineyard data types, providing the necessary capabilities for +data types during the data analysis process.

+

Moreover, the registered methods can be implemented and optimized according to specific +data analysis tasks, further enhancing efficiency.

+
+

Refer to Define Data Types in Python and Defining Custom Data Types in C++ for examples of how builders +and resolvers are implemented in Python and C++, respectively.

+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/key-concepts/streams.html b/notes/key-concepts/streams.html new file mode 100644 index 0000000000..e836e6f961 --- /dev/null +++ b/notes/key-concepts/streams.html @@ -0,0 +1,569 @@ + + + + + + + + + + + + + + + + + + + Streams in Vineyard - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Streams in Vineyard#

+

Streams in Vineyard serve as an abstraction over the immutable data sharing storage, +facilitating seamless pipelining between computing engines. Similar to +pipe, Vineyard’s streams enable +efficient inter-engine communication while minimizing the overhead associated with +data serialization/deserialization and copying.

+

A typical use case for streams in Vineyard involves one process continuously producing +data chunks (e.g., an IO reader) while another process performs scan computations +on the data (e.g., filtering and aggregation operations). A stream consists of a +sequence of immutable data chunks, produced by the former engine and consumed by the +latter engine.

+

This section will explore the utilization of streams in Vineyard.

+
+

Using streams#

+

We first import required packages:

+
import threading
+import time
+from typing import List
+
+import numpy as np
+import pandas as pd
+
+import vineyard
+from vineyard.io.recordbatch import RecordBatchStream
+
+
+
+

Tip

+

Vineyard has defined some built-in stream types, e.g., +vineyard.io.recordbatch.RecordBatchStream. For other stream types, +you could refer to Streams.

+
+
+
+

Producer and consumer#

+

We define a producer that generates random dataframe chunks and inserts them +into the stream:

+
+
A producer of RecordBatchStream#
+
 def generate_random_dataframe(dtypes, size):
+     columns = dict()
+     for k, v in dtypes.items():
+         columns[k] = np.random.random(size).astype(v)
+     return pd.DataFrame(columns)
+
+ def producer(stream: RecordBatchStream, total_chunks, dtypes, produced: List):
+     writer = stream.writer
+     for idx in range(total_chunks):
+         time.sleep(idx)
+         chunk = generate_random_dataframe(dtypes, 2)  # np.random.randint(10, 100))
+         chunk_id = vineyard_client.put(chunk)
+         writer.append(chunk_id)
+         produced.append((chunk_id, chunk))
+     writer.finish()
+
+
+
+

Additionally, we create a consumer that retrieves the chunks from the stream in a +loop, continuing until it encounters a StopIteration exception:

+
+
A consumer of RecordBatchStream#
+
 def consumer(stream: RecordBatchStream, total_chunks, produced: List):
+     reader = stream.reader
+     index = 0
+     while True:
+         try:
+             chunk = reader.next()
+             print('reader receive chunk:', type(chunk), chunk)
+             pd.testing.assert_frame_equal(produced[index][1], chunk)
+         except StopIteration:
+             break
+         index += 1
+
+
+
+
+
+

Streams between processes#

+

Finally, we can test the producer and consumer using two threads:

+
+
Connect the producer and consumer threads using vineyard stream#
+
 def test_recordbatch_stream(vineyard_client, total_chunks):
+     stream = RecordBatchStream.new(vineyard_client)
+     dtypes = {
+         'a': np.dtype('int'),
+         'b': np.dtype('float'),
+         'c': np.dtype('bool'),
+     }
+
+     client1 = vineyard_client.fork()
+     client2 = vineyard_client.fork()
+     stream1 = client1.get(stream.id)
+     stream2 = client2.get(stream.id)
+
+     produced = []
+
+     thread1 = threading.Thread(target=consumer, args=(stream1, total_chunks, produced))
+     thread1.start()
+
+     thread2 = threading.Thread(target=producer, args=(stream2, total_chunks, dtypes, produced))
+     thread2.start()
+
+     thread1.join()
+     thread2.join()
+
+ if __name__ == '__main__':
+     vineyard_client = vineyard.connect("/tmp/vineyard.sock")
+     test_recordbatch_stream(vineyard_client, total_chunks=10)
+
+
+
+

For more detailed API about the streams, please refer to Streams.

+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/key-concepts/vcdl.html b/notes/key-concepts/vcdl.html new file mode 100644 index 0000000000..403c5d56ea --- /dev/null +++ b/notes/key-concepts/vcdl.html @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + Code Generation for Boilerplate - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Code Generation for Boilerplate#

+

The process of sharing objects between engines involves two fundamental steps: defining +the data structure and establishing the protocol to represent the data type +as Objects. To alleviate the integration burden with custom data types, +Vineyard offers an auto-generation mechanism.

+

This mechanism, known as VCDL, relies on the custom annotation [[shared]] +applied to C++ classes.

+

Consider the following C++ class Array as an example:

+
template <typename T>
+class [[vineyard]] Array {
+  public:
+    [[shared]] const T& operator[](size_t loc) const { return data()[loc]; }
+    [[shared]] size_t size() const { return size_; }
+    [[shared]] const T* data() const {
+        return reinterpret_cast<const T*>(buffer_->data());
+    }
+
+  private:
+    [[shared]] size_t size_;
+    [[shared]] std::shared_ptr<Blob> buffer_;
+};
+
+
+
    +
  • When applied to classes: the class itself is identified as a shared vineyard +object, and a builder and resolver (see also Builders and resolvers) are +automatically synthesized.

  • +
  • When applied to data members: the data member is treated as a metadata +field or a sub-member.

  • +
  • When applied to method members: the method member is deemed +cross-language sharable, and FFI wrappers are automatically synthesized.

  • +
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/references.html b/notes/references.html new file mode 100644 index 0000000000..114502d865 --- /dev/null +++ b/notes/references.html @@ -0,0 +1,496 @@ + + + + + + + + + + + + + + + + + + + API Reference - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

API Reference#

+
+
+

Vineyard offers a comprehensive suite of SDKs, including Python and C++ versions. +For detailed API references, please explore the following pages:

+
+
+
+
+
+

Python

+
+
+

API reference for vineyard Python SDK.

+
+
+
+
+
+
+

C++

+
+
+

API reference for vineyard C++ SDK.

+
+
+
+
+
+

In addition, the command-line tool vineyard-ctl is available to facilitate interactions +with a local vineyardd instance, making inspection and debugging tasks more efficient.

+
+
+
+
+ +
+

Reference for vineyard command line tools.

+
+
+
+
+
+

All terms in the documentation site can use search from the following +indexing page:

+
+
+
+
+ +
+

Term indexes for the vineyard documentation.

+
+
+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/references/cpp-api.html b/notes/references/cpp-api.html new file mode 100644 index 0000000000..025cb874a0 --- /dev/null +++ b/notes/references/cpp-api.html @@ -0,0 +1,5492 @@ + + + + + + + + + + + + + + + + + + + C++ API Reference - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

C++ API Reference#

+
+

Objects#

+
+
+using vineyard::ObjectID = uint64_t#
+

ObjectID is an opaque type for vineyard’s object id. The object ID is generated by vineyard server, the underlying type of ObjectID is a 64-bit unsigned integer.

+
+ +
+
+class Object : public vineyard::ObjectBase, public std::enable_shared_from_this<Object>#
+

Object is the core concept in vineyard. Object can be a scalar, a tuple, a vector, a tensor, or even a distributed graph in vineyard. Objects are stored in vineyard, and can be shared to process that connects to the same vineyard cluster.

+

Every object in vineyard has a unique identifier ObjectID that can be passed back and forth in the computation pipeline. An object is composed by a metadata, and a set of blobs.

+

Object in vineyard is by-design to be hierarchical, and can have other Object as members. For example, a tensor object may has a vector as its payload, and a distributed dataframe has many dataframe objects as its chunks, and a dataframe is composed by an array of tensors as columns.

+

Subclassed by vineyard::Registered< Array< Entry > >, vineyard::Registered< Array< T > >, vineyard::Registered< ArrowFragmentGroup >, vineyard::Registered< BaseBinaryArray< ArrayType > >, vineyard::Registered< BaseListArray< ArrayType > >, vineyard::Registered< Blob >, vineyard::Registered< BooleanArray >, vineyard::Registered< DataFrame >, vineyard::Registered< FixedSizeBinaryArray >, vineyard::Registered< FixedSizeListArray >, vineyard::Registered< Hashmap< K, V, prime_number_hash_wy< K >, std::equal_to< K > > >, vineyard::Registered< HDataFrame< T > >, vineyard::Registered< NullArray >, vineyard::Registered< NumericArray< T > >, vineyard::Registered< ParallelStream >, vineyard::Registered< PerfectHashmap< K, V > >, vineyard::Registered< RecordBatch >, vineyard::Registered< Scalar< T > >, vineyard::Registered< SchemaProxy >, vineyard::Registered< Sequence >, vineyard::ArrowFragmentBase, vineyard::ITensor, vineyard::Registered< T >

+
+

Public Functions

+
+
+virtual ~Object()#
+
+ +
+
+const ObjectID id() const#
+

The object id of this object.

+
+ +
+
+const ObjectMeta &meta() const#
+

The metadata of this object.

+
+ +
+
+const size_t nbytes() const#
+

The nbytes of this object, can be treated as the memory usage of this object.

+
+ +
+
+virtual void Construct(const ObjectMeta &meta)#
+

Construct an object from metadata. The metadata meta should come from client’s GetMetaData method.

+

The implementation of Construct method is usually boilerplate. Vineyard provides a code generator to help developers code their own data structures and can be shared via vineyard.

+
+
Parameters
+

meta – The metadata that be used to construct the object.

+
+
+
+ +
+
+inline virtual void PostConstruct(const ObjectMeta &meta)#
+

PostConstruct is called at the end of Construct to perform user-specific constructions that the code generator cannot handle.

+
+
Parameters
+

meta – The metadata that be used to construct the object.

+
+
+
+ +
+
+inline virtual Status Build(Client &client) final#
+

Object is also a kind of ObjectBase, and can be used as a member to construct new objects. The Object type also has a Build method but it does nothing, though.

+
+ +
+
+virtual std::shared_ptr<Object> _Seal(Client &client) final#
+

Object is also a kind of ObjectBase, and can be used as a member to construct new objects. The Object type also has a _Seal method but it does nothing, though.

+
+ +
+
+Status Persist(ClientBase &client) const#
+

Persist the object to make it visible for clients that connected to other vineyardd instances in the cluster.

+
+
Parameters
+

client – The client that to be used to perform the Persist request.

+
+
+
+ +
+
+const bool IsLocal() const#
+

The verb “local” means it is a local object to the client. A local object’s blob can be accessed by the client in a zero-copy fashion. Otherwise only the metadata is accessible.

+
+
Returns
+

True iff the object is a local object.

+
+
+
+ +
+
+const bool IsPersist() const#
+

The verb “persist” means it is visible for client that connected to other vineyardd instances in the cluster. After Persist the object becomes persistent.

+
+
Returns
+

True iff the object is a persistent object.

+
+
+
+ +
+
+const bool IsGlobal() const#
+

The verb “global” means it is a global object and only refers some local objects.

+
+
Returns
+

True iff the object is a global object.

+
+
+
+ +
+
+

Protected Functions

+
+
+inline Object()#
+
+ +
+
+

Protected Attributes

+
+
+ObjectID id_#
+
+ +
+
+mutable ObjectMeta meta_#
+
+ +
+
+

Friends

+
+
+friend class ClientBase
+
+ +
+
+friend class Client
+
+ +
+
+friend class PlasmaClient
+
+ +
+
+friend class RPCClient
+
+ +
+
+friend class ObjectMeta
+
+ +
+
+ +
+
+class ObjectBuilder : public vineyard::ObjectBase#
+

Subclassed by vineyard::CollectionBuilder< DataFrame >, vineyard::CollectionBuilder< ITensor >, vineyard::CollectionBuilder< RecordBatch >, vineyard::ArrowFragmentGroupBuilder, vineyard::BlobWriter, vineyard::BooleanArrayBaseBuilder, vineyard::CollectionBuilder< T >, vineyard::DataFrameBaseBuilder, vineyard::FixedSizeBinaryArrayBaseBuilder, vineyard::FixedSizeListArrayBaseBuilder, vineyard::NullArrayBaseBuilder, vineyard::ParallelStreamBaseBuilder, vineyard::RecordBatchBaseBuilder, vineyard::SchemaProxyBaseBuilder, vineyard::SequenceBaseBuilder, vineyard::TensorBaseBuilder< std::string >

+
+

Public Functions

+
+
+inline virtual ~ObjectBuilder()#
+
+ +
+
+virtual Status Build(Client &client) override = 0#
+

Building the object means construct all blobs of this object to vineyard server.

+
+
Parameters
+

client – The vineyard client that been used to create blobs in the connected vineyard server.

+
+
+
+ +
+
+virtual std::shared_ptr<Object> Seal(Client &client)#
+
+ +
+
+virtual Status Seal(Client &client, std::shared_ptr<Object> &object)#
+
+ +
+
+virtual std::shared_ptr<Object> _Seal(Client &client) override#
+

Sealing the object means construct the metadata for the object and create metadata in vineyard server.

+
+
Parameters
+

client – The vineyard client that been used to create metadata in the connected vineyard server.

+
+
+
+ +
+
+virtual Status _Seal(Client &client, std::shared_ptr<Object> &object)#
+
+ +
+
+inline bool sealed() const#
+
+ +
+
+

Protected Functions

+
+
+inline void set_sealed(bool const sealed = true)#
+
+ +
+
+ +
+
+class ObjectBase#
+

ObjectBase is the most base class for vineyard’s Object and ObjectBuilder.

+

An ObjectBase instance is a build-able value that it’s Build method put blobs * into vineyard server, and it’s _Seal method is responsible for creating metadata in vineyard server for the object.

+

Subclassed by vineyard::Object, vineyard::ObjectBuilder

+
+

Public Functions

+
+
+virtual Status Build(Client &client) = 0#
+

Building the object means construct all blobs of this object to vineyard server.

+
+
Parameters
+

client – The vineyard client that been used to create blobs in the connected vineyard server.

+
+
+
+ +
+
+virtual std::shared_ptr<Object> _Seal(Client &client) = 0#
+

Sealing the object means construct the metadata for the object and create metadata in vineyard server.

+
+
Parameters
+

client – The vineyard client that been used to create metadata in the connected vineyard server.

+
+
+
+ +
+
+ +
+
+

Metadata#

+
+
+class ObjectMeta#
+

ObjectMeta is the type for metadata of an Object. The ObjectMeta can be treated as a dict-like type. If the metadata obtained from vineyard, the metadata is readonly. Otherwise key-value attributes or object members could be associated with the metadata to construct a new vineyard object.

+
+

Public Types

+
+
+using const_iterator = nlohmann::detail::iteration_proxy_value<json::const_iterator>#
+
+ +
+
+

Public Functions

+
+
+ObjectMeta()#
+
+ +
+
+~ObjectMeta()#
+
+ +
+
+ObjectMeta(const ObjectMeta&)#
+
+ +
+
+ObjectMeta &operator=(ObjectMeta const &other)#
+
+ +
+
+void SetClient(ClientBase *client)#
+

Associate the client with the metadata.

+
+ +
+
+ClientBase *GetClient() const#
+

Get the associate client with the metadata.

+
+ +
+
+void SetId(const ObjectID &id)#
+

Set the object ID for the metadata.

+
+ +
+
+const ObjectID GetId() const#
+

Get the corresponding object ID of the metadata.

+
+ +
+
+const Signature GetSignature() const#
+

Get the corresponding object signature of the metadata.

+
+ +
+
+void ResetSignature()#
+

Reset the signatures in the metadata (for duplicating objects).

+
+ +
+
+void SetGlobal(bool global = true)#
+

Mark the vineyard object as a global object.

+
+ +
+
+const bool IsGlobal() const#
+

Check whether the vineyard object is a global object.

+
+ +
+
+void SetTypeName(const std::string &type_name)#
+

Set the typename of the metadata. The typename will be used to resolve in the ObjectFactory to create new object instances when get objects from vineyard server.

+
+ +
+
+std::string const &GetTypeName() const#
+

Get the typename of the metadata.

+
+ +
+
+void SetNBytes(const size_t nbytes)#
+

Set the nbytes attribute for the metadata, basically it indicates the memory usage of the object.

+
+ +
+
+const size_t GetNBytes() const#
+

Get the nbytes attribute of the object. Note that the nbytes attribute doesn’t always reflect the TOTAL monopolistic space usage of the bulk store, since two objects may share some blobs.

+
+ +
+
+const InstanceID GetInstanceId() const#
+

Get the instance ID of vineyard server where the metadata is created on.

+
+ +
+
+const bool IsLocal() const#
+

Whether the object meta is the metadata of a local object.

+
+ +
+
+void ForceLocal() const#
+

Mark the metadata as a “local” metadata to make sure the construct process proceed.

+
+ +
+
+const bool Haskey(std::string const &key) const#
+

Whether specific key exists in this metadata.

+
+ +
+
+const bool HasKey(std::string const &key) const#
+

Whether specific key exists in this metadata.

+
+ +
+
+void ResetKey(std::string const &key)#
+

Reset the given key in the metadata.

+
+ +
+
+void AddKeyValue(const std::string &key, const std::string &value)#
+

Add a string value entry to the metadata.

+
+
Parameters
+
    +
  • key – The name of metadata entry.

  • +
  • value – The value of the metadata entry.

  • +
+
+
+
+ +
+
+template<typename T>
inline void AddKeyValue(const std::string &key, T const &value)#
+

Add a generic value entry to the metadata.

+
+
Parameters
+
    +
  • T – The type of metadata’s value.

  • +
  • key – The name of metadata entry.

  • +
  • value – The value of the metadata entry.

  • +
+
+
+
+ +
+
+template<typename T>
inline void AddKeyValue(const std::string &key, std::set<T> const &values)#
+

Add a generic set value entry to the metadata.

+
+
Parameters
+
    +
  • T – The type of metadata’s value.

  • +
  • key – The name of metadata entry, it will be first convert to JSON array by nlohmann::json.

  • +
  • value – The value of the metadata entry.

  • +
+
+
+
+ +
+
+template<typename T>
inline void AddKeyValue(const std::string &key, std::vector<T> const &values)#
+

Add a generic vector value entry to the metadata.

+
+
Parameters
+
    +
  • T – The type of metadata’s value.

  • +
  • key – The name of metadata entry, it will be first convert to JSON array by nlohmann::json.

  • +
  • value – The value of the metadata entry.

  • +
+
+
+
+ +
+
+template<typename T>
inline void AddKeyValue(const std::string &key, Tuple<T> const &values)#
+

Add a generic vector value entry to the metadata.

+
+
Parameters
+
    +
  • T – The type of metadata’s value.

  • +
  • key – The name of metadata entry, it will be first convert to JSON array by nlohmann::json.

  • +
  • value – The value of the metadata entry.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void AddKeyValue(const std::string &key, std::map<std::string, Value> const &values)#
+

Add a associated map value entry to the metadata.

+
+
Parameters
+
    +
  • Value – The type of metadata’s value.

  • +
  • key – The name of metadata entry, it will be first convert to string.

  • +
  • value – The value of the metadata entry.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void AddKeyValue(const std::string &key, Map<std::string, Value> const &values)#
+

Add a associated map value entry to the metadata.

+
+
Parameters
+
    +
  • Value – The type of metadata’s value.

  • +
  • key – The name of metadata entry, it will be first convert to string.

  • +
  • value – The value of the metadata entry.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void AddKeyValue(const std::string &key, std::map<json, Value> const &values)#
+

Add a associated map value entry to the metadata.

+
+
Parameters
+
    +
  • Value – The type of metadata’s value.

  • +
  • key – The name of metadata entry, it will be first convert to string.

  • +
  • value – The value of the metadata entry.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void AddKeyValue(const std::string &key, Map<json, Value> const &values)#
+

Add a associated map value entry to the metadata.

+
+
Parameters
+
    +
  • Value – The type of metadata’s value.

  • +
  • key – The name of metadata entry, it will be first convert to string.

  • +
  • value – The value of the metadata entry.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void AddKeyValue(const std::string &key, std::unordered_map<std::string, Value> const &values)#
+

Add a associated map value entry to the metadata.

+
+
Parameters
+
    +
  • Value – The type of metadata’s value.

  • +
  • key – The name of metadata entry, it will be first convert to string.

  • +
  • value – The value of the metadata entry.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void AddKeyValue(const std::string &key, UnorderedMap<std::string, Value> const &values)#
+

Add a associated map value entry to the metadata.

+
+
Parameters
+
    +
  • Value – The type of metadata’s value.

  • +
  • key – The name of metadata entry, it will be first convert to string.

  • +
  • value – The value of the metadata entry.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void AddKeyValue(const std::string &key, std::unordered_map<json, Value> const &values)#
+

Add a associated map value entry to the metadata.

+
+
Parameters
+
    +
  • Value – The type of metadata’s value.

  • +
  • key – The name of metadata entry, it will be first convert to string.

  • +
  • value – The value of the metadata entry.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void AddKeyValue(const std::string &key, UnorderedMap<json, Value> const &values)#
+

Add a associated map value entry to the metadata.

+
+
Parameters
+
    +
  • Value – The type of metadata’s value.

  • +
  • key – The name of metadata entry, it will be first convert to string.

  • +
  • value – The value of the metadata entry.

  • +
+
+
+
+ +
+
+void AddKeyValue(const std::string &key, json const &values)#
+

Add a nlohmann::json value entry to the metadata.

+
+
Parameters
+
    +
  • T – The type of metadata’s value.

  • +
  • key – The name of metadata entry, it will be first convert to string by nlohmann::json.

  • +
  • value – The value of the metadata entry.

  • +
+
+
+
+ +
+
+inline const std::string GetKeyValue(const std::string &key) const#
+

Get string metadata value.

+
+
Parameters
+

key – The key of metadata.

+
+
+
+ +
+
+template<typename T>
inline const T GetKeyValue(const std::string &key) const#
+

Get generic metadata value.

+
+
Parameters
+
    +
  • T – The type of metadata value.

  • +
  • key – The key of metadata.

  • +
+
+
+
+ +
+
+template<typename T>
inline void GetKeyValue(const std::string &key, T &value) const#
+

Get generic metadata value, with automatically type deduction.

+
+
Parameters
+
    +
  • T – The type of metadata value.

  • +
  • key – The key of metadata.

  • +
  • value – The result will be stored in value, the generic result is pass by reference to help type deduction.

  • +
+
+
+
+ +
+
+template<typename T>
inline void GetKeyValue(const std::string &key, std::set<T> &values) const#
+

Get generic set metadata value, with automatically type deduction.

+
+
Parameters
+
    +
  • T – The type of metadata value.

  • +
  • key – The key of metadata.

  • +
  • value – The result will be stored in value, the generic result is pass by reference to help type deduction.

  • +
+
+
+
+ +
+
+template<typename T>
inline void GetKeyValue(const std::string &key, std::vector<T> &values) const#
+

Get generic vector metadata value, with automatically type deduction.

+
+
Parameters
+
    +
  • T – The type of metadata value.

  • +
  • key – The key of metadata.

  • +
  • value – The result will be stored in value, the generic result is pass by reference to help type deduction.

  • +
+
+
+
+ +
+
+template<typename T>
inline void GetKeyValue(const std::string &key, Tuple<T> &values) const#
+

Get generic vector metadata value, with automatically type deduction.

+
+
Parameters
+
    +
  • T – The type of metadata value.

  • +
  • key – The key of metadata.

  • +
  • value – The result will be stored in value, the generic result is pass by reference to help type deduction.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void GetKeyValue(const std::string &key, std::map<std::string, Value> &values) const#
+

Get associated map metadata value, with automatically type deduction.

+
+
Parameters
+
    +
  • Value – The type of metadata value.

  • +
  • key – The key of metadata.

  • +
  • value – The result will be stored in value, the generic result is pass by reference to help type deduction.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void GetKeyValue(const std::string &key, Map<std::string, Value> &values) const#
+

Get associated map metadata value, with automatically type deduction.

+
+
Parameters
+
    +
  • Value – The type of metadata value.

  • +
  • key – The key of metadata.

  • +
  • value – The result will be stored in value, the generic result is pass by reference to help type deduction.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void GetKeyValue(const std::string &key, std::map<json, Value> &values) const#
+

Get associated map metadata value, with automatically type deduction.

+
+
Parameters
+
    +
  • Value – The type of metadata value.

  • +
  • key – The key of metadata.

  • +
  • value – The result will be stored in value, the generic result is pass by reference to help type deduction.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void GetKeyValue(const std::string &key, Map<json, Value> &values) const#
+

Get associated map metadata value, with automatically type deduction.

+
+
Parameters
+
    +
  • Value – The type of metadata value.

  • +
  • key – The key of metadata.

  • +
  • value – The result will be stored in value, the generic result is pass by reference to help type deduction.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void GetKeyValue(const std::string &key, std::unordered_map<std::string, Value> &values) const#
+

Get associated map metadata value, with automatically type deduction.

+
+
Parameters
+
    +
  • Value – The type of metadata value.

  • +
  • key – The key of metadata.

  • +
  • value – The result will be stored in value, the generic result is pass by reference to help type deduction.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void GetKeyValue(const std::string &key, UnorderedMap<std::string, Value> &values) const#
+

Get associated map metadata value, with automatically type deduction.

+
+
Parameters
+
    +
  • Value – The type of metadata value.

  • +
  • key – The key of metadata.

  • +
  • value – The result will be stored in value, the generic result is pass by reference to help type deduction.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void GetKeyValue(const std::string &key, std::unordered_map<json, Value> &values) const#
+

Get associated map metadata value, with automatically type deduction.

+
+
Parameters
+
    +
  • Value – The type of metadata value.

  • +
  • key – The key of metadata.

  • +
  • value – The result will be stored in value, the generic result is pass by reference to help type deduction.

  • +
+
+
+
+ +
+
+template<typename Value>
inline void GetKeyValue(const std::string &key, UnorderedMap<json, Value> &values) const#
+

Get associated map metadata value, with automatically type deduction.

+
+
Parameters
+
    +
  • Value – The type of metadata value.

  • +
  • key – The key of metadata.

  • +
  • value – The result will be stored in value, the generic result is pass by reference to help type deduction.

  • +
+
+
+
+ +
+
+void GetKeyValue(const std::string &key, json &value) const#
+

Get json metadata value.

+
+
Parameters
+
    +
  • key – The key of metadata.

  • +
  • value – The result will be stored in value.

  • +
+
+
+
+ +
+
+void AddMember(const std::string &name, const ObjectMeta &member)#
+

Add member to ObjectMeta.

+
+
Parameters
+
    +
  • name – The name of member object.

  • +
  • member – The metadata of member object to be added.

  • +
+
+
+
+ +
+
+void AddMember(const std::string &name, const Object &member)#
+

Add member to ObjectMeta.

+
+
Parameters
+
    +
  • name – The name of member object.

  • +
  • member – The member object to be added.

  • +
+
+
+
+ +
+
+void AddMember(const std::string &name, const Object *member)#
+

Add member to ObjectMeta.

+
+
Parameters
+
    +
  • name – The name of member object.

  • +
  • member – The member object to be added.

  • +
+
+
+
+ +
+
+void AddMember(const std::string &name, const std::shared_ptr<Object> &member)#
+

Add member to ObjectMeta.

+
+
Parameters
+
    +
  • name – The name of member object.

  • +
  • member – The member object to be added.

  • +
+
+
+
+ +
+
+void AddMember(const std::string &name, const ObjectID member_id)#
+

Add member to ObjectMeta.

+
+
Parameters
+
    +
  • name – The name of member object.

  • +
  • member – The object ID of member object to be added.

  • +
+
+
+
+ +
+
+std::shared_ptr<Object> GetMember(const std::string &name) const#
+

Get member value from vineyard.

+
+
Parameters
+

name – The name of member object.

+
+
Returns
+

member The member object.

+
+
+
+ +
+
+Status GetMember(const std::string &name, std::shared_ptr<Object> &object) const#
+

Get member value from vineyard.

+
+
Parameters
+

name – The name of member object.

+
+
Returns
+

member The member object.

+
+
+
+ +
+
+template<typename T>
inline std::shared_ptr<T> GetMember(const std::string &name) const#
+

Get member value from vineyard.

+
+
Parameters
+

name – The name of member object.

+
+
Returns
+

member The member object.

+
+
+
+ +
+
+template<typename T>
inline Status GetMember(const std::string &name, std::shared_ptr<T> &object) const#
+

Get member value from vineyard.

+
+
Parameters
+

name – The name of member object.

+
+
Returns
+

member The member object.

+
+
+
+ +
+
+ObjectMeta GetMemberMeta(const std::string &name) const#
+

Get member’s ObjectMeta value.

+
+
Parameters
+

name – The name of member object.

+
+
Returns
+

member The metadata of member object. will be stored in value.

+
+
+
+ +
+
+Status GetMemberMeta(const std::string &name, ObjectMeta &meta) const#
+

Get member’s ObjectMeta value.

+
+
Parameters
+
    +
  • name – The name of member object.

  • +
  • meta – The metadata of member object.

  • +
+
+
Returns
+

Whether the member metadata has been found.

+
+
+
+ +
+
+Status GetBuffer(const ObjectID blob_id, std::shared_ptr<Buffer> &buffer) const#
+

Get buffer member (directed or indirected) from the metadata. The metadata should has already been initialized.

+
+ +
+
+void SetBuffer(const ObjectID &id, const std::shared_ptr<Buffer> &buffer)#
+
+ +
+
+void Reset()#
+

Reset the metadata as an initialized one.

+
+ +
+
+size_t MemoryUsage() const#
+

Compute the memory usage of this object.

+
+ +
+
+size_t MemoryUsage(json &usages, const bool pretty = true) const#
+

Compute the memory usage of this object, in a json tree format.

+
+ +
+
+uint64_t Timestamp() const#
+

Get the associate timestamp (in milliseconds) inside the metadata, 0 means unknown.

+
+ +
+
+json Labels() const#
+
+ +
+
+const std::string Label(const std::string &key) const#
+
+ +
+
+std::string ToString() const#
+
+ +
+
+void PrintMeta() const#
+
+ +
+
+const bool incomplete() const#
+
+ +
+
+const json &MetaData() const#
+
+ +
+
+json &MutMetaData()#
+
+ +
+
+void SetMetaData(ClientBase *client, const json &meta)#
+
+ +
+
+inline const_iterator begin() const#
+
+ +
+
+inline const_iterator end() const#
+
+ +
+
+const std::shared_ptr<BufferSet> &GetBufferSet() const#
+
+ +
+
+template<>
const json GetKeyValue(const std::string &key) const#
+
+ +
+
+template<>
const json GetKeyValue(const std::string &key) const
+
+ +
+
+

Public Static Functions

+
+
+static std::unique_ptr<ObjectMeta> Unsafe(std::string meta, size_t nobjects, ObjectID *objects, uintptr_t *pointers, size_t *sizes)#
+

Construct object metadata from unsafe sources.

+
+ +
+
+static std::unique_ptr<ObjectMeta> Unsafe(json meta, size_t nobjects, ObjectID *objects, uintptr_t *pointers, size_t *sizes)#
+

Construct object metadata from unsafe sources.

+
+ +
+
+ +
+
+

Vineyard Clients#

+
+
+class ClientBase#
+

ClientBase is the base class for vineyard IPC and RPC client.

+

ClientBase implements common communication stuffs, and leave the IPC and RPC specific functionalities to Client and RPCClient.

+

Vineyard’s Client and RPCClient is non-copyable.

+

Subclassed by vineyard::BasicIPCClient, vineyard::RPCClient

+
+

Public Functions

+
+
+ClientBase()#
+
+ +
+
+inline virtual ~ClientBase()#
+
+ +
+
+inline virtual Status Release(ObjectID const &id)#
+
+ +
+
+ClientBase(const ClientBase&) = delete#
+
+ +
+
+ClientBase(ClientBase&&) = delete#
+
+ +
+
+ClientBase &operator=(const ClientBase&) = delete#
+
+ +
+
+ClientBase &operator=(ClientBase&&) = delete#
+
+ +
+
+Status GetData(const ObjectID id, json &tree, const bool sync_remote = false, const bool wait = false)#
+

Get object metadata from vineyard using given object ID.

+
+
Parameters
+
    +
  • id – The ID of the requested object.

  • +
  • tree – The returned metadata tree of the requested object.

  • +
  • sync_remote – Whether to trigger an immediate remote metadata synchronization before get specific metadata. Default is false.

  • +
  • wait – The request could be blocked util the object with given id has been created on vineyard by other clients. Default is false.

  • +
+
+
Returns
+

Status that indicates whether the get action succeeds.

+
+
+
+ +
+
+Status GetData(const std::vector<ObjectID> &ids, std::vector<json> &trees, const bool sync_remote = false, const bool wait = false)#
+

Get multiple object metadatas from vineyard using given object IDs.

+
+
Parameters
+
    +
  • ids – The IDs of the requested objects

  • +
  • trees – The returned metadata trees of the requested objects

  • +
  • sync_remote – Whether to trigger an immediate remote metadata synchronization before get specific metadata. Default is false.

  • +
  • wait – The request could be blocked util the object with given id has been created on vineyard by other clients. Default is false.

  • +
+
+
Returns
+

Status that indicates whether the get action has succeeded.

+
+
+
+ +
+
+Status CreateData(const json &tree, ObjectID &id, Signature &signature, InstanceID &instance_id)#
+

Create the metadata in the vineyard server.

+
+
Parameters
+
    +
  • tree – The metadata that will be created in vineyard.

  • +
  • id – The returned object ID of the created data.

  • +
  • instance_id – The vineyard instance ID where this object is created. at.

  • +
+
+
Returns
+

Status that indicates whether the create action has succeeded.

+
+
+
+ +
+
+Status CreateMetaData(ObjectMeta &meta_data, ObjectID &id)#
+

Create the metadata in the vineyard server, after created, the resulted object id in the meta_data will be filled.

+
+
Parameters
+
    +
  • meta_data – The metadata that will be created in vineyard.

  • +
  • id – The returned object ID of the created metadata.

  • +
+
+
Returns
+

Status that indicates whether the create action has succeeded.

+
+
+
+ +
+
+Status CreateMetaData(ObjectMeta &meta_data, InstanceID const &instance_id, ObjectID &id)#
+

Create the metadata in the vineyard server with specified instance id, after created, the resulted object id in the meta_data will be filled.

+

The specified instance id is required that the metadata can be created using the RPC client on the specified instance as a placeholder.

+
+
Parameters
+
    +
  • meta_data – The metadata that will be created in vineyard.

  • +
  • id – The returned object ID of the created metadata.

  • +
+
+
Returns
+

Status that indicates whether the create action has succeeded.

+
+
+
+ +
+
+virtual Status GetMetaData(const ObjectID id, ObjectMeta &meta_data, const bool sync_remote = false) = 0#
+

Get the meta-data of the requested object.

+
+
Parameters
+
    +
  • id – The ID of the requested object

  • +
  • meta_data – The returned metadata of the requested object

  • +
  • sync_remote – Whether trigger remote sync

  • +
+
+
Returns
+

Status that indicates whether the get action has succeeded.

+
+
+
+ +
+
+Status SyncMetaData()#
+

Sync remote metadata from etcd to the connected vineyardd.

+
+
Returns
+

Status that indicates whether the sync action has succeeded.

+
+
+
+ +
+
+Status DelData(const ObjectID id, const bool force = false, const bool deep = true)#
+

Delete metadata in vineyard. When the object is a used by other object, it will be deleted only when the force parameter is specified.

+
+
Parameters
+
    +
  • id – The ID to delete.

  • +
  • force – Whether to delete the object forcely. Forcely delete an object means the object and objects which use this object will be delete. Default is false.

  • +
  • deep – Whether to delete the member of this object. Default is true. Note that when deleting object which has direct blob members, the processing on those blobs yields a “deep” behavior.

  • +
+
+
Returns
+

Status that indicates whether the delete action has succeeded.

+
+
+
+ +
+
+Status DelData(const std::vector<ObjectID> &ids, const bool force = false, const bool deep = true)#
+

Delete multiple metadatas in vineyard.

+
+
Parameters
+
    +
  • ids – The IDs to delete.

  • +
  • force – Whether to delete the object forcely. Forcely delete an object means the object and objects which use this object will be delete. Default is false.

  • +
  • deep – Whether to delete the member of this object. Default is true. Note that when deleting objects which have direct blob members, the processing on those blobs yields a “deep” behavior.

  • +
+
+
Returns
+

Status that indicates whether the delete action has succeeded.

+
+
+
+ +
+
+Status ListData(std::string const &pattern, bool const regex, size_t const limit, std::unordered_map<ObjectID, json> &meta_trees)#
+

List objectmetas in vineyard, using the given typename patterns.

+
+
Parameters
+
    +
  • pattern – The pattern string that will be used to matched against objects’ typename.

  • +
  • regex – Whether the pattern is a regular expression pattern. Default is false. When regex is false, the pattern will be treated as a glob pattern.

  • +
  • limit – The number limit for how many objects will be returned at most.

  • +
  • meta_trees – An map that contains the returned object metadatas.

  • +
+
+
Returns
+

Status that indicates whether the list action has succeeded.

+
+
+
+ +
+
+Status ListNames(std::string const &pattern, bool const regex, size_t const limit, std::map<std::string, ObjectID> &names)#
+

List names in vineyard, using the given name patterns.

+
+
Parameters
+
    +
  • pattern – The pattern string that will be used to matched against objects’ name.

  • +
  • regex – Whether the pattern is a regular expression pattern. Default is false. When regex is false, the pattern will be treated as a glob pattern.

  • +
  • limit – The number limit for how many objects will be returned at most.

  • +
  • names – An map that contains the returned names and corresponding object ids.

  • +
+
+
Returns
+

Status that indicates whether the list action has succeeded.

+
+
+
+ +
+
+Status CreateStream(const ObjectID &id)#
+

Allocate a stream on vineyard. The metadata of parameter id must has already been created on vineyard.

+
+
Parameters
+

id – The id of metadata that will be used to create stream.

+
+
Returns
+

Status that indicates whether the create action has succeeded.

+
+
+
+ +
+
+Status OpenStream(const ObjectID &id, StreamOpenMode mode)#
+

open a stream on vineyard. Failed if the stream is already opened on the given mode.

+
+
Parameters
+
    +
  • id – The id of stream to mark.

  • +
  • mode – The mode, StreamOpenMode::read or StreamOpenMode::write.

  • +
+
+
Returns
+

Status that indicates whether the open action has succeeded.

+
+
+
+ +
+
+Status PushNextStreamChunk(ObjectID const id, ObjectID const chunk)#
+

Push a chunk from a stream. When there’s no more chunk available in the stream, i.e., the stream has been stopped, a status code kStreamDrained or kStreamFinish will be returned, otherwise the reader will be blocked until writer creates a new chunk in the stream.

+
+
Parameters
+
    +
  • id – The id of the stream.

  • +
  • blob – The immutable chunk generated by the writer of the stream.

  • +
+
+
Returns
+

Status that indicates whether the polling has succeeded.

+
+
+
+ +
+
+Status PullNextStreamChunk(ObjectID const id, ObjectID &chunk)#
+

Pull a chunk from a stream. When there’s no more chunk available in the stream, i.e., the stream has been stopped, a status code kStreamDrained or kStreamFinish will be returned, otherwise the reader will be blocked until writer creates a new chunk in the stream.

+
+
Parameters
+
    +
  • id – The id of the stream.

  • +
  • chunk – The immutable chunk generated by the writer of the stream.

  • +
+
+
Returns
+

Status that indicates whether the polling has succeeded.

+
+
+
+ +
+
+Status PullNextStreamChunk(ObjectID const id, ObjectMeta &chunk)#
+

Pull a chunk from a stream. When there’s no more chunk available in the stream, i.e., the stream has been stopped, a status code kStreamDrained or kStreamFinish will be returned, otherwise the reader will be blocked until writer creates a new chunk in the stream.

+
+
Parameters
+
    +
  • id – The id of the stream.

  • +
  • chunk – The immutable chunk generated by the writer of the stream.

  • +
+
+
Returns
+

Status that indicates whether the polling has succeeded.

+
+
+
+ +
+
+Status PullNextStreamChunk(ObjectID const id, std::shared_ptr<Object> &chunk)#
+

Pull a chunk from a stream. When there’s no more chunk available in the stream, i.e., the stream has been stopped, a status code kStreamDrained or kStreamFinish will be returned, otherwise the reader will be blocked until writer creates a new chunk in the stream.

+
+
Parameters
+
    +
  • id – The id of the stream.

  • +
  • chunk – The immutable chunk generated by the writer of the stream.

  • +
+
+
Returns
+

Status that indicates whether the polling has succeeded.

+
+
+
+ +
+
+Status StopStream(ObjectID const id, bool failed)#
+

Stop a stream, mark it as finished or aborted.

+
+
Parameters
+
    +
  • id – The id of the stream.

  • +
  • failed – Whether the stream is stopped at a successful state. True means the stream has been exited normally, otherwise false.

  • +
+
+
Returns
+

Status that indicates whether the request has succeeded.

+
+
+
+ +
+
+Status DropStream(ObjectID const id)#
+

Close a stream, mark it as aborted if it is not finished yet.

+
+
Parameters
+

id – The id of the stream.

+
+
Returns
+

Status that indicates whether the request has succeeded.

+
+
+
+ +
+
+Status Persist(const ObjectID id)#
+

Persist the given object to etcd to make it visible to clients that been connected to vineyard servers in the cluster.

+
+
Parameters
+

id – The object id of object that will be persisted.

+
+
Returns
+

Status that indicates whether the persist action has succeeded.

+
+
+
+ +
+
+Status IfPersist(const ObjectID id, bool &persist)#
+

Check if the given object has been persist to etcd.

+
+
Parameters
+
    +
  • id – The object id to check.

  • +
  • persist – The result variable will be stored in persist as return value. The value true means the object is visible by other vineyard servers.

  • +
+
+
Returns
+

Status that indicates whether the check has succeeded.

+
+
+
+ +
+
+Status Exists(const ObjectID id, bool &exists)#
+

Check if the given object exists in vineyard server.

+
+
Parameters
+
    +
  • id – The object id to check.

  • +
  • exists – The result variable will be stored in exists as return value. The value true means the object exists.

  • +
+
+
Returns
+

Status that indicates whether the check has succeeded.

+
+
+
+ +
+
+Status ShallowCopy(const ObjectID id, ObjectID &target_id)#
+

Make a shallow copy on the given object. A “shallow copy” means the result object has the same type with the source object and they shares all member objects.

+
+
Parameters
+
    +
  • id – The object id to shallow copy.

  • +
  • target_id – The result object id will be stored in target_id as return value.

  • +
+
+
Returns
+

Status that indicates whether the shallow copy has succeeded.

+
+
+
+ +
+
+Status ShallowCopy(const ObjectID id, json const &extra_metadata, ObjectID &target_id)#
+

Make a shallow copy on the given object. A “shallow copy” means the result object has the same type with the source object and they share all member objects.

+
+
Parameters
+
    +
  • id – The object id to shallow copy.

  • +
  • extra_metadata – Feed extra metadata when shallow copying.

  • +
  • target_id – The result object id will be stored in target_id as return value.

  • +
+
+
Returns
+

Status that indicates whether the shallow copy has succeeded.

+
+
+
+ +
+
+Status PutName(const ObjectID id, std::string const &name)#
+

Vineyard support associating a user-specific name with an object. PutName registers a name entry in vineyard server. An object can be assoiciated with more than one names.

+
+
Parameters
+
    +
  • id – The ID of the object.

  • +
  • name – The user-specific name that will be associated with the given object.

  • +
+
+
Returns
+

Status that indicates whether the request has succeeded.

+
+
+
+ +
+
+Status GetName(const std::string &name, ObjectID &id, const bool wait = false)#
+

Retrieve the object ID by associated name.

+
+
Parameters
+
    +
  • name – The name of the requested object.

  • +
  • id – The returned object ID.

  • +
  • wait – If wait is specified, the request will be blocked util the given name has been registered on vineyard by other clients.

  • +
+
+
Returns
+

Status that indicates whether the query has succeeded.

+
+
+
+ +
+
+Status DropName(const std::string &name)#
+

Deregister a name entry. The associated object will be kept and won’t be deleted.

+
+
Parameters
+

name – The name that will be deregistered.

+
+
Returns
+

Status that indicates whether the query has succeeded.

+
+
+
+ +
+
+Status MigrateObject(const ObjectID object_id, ObjectID &result_id)#
+

Migrate remote object to connected instance.

+
+
Parameters
+
    +
  • object_id – The existing object that will be migrated to current vineyardd.

  • +
  • result_id – Record the result object id.

  • +
+
+
Returns
+

Status that indicates if the migration success.

+
+
+
+ +
+
+Status Clear()#
+

Clear all objects that are visible to current instances in the cluster.

+
+ +
+
+Status Label(const ObjectID object, std::string const &key, std::string const &value)#
+

Associate given labels to an existing object.

+
+
Parameters
+

objectObject to be labeled.

+
+
+
+ +
+
+Status Label(const ObjectID object, std::map<std::string, std::string> const &labels)#
+

Associate given labels to an existing object.

+
+
Parameters
+

objectObject to be labeled.

+
+
+
+ +
+
+Status Evict(std::vector<ObjectID> const &objects)#
+

Evict objects from the vineyardd server.

+
+
Parameters
+

objects – Objects to be evicted.

+
+
+
+ +
+
+Status Load(std::vector<ObjectID> const &objects, const bool pin = false)#
+

Load objects to ensure they resident in vineyardd server’s memory, with an optional arguments to pin these objects to prevent from being spilled.

+
+
Parameters
+

objects – Objects to be reloaded, and possibly pinned.

+
+
+
+ +
+
+Status Unpin(std::vector<ObjectID> const &objects)#
+

Unpin objects from the vineyardd server’s memory.

+
+
Parameters
+

objects – Objects to be unpinned.

+
+
+
+ +
+
+bool Connected() const#
+

Check if the client still connects to the vineyard server.

+
+
Returns
+

True when the connection is still alive, otherwise false.

+
+
+
+ +
+
+void Disconnect()#
+

Disconnect this client.

+
+ +
+
+Status Open(std::string const &ipc_socket)#
+

Create a new anonymous session in vineyardd and connect to it .

+
+
Parameters
+

ipc_socket – Location of the UNIX domain socket.

+
+
Returns
+

Status that indicates whether the connection of has succeeded.

+
+
+
+ +
+
+void CloseSession()#
+

Close the session that the client is connecting to.

+
+ +
+
+inline std::string const &IPCSocket()#
+

Get the UNIX domain socket location of the connected vineyardd server.

+
+
Returns
+

Location of the IPC socket.

+
+
+
+ +
+
+inline std::string const &RPCEndpoint()#
+

The RPC endpoint of the connected vineyardd server.

+
+
Returns
+

The RPC endpoint.

+
+
+
+ +
+
+inline const InstanceID instance_id() const#
+

Get the instance id of the connected vineyard server.

+

Note that for RPC client the instance id is not available.

+
+
Returns
+

The vineyard server’s instance id.

+
+
+
+ +
+
+inline virtual const InstanceID remote_instance_id() const#
+

Get the remote instance id of the connected vineyard server.

+

Note that for RPC client the instance id is not available, thus we have the “remote instance id” to indicate which server we are connecting to.

+
+
Returns
+

The vineyard server’s instance id.

+
+
+
+ +
+
+inline const SessionID session_id() const#
+

Get the session id of the connected vineyard server.

+

Note that for RPC client the instance id is not available.

+
+
Returns
+

The vineyard server’s session id.

+
+
+
+ +
+
+Status ClusterInfo(std::map<InstanceID, json> &meta)#
+

Retrieve the cluster information of the connected vineyard server.

+

The cluster information for every instance mainly includes the host address (i.e., ip address).

+
+
Returns
+

Status that indicates whether the query has succeeded.

+
+
+
+ +
+
+Status InstanceStatus(std::shared_ptr<struct InstanceStatus> &status)#
+

Return the status of connected vineyard instance.

+

If success, the status parameter will be reset as an instance of InstanceStatus.

+
+
Parameters
+

status – The result instance status.

+
+
Returns
+

Status that indicates whether the query has succeeded.

+
+
+
+ +
+
+Status Instances(std::vector<InstanceID> &instances)#
+

List all instances in the connected vineyard cluster.

+
+
Parameters
+

A – list of instance IDs will be stored in instances.

+
+
Returns
+

Status that indicates whether the query has succeeded.

+
+
+
+ +
+
+inline const std::string &Version() const#
+

Get the version of connected vineyard server.

+
+
Returns
+

Return a version string MAJOR.MINOR.PATCH that follows the semver convention.

+
+
+
+ +
+
+Status Debug(const json &debug, json &tree)#
+

Issue a debug request.

+
+
Parameters
+
    +
  • debug – The payload that will be sent to the debug handler.

  • +
  • result – The result that returned by the debug handler.

  • +
+
+
Returns
+

Status that indicates whether the debug action succeeds.

+
+
+
+ +
+
+

Protected Functions

+
+
+Status doWrite(const std::string &message_out)#
+
+ +
+
+Status doRead(std::string &message_in)#
+
+ +
+
+Status doRead(json &root)#
+
+ +
+
+

Protected Attributes

+
+
+mutable bool connected_#
+
+ +
+
+std::string ipc_socket_#
+
+ +
+
+std::string rpc_endpoint_#
+
+ +
+
+int vineyard_conn_#
+
+ +
+
+SessionID session_id_#
+
+ +
+
+InstanceID instance_id_#
+
+ +
+
+std::string server_version_#
+
+ +
+
+mutable std::recursive_mutex client_mutex_#
+
+ +
+
+ +
+
+class Client : public vineyard::BasicIPCClient, protected vineyard::detail::UsageTracker<ObjectID, Payload, Client>#
+

Vineyard’s IPC Client connects to to UNIX domain socket of the vineyard server. Vineyard’s IPC Client talks to vineyard server and manipulate objects in vineyard.

+
+

Public Functions

+
+
+inline Client()#
+
+ +
+
+~Client() override#
+
+ +
+
+Status Connect()#
+

Connect to vineyard using the UNIX domain socket file specified by the environment variable VINEYARD_IPC_SOCKET.

+
+
Returns
+

Status that indicates whether the connect has succeeded.

+
+
+
+ +
+
+Status Connect(std::string const &username, std::string const &password)#
+

Connect to vineyard using the UNIX domain socket file specified by the environment variable VINEYARD_IPC_SOCKET.

+
+
Returns
+

Status that indicates whether the connect has succeeded.

+
+
+
+ +
+
+Status Connect(const std::string &ipc_socket)#
+

Connect to vineyardd using the given UNIX domain socket ipc_socket.

+
+
Parameters
+

ipc_socket – Location of the UNIX domain socket.

+
+
Returns
+

Status that indicates whether the connect has succeeded.

+
+
+
+ +
+
+Status Connect(const std::string &ipc_socket, std::string const &username, std::string const &password)#
+

Connect to vineyardd using the given UNIX domain socket ipc_socket.

+
+
Parameters
+

ipc_socket – Location of the UNIX domain socket.

+
+
Returns
+

Status that indicates whether the connect has succeeded.

+
+
+
+ +
+
+void Disconnect()#
+

Disconnect this client.

+
+ +
+
+Status Open(std::string const &ipc_socket)#
+

Create a new anonymous session in vineyardd and connect to it .

+
+
Parameters
+

ipc_socket – Location of the UNIX domain socket.

+
+
Returns
+

Status that indicates whether the connection of has succeeded.

+
+
+
+ +
+
+Status Open(std::string const &ipc_socket, std::string const &username, std::string const &password)#
+

Create a new anonymous session in vineyardd and connect to it .

+
+
Parameters
+

ipc_socket – Location of the UNIX domain socket.

+
+
Returns
+

Status that indicates whether the connection of has succeeded.

+
+
+
+ +
+
+Status Fork(Client &client)#
+

Create a new client using self UNIX domain socket.

+
+ +
+
+virtual Status GetMetaData(const ObjectID id, ObjectMeta &meta_data, const bool sync_remote = false) override#
+

Obtain metadata from vineyard server.

+
+
Parameters
+
    +
  • id – The object id to get.

  • +
  • meta_data – The result metadata will be store in meta_data as return value.

  • +
  • sync_remote – Whether to trigger an immediate remote metadata synchronization before get specific metadata. Default is false.

  • +
+
+
Returns
+

Status that indicates whether the get action has succeeded.

+
+
+
+ +
+
+Status FetchAndGetMetaData(const ObjectID id, ObjectMeta &meta_data, const bool sync_remote = false)#
+

Obtain metadata from vineyard server.

+
+
Parameters
+
    +
  • id – The object id to get.

  • +
  • meta_data – The result metadata will be store in meta_data as return value.

  • +
  • sync_remote – Whether to trigger an immediate remote metadata synchronization before get specific metadata. Default is false.

  • +
+
+
Returns
+

Status that indicates whether the get action has succeeded.

+
+
+
+ +
+
+Status GetMetaData(const std::vector<ObjectID> &ids, std::vector<ObjectMeta>&, const bool sync_remote = false)#
+

Obtain multiple metadatas from vineyard server.

+
+
Parameters
+
    +
  • ids – The object ids to get.

  • +
  • meta_data – The result metadata will be store in meta_data as return value.

  • +
  • sync_remote – Whether to trigger an immediate remote metadata synchronization before get specific metadata. Default is false.

  • +
+
+
Returns
+

Status that indicates whether the get action has succeeded.

+
+
+
+ +
+
+Status CreateBlob(size_t size, std::unique_ptr<BlobWriter> &blob)#
+

Create a blob in vineyard server. When creating a blob, vineyard server’s bulk allocator will prepare a block of memory of the requested size, then map the memory to client’s process to share the allocated memory.

+
+
Parameters
+
    +
  • size – The size of requested blob.

  • +
  • blob – The result mutable blob will be set in blob.

  • +
+
+
Returns
+

Status that indicates whether the create action has succeeded.

+
+
+
+ +
+
+Status GetBlob(ObjectID const id, std::shared_ptr<Blob> &blob)#
+

Get a blob from vineyard server.

+
+
Parameters
+

id – the blob to get.

+
+
Returns
+

Status that indicates whether the get action has succeeded.

+
+
+
+ +
+
+Status GetBlob(ObjectID const id, bool unsafe, std::shared_ptr<Blob> &blob)#
+

Get a blob from vineyard server, and optionally bypass the “sealed” check.

+
+
Parameters
+

id – the blob to get.

+
+
Returns
+

Status that indicates whether the get action has succeeded.

+
+
+
+ +
+
+Status GetBlobs(std::vector<ObjectID> const ids, std::vector<std::shared_ptr<Blob>> &blobs)#
+

Get a blob from vineyard server.

+
+
Parameters
+

id – the blob to get.

+
+
Returns
+

Status that indicates whether the get action has succeeded.

+
+
+
+ +
+
+Status GetBlobs(std::vector<ObjectID> const ids, const bool unsafe, std::vector<std::shared_ptr<Blob>> &blobs)#
+

Get a blob from vineyard server, and optionally bypass the “sealed” check.

+
+
Parameters
+

id – the blob to get.

+
+
Returns
+

Status that indicates whether the get action has succeeded.

+
+
+
+ +
+
+Status CreateDiskBlob(size_t size, const std::string &path, std::unique_ptr<BlobWriter> &blob)#
+

Claim a shared blob that backed by a file on disk. Users need to provide either a filename to mmap, or an expected size to allocate the file on disk.

+

When mapping existing file as a blob, if the existing file size is smaller than specified “size”, the file will be enlarged using ftruncate().

+

Note that when deleting the blob that backed by files, the file won’t be automatically deleted by vineyard.

+
+
Parameters
+
    +
  • size – expected file size to allocate.

  • +
  • path – use existing file as the mmap buffer.

  • +
+
+
Returns
+

Status that indicates whether the get action has succeeded.

+
+
+
+ +
+
+Status GetNextStreamChunk(ObjectID const id, size_t const size, std::unique_ptr<MutableBuffer> &blob)#
+

Allocate a chunk of given size in vineyard for a stream. When the request cannot be satisfied immediately, e.g., vineyard doesn’t have enough memory or the specified has accumulated too many chunks, the request will be blocked until the request been processed.

+
+
Parameters
+
    +
  • id – The id of the stream.

  • +
  • size – The size of the chunk to allocate.

  • +
  • blob – The allocated mutable buffer will be set in blob.

  • +
+
+
Returns
+

Status that indicates whether the allocation has succeeded.

+
+
+
+ +
+
+Status PullNextStreamChunk(ObjectID const id, std::unique_ptr<Buffer> &chunk)#
+

Pull a chunk from a stream. When there’s no more chunk available in the stream, i.e., the stream has been stopped, a status code kStreamDrained or kStreamFinish will be returned, otherwise the reader will be blocked until writer creates a new chunk in the stream.

+
+
Parameters
+
    +
  • id – The id of the stream.

  • +
  • chunk – The immutable chunk generated by the writer of the stream.

  • +
+
+
Returns
+

Status that indicates whether the polling has succeeded.

+
+
+
+ +
+
+std::shared_ptr<Object> GetObject(const ObjectID id)#
+

Get an object from vineyard. The ObjectFactory will be used to resolve the constructor of the object.

+
+
Parameters
+

id – The object id to get.

+
+
Returns
+

A std::shared_ptr<Object> that can be safely cast to the underlying concrete object type. When the object doesn’t exists an std::runtime_error exception will be raised.

+
+
+
+ +
+
+std::shared_ptr<Object> FetchAndGetObject(const ObjectID id)#
+

Get an object from vineyard. The ObjectFactory will be used to resolve the constructor of the object.

+
+
Parameters
+

id – The object id to get.

+
+
Returns
+

A std::shared_ptr<Object> that can be safely cast to the underlying concrete object type. When the object doesn’t exists an std::runtime_error exception will be raised.

+
+
+
+ +
+
+Status GetObject(const ObjectID id, std::shared_ptr<Object> &object)#
+

Get an object from vineyard. The ObjectFactory will be used to resolve the constructor of the object.

+
+
Parameters
+
    +
  • id – The object id to get.

  • +
  • object – The result object will be set in parameter object.

  • +
+
+
Returns
+

When errors occur during the request, this method won’t throw exceptions, rather, it results a status to represents the error.

+
+
+
+ +
+
+Status FetchAndGetObject(const ObjectID id, std::shared_ptr<Object> &object)#
+

Get an object from vineyard. The ObjectFactory will be used to resolve the constructor of the object.

+
+
Parameters
+
    +
  • id – The object id to get.

  • +
  • object – The result object will be set in parameter object.

  • +
+
+
Returns
+

When errors occur during the request, this method won’t throw exceptions, rather, it results a status to represents the error.

+
+
+
+ +
+
+template<typename T>
inline std::shared_ptr<T> GetObject(const ObjectID id)#
+

Get an object from vineyard. The type parameter T will be used to resolve the constructor of the object.

+
+
Parameters
+

id – The object id to get.

+
+
Returns
+

A std::shared_ptr<Object> that can be safely cast to the underlying concrete object type. When the object doesn’t exists an std::runtime_error exception will be raised.

+
+
+
+ +
+
+template<typename T>
inline std::shared_ptr<T> FetchAndGetObject(const ObjectID id)#
+

Get an object from vineyard. The type parameter T will be used to resolve the constructor of the object.

+
+
Parameters
+

id – The object id to get.

+
+
Returns
+

A std::shared_ptr<Object> that can be safely cast to the underlying concrete object type. When the object doesn’t exists an std::runtime_error exception will be raised.

+
+
+
+ +
+
+template<typename T>
inline Status GetObject(const ObjectID id, std::shared_ptr<T> &object)#
+

Get an object from vineyard. The type parameter T will be used to resolve the constructor of the object.

+

This method can be used to get concrete object from vineyard without explicitly dynamic_cast, and the template type parameter can be deduced in many situations:

+
std::shared_ptr<Array<int>> int_array;
+client.GetObject(id, int_array);
+
+
+
+
Parameters
+
    +
  • id – The object id to get.

  • +
  • object – The result object will be set in parameter object.

  • +
+
+
Returns
+

When errors occur during the request, this method won’t throw exceptions, rather, it results a status to represents the error.

+
+
+
+ +
+
+template<typename T>
inline Status FetchAndGetObject(const ObjectID id, std::shared_ptr<T> &object)#
+

Get an object from vineyard. The type parameter T will be used to resolve the constructor of the object.

+

This method can be used to get concrete object from vineyard without explicitly dynamic_cast, and the template type parameter can be deduced in many situations:

+
std::shared_ptr<Array<int>> int_array;
+client.FetchAndGetObject(id, int_array);
+
+
+
+
Parameters
+
    +
  • id – The object id to get.

  • +
  • object – The result object will be set in parameter object.

  • +
+
+
Returns
+

When errors occur during the request, this method won’t throw exceptions, rather, it results a status to represents the error.

+
+
+
+ +
+
+std::vector<std::shared_ptr<Object>> GetObjects(const std::vector<ObjectID> &ids)#
+

Get multiple objects from vineyard.

+
+
Parameters
+

ids – The object IDs to get.

+
+
Returns
+

A list of objects.

+
+
+
+ +
+
+std::vector<ObjectMeta> ListObjectMeta(std::string const &pattern, const bool regex = false, size_t const limit = 5, bool nobuffer = false)#
+

List object metadatas in vineyard, using the given typename patterns.

+
+
Parameters
+
    +
  • pattern – The pattern string that will be used to matched against objects’ typename.

  • +
  • regex – Whether the pattern is a regular expression pattern. Default is false. When regex is false, the pattern will be treated as a glob pattern.

  • +
  • limit – The number limit for how many objects will be returned at most.

  • +
+
+
Returns
+

A vector of object metadatas that listed from vineyard server.

+
+
+
+ +
+
+std::vector<std::shared_ptr<Object>> ListObjects(std::string const &pattern, const bool regex = false, size_t const limit = 5)#
+

List objects in vineyard, using the given typename patterns.

+
+
Parameters
+
    +
  • pattern – The pattern string that will be used to matched against objects’ typename.

  • +
  • regex – Whether the pattern is a regular expression pattern. Default is false. When regex is false, the pattern will be treated as a glob pattern.

  • +
  • limit – The number limit for how many objects will be returned at most.

  • +
+
+
Returns
+

A vector of objects that listed from vineyard server.

+
+
+
+ +
+
+bool IsSharedMemory(const void *target) const#
+

Check if the given address belongs to the shared memory region.

+

+Return true if the address (client-side address) comes from the vineyard server.

+
+
Parameters
+

target – The pointer that been queried.

+
+
+
+ +
+
+bool IsSharedMemory(const uintptr_t target) const#
+

Check if the given address belongs to the shared memory region.

+

+Return true if the address (client-side address) comes from the vineyard server.

+
+
Parameters
+

target – The pointer that been queried.

+
+
+
+ +
+
+bool IsSharedMemory(const void *target, ObjectID &object_id) const#
+

Check if the given address belongs to the shared memory region.

+

+Return true if the address (client-side address) comes from the vineyard server.

+
+
Parameters
+
    +
  • target – The pointer that been queried.

  • +
  • object_id – Return the object id of the queried pointer, if found.

  • +
+
+
+
+ +
+
+bool IsSharedMemory(const uintptr_t target, ObjectID &object_id) const#
+

Check if the given address belongs to the shared memory region.

+

+Return true if the address (client-side address) comes from the vineyard server.

+
+
Parameters
+
    +
  • target – The pointer that been queried.

  • +
  • object_id – Return the object id of the queried pointer, if found.

  • +
+
+
+
+ +
+
+Status IsInUse(ObjectID const &id, bool &is_in_use)#
+

Check if the blob is a cold blob (no client is using it).

+

Return true if the the blob is in-use.

+
+ +
+
+Status IsSpilled(ObjectID const &id, bool &is_spilled)#
+

Check if the blob is a spilled blob (those no client is using and be dumped on disk).

+

Return true if the the blob is spilled.

+
+ +
+
+Status AllocatedSize(const ObjectID id, size_t &size)#
+

Get the allocated size for the given object.

+
+ +
+
+Status CreateArena(const size_t size, int &fd, size_t &available_size, uintptr_t &base, uintptr_t &space)#
+
+ +
+
+Status ReleaseArena(const int fd, std::vector<size_t> const &offsets, std::vector<size_t> const &sizes)#
+
+ +
+
+Status ShallowCopy(ObjectID const id, ObjectID &target_id, Client &source_client)#
+

Move the selected objects from the source session to the target.

+
+ +
+
+Status ShallowCopy(PlasmaID const plasma_id, ObjectID &target_id, PlasmaClient &source_client)#
+
+ +
+
+Status Release(std::vector<ObjectID> const &ids)#
+

Decrease the reference count of the object. It will trigger OnRelease behavior when reference count reaches zero. See UsageTracker.

+
+ +
+
+virtual Status Release(ObjectID const &id) override#
+
+ +
+
+Status DelData(const ObjectID id, const bool force = false, const bool deep = true)#
+

Delete metadata in vineyard. When the object is a used by other object, it will be deleted only when the force parameter is specified.

+
+
Parameters
+
    +
  • id – The ID to delete.

  • +
  • force – Whether to delete the object forcely. Forcely delete an object means the object and objects which use this object will be delete. Default is false.

  • +
  • deep – Whether to delete the member of this object. Default is true. Note that when deleting object which has direct blob members, the processing on those blobs yields a “deep” behavior.

  • +
+
+
Returns
+

Status that indicates whether the delete action has succeeded.

+
+
+
+ +
+
+Status DelData(const std::vector<ObjectID> &ids, const bool force = false, const bool deep = true)#
+

Delete multiple metadatas in vineyard.

+
+
Parameters
+
    +
  • ids – The IDs to delete.

  • +
  • force – Whether to delete the object forcely. Forcely delete an object means the object and objects which use this object will be delete. Default is false.

  • +
  • deep – Whether to delete the member of this object. Default is true. Note that when deleting objects which have direct blob members, the processing on those blobs yields a “deep” behavior.

  • +
+
+
Returns
+

Status that indicates whether the delete action has succeeded.

+
+
+
+ +
+
+Status CreateGPUBuffer(const size_t size, ObjectID &id, Payload &payload, std::shared_ptr<GPUUnifiedAddress> &gua)#
+
+ +
+
+Status GetGPUBuffers(const std::set<ObjectID> &ids, const bool unsafe, std::map<ObjectID, GPUUnifiedAddress> &GUAs)#
+

Get a set of blobs from vineyard server. See also GetBuffer.

+
+
Parameters
+
    +
  • idsObject ids for the blobs to get.

  • +
  • buffers – The result result cudaIpcMemhandles related to GPU blobs.

  • +
+
+
Returns
+

Status that indicates whether the get action has succeeded.

+
+
+
+ +
+
+Status PullNextStreamChunk(ObjectID const id, ObjectID &chunk)#
+

Pull a chunk from a stream. When there’s no more chunk available in the stream, i.e., the stream has been stopped, a status code kStreamDrained or kStreamFinish will be returned, otherwise the reader will be blocked until writer creates a new chunk in the stream.

+
+
Parameters
+
    +
  • id – The id of the stream.

  • +
  • chunk – The immutable chunk generated by the writer of the stream.

  • +
+
+
Returns
+

Status that indicates whether the polling has succeeded.

+
+
+
+ +
+
+Status PullNextStreamChunk(ObjectID const id, ObjectMeta &chunk)#
+

Pull a chunk from a stream. When there’s no more chunk available in the stream, i.e., the stream has been stopped, a status code kStreamDrained or kStreamFinish will be returned, otherwise the reader will be blocked until writer creates a new chunk in the stream.

+
+
Parameters
+
    +
  • id – The id of the stream.

  • +
  • chunk – The immutable chunk generated by the writer of the stream.

  • +
+
+
Returns
+

Status that indicates whether the polling has succeeded.

+
+
+
+ +
+
+Status PullNextStreamChunk(ObjectID const id, std::shared_ptr<Object> &chunk)#
+

Pull a chunk from a stream. When there’s no more chunk available in the stream, i.e., the stream has been stopped, a status code kStreamDrained or kStreamFinish will be returned, otherwise the reader will be blocked until writer creates a new chunk in the stream.

+
+
Parameters
+
    +
  • id – The id of the stream.

  • +
  • chunk – The immutable chunk generated by the writer of the stream.

  • +
+
+
Returns
+

Status that indicates whether the polling has succeeded.

+
+
+
+ +
+
+

Public Static Functions

+
+
+static Client &Default()#
+

Get a default client reference, using the UNIX domain socket file specified by the environment variable VINEYARD_IPC_SOCKET.

+
+
Returns
+

A reference of the default Client instance.

+
+
+
+ +
+
+

Protected Functions

+
+
+Status OnRelease(ObjectID const &id)#
+

Required by UsageTracker. When reference count reaches zero, send the ReleaseRequest to server.

+
+ +
+
+Status OnDelete(ObjectID const &id)#
+

Required by UsageTracker. Currently, the deletion does not respect the reference count, it will send the DelData to server and do the deletion forcely.

+
+ +
+
+Status PostSeal(ObjectMeta const &meta_data)#
+

Increase reference count after a new object is sealed.

+
+ +
+
+Status GetDependency(ObjectID const &id, std::set<ObjectID> &bids)#
+

Send request to server to get all underlying blobs of a object.

+
+ +
+
+Status CreateBuffer(const size_t size, ObjectID &id, Payload &payload, std::shared_ptr<MutableBuffer> &buffer)#
+
+ +
+
+Status GetBuffer(const ObjectID id, std::shared_ptr<Buffer> &buffer)#
+

Get a blob from vineyard server. When obtaining blobs from vineyard server, the memory address in the server process will be mmapped to the client’s process to share the memory.

+
+
Parameters
+
    +
  • idObject id for the blob to get.

  • +
  • buffer – The result immutable blob will be set in blob. Note that blob is special, since it can be get as immutable object before sealing.

  • +
+
+
Returns
+

Status that indicates whether the create action has succeeded.

+
+
+
+ +
+
+Status GetBuffers(const std::set<ObjectID> &ids, std::map<ObjectID, std::shared_ptr<Buffer>> &buffers)#
+

Get a set of blobs from vineyard server. See also GetBuffer.

+
+
Parameters
+
    +
  • idsObject ids for the blobs to get.

  • +
  • buffers – The result immutable blobs will be added to buffers.

  • +
+
+
Returns
+

Status that indicates whether the get action has succeeded.

+
+
+
+ +
+
+Status GetBufferSizes(const std::set<ObjectID> &ids, std::map<ObjectID, size_t> &sizes)#
+

Get the size of blobs from vineyard server.

+
+
Parameters
+
    +
  • idsObject ids for the blobs to get.

  • +
  • sizes – The result sizes of immutable blobs will be added to sizes.

  • +
+
+
Returns
+

Status that indicates whether the get action has succeeded.

+
+
+
+ +
+
+Status DropBuffer(const ObjectID id, const int fd)#
+

An (unsafe) internal-usage method that drop the buffer, without checking the dependency. To achieve the “DeleteObject” semantic for blobs, use DelData instead.

+

Note that the target buffer could be both sealed and unsealed.

+
+ +
+
+Status ShrinkBuffer(const ObjectID id, const size_t size)#
+

An (unsafe) internal-usage method that shrink the buffer, without allocating a new buffer and copying. The buffer to be shrink shouldn’t be sealed.

+

In the underlying server-side implementation, madvise is used.

+
+ +
+
+Status Seal(ObjectID const &object_id)#
+

mark the blob as sealed to control the visibility of a blob, client can never Get an unsealed blob.

+
+ +
+
+

Friends

+
+
+friend class detail::UsageTracker< ObjectID, Payload, Client >
+
+ +
+
+ +
+
+class RPCClient : public vineyard::ClientBase#
+
+

Public Functions

+
+
+~RPCClient() override#
+
+ +
+
+Status Connect()#
+

Connect to vineyard using the TCP endpoint specified by the environment variable VINEYARD_RPC_ENDPOINT.

+
+
Returns
+

Status that indicates whether the connect has succeeded.

+
+
+
+ +
+
+Status Connect(std::string const &username, std::string const &password)#
+

Connect to vineyard using the TCP endpoint specified by the environment variable VINEYARD_RPC_ENDPOINT.

+
+
Returns
+

Status that indicates whether the connect has succeeded.

+
+
+
+ +
+
+Status Connect(const std::string &rpc_endpoint)#
+

Connect to vineyardd using the given TCP endpoint rpc_endpoint.

+
+
Parameters
+

rpc_endpoint – The TPC endpoint of vineyard server, in the format of host:port.

+
+
Returns
+

Status that indicates whether the connect has succeeded.

+
+
+
+ +
+
+Status Connect(const std::string &rpc_endpoint, std::string const &username, std::string const &password)#
+

Connect to vineyardd using the given TCP endpoint rpc_endpoint.

+
+
Parameters
+

rpc_endpoint – The TPC endpoint of vineyard server, in the format of host:port.

+
+
Returns
+

Status that indicates whether the connect has succeeded.

+
+
+
+ +
+
+Status Connect(const std::string &rpc_endpoint, const SessionID session_id, std::string const &username = "", std::string const &password = "")#
+

Connect to vineyardd using the given TCP endpoint rpc_endpoint.

+
+
Parameters
+
    +
  • rpc_endpoint – The TPC endpoint of vineyard server, in the format of host:port.

  • +
  • session_id – Connect to specified session.

  • +
+
+
Returns
+

Status that indicates whether the connect has succeeded.

+
+
+
+ +
+
+Status Connect(const std::string &host, uint32_t port)#
+

Connect to vineyardd using the given TCP host and port.

+
+
Parameters
+
    +
  • host – The host of vineyard server.

  • +
  • port – The TCP port of vineyard server’s RPC service.

  • +
+
+
Returns
+

Status that indicates whether the connect has succeeded.

+
+
+
+ +
+
+Status Connect(const std::string &host, uint32_t port, std::string const &username, std::string const &password)#
+

Connect to vineyardd using the given TCP host and port.

+
+
Parameters
+
    +
  • host – The host of vineyard server.

  • +
  • port – The TCP port of vineyard server’s RPC service.

  • +
+
+
Returns
+

Status that indicates whether the connect has succeeded.

+
+
+
+ +
+
+Status Connect(const std::string &host, uint32_t port, const SessionID session_id, std::string const &username = "", std::string const &password = "")#
+

Connect to vineyardd using the given TCP host and port.

+
+
Parameters
+
    +
  • host – The host of vineyard server.

  • +
  • port – The TCP port of vineyard server’s RPC service.

  • +
  • session_id – Connect to specified session.

  • +
+
+
Returns
+

Status that indicates whether the connect has succeeded.

+
+
+
+ +
+
+Status Fork(RPCClient &client)#
+

Create a new client using self endpoint.

+
+ +
+
+virtual Status GetMetaData(const ObjectID id, ObjectMeta &meta_data, const bool sync_remote = false) override#
+

Obtain metadata from vineyard server. Note that unlike IPC client, RPC client doesn’t map shared memorys to the client’s process.

+
+
Parameters
+
    +
  • id – The object id to get.

  • +
  • meta_data – The result metadata will be store in meta_data as return value.

  • +
  • sync_remote – Whether to trigger an immediate remote metadata synchronization before get specific metadata. Default is false.

  • +
+
+
Returns
+

Status that indicates whether the get action has succeeded.

+
+
+
+ +
+
+Status GetMetaData(const std::vector<ObjectID> &id, std::vector<ObjectMeta> &meta_data, const bool sync_remote = false)#
+

Obtain multiple metadatas from vineyard server.

+
+
Parameters
+
    +
  • ids – The object ids to get.

  • +
  • meta_data – The result metadata will be store in meta_data as return value.

  • +
  • sync_remote – Whether to trigger an immediate remote metadata synchronization before get specific metadata. Default is false.

  • +
+
+
Returns
+

Status that indicates whether the get action has succeeded.

+
+
+
+ +
+
+std::shared_ptr<Object> GetObject(const ObjectID id)#
+

Get an object from vineyard. The ObjectFactory will be used to resolve the constructor of the object.

+

In RPCClient, all blob fields in the result object are unaccessible, access those fields will trigger an std::runtime_error.

+
+
Parameters
+

id – The object id to get.

+
+
Returns
+

A std::shared_ptr<Object> that can be safely cast to the underlying concrete object type. When the object doesn’t exists an std::runtime_error exception will be raised.

+
+
+
+ +
+
+Status GetObject(const ObjectID id, std::shared_ptr<Object> &object)#
+

Get an object from vineyard. The ObjectFactory will be used to resolve the constructor of the object.

+
+
Parameters
+
    +
  • id – The object id to get.

  • +
  • object – The result object will be set in parameter object.

  • +
+
+
Returns
+

When errors occur during the request, this method won’t throw exceptions, rather, it results a status to represents the error.

+
+
+
+ +
+
+std::vector<std::shared_ptr<Object>> GetObjects(const std::vector<ObjectID> &ids)#
+

Get multiple objects from vineyard.

+
+
Parameters
+

ids – The object IDs to get.

+
+
Returns
+

A list of objects.

+
+
+
+ +
+
+template<typename T>
inline std::shared_ptr<T> GetObject(const ObjectID id)#
+

Get an object from vineyard. The type parameter T will be used to resolve the constructor of the object.

+
+
Parameters
+

id – The object id to get.

+
+
Returns
+

A std::shared_ptr<Object> that can be safely cast to the underlying concrete object type. When the object doesn’t exists an std::runtime_error exception will be raised.

+
+
+
+ +
+
+template<typename T>
inline Status GetObject(const ObjectID id, std::shared_ptr<T> &object)#
+

Get an object from vineyard. The type parameter T will be used to resolve the constructor of the object.

+

This method can be used to get concrete object from vineyard without explicitly dynamic_cast, and the template type parameter can be deduced in many situations:

+
std::shared_ptr<Array<int>> int_array;
+client.GetObject(id, int_array);
+
+
+
+
Parameters
+
    +
  • id – The object id to get.

  • +
  • object – The result object will be set in parameter object.

  • +
+
+
Returns
+

When errors occur during the request, this method won’t throw exceptions, rather, it results a status to represents the error.

+
+
+
+ +
+
+std::vector<ObjectMeta> ListObjectMeta(std::string const &pattern, const bool regex = false, size_t const limit = 5, bool nobuffer = false)#
+

List object metadatas in vineyard, using the given typename patterns.

+
+
Parameters
+
    +
  • pattern – The pattern string that will be used to matched against objects’ typename.

  • +
  • regex – Whether the pattern is a regular expression pattern. Default is false. When regex is false, the pattern will be treated as a glob pattern.

  • +
  • limit – The number limit for how many objects will be returned at most.

  • +
+
+
Returns
+

A vector of object metadatas that listed from vineyard server.

+
+
+
+ +
+
+std::vector<std::shared_ptr<Object>> ListObjects(std::string const &pattern, const bool regex = false, size_t const limit = 5)#
+

List objects in vineyard, using the given typename patterns.

+
+
Parameters
+
    +
  • pattern – The pattern string that will be used to matched against objects’ typename.

  • +
  • regex – Whether the pattern is a regular expression pattern. Default is false. When regex is false, the pattern will be treated as a glob pattern.

  • +
  • limit – The number limit for how many objects will be returned at most.

  • +
+
+
Returns
+

A vector of objects that listed from vineyard server.

+
+
+
+ +
+
+inline virtual const InstanceID remote_instance_id() const override#
+

Get the remote instance id of the connected vineyard server.

+

Note that for RPC client the instance id is not available, thus we have the “remote instance id” to indicate which server we are connecting to.

+
+
Returns
+

The vineyard server’s instance id.

+
+
+
+ +
+
+Status CreateRemoteBlob(std::shared_ptr<RemoteBlobWriter> const &buffer, ObjectID &id)#
+
+ +
+
+Status GetRemoteBlob(const ObjectID &id, std::shared_ptr<RemoteBlob> &buffer)#
+

Get the remote blob of the connected vineyard server, using the RPC socket.

+

Note that getting remote blobs requires an expensive copy over network.

+
+ +
+
+Status GetRemoteBlob(const ObjectID &id, const bool unsafe, std::shared_ptr<RemoteBlob> &buffer)#
+

Get the remote blob of the connected vineyard server, using the RPC socket, and optionally bypass the “seal” check.

+

Note that getting remote blobs requires an expensive copy over network.

+
+ +
+
+Status GetRemoteBlobs(std::vector<ObjectID> const &ids, std::vector<std::shared_ptr<RemoteBlob>> &remote_blobs)#
+

Get the remote blobs of the connected vineyard server, using the RPC socket.

+

Note that getting remote blobs requires an expensive copy over network.

+
+ +
+
+Status GetRemoteBlobs(std::vector<ObjectID> const &ids, const bool unsafe, std::vector<std::shared_ptr<RemoteBlob>> &remote_blobs)#
+

Get the remote blobs of the connected vineyard server, using the RPC socket. and optionally bypass the “seal” check.

+

Note that getting remote blobs requires an expensive copy over network.

+
+ +
+
+ +
+
+

Vineyard Server#

+
+
+struct InstanceStatus#
+
+

Public Functions

+
+
+explicit InstanceStatus(const json &tree)#
+

Initialize the status value using a json returned from the vineyard server.

+
+
Parameters
+

tree – JSON that returned from the vineyard server.

+
+
+
+ +
+
+

Public Members

+
+
+const InstanceID instance_id#
+

The connected instance id.

+
+ +
+
+const std::string deployment#
+

The deployment manner, can be local or distributed.

+
+ +
+
+const size_t memory_usage#
+

The current memory usage in vineyard server, in bytes.

+
+ +
+
+const size_t memory_limit#
+

The memory upper bound of this vineyard server, in bytes.

+
+ +
+
+const size_t deferred_requests#
+

How many requests are deferred in the queue.

+
+ +
+
+const size_t ipc_connections#
+

How many Client connects to this vineyard server.

+
+ +
+
+const size_t rpc_connections#
+

How many RPCClient connects to this vineyard server.

+
+ +
+
+ +
+
+

Blob#

+
+
+class Blob : public vineyard::Registered<Blob>#
+

The unit to store data payload in vineyard.

+

When the client gets a blob from vineyard, the vineyard server maps a chunk of memory from its memory space to the client space in a zero-copy fashion.

+
+

Public Functions

+
+
+size_t size() const#
+

Get the size of the blob, i.e., the number of bytes of the data payload in the blob.

+

Note that the size of blob is the “allocated size” of the blob, and may (usually) not be the same value of the requested size.

+
+
Returns
+

The (allocated) size of the blob.

+
+
+
+ +
+
+size_t allocated_size() const#
+

Get the allocated size of the blob, i.e., the number of bytes of the data payload in the blob.

+
+
Returns
+

The allocated size of the blob.

+
+
+
+ +
+
+const char *data() const#
+

Get the const data pointer of the data payload in the blob.

+
+
Returns
+

The const data pointer.

+
+
+
+ +
+
+const std::shared_ptr<vineyard::Buffer> &Buffer() const#
+

Get the buffer of the blob.

+
+
Returns
+

The buffer which holds the data payload of the blob.

+
+
+
+ +
+
+const std::shared_ptr<arrow::Buffer> ArrowBuffer() const#
+

Get the arrow buffer of the blob.

+
+
Returns
+

The buffer which holds the data payload of the blob.

+
+
+
+ +
+
+const std::shared_ptr<vineyard::Buffer> BufferOrEmpty() const#
+

Get the buffer of the blob, ensure a valid shared_ptr been returned even the blob is empty (size == 0).

+
+
Returns
+

The buffer which holds the data payload of the blob.

+
+
+
+ +
+
+const std::shared_ptr<arrow::Buffer> ArrowBufferOrEmpty() const#
+

Get the arrow buffer of the blob, ensure a valid shared_ptr been returned even the blob is empty (size == 0).

+
+
Returns
+

The buffer which holds the data payload of the blob.

+
+
+
+ +
+
+virtual void Construct(ObjectMeta const &meta) override#
+

Construct the blob locally for the given object meta.

+
+
Parameters
+

meta – The given object meta.

+
+
+
+ +
+
+void Dump() const#
+

Dump the buffer for debugging.

+
+ +
+
+

Public Static Functions

+
+
+static inline std::unique_ptr<Object> Create()#
+
+ +
+
+static std::shared_ptr<Blob> MakeEmpty(Client &client)#
+

Create an empty blob in the vineyard server.

+
+
Parameters
+

client – The client connected to the vineyard server.

+
+
+
+ +
+
+static std::shared_ptr<Blob> FromAllocator(Client &client, const ObjectID object_id, const uintptr_t pointer, const size_t size)#
+

Create the blob from a buffer from the client-side allocator.

+
+
Parameters
+
    +
  • object_id – The object ID of this blob.

  • +
  • pointer – The address of buffer in the client-side allocator.

  • +
  • size – The estimated size of the buffer.

  • +
+
+
+
+ +
+
+static std::shared_ptr<Blob> FromPointer(Client &client, const uintptr_t pointer, const size_t size)#
+

Create the blob from a given buffer. If the buffer already lies in the vineyardd, it would return immediately without copying, otherwise a blob writer will be created and the content of the buffer will be copied into.

+
+
Parameters
+
    +
  • pointer – The address of the buffer.

  • +
  • size – The estimated size of the buffer.

  • +
+
+
+
+ +
+
+ +
+
+class BlobWriter : public vineyard::ObjectBuilder#
+

The writer to write a blob in vineyard.

+

The writer is initialized in the client with a local buffer and its size, and a blob in vineyard will be created when Build is invoked.

+
+

Public Functions

+
+
+ObjectID id() const#
+

Return the object id of this blob builder. Note that before sealing the blob builder the object id cannot be used to get “Blob” objects.

+
+
Returns
+

The ObjectID of the blob writer.

+
+
+
+ +
+
+size_t size() const#
+

Get the size of the blob, i.e., the number of bytes of the data payload in the blob.

+
+
Returns
+

The size of the blob.

+
+
+
+ +
+
+char *data()#
+

Get the data pointer of the data payload in the blob.

+
+
Returns
+

The data pointer.

+
+
+
+ +
+
+const char *data() const#
+

Get the const data pointer of the data payload in the blob.

+
+
Returns
+

The const data pointer.

+
+
+
+ +
+
+const std::shared_ptr<MutableBuffer> &Buffer() const#
+

Get the mutable buffer of the blob.

+
+
Returns
+

The mutable buffer of the blob, which can be modified to update the content in the blob.

+
+
+
+ +
+
+virtual Status Build(Client &client) override#
+

Build a blob in vineyard server.

+
+
Parameters
+

client – The client connected to the vineyard server.

+
+
+
+ +
+
+Status Abort(Client &client)#
+

Abort the blob builder.

+
+
Parameters
+

client – Release the blob builder object if it is not sealed.

+
+
+
+ +
+
+Status Shrink(Client &client, const size_t size)#
+

Shrink the blob builder to the given size without reallocating and copying.

+
+ +
+
+void AddKeyValue(std::string const &key, std::string const &value)#
+

Add key-value metadata for the blob.

+
+
Parameters
+
    +
  • key – The key of the metadata.

  • +
  • value – The value of the metadata.

  • +
+
+
+
+ +
+
+void AddKeyValue(std::string const &key, std::string &&value)#
+

Add key-value metadata for the blob.

+
+
Parameters
+
    +
  • key – The key of the metadata.

  • +
  • value – The value of the metadata.

  • +
+
+
+
+ +
+
+void Dump() const#
+

Dump the buffer for debugging.

+
+ +
+
+ +
+
+

Stream#

+
+
+class ByteStream : public vineyard::BareRegistered<ByteStream>, public vineyard::Stream<Blob>#
+
+

Public Functions

+
+
+inline void SetBufferSizeLimit(size_t limit)#
+
+ +
+
+Status WriteBytes(const char *ptr, size_t len)#
+
+ +
+
+Status WriteLine(const std::string &line)#
+
+ +
+
+Status FlushBuffer()#
+
+ +
+
+Status ReadLine(std::string &line)#
+
+ +
+
+

Public Static Functions

+
+
+static inline std::unique_ptr<Object> Create()#
+
+ +
+
+ +
+
+

Basic Data Types#

+
+
+template<typename T>
class Array : public vineyard::Registered<Array<T>>#
+

The array type in vineyard.

+
+
Template Parameters
+

T – The type for the elements.

+
+
+
+

Public Functions

+
+
+inline virtual void Construct(const ObjectMeta &meta) override#
+

Construct an object from metadata. The metadata meta should come from client’s GetMetaData method.

+

The implementation of Construct method is usually boilerplate. Vineyard provides a code generator to help developers code their own data structures and can be shared via vineyard.

+
+
Parameters
+

meta – The metadata that be used to construct the object.

+
+
+
+ +
+
+inline const T &operator[](size_t loc) const#
+

Get the element at the given location.

+
+
Parameters
+

loc – The given location to get the element.

+
+
+
+ +
+
+inline size_t size() const#
+

Get the size of the array.

+
+
Returns
+

The size.

+
+
+
+ +
+
+inline const T *data() const#
+

Get the pointer to the beginning of the data buffer.

+
+
Parameters
+

The – pointer to the data buffer

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline std::unique_ptr<Object> Create()#
+
+ +
+
+ +
+
+template<typename T>
class ArrayBuilder : public vineyard::ArrayBaseBuilder<T>#
+

ArrayBuilder is designed for constructing arrays that supported by vineyard.

+
+
Template Parameters
+

T – The type for the elements.

+
+
+
+

Public Functions

+
+
+inline ArrayBuilder(Client &client, size_t size)#
+
+ +
+
+inline ArrayBuilder(Client &client, std::vector<T> const &vec)#
+

Initialize the ArrayBuilder from an existing std::vector of type T.

+
+
Parameters
+
    +
  • client – The client connected to the vineyard server.

  • +
  • vec – The local std::vector of type T.

  • +
+
+
+
+ +
+
+inline ArrayBuilder(Client &client, const T *data, size_t size)#
+

Initialize the ArrayBuilder from an existing C array of type T.

+
+
Parameters
+
    +
  • client – The client connected to the vineyard server.

  • +
  • data – The pointer to the array.

  • +
  • size – The size of the array.

  • +
+
+
+
+ +
+
+inline ~ArrayBuilder()#
+
+ +
+
+inline const size_t size() const#
+

Get the size of the array, i.e., number of elements in the array.

+
+
Returns
+

The size.

+
+
+
+ +
+
+inline T &operator[](size_t idx)#
+

Get the element located in the given index of the array.

+
+
Parameters
+

idx – The give index.

+
+
Returns
+

The element at the given index.

+
+
+
+ +
+
+inline T *data() noexcept#
+

Get the data pointer to the array.

+
+
Returns
+

The data pointer.

+
+
+
+ +
+
+inline const T *data() const noexcept#
+

Get the const data pointer to the array.

+
+
Returns
+

The const data pointer.

+
+
+
+ +
+
+inline Status Build(Client &client) override#
+

Build the array object.

+
+
Parameters
+

client – The client connected to the vineyard server.

+
+
+
+ +
+
+ +
+
+template<typename K, typename V, typename H = prime_number_hash_wy<K>, typename E = std::equal_to<K>>
class Hashmap : public vineyard::Registered<Hashmap<K, V, prime_number_hash_wy<K>, std::equal_to<K>>>, public vineyard::prime_number_hash_wy<K>, public std::equal_to<K>#
+

The hash map in vineyard.

+
+
Template Parameters
+
    +
  • K – The type for the key.

  • +
  • V – The type for the value.

  • +
  • std::hash<K> – The hash function for the key.

  • +
  • std::equal_to<K> – The compare function for the key.

  • +
+
+
+
+

Public Types

+
+
+using KeyHash = H#
+
+ +
+
+using KeyEqual = E#
+
+ +
+
+using T = std::pair<K, V>#
+
+ +
+
+using Entry = ska::detailv3::sherwood_v3_entry<T>#
+
+ +
+
+using EntryPointer = const Entry*#
+
+ +
+
+using Hasher = ska::detailv3::KeyOrValueHasher<K, std::pair<K, V>, H>#
+
+ +
+
+using Equal = ska::detailv3::KeyOrValueEquality<K, std::pair<K, V>, E>#
+
+ +
+
+using value_type = T#
+
+ +
+
+using size_type = size_t#
+
+ +
+
+using difference_type = std::ptrdiff_t#
+
+ +
+
+using hasher = H#
+
+ +
+
+using key_equal = E#
+
+ +
+
+using reference = value_type&#
+
+ +
+
+using const_reference = const value_type&#
+
+ +
+
+using pointer = value_type*#
+
+ +
+
+using const_pointer = value_type*#
+
+ +
+
+using flat_hash_table_type = ska::detailv3::sherwood_v3_table<T, K, H, Hasher, E, Equal, std::allocator<T>, typename std::allocator_traits<std::allocator<T>>::template rebind_alloc<ska::detailv3::sherwood_v3_entry<T>>>#
+
+ +
+
+

Public Functions

+
+
+inline virtual void Construct(const ObjectMeta &meta) override#
+

Construct an object from metadata. The metadata meta should come from client’s GetMetaData method.

+

The implementation of Construct method is usually boilerplate. Vineyard provides a code generator to help developers code their own data structures and can be shared via vineyard.

+
+
Parameters
+

meta – The metadata that be used to construct the object.

+
+
+
+ +
+
+inline virtual void PostConstruct(const ObjectMeta &meta) override#
+

Set the hash policy after the construction of the HashMap.

+
+ +
+
+inline iterator begin() const#
+

The beginning iterator.

+
+ +
+
+inline iterator end() const#
+

The ending iterator.

+
+ +
+
+inline iterator find(const K &key)#
+

Find the iterator by key.

+
+ +
+
+inline const iterator find(const K &key) const#
+

Return the const iterator by key.

+
+ +
+
+inline size_t count(const K &key) const#
+

Return the number of occurancies of the key.

+
+ +
+
+inline size_t size() const#
+

Return the size of the HashMap, i.e., the number of elements stored in the HashMap.

+
+ +
+
+inline size_t bucket_count() const#
+

Return the max size of the HashMap, i.e., the number of allocated cells for elements stored in the HashMap.

+
+ +
+
+inline float load_factor() const#
+

Return the load factor of the HashMap.

+
+ +
+
+inline bool empty() const#
+

Check whether the HashMap is empty.

+
+ +
+
+inline const V &at(const K &key) const#
+

Get the value by key. Here the existence of the key is checked.

+
+ +
+
+

Public Static Functions

+
+
+static inline std::unique_ptr<Object> Create()#
+
+ +
+
+
+struct iterator#
+

The iterator to iterate key-value mappings in the HashMap.

+
+

Public Functions

+
+
+iterator() = default#
+
+ +
+
+inline explicit iterator(EntryPointer current)#
+
+ +
+
+inline iterator &operator++()#
+
+ +
+
+inline iterator operator++(int)#
+
+ +
+
+inline const value_type &operator*() const#
+
+ +
+
+inline const value_type *operator->() const#
+
+ +
+
+

Public Members

+
+
+EntryPointer current = EntryPointer()#
+
+ +
+
+

Friends

+
+
+inline friend bool operator==(const iterator &lhs, const iterator &rhs)#
+
+ +
+
+inline friend bool operator!=(const iterator &lhs, const iterator &rhs)#
+
+ +
+
+ +
+ +
+
+template<typename K, typename V, typename H = prime_number_hash_wy<K>, typename E = std::equal_to<K>>
class HashmapBuilder : public vineyard::HashmapBaseBuilder<K, V, prime_number_hash_wy<K>, std::equal_to<K>>#
+

HashmapBuilder is used for constructing hashmaps that supported by vineyard.

+
+
Template Parameters
+
    +
  • K – The type for the key.

  • +
  • V – The type for the value.

  • +
  • std::hash<K> – The hash function for the key.

  • +
  • std::equal_to<K> – The compare function for the key.

  • +
+
+
+
+

Public Functions

+
+
+inline explicit HashmapBuilder(Client &client)#
+
+ +
+
+inline HashmapBuilder(Client &client, ska::flat_hash_map<K, V, H, E> &&hashmap)#
+
+ +
+
+inline V &operator[](const K &key)#
+

Get the mapping value of the given key.

+
+ +
+
+inline V &operator[](K &&key)#
+

Get the mapping value of the given key.

+
+ +
+
+template<class ...Args>
inline bool emplace(Args&&... args)#
+

Emplace key-value pair into the hashmap.

+
+ +
+
+inline V &at(const K &key)#
+

Get the mapping value of the given key.

+
+ +
+
+inline const V &at(const K &key) const#
+

Get the const mapping value of the given key.

+
+ +
+
+inline size_t size() const#
+

Get the size of the hashmap.

+
+ +
+
+inline void reserve(size_t size)#
+

Reserve the size for the hashmap.

+
+ +
+
+inline size_t bucket_count() const#
+

Return the maximum possible size of the HashMap, i.e., the number of elements that can be stored in the HashMap.

+
+ +
+
+inline float load_factor() const#
+

Return the load factor of the HashMap.

+
+ +
+
+inline bool empty() const#
+

Check whether the hashmap is empty.

+
+ +
+
+inline ska::flat_hash_map<K, V, H, E>::iterator begin()#
+

Return the beginning iterator.

+
+ +
+
+inline ska::flat_hash_map<K, V, H, E>::const_iterator begin() const#
+

Return the const beginning iterator.

+
+ +
+
+inline ska::flat_hash_map<K, V, H, E>::const_iterator cbegin() const#
+

Return the const beginning iterator.

+
+ +
+
+inline ska::flat_hash_map<K, V, H, E>::iterator end()#
+

Return the ending iterator.

+
+ +
+
+inline ska::flat_hash_map<K, V, H, E>::const_iterator end() const#
+

Return the const ending iterator.

+
+ +
+
+inline ska::flat_hash_map<K, V, H, E>::const_iterator cend() const#
+

Return the const ending iterator.

+
+ +
+
+inline ska::flat_hash_map<K, V, H, E>::iterator find(const K &key)#
+

Find the value by key.

+
+ +
+
+inline void AssociateDataBuffer(std::shared_ptr<Blob> data_buffer)#
+

Associated with a given data buffer.

+
+ +
+
+inline Status Build(Client &client) override#
+

Build the hashmap object.

+
+ +
+
+ +
+
+template<typename T>
class Tensor : public vineyard::ITensor, public vineyard::BareRegistered<Tensor<T>>#
+
+

Public Types

+
+
+using value_t = T#
+
+ +
+
+using value_pointer_t = T*#
+
+ +
+
+using value_const_pointer_t = const T*#
+
+ +
+
+using ArrowTensorT = typename detail::ArrowTensorType<T>::type#
+
+ +
+
+

Public Functions

+
+
+inline virtual void Construct(const ObjectMeta &meta) override#
+

Construct an object from metadata. The metadata meta should come from client’s GetMetaData method.

+

The implementation of Construct method is usually boilerplate. Vineyard provides a code generator to help developers code their own data structures and can be shared via vineyard.

+
+
Parameters
+

meta – The metadata that be used to construct the object.

+
+
+
+ +
+
+inline std::vector<int64_t> strides() const#
+

Get the strides of the tensor.

+
+
Returns
+

The strides of the tensor. The definition of the tensor’s strides can be found in https://pytorch.org/docs/stable/tensor_attributes.html

+
+
+
+ +
+
+inline virtual std::vector<int64_t> const &shape() const override#
+

Get the shape of the tensor.

+
+
Returns
+

The shape vector where the ith element represents the size of the ith axis.

+
+
+
+ +
+
+inline virtual std::vector<int64_t> const &partition_index() const override#
+

Get the index of this partition in the global tensor.

+
+
Returns
+

The index vector where the ith element represents the index in the ith axis.

+
+
+
+ +
+
+inline virtual AnyType value_type() const override#
+

Get the type of tensor’s elements.

+
+
Returns
+

The type of the tensor’s elements.

+
+
+
+ +
+
+inline value_const_pointer_t data() const#
+

Get the data pointer to the tensor’s data buffer.

+
+
Returns
+

The data pointer.

+
+
+
+ +
+
+inline const value_t operator[](size_t index) const#
+

Get the data in the tensor by index.

+
+
Returns
+

The data reference.

+
+
+
+ +
+
+inline virtual const std::shared_ptr<arrow::Buffer> buffer() const override#
+

Get the buffer of the tensor.

+
+
Returns
+

The shared pointer to an arrow buffer which holds the data buffer of the tensor.

+
+
+
+ +
+
+inline virtual const std::shared_ptr<arrow::Buffer> auxiliary_buffer() const override#
+
+ +
+
+inline const std::shared_ptr<ArrowTensorT> ArrowTensor()#
+

Return a view of the original tensor so that it can be used as arrow’s Tensor.

+
+ +
+
+

Public Static Functions

+
+
+static inline std::unique_ptr<Object> Create()#
+
+ +
+
+ +
+
+template<typename T>
class TensorBuilder : public vineyard::ITensorBuilder, public vineyard::TensorBaseBuilder<T>#
+

TensorBuilder is used for building tensors that supported by vineyard.

+
+
Template Parameters
+

T

+
+
+
+

Public Types

+
+
+using value_t = T#
+
+ +
+
+using value_pointer_t = T*#
+
+ +
+
+using value_const_pointer_t = const T*#
+
+ +
+
+

Public Functions

+
+
+inline TensorBuilder(Client &client, std::vector<int64_t> const &shape)#
+

Initialize the TensorBuilder with the tensor shape.

+
+
Parameters
+
    +
  • client – The client connected to the vineyard server.

  • +
  • shape – The shape of the tensor.

  • +
+
+
+
+ +
+
+inline TensorBuilder(Client &client, std::vector<int64_t> const &shape, std::vector<int64_t> const &partition_index)#
+

Initialize the TensorBuilder for a partition of a GlobalTensor.

+
+
Parameters
+
    +
  • client – The client connected to the vineyard server.

  • +
  • shape – The shape of the partition.

  • +
  • partition_index – The partition index in the global tensor.

  • +
+
+
+
+ +
+
+inline std::vector<int64_t> const &shape() const#
+

Get the shape of the tensor.

+
+
Returns
+

The shape vector where the ith element represents the size of the ith axis.

+
+
+
+ +
+
+inline std::vector<int64_t> const &partition_index() const#
+

Get the index of this partition in the global tensor.

+
+
Returns
+

The index vector where the ith element represents the index in the ith axis.

+
+
+
+ +
+
+inline void set_shape(std::vector<int64_t> const &shape)#
+

Set the shape of the tensor.

+
+
Parameters
+

shape – The vector for the shape, where the ith element represents the size of the shape in the ith axis.

+
+
+
+ +
+
+inline void set_partition_index(std::vector<int64_t> const &partition_index)#
+

Set the index in the global tensor.

+
+
Parameters
+

partition_index – The vector of indices, where the ith element represents the index in the ith axis.

+
+
+
+ +
+
+inline std::vector<int64_t> strides() const#
+

Get the strides of the tensor.

+
+
Returns
+

The strides of the tensor. The definition of the tensor’s strides can be found in https://pytorch.org/docs/stable/tensor_attributes.html

+
+
+
+ +
+
+inline value_pointer_t data() const#
+

Get the data pointer of the tensor.

+
+ +
+
+inline Status Build(Client &client) override#
+

Build the tensor.

+
+
Parameters
+

client – The client connceted to the vineyard server.

+
+
+
+ +
+
+ +
+
+class DataFrame : public vineyard::Registered<DataFrame>#
+
+

Public Functions

+
+
+inline virtual void Construct(const ObjectMeta &meta) override#
+

Construct an object from metadata. The metadata meta should come from client’s GetMetaData method.

+

The implementation of Construct method is usually boilerplate. Vineyard provides a code generator to help developers code their own data structures and can be shared via vineyard.

+
+
Parameters
+

meta – The metadata that be used to construct the object.

+
+
+
+ +
+
+const std::vector<json> &Columns() const#
+

Get the column names.

+
+
Returns
+

The vector of column names.

+
+
+
+ +
+
+std::shared_ptr<ITensor> Index() const#
+

Get the index of dataframe.

+
+
Returns
+

The shared pointer to the index tensor.

+
+
+
+ +
+
+std::shared_ptr<ITensor> Column(json const &column) const#
+

Get the column of the given column name.

+
+
Parameters
+

column – The given column name.

+
+
Returns
+

The shared pointer to the column tensor.

+
+
+
+ +
+
+const std::pair<size_t, size_t> partition_index() const#
+

Get the partition index of the global dataframe.

+
+
Returns
+

The pair of the partition_index on rows and the partition_index on columns.

+
+
+
+ +
+
+const std::pair<size_t, size_t> shape() const#
+

Get the shape of the dataframe.

+
+
Returns
+

The pair of the number of rows and the number of columns.

+
+
+
+ +
+
+const std::shared_ptr<arrow::RecordBatch> AsBatch(bool copy = false) const#
+

Get a RecordBatch view for the dataframe.

+
+ +
+
+

Public Static Functions

+
+
+static inline std::unique_ptr<Object> Create()#
+
+ +
+
+ +
+
+class DataFrameBuilder : public vineyard::DataFrameBaseBuilder#
+

DataFrameBuilder is used for constructing dataframes that supported by vineyard.

+
+

Public Functions

+
+
+explicit DataFrameBuilder(Client &client)#
+
+ +
+
+const std::pair<size_t, size_t> partition_index() const#
+

Get the partition index of the global dataframe.

+
+
Returns
+

The pair of the partition_index on rows and the partition_index on columns.

+
+
+
+ +
+
+void set_partition_index(size_t partition_index_row, size_t partition_index_column)#
+

Set the index in the global dataframe.

+
+
Parameters
+
    +
  • partition_index_row – The row index.

  • +
  • partition_index_column – The column index.

  • +
+
+
+
+ +
+
+void set_row_batch_index(size_t row_batch_index)#
+

Set the row batch index in the global dataframe. Note that the row batch index gives the order of batches on rows.

+
+
Parameters
+

row_batch_index – The row batch index.

+
+
+
+ +
+
+void set_index(std::shared_ptr<ITensorBuilder> builder)#
+

Set the index of dataframe by add a index column to dataframe.

+
+
Parameters
+

builder – The index tensor builder.

+
+
+
+ +
+
+std::shared_ptr<ITensorBuilder> Column(json const &column) const#
+

Get the column of the given column name.

+
+
Parameters
+

column – The given column name.

+
+
Returns
+

The shared pointer to the column tensor.

+
+
+
+ +
+
+void AddColumn(json const &column, std::shared_ptr<ITensorBuilder> builder)#
+

Add a column to the dataframe by registering a tensor builder to the column name. When the dataframe is built, the tensor builder will be employed to build the column.

+
+
Parameters
+
    +
  • column – The name of the column.

  • +
  • builder – The tensor builder for the column.

  • +
+
+
+
+ +
+
+void DropColumn(json const &column)#
+

Drop the column with the given column name.

+
+
Parameters
+

column – The name of column to be dropped.

+
+
+
+ +
+
+virtual Status Build(Client &client) override#
+

Build the dataframe object.

+
+
Parameters
+

client – The client connected to the vineyard server.

+
+
+
+ +
+
+ +
+
+class Sequence : public vineyard::Registered<Sequence>#
+

The sequence type in vineyard.

+
+

Public Functions

+
+
+inline virtual void Construct(const ObjectMeta &meta) override#
+

Construct an object from metadata. The metadata meta should come from client’s GetMetaData method.

+

The implementation of Construct method is usually boilerplate. Vineyard provides a code generator to help developers code their own data structures and can be shared via vineyard.

+
+
Parameters
+

meta – The metadata that be used to construct the object.

+
+
+
+ +
+
+inline const size_t Size() const#
+

Get the size of the sequence, i.e., the number of elements it contains.

+
+
Returns
+

The size of the sequence.

+
+
+
+ +
+
+inline const std::shared_ptr<Object> At(size_t index) const#
+

Get the value at the given index.

+
+
Parameters
+

index – The given index to get the value.

+
+
+
+ +
+
+inline const std::shared_ptr<Object> First() const#
+

Get the first element of the pair.

+
+
Returns
+

The shared pointer to the first object.

+
+
+
+ +
+
+inline const std::shared_ptr<Object> Second() const#
+

Get the second element of the pair.

+
+
Returns
+

The shared pointer to the second object.

+
+
+
+ +
+
+inline const iterator begin() const#
+

Get the beginning iterator.

+
+
Returns
+

The beginning iterator.

+
+
+
+ +
+
+inline const iterator end() const#
+

Get the ending iterator.

+
+
Returns
+

The ending iterator.

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline std::unique_ptr<Object> Create()#
+
+ +
+
+
+class iterator : public std::iterator<std::bidirectional_iterator_tag, std::shared_ptr<Object>, size_t, const std::shared_ptr<Object>*, std::shared_ptr<Object>>#
+

The iterator for the sequence object to iterate from the first to the last element.

+
+

Public Functions

+
+
+inline explicit iterator(Sequence const *sequence, size_t index = 0)#
+
+ +
+
+inline iterator &operator++()#
+
+ +
+
+inline bool operator==(iterator other) const#
+
+ +
+
+inline bool operator!=(iterator other) const#
+
+ +
+
+inline reference operator*() const#
+
+ +
+
+ +
+ +
+
+class SequenceBuilder : public vineyard::SequenceBaseBuilder#
+

SequenceBuilder is designed for generating sequences.

+
+

Public Functions

+
+
+inline explicit SequenceBuilder(Client &client)#
+
+ +
+
+inline explicit SequenceBuilder(Client &client, size_t const size)#
+

Initialize the SequenceBuilder with a given size.

+
+
Parameters
+
    +
  • client – The client connected to the vineyard server.

  • +
  • size – The size of the sequence to build.

  • +
+
+
+
+ +
+
+inline const size_t Size() const#
+

Get the size of the sequence, i.e., the number of elements it contains.

+
+
Returns
+

The size of the sequence.

+
+
+
+ +
+
+inline void SetSize(size_t size)#
+

Set the size for the sequence. Note that the size of a sequence can be set only once.

+
+
Parameters
+

size – The size for the sequence.

+
+
+
+ +
+
+inline std::shared_ptr<ObjectBuilder> At(size_t index)#
+

Get the builder at the given index. Here the index is bound-checked.

+
+
Parameters
+

index – The given index.

+
+
Returns
+

The builder at the given index.

+
+
+
+ +
+
+inline void SetValue(size_t idx, std::shared_ptr<ObjectBuilder> const &value)#
+

Set the builder for the value at the given index. When building the sequence, the builder will be invoked to build the value.

+
+
Parameters
+
    +
  • idx – The index of the value.

  • +
  • value – The builder for the value for the given index.

  • +
+
+
+
+ +
+
+inline void SetValue(size_t idx, std::shared_ptr<Object> const &value)#
+

Set the builder for the value at the given index. When building the sequence, the builder will be invoked to build the value.

+
+
Parameters
+
    +
  • idx – The index of the value.

  • +
  • value – The value for the given index.

  • +
+
+
+
+ +
+
+ +
+
+template<typename T>
class Scalar : public vineyard::Registered<Scalar<T>>#
+

The scalar type in vineyard. Note that the value of the scalar is writing into the meta tree as a string directly, instead of storing the value in the shared memory with a blob.

+
+
Template Parameters
+

T – The type for the value.

+
+
+
+

Public Functions

+
+
+inline virtual void Construct(const ObjectMeta &meta) override#
+

Construct an object from metadata. The metadata meta should come from client’s GetMetaData method.

+

The implementation of Construct method is usually boilerplate. Vineyard provides a code generator to help developers code their own data structures and can be shared via vineyard.

+
+
Parameters
+

meta – The metadata that be used to construct the object.

+
+
+
+ +
+
+inline const T Value() const#
+

Get the value of the scalar.

+
+
Returns
+

The value of the scalar.

+
+
+
+ +
+
+inline AnyType Type() const#
+

Get the type of the scalar.

+
+
Returns
+

The type of the scalar.

+
+
+
+ +
+
+

Public Static Functions

+
+
+static inline std::unique_ptr<Object> Create()#
+
+ +
+
+ +
+
+template<typename T>
class ScalarBuilder : public vineyard::ScalarBaseBuilder<T>#
+

ScalarBuilder is used for building scalars that supported by vineyard.

+
+
Template Parameters
+

T – The type for the scalar.

+
+
+
+

Public Functions

+
+
+inline explicit ScalarBuilder(Client &client)#
+
+ +
+
+inline explicit ScalarBuilder(Client &client, T const &value)#
+

Initialize the scalar with the value.

+
+
Parameters
+
    +
  • client – The client connected to the vineyard server.

  • +
  • value – The value for the scalar.

  • +
+
+
+
+ +
+
+inline void SetValue(T const &value)#
+

Set the value of the scalar.

+
+
Parameters
+

value – The value for the scalar.

+
+
+
+ +
+
+ +
+
+

Distributed Data Types#

+
+
+class GlobalTensor : public vineyard::BareRegistered<GlobalTensor>, public vineyard::Collection<ITensor>#
+

GlobalTensor is a holder for a set of tensor chunks that are distributed over many vineyard nodes.

+
+

Public Functions

+
+
+void PostConstruct(const ObjectMeta &meta) override#
+
+ +
+
+std::vector<int64_t> const &shape() const#
+
+ +
+
+std::vector<int64_t> const &partition_shape() const#
+
+ +
+
+const std::vector<std::shared_ptr<ITensor>> LocalPartitions(Client &client) const#
+

backwards compatibility

+
+ +
+
+

Public Static Functions

+
+
+static inline std::unique_ptr<Object> Create()#
+
+ +
+
+ +
+
+class GlobalTensorBuilder : public vineyard::CollectionBuilder<ITensor>#
+

GlobalTensorBuilder is designed for building global tensors.

+
+

Public Functions

+
+
+inline explicit GlobalTensorBuilder(Client &client)#
+
+ +
+
+std::vector<int64_t> const &partition_shape() const#
+

Get the partition shape of the global tensor. Here the ith element represents how many partitions are made on the ith axis.

+
+ +
+
+void set_partition_shape(std::vector<int64_t> const &partition_shape)#
+

Set the partition shape of the global tensor. Here the ith element represents how many partitions are made on the ith axis.

+
+ +
+
+std::vector<int64_t> const &shape() const#
+

Get the entire shape of the global tensor.

+
+ +
+
+void set_shape(std::vector<int64_t> const &shape)#
+

Set the entire shape of the global tensor.

+
+ +
+
+void AddPartition(const ObjectID partition_id)#
+

Backwards compatibility.

+
+ +
+
+void AddPartitions(const std::vector<ObjectID> &partition_ids)#
+
+ +
+
+ +
+
+class GlobalDataFrame : public vineyard::BareRegistered<GlobalDataFrame>, public vineyard::Collection<DataFrame>#
+

GlobalDataFrame is a DataFrame that refers a set of dataframe chunks in many vineyardd nodes.

+
+

Public Functions

+
+
+void PostConstruct(const ObjectMeta &meta) override#
+
+ +
+
+const std::pair<size_t, size_t> partition_shape() const#
+

Set the partition shape of the global dataframe.

+
+
Parameters
+
    +
  • partition_shape_row – The number of partitions on rows.

  • +
  • partition_shape_column – The number of partitions on columns.

  • +
+
+
+
+ +
+
+const std::vector<std::shared_ptr<DataFrame>> LocalPartitions(Client &client) const#
+

backwards compatibility

+
+ +
+
+

Public Static Functions

+
+
+static inline std::unique_ptr<Object> Create()#
+
+ +
+
+ +
+
+class GlobalDataFrameBuilder : public vineyard::CollectionBuilder<DataFrame>#
+

GlobalDataFrameBuilder is designed for building global dataframes.

+
+

Public Functions

+
+
+inline explicit GlobalDataFrameBuilder(Client &client)#
+
+ +
+
+const std::pair<size_t, size_t> partition_shape() const#
+

Get the partition shape of the global dataframe.

+
+
Returns
+

The pair of <number_of_partitions_on_rows, number_of_partitions_on_columns>.

+
+
+
+ +
+
+void set_partition_shape(const size_t partition_shape_row, const size_t partition_shape_column)#
+

Set the partition shape of the global dataframe.

+
+
Parameters
+
    +
  • partition_shape_row – The number of partitions on rows.

  • +
  • partition_shape_column – The number of partitions on columns.

  • +
+
+
+
+ +
+
+void AddPartition(const ObjectID partition_id)#
+

Backwards compatibility.

+
+ +
+
+void AddPartitions(const std::vector<ObjectID> &partition_ids)#
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/references/ctl.html b/notes/references/ctl.html new file mode 100644 index 0000000000..4a2448303c --- /dev/null +++ b/notes/references/ctl.html @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + Vineyard Cli - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Vineyard Cli#

+

vineyard-ctl: A command-line tool for vineyard.

+
+

Connect to vineyard#

+
    +
  • Via command-line:

    +

    Options:

    +
      +
    • ipc_socket: Socket location of connected vineyard server.

    • +
    • rpc_host: RPC HOST of the connected vineyard server.

    • +
    • rpc_port: RPC PORT of the connected vineyard server.

    • +
    • rpc_endpoint: RPC endpoint of the connected vineyard server.

    • +
    +

    Example:

    +
    vineyard-ctl --ipc_socket /var/run/vineyard.sock
    +
    +
    +
  • +
  • Via vineyard configuration file:

    +

    This will pick IPC or RPC values from the vineyard configuration file or +environment variables.

    +
  • +
+
+
+

Supported Commands#

+
    +
  • ls

  • +
  • query

  • +
  • head

  • +
  • copy

  • +
  • del

  • +
  • stat

  • +
  • put

  • +
  • config

  • +
  • migrate

  • +
  • debug

  • +
  • start

  • +
+
+

Note

+
vineyard-ctl {command}
+
+
+
+
+

ls#

+

List vineyard objects.

+

Options:

+
    +
  • pattern: The pattern string that will be matched against the object’s typename.

  • +
  • regex: The pattern string will be considered as a regex expression.

  • +
  • limit: The limit to list.

  • +
+

Example:

+
vineyard-ctl ls --pattern * --regex --limit 8
+
+
+
+
+

query#

+

Query a vineyard object.

+

Options:

+
    +
  • object_id: ID of the object to be fetched.

  • +
  • meta: Metadata of the object (Simple or JSON).

  • +
  • metric: Metric data of the object (nbytes or signature or typename).

  • +
  • exists: Check if the object exists or not.

  • +
  • stdout: Get object to stdout.

  • +
  • output_file: Get object to file.

  • +
  • tree: Get object lineage in tree-like style.

  • +
  • memory_status: Get the memory used by the vineyard object.

  • +
  • detail: Get detailed memory used by the vineyard object.

  • +
+

Example:

+
vineyard-ctl query --object_id 00002ec13bc81226 --meta json --metric typename
+
+
+
+ +
+

copy#

+

Copy a vineyard object.

+

Options:

+
    +
  • object_id: ID of the object to be copied.

  • +
  • shallow: Get a shallow copy of the object.

  • +
  • deep: Get a deep copy of the object.

  • +
+

Example:

+
vineyard-ctl copy --object_id 00002ec13bc81226 --shallow
+
+
+
+
+

del#

+

Delete a vineyard object.

+

Options:

+
    +
  • object_id: ID of the object to be deleted.

  • +
  • regex_pattern: Delete all the objects that match the regex pattern.

  • +
  • force: Recursively delete even if the member object is also referred by others.

  • +
  • deep: Deeply delete an object means we will deleting the members recursively.

  • +
+

Example:

+
vineyard-ctl del --object_id 00002ec13bc81226 --force
+
+
+
+
+

stat#

+

Get the status of connected vineyard server.

+

Options:

+
    +
  • instance_id: Instance ID of vineyardd that the client is connected to.

  • +
  • deployment: The deployment mode of the connected vineyardd cluster.

  • +
  • memory_usage: Memory usage (in bytes) of current vineyardd instance.

  • +
  • memory_limit: Memory limit (in bytes) of current vineyardd instance.

  • +
  • deferred_requests: Number of waiting requests of current vineyardd instance.

  • +
  • ipc_connections: Number of alive IPC connections on the current vineyardd instance.

  • +
  • rpc_connections: Number of alive RPC connections on the current vineyardd instance.

  • +
+

Example:

+
vineyard-ctl stat
+
+
+
+
+

put#

+

Put a python value to vineyard.

+

Options:

+
    +
  • value: The python value you want to put to the vineyard server.

  • +
  • file: The file you want to put to the vineyard server as a pandas dataframe.

  • +
  • sep: Delimiter used in the file.

  • +
  • delimiter: Delimiter used in the file.

  • +
  • header: Row number to use as the column names.

  • +
+

Example:

+
vineyard-ctl put --file example_csv_file.csv --sep ,
+
+
+
+
+

config#

+

Edit configuration file.

+

Options:

+
    +
  • ipc_socket_value: The ipc_socket value to enter in the config file.

  • +
  • rpc_host_value: The rpc_host value to enter in the config file.

  • +
  • rpc_port_value: The rpc_port value to enter in the config file.

  • +
  • rpc_endpoint_value: The rpc_endpoint value to enter in the config file.

  • +
+

Example:

+
vineyard-ctl config --ipc_socket_value /var/run/vineyard.sock
+
+
+
+
+

migrate#

+

Migrate a vineyard object.

+

Options:

+
    +
  • ipc_socket_value: The ipc_socket value for the second client.

  • +
  • rpc_host_value: The rpc_host value for the second client.

  • +
  • rpc_port_value: The rpc_port value for the second client.

  • +
  • rpc_endpoint_value: The rpc_endpoint value for the second client.

  • +
  • object_id: ID of the object to be migrated.

  • +
  • local: Migrate the vineyard object local to local.

  • +
  • remote: Migrate the vineyard object remote to local.

  • +
+

Example:

+
vineyard-ctl migrate --ipc_socket_value /tmp/vineyard.sock --object_id 00002ec13bc81226 --remote
+
+
+
+
+

debug#

+

Issue a debug request.

+

Options:

+
    +
  • payload: The payload that will be sent to the debug handler.

  • +
+

Example:

+
vineyard-ctl debug --payload '{"instance_status":[], "memory_size":[]}'
+
+
+
+
+

start#

+

Start vineyardd.

+

Options:

+
    +
  • local: start a local vineyard cluster.

  • +
  • distributed: start a local vineyard cluster in a distributed fashion.

  • +
  • hosts: A list of machines to launch vineyard server.

  • +
  • etcd_endpoints: Launching vineyard using specified etcd endpoints. +If not specified, vineyard will launch its own etcd instance.

  • +
  • vineyardd_path: Location of vineyard server program. If not specified, +vineyard will use its own bundled vineyardd binary.

  • +
  • size: The memory size limit for vineyard’s shared memory. The memory size +can be a plain integer or as a fixed-point number using one of these suffixes: +E, P, T, G, M, K. You can also +use the power-of-two equivalents: Ei, Pi, Ti, Gi, +Mi, Ki.

  • +
  • socket: The UNIX domain socket socket path that vineyard server will +bind and listen on. When the socket parameter is None, a random path under +temporary directory will be generated and used.

  • +
  • rpc_socket_port: The port that vineyard will use to privode RPC service.

  • +
  • debug: Whether to print debug logs.

  • +
+

Example:

+
vineyard-ctl start --local
+
+
+
+
+
+

Autocomplete#

+

Autocomplete for vineyard-ctl is only supported for the bash shell currently.

+

Follow the following steps to enable autocomplete for vineyard-ctl on your system:

+
    +
  • Install argcomplete via pip3: pip3 install argcomplete.

  • +
  • Copy the python/vineyard/cli.py file to /usr/local/bin.

  • +
  • Add eval "$(register-python-argcomplete cli.py)" to ~/.bashrc.

  • +
  • Run source /etc/profile.

  • +
  • Run source ~/.bashrc.

  • +
  • Run activate-global-python-argcomplete

  • +
+

That is it. You’re good to go. Autocomplete will be enabled working for vineyard-ctl.

+
+

Note

+

In the bash shell, type vineyard-ctl sta and press tab, it will autocomplete +to vineyard-ctl start

+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/notes/references/python-api.html b/notes/references/python-api.html new file mode 100644 index 0000000000..364c50b692 --- /dev/null +++ b/notes/references/python-api.html @@ -0,0 +1,3728 @@ + + + + + + + + + + + + + + + + + + + Python API Reference - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Python API Reference#

+
+

Objects#

+
+
+class vineyard.ObjectID#
+

Opaque type for vineyard’s object id. The object ID is generated by vineyard server, +the underlying type of ObjectID is a 64-bit unsigned integer. Wrapper +utilities are provided to interact with the external python world.

+
>>> id = ObjectID("000043c5c6d5e646")
+>>> id
+000043c5c6d5e646
+>>> repr(id)
+'000043c5c6d5e646'
+>>> print(id)
+ObjectID <"000043c5c6d5e646">
+>>> int(id)
+74516723525190
+
+
+
+
+__eq__()#
+

Return self==value.

+
+ +
+
+__hash__()#
+

Return hash(self).

+
+ +
+
+__init__()#
+
+ +
+
+__repr__()#
+

Return repr(self).

+
+ +
+
+__str__()#
+

Return str(self).

+
+ +
+ +
+
+class vineyard.Object#
+

Base class for vineyard objects.

+
+
+property id#
+

The object id of this object.

+
+ +
+
+property isglobal#
+

Whether the object is a global object.

+
+ +
+
+property islocal#
+

Whether the object is a local object.

+
+ +
+
+property ispersist#
+

Whether the object is a persistent object. The word “persistent” means the object could +be seen by clients that connect to other vineyard server instances.

+
+ +
+
+member()#
+
+
+member(self, name: str) Object
+
+ +

Get the member object of this object.

+
+
Parameters
+

name – str +The name of the member object.

+
+
Returns
+

The member object.

+
+
Return type
+

Object

+
+
+
+

See also

+

ObjectMeta.get, ObjectMeta.__getitem__

+
+
+ +
+
+property meta#
+

The metadata of this object.

+
+ +
+
+property nbytes#
+

The nbytes of this object.

+
+ +
+
+property signature#
+

The object signature of this object.

+
+ +
+
+property typename#
+

The typename of this object. typename is the string value of the C++ type, +e.g., vineyard::Array<int>, vineyard::Table.

+
+ +
+ +
+
+class vineyard.ObjectBuilder#
+
+ +
+
+

Metadata#

+
+
+class vineyard.ObjectMeta#
+

ObjectMeta is the type for metadata of an Object. +The ObjectMeta can be treat as a dict-like type. If the the metadata if +the metadata obtained from vineyard, the metadata is readonly. Otherwise key-value +attributes or object members could be associated with the metadata to construct a +new vineyard object.

+

We can inspect the key-value attributes and members of an ObjectMeta:

+
>>> meta = client.get_meta(hashmap_id)
+>>> meta
+ObjectMeta {
+    "id": "0000347aebe92dd0",
+    "instance_id": "0",
+    ...
+}
+>>> meta['num_elements_']
+'5'
+>>> meta['entries']
+ObjectMeta {
+    "id": "0000347aebe92dd0",
+    "instance_id": "0",
+    ...
+}
+
+
+

ObjectMeta value can be iterated over:

+
>>> list(k for k in meta['entries'])
+['transient', 'num_slots_minus_one_', 'max_lookups_', 'num_elements_', 'entries_',
+ 'nbytes', 'typename', 'instance_id', 'id']
+
+
+
+
+__contains__()#
+

Check if given key exists in the object metadata.

+
+
Parameters
+

key – str +The name to be looked up.

+
+
Returns
+

True if the queried key exists in this object metadata, otherwise +False.

+
+
Return type
+

bool

+
+
+
+ +
+
+__getitem__()#
+
+
+__getitem__(self, key: str) string or Object
+
+ +

Get meta or member’s meta from metadata.

+
+
Parameters
+

key – str +The name to be looked up.

+
+
Returns
+

    +
  • string – If the given key is a key of meta, returns the meta value.

  • +
  • Object – If the given key is a key of member, return the meta of this member.

  • +
+

+
+
+
+ +
+
+__init__()#
+
+
+__init__(global_: bool = False)
+
+ +

Create an empty metadata, the metadata will be used to create a vineyard object.

+
+
Parameters

global_: bool, if the object meta is for creating a global object.

+
+
+
+ +
+
+__repr__()#
+

Return repr(self).

+
+ +
+
+__setitem__()#
+
+
+__setitem__(self, key: str, value) None
+
+ +

Add a metadata to the ObjectMeta.

+
+
Parameters
+
    +
  • key – str +The name of the new metadata entry.

  • +
  • value

    str, int, float, bool or list of int +The value of the new metadata entry.

    +
      +
    • When the value is a str, it will be convert to string at first.

    • +
    • When the value is a list of str, int or float, it will be first dumpped +as string using json.dumps.

    • +
    +

  • +
+
+
+
+
+__setitem__(self, key: str, ObjectID, Object or ObjectMeta) None
+
+ +

Add a member object.

+
+
Parameters
+
    +
  • key – str +The name of the member object.

  • +
  • objectObject, ObjectID or ObjectMeta +The reference to the member object or the object id of the member object.

  • +
+
+
+
+ +
+
+__str__()#
+

Return str(self).

+
+ +
+
+add_member()#
+
+
+add_member(self, key: str, ObjectID, Object or ObjectMeta) None
+
+ +

Add a member object.

+
+
Parameters
+
    +
  • key – str +The name of the member object.

  • +
  • objectObject, ObjectID or ObjectMeta +The reference to the member object or the object id of the member object.

  • +
+
+
+
+ +
+
+get()#
+
+
+get(self, key: str, default=None) string or Object
+
+ +

Get meta or member’s meta from metadata, return default value if the given key is not +presented.

+
+
Parameters
+

key – str +The name to be looked up.

+
+
Returns
+

    +
  • str – When the given key belongs to a metadata pair. Note that the metadata value +of type int or float will be returned in string format as well.

  • +
  • ObjectMeta – When the given key is mapped to a member object.

  • +
  • See Also – ObjectMeta.__getitem__

  • +
+

+
+
+
+ +
+
+get_member()#
+
+
+get_member(self, key: str) Object
+
+ +

Get member object from metadata, return None if the given key is not presented, and +raise exception RuntimeError if the given key is associated with a plain +metadata, rather than member object.

+
+
Parameters
+

key – str +The name to be looked up.

+
+
Raises
+

RuntimeError – When the given key is associated with a plain metadata, rather than member + object.

+
+
+
+

See also

+

ObjectMeta.__getitem__, ObjectMeta.get

+
+
+ +
+
+property id#
+

The corresponding object ID of this metadata.

+
+ +
+
+property instance_id#
+

The "instance_id" of vineyard instance that the metadata been placed on.

+
+ +
+
+property isglobal#
+

True if the object is a global object, otherwise a local object or remote object.

+
+ +
+
+property islocal#
+

True if the object is a local object, otherwise a global object or remote object.

+
+ +
+
+property memory_usage#
+

Get the total memory usage of buffers in this object meta.

+
+ +
+
+property nbytes#
+

The "nbytes" attribute of this metadata.

+
+ +
+
+set_global()#
+

Mark the building object as a global object.

+
+
Parameters
+

global – bool, default is True

+
+
+
+ +
+
+property signature#
+

The corresponding object signature of this metadata.

+
+ +
+
+property typename#
+

The "typename" attribute of this metadata.

+
+ +
+ +
+
+

Vineyard client#

+
+
+vineyard.connect(*args, **kwargs)[source]#
+

Connect to vineyard by specified UNIX-domain socket or TCP endpoint.

+

If no arguments are provided and failed to resolve both the environment +variables VINEYARD_IPC_SOCKET and VINEYARD_RPC_ENDPOINT, +it will launch a standalone vineyardd server in the background and then +connect to it.

+

The connect() method has various overloading:

+
+
+connect(socket: str,
+
+username: str = None,
+
+password: str = None) -> IPCClient
+

Connect to vineyard via UNIX domain socket for IPC service:

+
client = vineyard.connect('/var/run/vineyard.sock')
+
+
+
+
Parameters:
+
socket: str

UNIX domain socket path to setup an IPC connection.

+
+
username: str

Username to login, default to None.

+
+
password: str

Password to login, default to None.

+
+
+
+
Returns:

IPCClient: The connected IPC client.

+
+
+
+ +
+
+connect(host: str,
+
+port: int or str,
+
+username: str = None,
+
+password: str = None) -> RPCClient
+

Connect to vineyard via TCP socket.

+
+
Parameters:
+
host: str

Hostname to connect to.

+
+
port: int or str

The TCP that listened by vineyard TCP service.

+
+
username: str

Username to login, default to None.

+
+
password: str

Password to login, default to None.

+
+
+
+
Returns:

RPCClient: The connected RPC client.

+
+
+
+ +
+
+connect(endpoint: (str, int or str),
+
+username: str = None,
+
+password: str = None) -> RPCClient
+

Connect to vineyard via TCP socket.

+
+
Parameters:
+
endpoint: tuple(str, int or str)

Endpoint to connect to. The parameter is a tuple, in which the first +element is the host, and the second parameter is the port (can be int +a str).

+
+
username: str

Username to login, default to None.

+
+
password: str

Password to login, default to None.

+
+
+
+
Returns:

RPCClient: The connected RPC client.

+
+
+
+ +
+
+connect(username: str = None,
+
+password: str = None) -> IPCClient or RPCClient
+

Connect to vineyard via UNIX domain socket or TCP endpoint. This method normally +usually no arguments, and will first tries to resolve IPC socket from the +environment variable VINEYARD_IPC_SOCKET and connect to it. If it fails to +establish a connection with vineyard server, the method will tries to resolve +RPC endpoint from the environment variable VINEYARD_RPC_ENDPOINT.

+

If both tries are failed, this method will raise a ConnectionFailed +exception.

+

In rare cases, user may be not sure about if the IPC socket or RPC endpoint +is available, i.e., the variable might be None. In such cases this +method can accept a None as arguments, and do resolution as described above.

+
+
Parameters:
+
username: str

Username to login, default to None.

+
+
password: str

Password to login, default to None.

+
+
+
+
Raises:

ConnectionFailed

+
+
+
+ +
+ +
+
+class vineyard.IPCClient#
+

IPC client that connects to vineyard instance’s UNIX domain socket.

+
+
+allocated_size()#
+
+
+allocated_size(target: Object or ObjectID) int
+
+ +

Get the allocated size of the given object.

+
+
Parameters
+

target – Object or ObjectID +The given Object.

+
+
Returns
+

int

+
+
+
+ +
+
+clear()#
+
+
+clear() None
+
+ +

Drop all objects that visible to the current instance in the vineyard cluster.

+
+ +
+
+close()#
+

Close the client.

+
+ +
+
+property connected#
+

Whether the client instance has been connected to the vineyard server.

+
+ +
+
+create_blob()#
+
+
+create_blob(size: int) Blob
+
+ +

Allocate a blob in vineyard server.

+
+
Parameters
+

size – int +The size of blob that will be allocated on vineyardd.

+
+
Returns
+

BlobBuilder

+
+
+
+ +
+
+create_empty_blob()#
+
+
+create_empty_blob() Blob
+
+ +

Create an empty blob in vineyard server.

+
+
Returns
+

Blob

+
+
+
+ +
+
+create_metadata()#
+
+
+create_metadata(metadata: ObjectMeta) ObjectMeta
+
+ +

Create metadata in vineyardd.

+
+
Parameters
+

metadata – ObjectMeta +The metadata that will be created on vineyardd.

+
+
Returns
+

The result created metadata.

+
+
+
+
+create_metadata(metadata: ObjectMeta, instance_id: InstanceID) ObjectMeta
+
+ +

Create metadata in vineyardd with a specified instance id.

+
+
Parameters
+
    +
  • metadata – ObjectMeta +The metadata that will be created on vineyardd.

  • +
  • instance_id – InstanceID +The instance to place the object metadata.

  • +
+
+
Returns
+

The result created metadata.

+
+
+
+ +
+
+delete()#
+
+
+delete(object_id: ObjectID or List[ObjectID], force: bool = false,
+
+deep: bool = true) -> None
+
+ +

Delete the specific vineyard object.

+
+
Parameters
+
    +
  • object_id – ObjectID or list of ObjectID +Objects that will be deleted. The object_id can be a single +ObjectID, or a list of ObjectID.

  • +
  • force – bool +Forcedly delete an object means the member will be recursively deleted +even if the member object is also referred by others. The default value +is True.

  • +
  • deep

    bool +Deeply delete an object means we will deleting the members recursively. +The default value is True.

    +

    Note that when deleting objects which have direct blob members, the +processing on those blobs yields a “deep” behavior.

    +

  • +
+
+
+
+
+delete(object_meta: ObjectMeta, force: bool = false, deep: bool = true)
+
+-> None
+
+ +

Delete the specific vineyard object.

+
+
Parameters
+

object_meta – The corresponding object meta to delete.

+
+
+
+
+delete(object: Object, force: bool = false, deep: bool = true) None
+
+ +

Delete the specific vineyard object.

+
+
Parameters
+

object – The corresponding object meta to delete.

+
+
+
+ +
+
+drop_name()#
+
+
+drop_name(name: str or ObjectName) None
+
+ +

Remove the association of the given name.

+
+
Parameters
+

name – str +The name that will be removed.

+
+
+
+ +
+
+exists()#
+
+
+exists(object_id: ObjectID) bool
+
+ +

Whether the given object exists.

+
+
Parameters
+

object_id – ObjectID +The object id to check if exists.

+
+
Returns
+

True when the specified object exists.

+
+
Return type
+

bool

+
+
+
+ +
+
+find_shared_memory()#
+
+
+find_shared_memory(target: ptr) bool
+
+ +

Find the corresponding blob (if exists) of the given pointer.

+
+
Parameters
+

target – address, in int format +The given address.

+
+
Returns
+

ObjectID

+
+
+
+
+find_shared_memory(target: ptr) bool
+
+ +

Find the corresponding blob (if exists) of the given pointer.

+
+
Parameters
+

target – address, in int format +The given address.

+
+
Returns
+

ObjectID

+
+
+
+ +
+
+get(object_id: Optional[ObjectID] = None, name: Optional[str] = None, resolver: Optional[ResolverContext] = None, fetch: bool = False, **kw)#
+

Get vineyard object as python value.

+
>>> arr_id = vineyard.ObjectID('00002ec13bc81226')
+>>> arr = client.get(arr_id)
+>>> arr
+array([0, 1, 2, 3, 4, 5, 6, 7])
+
+
+
+
Parameters
+
    +
  • client – IPCClient or RPCClient +The vineyard client to use.

  • +
  • object_id – ObjectID +The object id that will be obtained from vineyard.

  • +
  • name – ObjectID +The object name that will be obtained from vineyard, ignored if +object_id is not None.

  • +
  • resolver – When retrieving vineyard object, an optional resolver can be specified. +If no resolver given, the default resolver context will be used.

  • +
  • fetch – Whether to trigger a migration when the target object is located on +remote instances.

  • +
  • kw – User-specific argument that will be passed to the builder.

  • +
+
+
Returns
+

A python object that return by the resolver, by resolving an vineyard object.

+
+
+
+ +
+
+get_blob()#
+
+
+get_blob(object_id: ObjectID, unsafe: bool = false) Blob
+
+ +

Getting a blob from vineyard using the given object ID.

+
+
Parameters
+
    +
  • object_id – ObjectID +The blob to get.

  • +
  • unsafe – bool +unsafe means getting the blob even the blob is not sealed yet. +Default is False.

  • +
+
+
Returns
+

Blob

+
+
+
+

See also

+

IPCClient.get_blob +RPCClient.get_remote_blob +RPCClient.get_remote_blobs

+
+
+ +
+
+get_blobs()#
+
+
+get_blobs(object_ids: List[ObjectID], unsafe: bool = false) List[Blob]
+
+ +

Getting blobs from vineyard using the given object IDs.

+
+
Parameters
+
    +
  • object_ids – List[ObjectID] +The blobs to get.

  • +
  • unsafe – bool +unsafe means getting the blob even the blob is not sealed yet. +Default is False.

  • +
+
+
Returns
+

List[Blob]

+
+
+
+

See also

+

IPCClient.get_blobs +RPCClient.get_remote_blob +RPCClient.get_remote_blobs

+
+
+ +
+
+get_meta()#
+
+
+get_meta(object_id: ObjectID, sync_remote: bool = False) ObjectMeta
+
+ +

Get object metadata from vineyard.

+
+
Parameters
+
    +
  • object_id – ObjectID +The object id to get.

  • +
  • sync_remote – bool +If the target object is a remote object, code_remote=True will force +a meta synchronization on the vineyard server. Default is False.

  • +
+
+
Returns
+

ObjectMeta

+
+
+
+ +
+
+get_metas()#
+
+
+get_metas(object_ids: List[ObjectID], sync_remote: bool = False)
+
+-> List[ObjectMeta]
+
+ +

Get metadatas of multiple objects from vineyard.

+
+
Parameters
+
    +
  • object_ids – List[ObjectID] +The object ids to get.

  • +
  • sync_remote – bool +If the target object is a remote object, code_remote=True will force +a meta synchronization on the vineyard server. Default is False.

  • +
+
+
Returns
+

List[ObjectMeta]

+
+
+
+ +
+
+get_name()#
+
+
+get_name(name: str or ObjectName, wait: bool = False) ObjectID
+
+ +

Get the associated object id of the given name.

+
+
Parameters
+
    +
  • name – str +The name that will be queried.

  • +
  • wait – bool +Whether to wait util the name appears, if wait, the request will be blocked +until the name been registered.

  • +
+
+
Returns
+

The associated object id with the name.

+
+
Return type
+

ObjectID

+
+
+
+ +
+
+get_object()#
+
+
+get_object(object_id: ObjectID) Object
+
+ +

Get object from vineyard.

+
+
Parameters
+

object_id – ObjectID +The object id to get.

+
+
Returns
+

Object

+
+
+
+ +
+
+get_objects()#
+
+
+get_objects(object_ids: List[ObjectID]) List[Object]
+
+ +

Get multiple objects from vineyard.

+
+
Parameters
+

object_ids – List[ObjectID]

+
+
Returns
+

List[Object]

+
+
+
+ +
+
+property instance_id#
+

The instance id of the connected vineyard server.

+
+ +
+
+property ipc_socket#
+

The UNIX domain socket location of connected vineyard server.

+
+ +
+
+is_shared_memory()#
+
+
+is_shared_memory(target: ptr) bool
+
+ +

Check if the address is on the shared memory region.

+
+
Parameters
+

target – address, in int format +The given address.

+
+
Returns
+

bool

+
+
+
+
+is_shared_memory(target: ptr) bool
+
+ +

Check if the address is on the shared memory region.

+
+
Parameters
+

target – address, in int format +The given address.

+
+
Returns
+

bool

+
+
+
+ +
+
+list_metadatas()#
+
+
+list_metadatas(pattern: str, regex: bool = False, limit: int = 5,
+
+nobuffer: bool = False) -> List[Object]
+
+ +

List all objects in current vineyard server.

+
+
Parameters
+
    +
  • pattern – str +The pattern string that will be matched against the object’s typename.

  • +
  • regex – bool +Whether the pattern is a regex expression, otherwise the pattern will be +used as wildcard pattern. Default value is False.

  • +
  • limit – int +The limit to list. Default value is 5.

  • +
  • nobuffer – bool +Whether to fill the buffers in returned object metadatas. Default value +is False.

  • +
+
+
Returns
+

List[ObjectMeta]

+
+
+
+ +
+
+list_names()#
+
+
+list_names(pattern: str, regex: bool = False, limit: int = 5)
+
+-> Dict[str, ObjectID]
+
+ +

List all names in current vineyard server.

+
+
Parameters
+
    +
  • pattern – str +The pattern string that will be matched against the name.

  • +
  • regex – bool +Whether the pattern is a regex expression, otherwise the pattern will be used +as wildcard pattern. Default value is False.

  • +
  • limit – int +The limit to list. Default value is 5.

  • +
+
+
Returns
+

Dict[str, ObjectID]

+
+
+
+ +
+
+list_objects()#
+
+
+list_objects(pattern: str, regex: bool = False, limit: int = 5)
+
+-> List[Object]
+
+ +

List all objects in current vineyard server.

+
+
Parameters
+
    +
  • pattern – str +The pattern string that will be matched against the object’s typename.

  • +
  • regex – bool +Whether the pattern is a regex expression, otherwise the pattern will be used +as wildcard pattern. Default value is False.

  • +
  • limit – int +The limit to list. Default value is 5.

  • +
+
+
Returns
+

List[Object]

+
+
+
+ +
+
+property meta#
+

The metadata information of the vineyard server. The value is a nested dict, the +first-level key is the instance id, and the second-level key is the cluster metadata +fields.

+
>>> client.meta
+{
+    14: {
+        'hostid': '54058007061210',
+        'hostname': '127.0.0.1',
+        'timestamp': '6882550126788354072'
+    },
+    15: {
+        'hostid': '48843417291806',
+        'hostname': '127.0.0.1',
+        'timestamp': '6882568290204737414'
+    }
+}
+
+
+
+ +
+
+persist()#
+
+
+persist(object_id: ObjectID) None
+
+ +

Persist the object of the given object id. After persisting, the object will be visible +by clients that connect to other vineyard server instances.

+
+
Parameters
+

object_id – ObjectID +The object that will be persist.

+
+
+
+
+persist(object_meta: ObjectMeta) None
+
+ +

Persist the given object.

+
+
Parameters
+

object_meta – ObjectMeta +The object that will be persist.

+
+
+
+
+persist(object: Object) None
+
+ +

Persist the given object.

+
+
Parameters
+

object – Object +The object that will be persist.

+
+
+
+ +
+
+put(value: Any, builder: Optional[BuilderContext] = None, persist: bool = False, name: Optional[str] = None, **kwargs)#
+

Put python value to vineyard.

+
>>> arr = np.arange(8)
+>>> arr_id = client.put(arr)
+>>> arr_id
+00002ec13bc81226
+
+
+
+
Parameters
+
    +
  • client – IPCClient +The vineyard client to use.

  • +
  • value – The python value that will be put to vineyard. Supported python value +types are decided by modules that registered to vineyard. By default, +python value can be put to vineyard after serialized as a bytes buffer +using pickle.

  • +
  • builder – optional +When putting python value to vineyard, an optional builder can be +specified to tell vineyard how to construct the corresponding vineyard +Object. If not specified, the default builder context will be +used to select a proper builder.

  • +
  • persist – bool, optional +If true, persist the object after creation.

  • +
  • name – str, optional +If given, the name will be automatically associated with the resulted +object. Note that only take effect when the object is persisted.

  • +
  • kw – User-specific argument that will be passed to the builder.

  • +
+
+
Returns
+

The result object id will be returned.

+
+
Return type
+

ObjectID

+
+
+
+ +
+
+put_name()#
+
+
+put_name(object: ObjectID or ObjectMeta or Object,
+
+name: str or ObjectName) -> None
+
+ +

Associate the given object id with a name. An ObjectID can be associated with +more than one names.

+
+
Parameters
+
    +
  • object_id – ObjectID

  • +
  • name – str

  • +
+
+
+
+ +
+
+reset()#
+
+
+reset() None
+
+ +

Alias of ClientBase.clear().

+
+ +
+
+property rpc_endpoint#
+

The RPC endpoint of the connected vineyard server.

+
+ +
+
+shallow_copy()#
+
+
+shallow_copy(object_id: ObjectID) ObjectID
+
+ +

Create a shallow copy of the given vineyard object.

+
+
Parameters
+

object_id – ObjectID +The vineyard object that is requested to be shallow-copied.

+
+
Returns
+

The object id of newly shallow-copied vineyard object.

+
+
Return type
+

ObjectID

+
+
+
+
+shallow_copy(object_id: ObjectID, extra_metadata: dict) ObjectID
+
+ +

Create a shallow copy of the given vineyard object, with extra metadata.

+
+
Parameters
+
    +
  • object_id – ObjectID +The vineyard object that is requested to be shallow-copied.

  • +
  • extra_metadata – dict +Extra metadata to apply to the newly created object. The fields of extra +metadata must be primitive types, e.g., string, number, and cannot be +array or dict.

  • +
+
+
Returns
+

The object id of newly shallow-copied vineyard object.

+
+
Return type
+

ObjectID

+
+
+
+ +
+
+property status#
+

The status the of connected vineyard server, returns a InstanceStatus.

+
+

See also

+

InstanceStatus

+
+
+ +
+
+sync_meta()#
+
+
+sync_meta() None
+
+ +

Synchronize remote metadata to local immediately.

+
+ +
+
+property version#
+

The version number string of connected vineyard server, in the format of semver: +MAJOR.MINOR.PATCH.

+
+ +
+ +
+
+class vineyard.RPCClient#
+

RPC client that connects to vineyard instance’s RPC endpoints.

+

The RPC client can only access the metadata of objects, any access to the blob payload +will trigger a RuntimeError exception.

+
+
+clear()#
+
+
+clear() None
+
+ +

Drop all objects that visible to the current instance in the vineyard cluster.

+
+ +
+
+close()#
+

Close the client.

+
+ +
+
+property connected#
+

Whether the client instance has been connected to the vineyard server.

+
+ +
+
+create_metadata()#
+
+
+create_metadata(metadata: ObjectMeta) ObjectMeta
+
+ +

Create metadata in vineyardd.

+
+
Parameters
+

metadata – ObjectMeta +The metadata that will be created on vineyardd.

+
+
Returns
+

The result created metadata.

+
+
+
+
+create_metadata(metadata: ObjectMeta, instance_id: InstanceID) ObjectMeta
+
+ +

Create metadata in vineyardd with a specified instance id.

+
+
Parameters
+
    +
  • metadata – ObjectMeta +The metadata that will be created on vineyardd.

  • +
  • instance_id – InstanceID +The instance to place the object metadata.

  • +
+
+
Returns
+

The result created metadata.

+
+
+
+ +
+
+create_remote_blob()#
+
+
+create_remote_blob(blob_builder: RemoteBlobBuilder) ObjectID
+
+ +

Put the remote blob to connected remote vineyard instance. The blob_builder +is assumed to be ready and modification on the blob_builder after creation +won’t take effect.

+

Note that creating remote blobs requires network transfer and may yields significate +overhead.

+
vineyard_rpc_client = vineyard.connect(*vineyard_endpoint.split(':'))
+
+buffer_writer = RemoteBlobBuilder(len(payload))
+buffer_writer.copy(0, payload)
+blob_id = vineyard_rpc_client.create_remote_blob(buffer_writer)
+
+
+
+
Parameters
+

blob_builder – RemoteBlobBuilder +The remote blob to create.

+
+
Returns
+

ObjectID

+
+
+
+

See also

+

RPCClient.get_remote_blob +RPCClient.get_remote_blobs

+
+
+ +
+
+delete()#
+
+
+delete(object_id: ObjectID or List[ObjectID], force: bool = false,
+
+deep: bool = true) -> None
+
+ +

Delete the specific vineyard object.

+
+
Parameters
+
    +
  • object_id – ObjectID or list of ObjectID +Objects that will be deleted. The object_id can be a single +ObjectID, or a list of ObjectID.

  • +
  • force – bool +Forcedly delete an object means the member will be recursively deleted +even if the member object is also referred by others. The default value +is True.

  • +
  • deep

    bool +Deeply delete an object means we will deleting the members recursively. +The default value is True.

    +

    Note that when deleting objects which have direct blob members, the +processing on those blobs yields a “deep” behavior.

    +

  • +
+
+
+
+
+delete(object_meta: ObjectMeta, force: bool = false, deep: bool = true)
+
+-> None
+
+ +

Delete the specific vineyard object.

+
+
Parameters
+

object_meta – The corresponding object meta to delete.

+
+
+
+
+delete(object: Object, force: bool = false, deep: bool = true) None
+
+ +

Delete the specific vineyard object.

+
+
Parameters
+

object – The corresponding object meta to delete.

+
+
+
+ +
+
+drop_name()#
+
+
+drop_name(name: str or ObjectName) None
+
+ +

Remove the association of the given name.

+
+
Parameters
+

name – str +The name that will be removed.

+
+
+
+ +
+
+exists()#
+
+
+exists(object_id: ObjectID) bool
+
+ +

Whether the given object exists.

+
+
Parameters
+

object_id – ObjectID +The object id to check if exists.

+
+
Returns
+

True when the specified object exists.

+
+
Return type
+

bool

+
+
+
+ +
+
+get(object_id: Optional[ObjectID] = None, name: Optional[str] = None, resolver: Optional[ResolverContext] = None, fetch: bool = False, **kw)#
+

Get vineyard object as python value.

+
>>> arr_id = vineyard.ObjectID('00002ec13bc81226')
+>>> arr = client.get(arr_id)
+>>> arr
+array([0, 1, 2, 3, 4, 5, 6, 7])
+
+
+
+
Parameters
+
    +
  • client – IPCClient or RPCClient +The vineyard client to use.

  • +
  • object_id – ObjectID +The object id that will be obtained from vineyard.

  • +
  • name – ObjectID +The object name that will be obtained from vineyard, ignored if +object_id is not None.

  • +
  • resolver – When retrieving vineyard object, an optional resolver can be specified. +If no resolver given, the default resolver context will be used.

  • +
  • fetch – Whether to trigger a migration when the target object is located on +remote instances.

  • +
  • kw – User-specific argument that will be passed to the builder.

  • +
+
+
Returns
+

A python object that return by the resolver, by resolving an vineyard object.

+
+
+
+ +
+
+get_meta()#
+
+
+get_meta(object_id: ObjectID) ObjectMeta
+
+ +

Get object metadata from vineyard.

+
+
Parameters
+

object_id – ObjectID +The object id to get.

+
+
Returns
+

ObjectMeta

+
+
+
+ +
+
+get_metas()#
+
+
+get_metas(object_ids: List[ObjectID] -> List[ObjectMeta]
+
+ +

Get metadatas of multiple objects from vineyard.

+
+
Parameters
+

object_ids – List[ObjectID]

+
+
Returns
+

List[ObjectMeta]

+
+
+
+ +
+
+get_name()#
+
+
+get_name(name: str or ObjectName, wait: bool = False) ObjectID
+
+ +

Get the associated object id of the given name.

+
+
Parameters
+
    +
  • name – str +The name that will be queried.

  • +
  • wait – bool +Whether to wait util the name appears, if wait, the request will be blocked +until the name been registered.

  • +
+
+
Returns
+

The associated object id with the name.

+
+
Return type
+

ObjectID

+
+
+
+ +
+
+get_object()#
+
+
+get_object(object_id: ObjectID) Object
+
+ +

Get object from vineyard.

+
+
Parameters
+

object_id – ObjectID +The object id to get.

+
+
Returns
+

Object

+
+
+
+ +
+
+get_objects()#
+
+
+get_objects(object_ids: List[ObjectID]) List[Object]
+
+ +

Get multiple objects from vineyard.

+
+
Parameters
+

object_ids – List[ObjectID]

+
+
Returns
+

List[Object]

+
+
+
+ +
+
+get_remote_blob()#
+
+
+get_remote_blob(object_id: ObjectID, unsafe: bool = false) RemoteBlob
+
+ +

Getting a remote blob from vineyard using the given object ID.

+

Note that getting remote blobs requires network transfer and may yields significate +overhead.

+
+
Parameters
+
    +
  • object_id – ObjectID +The remote blob to get.

  • +
  • unsafe – bool +unsafe means getting the blob even the blob is not sealed yet. +Default is False.

  • +
+
+
Returns
+

RemoteBlob

+
+
+
+

See also

+

IPCClient.get_blob +IPCClient.get_blobs +RPCClient.get_remote_blobs

+
+
+ +
+
+get_remote_blobs()#
+
+
+get_remote_blobs(object_ids: List[ObjectID], unsafe: bool = false)
+
+-> List[RemoteBlob]
+
+ +

Getting remote blobs from vineyard using the given object IDs.

+

Note that getting remote blobs requires network transfer and may yields significate +overhead.

+
+
Parameters
+
    +
  • object_ids – List[ObjectID] +The remote blobs to get.

  • +
  • unsafe – bool +unsafe means getting the blob even the blob is not sealed yet. +Default is False.

  • +
+
+
Returns
+

List[RemoteBlob]

+
+
+
+

See also

+

IPCClient.get_blob +IPCClient.get_blobs +RPCClient.get_remote_blob

+
+
+ +
+
+property instance_id#
+

The instance id of the connected vineyard server.

+
+ +
+
+property ipc_socket#
+

The UNIX domain socket location of connected vineyard server.

+
+ +
+
+list_metadatas()#
+
+
+list_metadatas(pattern: str, regex: bool = False, limit: int = 5,
+
+nobuffer: bool = False) -> List[Object]
+
+ +

List all objects in current vineyard server.

+
+
Parameters
+
    +
  • pattern – str +The pattern string that will be matched against the object’s typename.

  • +
  • regex – bool +Whether the pattern is a regex expression, otherwise the pattern will be +used as wildcard pattern. Default value is False.

  • +
  • limit – int +The limit to list. Default value is 5.

  • +
  • nobuffer – bool +Whether to fill the buffers in returned object metadatas. Default value +is False.

  • +
+
+
Returns
+

List[ObjectMeta]

+
+
+
+ +
+
+list_names()#
+
+
+list_names(pattern: str, regex: bool = False, limit: int = 5)
+
+-> Dict[str, ObjectID]
+
+ +

List all names in current vineyard server.

+
+
Parameters
+
    +
  • pattern – str +The pattern string that will be matched against the name.

  • +
  • regex – bool +Whether the pattern is a regex expression, otherwise the pattern will be used +as wildcard pattern. Default value is False.

  • +
  • limit – int +The limit to list. Default value is 5.

  • +
+
+
Returns
+

Dict[str, ObjectID]

+
+
+
+ +
+
+list_objects()#
+
+
+list_objects(pattern: str, regex: bool = False, limit: int = 5)
+
+-> List[Object]
+
+ +

List all objects in current vineyard server.

+
+
Parameters
+
    +
  • pattern – str +The pattern string that will be matched against the object’s typename.

  • +
  • regex – bool +Whether the pattern is a regex expression, otherwise the pattern will be +used as wildcard pattern. Default value is False.

  • +
  • limit – int +The limit to list. Default value is 5.

  • +
+
+
Returns
+

List[Object]

+
+
+
+ +
+
+property meta#
+

The metadata information of the vineyard server. The value is a nested dict, the +first-level key is the instance id, and the second-level key is the cluster metadata +fields.

+
>>> client.meta
+{
+    14: {
+        'hostid': '54058007061210',
+        'hostname': '127.0.0.1',
+        'timestamp': '6882550126788354072'
+    },
+    15: {
+        'hostid': '48843417291806',
+        'hostname': '127.0.0.1',
+        'timestamp': '6882568290204737414'
+    }
+}
+
+
+
+ +
+
+persist()#
+
+
+persist(object_id: ObjectID) None
+
+ +

Persist the object of the given object id. After persisting, the object will be visible +by clients that connect to other vineyard server instances.

+
+
Parameters
+

object_id – ObjectID +The object that will be persist.

+
+
+
+
+persist(object_meta: ObjectMeta) None
+
+ +

Persist the given object.

+
+
Parameters
+

object_meta – ObjectMeta +The object that will be persist.

+
+
+
+
+persist(object: Object) None
+
+ +

Persist the given object.

+
+
Parameters
+

object – Object +The object that will be persist.

+
+
+
+ +
+
+put(value: Any, builder: Optional[BuilderContext] = None, persist: bool = False, name: Optional[str] = None, **kwargs)#
+

Put python value to vineyard.

+
>>> arr = np.arange(8)
+>>> arr_id = client.put(arr)
+>>> arr_id
+00002ec13bc81226
+
+
+
+
Parameters
+
    +
  • client – IPCClient +The vineyard client to use.

  • +
  • value – The python value that will be put to vineyard. Supported python value +types are decided by modules that registered to vineyard. By default, +python value can be put to vineyard after serialized as a bytes buffer +using pickle.

  • +
  • builder – optional +When putting python value to vineyard, an optional builder can be +specified to tell vineyard how to construct the corresponding vineyard +Object. If not specified, the default builder context will be +used to select a proper builder.

  • +
  • persist – bool, optional +If true, persist the object after creation.

  • +
  • name – str, optional +If given, the name will be automatically associated with the resulted +object. Note that only take effect when the object is persisted.

  • +
  • kw – User-specific argument that will be passed to the builder.

  • +
+
+
Returns
+

The result object id will be returned.

+
+
Return type
+

ObjectID

+
+
+
+ +
+
+put_name()#
+
+
+put_name(object: ObjectID or ObjectMeta or Object,
+
+name: str or ObjectName) -> None
+
+ +

Associate the given object id with a name. An ObjectID can be associated with +more than one names.

+
+
Parameters
+
    +
  • object_id – ObjectID

  • +
  • name – str

  • +
+
+
+
+ +
+
+property remote_instance_id#
+

The instance id of the connected remote vineyard server.

+
+ +
+
+reset()#
+
+
+reset() None
+
+ +

Alias of ClientBase.clear().

+
+ +
+
+property rpc_endpoint#
+

The RPC endpoint of the connected vineyard server.

+
+ +
+
+shallow_copy()#
+
+
+shallow_copy(object_id: ObjectID) ObjectID
+
+ +

Create a shallow copy of the given vineyard object.

+
+
Parameters
+

object_id – ObjectID +The vineyard object that is requested to be shallow-copied.

+
+
Returns
+

The object id of newly shallow-copied vineyard object.

+
+
Return type
+

ObjectID

+
+
+
+
+shallow_copy(object_id: ObjectID, extra_metadata: dict) ObjectID
+
+ +

Create a shallow copy of the given vineyard object, with extra metadata.

+
+
Parameters
+
    +
  • object_id – ObjectID +The vineyard object that is requested to be shallow-copied.

  • +
  • extra_metadata – dict +Extra metadata to apply to the newly created object. The fields of extra +metadata must be primitive types, e.g., string, number, and cannot be +array or dict.

  • +
+
+
Returns
+

The object id of newly shallow-copied vineyard object.

+
+
Return type
+

ObjectID

+
+
+
+ +
+
+property status#
+

The status the of connected vineyard server, returns a InstanceStatus.

+
+

See also

+

InstanceStatus

+
+
+ +
+
+sync_meta()#
+
+
+sync_meta() None
+
+ +

Synchronize remote metadata to local immediately.

+
+ +
+
+property version#
+

The version number string of connected vineyard server, in the format of semver: +MAJOR.MINOR.PATCH.

+
+ +
+ +
+
+

Vineyard cluster#

+
+
+class vineyard.InstanceStatus#
+

InstanceStatus represents the status of connected vineyard instance, including +the instance identity, memory statistics and workloads on this instance.

+
>>> status = client.status
+>>> print(status)
+InstanceStatus:
+    instance_id: 5
+    deployment: local
+    memory_usage: 360
+    memory_limit: 268435456
+    deferred_requests: 0
+    ipc_connections: 1
+    rpc_connections: 0
+>>> status.instance_id
+5
+>>> status.deployment
+'local'
+>>> status.memory_usage
+360
+>>> status.memory_limit
+268435456
+>>> status.deferred_requests
+0
+>>> status.ipc_connections
+1
+>>> status.rpc_connections
+0
+
+
+
+
+__init__(*args, **kwargs)#
+
+ +
+
+__repr__()#
+

Return repr(self).

+
+ +
+
+__str__()#
+

Return str(self).

+
+ +
+
+property deferred_requests#
+

Report number of waiting requests of current vineyardd instance.

+
+ +
+
+property deployment#
+

The deployment mode of the connected vineyardd cluster, can be "local" and +"distributed".

+
+ +
+
+property instance_id#
+

Return the instance id of vineyardd that the client is connected to.

+
+ +
+
+property ipc_connections#
+

Report number of alive IPC connections on the current vineyardd instance.

+
+ +
+
+property memory_limit#
+

Report memory limit (in bytes) of current vineyardd instance.

+
+ +
+
+property memory_usage#
+

Report memory usage (in bytes) of current vineyardd instance.

+
+ +
+
+property rpc_connections#
+

Report number of alive RPC connections on the current vineyardd instance.

+
+ +
+ +
+
+

Blob#

+
+
+class vineyard.Blob#
+

Blob in vineyard is a consecutive readonly shared memory.

+
+
+property address#
+

The memory address value of this blob.

+
+ +
+
+property buffer#
+

The readonly buffer behind this blob. The result buffer has type +memoryview.

+
+ +
+
+static empty()#
+

Create an empty blob (with size as 0).

+
+ +
+
+property is_empty#
+

Whether the blob is an empty blob, i.e., the size of this blob is 0.

+
+ +
+
+property size#
+

Size of the blob.

+
+ +
+ +
+
+class vineyard.BlobBuilder#
+

BlobBuilder is the builder for creating a finally immutable blob in +vineyard server.

+

A BlobBuilder can only be explicitly created using the +IPCClient.create_blob().

+
+

See also

+

IPCClient.create_blob +IPCClient.create_empty_blob

+
+
+
+abort()#
+

Abort the blob builder if it is not sealed yet.

+
+ +
+
+property address#
+

The memory address value of this blob builder.

+
+ +
+
+property buffer#
+

The writeable buffer behind this blob builder. The result buffer has type +memoryview, and it is a mutable one.

+
+ +
+
+copy()#
+
+
+copy(self, offset: int, ptr: int, size: int)
+
+ +

Copy the given address to the given offset.

+
+ +
+
+property id#
+

ObjectID of this blob builder.

+
+ +
+
+shrink()#
+

Shrink the blob builder to the given size if it is not sealed yet.

+
+ +
+
+property size#
+

Size of this blob builder.

+
+ +
+ +
+
+class vineyard.RemoteBlob#
+

RemoteBlob is a holder for Blob in cases like the Blob +doesn’t exist in the local vineyardd instance but the client still want th access +the data with a tolerable network-transfer overhead.

+
+
+property address#
+

The memory address value of this blob.

+
+ +
+
+property buffer#
+

The readonly buffer behind this blob. The result buffer has type +memoryview.

+
+ +
+
+property id#
+

Object ID of the remote blob.

+
+ +
+
+property instance_id#
+

The instance ID where the blob is actually placed at.

+
+ +
+
+property is_empty#
+

Whether the blob is an empty blob, i.e., the size of this blob is 0.

+
+ +
+
+property size#
+

The size of this blob.

+
+ +
+ +
+
+class vineyard.RemoteBlobBuilder#
+

RemoteBlobBuilder is the builder for creating a finally immutable blob in +vineyard server over a RPC client.

+

A RemoteBlobBuilder can only be explicitly initialized using +RemoteBlobBuilder(), then be filled the content and finally be sent to remote +vineyard instance over the network.

+
+

See also

+

IPCClient.create_blob +IPCClient.create_empty_blob

+
+
+
+abort()#
+

Abort the blob builder if it is not sealed yet.

+
+ +
+
+property address#
+

The memory address value of this blob builder.

+
+ +
+
+property buffer#
+

The writeable buffer behind this blob builder. The result buffer has type +memoryview, and it is a mutable one.

+
+ +
+
+copy()#
+
+
+copy(self, offset: int, ptr: int, size: int)
+
+ +

Copy the given address to the given offset.

+
+ +
+
+property size#
+

Size of this blob builder.

+
+ +
+ +
+
+

Resolvers and builders#

+
+
+class vineyard.core.resolver.ResolverContext(parent_context: Optional[ResolverContext] = None)[source]#
+
+ +
+
+vineyard.core.resolver.get_current_resolvers() ResolverContext[source]#
+

Obtain current resolver context.

+
+ +
+
+vineyard.core.resolver.resolver_context(resolvers: Optional[Dict[str, Callable]] = None, base: Optional[ResolverContext] = None) Generator[ResolverContext, Any, Any][source]#
+

Open a new context for register resolvers, without populating outside +the global environment.

+

The resolver_context can be useful when users have more than +more resolver for a certain type, e.g., the vineyard::Tensor +object can be resolved as numpy.ndarray or xgboost::DMatrix.

+

We could have

+
def numpy_resolver(obj):
+    ...
+
+default_resolver_context.register('vineyard::Tensor', numpy_resolver)
+
+
+

and

+
def xgboost_resolver(obj):
+    ...
+
+default_resolver_context.register('vineyard::Tensor', xgboost_resolver)
+
+
+

Obviously there’s a conflict, and the stackable resolver_context could +help there,

+
with resolver_context({'vineyard::Tensor', xgboost_resolver}):
+    ...
+
+
+

Assuming the default context resolves vineyard::Tensor to +numpy.ndarray, inside the with resolver_context the +vineyard::Tensor will be resolved to xgboost::DMatrix, +and after exiting the context the global environment will be restored +back as default.

+

The with resolver_context is nestable as well.

+
+

See also

+

builder_context +driver_context

+
+
+ +
+
+class vineyard.core.builder.BuilderContext(parent_context: Optional[BuilderContext] = None)[source]#
+
+
+register(type_id: type, builder: Callable)[source]#
+

Register a Python type to the builder context.

+
+
Parameters
+
    +
  • type_id (Python type) – Like int, or numpy.ndarray

  • +
  • builder (callable, e.g., a method, callable object) – A builder translates a python object to vineyard, it accepts a Python +value as parameter, and returns an vineyard object as result.

  • +
+
+
+
+ +
+
+run(client, value, **kw)[source]#
+

Follows the MRO to find the proper builder for given python value.

+

Here “Follows the MRO” implies:

+
    +
  • If the type of python value has been found in the context, the registered +builder will be used.

  • +
  • If not, it follows the MRO chain from down to top to find a registered +Python type and used the associated builder.

  • +
  • When the traversal reaches the object type, since there’s a default +builder that serialization the python value, the parameter will be serialized +and be put into a blob.

  • +
+
+ +
+ +
+
+vineyard.core.builder.get_current_builders() BuilderContext[source]#
+

Obtain the current builder context.

+
+ +
+
+vineyard.core.builder.builder_context(builders: Optional[Dict[type, Callable]] = None, base: Optional[BuilderContext] = None) Generator[BuilderContext, Any, Any][source]#
+

Open a new context for register builders, without populating outside global +environment.

+
+

See also

+

resolver_context +driver_context

+
+
+ +
+
+class vineyard.core.driver.DriverContext[source]#
+
+ +
+
+vineyard.core.driver.get_current_drivers()[source]#
+

Obtain current driver context.

+
+ +
+
+vineyard.core.driver.driver_context(drivers=None, base=None)[source]#
+

Open a new context for register drivers, without populting outside global +environment.

+
+

See also

+

builder_context +resolver_context

+
+
+ +
+
+

Shared memory#

+
+
+class vineyard.shared_memory.SharedMemory(vineyard_client, name=None, create=False, size=0)[source]#
+
+
+property buf#
+

A memoryview of contents of the shared memory block.

+
+ +
+
+freeze()[source]#
+

Seal the shared memory to make it visible for other processes.

+
+ +
+
+property name#
+

Unique name that identifies the shared memory block.

+
+ +
+
+property size#
+

Size in bytes.

+
+ +
+ +

Requests that the underlying shared memory block be destroyed.

+
+ +
+ +
+
+class vineyard.shared_memory.ShareableList(vineyard_client, sequence=None, *, name=None)[source]#
+

Pattern for a mutable list-like object shareable via a shared +memory block. It differs from the built-in list type in that these +lists can not change their overall length (i.e. no append, insert, +etc.)

+

Because values are packed into a memoryview as bytes, the struct +packing format for any storable value must require no more than 8 +characters to describe its format.

+

The ShareableList in vineyard differs slightly with its equivalent +in the multiprocessing.shared_memory.ShareableList, as it becomes +immutable after obtaining from the vineyard backend.

+
+

See also

+

multiprocessing.shared_memory.ShareableList

+
+
+
+freeze()[source]#
+

Make the shareable list immutable and visible for other vineyard clients.

+
+ +
+ +
+
+

Deployment#

+
+
+vineyard.connect(*args, **kwargs)[source]#
+

Connect to vineyard by specified UNIX-domain socket or TCP endpoint.

+

If no arguments are provided and failed to resolve both the environment +variables VINEYARD_IPC_SOCKET and VINEYARD_RPC_ENDPOINT, +it will launch a standalone vineyardd server in the background and then +connect to it.

+

The connect() method has various overloading:

+
+
+connect(socket: str,
+
+username: str = None,
+
+password: str = None) -> IPCClient
+

Connect to vineyard via UNIX domain socket for IPC service:

+
client = vineyard.connect('/var/run/vineyard.sock')
+
+
+
+
Parameters:
+
socket: str

UNIX domain socket path to setup an IPC connection.

+
+
username: str

Username to login, default to None.

+
+
password: str

Password to login, default to None.

+
+
+
+
Returns:

IPCClient: The connected IPC client.

+
+
+
+ +
+
+connect(host: str,
+
+port: int or str,
+
+username: str = None,
+
+password: str = None) -> RPCClient
+

Connect to vineyard via TCP socket.

+
+
Parameters:
+
host: str

Hostname to connect to.

+
+
port: int or str

The TCP that listened by vineyard TCP service.

+
+
username: str

Username to login, default to None.

+
+
password: str

Password to login, default to None.

+
+
+
+
Returns:

RPCClient: The connected RPC client.

+
+
+
+ +
+
+connect(endpoint: (str, int or str),
+
+username: str = None,
+
+password: str = None) -> RPCClient
+

Connect to vineyard via TCP socket.

+
+
Parameters:
+
endpoint: tuple(str, int or str)

Endpoint to connect to. The parameter is a tuple, in which the first +element is the host, and the second parameter is the port (can be int +a str).

+
+
username: str

Username to login, default to None.

+
+
password: str

Password to login, default to None.

+
+
+
+
Returns:

RPCClient: The connected RPC client.

+
+
+
+ +
+
+connect(username: str = None,
+
+password: str = None) -> IPCClient or RPCClient
+

Connect to vineyard via UNIX domain socket or TCP endpoint. This method normally +usually no arguments, and will first tries to resolve IPC socket from the +environment variable VINEYARD_IPC_SOCKET and connect to it. If it fails to +establish a connection with vineyard server, the method will tries to resolve +RPC endpoint from the environment variable VINEYARD_RPC_ENDPOINT.

+

If both tries are failed, this method will raise a ConnectionFailed +exception.

+

In rare cases, user may be not sure about if the IPC socket or RPC endpoint +is available, i.e., the variable might be None. In such cases this +method can accept a None as arguments, and do resolution as described above.

+
+
Parameters:
+
username: str

Username to login, default to None.

+
+
password: str

Password to login, default to None.

+
+
+
+
Raises:

ConnectionFailed

+
+
+
+ +
+ +
+
+vineyard.get_current_socket() str[source]#
+

Get current vineyard UNIX-domain socket established by vineyard.try_init().

+
+
Raises
+

ValueError if vineyard is not initialized.

+
+
+
+ +
+
+vineyard.deploy.local.start_vineyardd(meta: Optional[str] = 'etcd', etcd_endpoints: Optional[str] = None, etcd_prefix: Optional[str] = None, vineyardd_path: Optional[str] = None, size: Optional[str] = '', socket: Optional[str] = None, rpc: Optional[str] = True, rpc_socket_port: Optional[str] = 9600, debug=False) Generator[Tuple[Popen, str, str], None, None][source]#
+

Launch a local vineyard cluster.

+
+
Parameters
+
    +
  • meta – str, optional. +Metadata backend, can be “etcd”, “redis” and “local”. Defaults to +“etcd”.

  • +
  • etcd_endpoint – str +Launching vineyard using specified etcd endpoints. If not specified, +vineyard will launch its own etcd instance.

  • +
  • etcd_prefix – str +Specify a common prefix to establish a local vineyard cluster.

  • +
  • vineyardd_path – str +Location of vineyard server program. If not specified, vineyard will +use its own bundled vineyardd binary.

  • +
  • size

    int +The memory size limit for vineyard’s shared memory. The memory size +can be a plain integer or as a fixed-point number using one of these +suffixes:

    +
    E, P, T, G, M, K.
    +
    +
    +

    You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. +Defaults to “”, means not limited.

    +

    For example, the following represent roughly the same value:

    +
    128974848, 129k, 129M, 123Mi, 1G, 10Gi, ...
    +
    +
    +

  • +
  • socket

    str +The UNIX domain socket socket path that vineyard server will listen on. +Default is None.

    +

    When the socket parameter is None, a random path under temporary directory +will be generated and used.

    +

  • +
  • rpc_socket_port – int +The port that vineyard will use to provided RPC service.

  • +
  • debug – bool +Whether print debug logs.

  • +
+
+
Returns
+

Yields a tuple with the subprocess as the first element and the UNIX-domain +IPC socket as the second element.

+
+
Return type
+

(proc, socket)

+
+
+
+ +
+
+vineyard.deploy.distributed.start_vineyardd(hosts=None, etcd_endpoints=None, vineyardd_path=None, size='', socket='/var/run/vineyard.sock', rpc_socket_port=9600, debug=False)[source]#
+

Launch a local vineyard cluster in a distributed fashion.

+
+
Parameters
+
    +
  • hosts – list of str +A list of machines to launch vineyard server.

  • +
  • etcd_endpoint – str +Launching vineyard using specified etcd endpoints. If not specified, +vineyard will launch its own etcd instance.

  • +
  • vineyardd_path – str +Location of vineyard server program. If not specified, vineyard will +use its own bundled vineyardd binary.

  • +
  • size

    int +The memory size limit for vineyard’s shared memory. The memory size +can be a plain integer or as a fixed-point number using one of these +suffixes:

    +
    E, P, T, G, M, K.
    +
    +
    +

    You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. +Defaults to “”, means not limited.

    +

    For example, the following represent roughly the same value:

    +
    128974848, 129k, 129M, 123Mi, 1G, 10Gi, ...
    +
    +
    +

  • +
  • socket – str +The UNIX domain socket socket path that vineyard server will listen on.

  • +
  • rpc_socket_port – int +The port that vineyard will use to privode RPC service.

  • +
  • debug – bool +Whether print debug logs.

  • +
+
+
+
+ +
+
+vineyard.deploy.kubernetes.start_vineyardd(namespace='vineyard', size='512Mi', socket='/var/run/vineyard.sock', rpc_socket_port=9600, vineyard_image='vineyardcloudnative/vineyardd:latest', vineyard_image_pull_policy='IfNotPresent', vineyard_image_pull_secrets=None, k8s_client=None)[source]#
+

Launch a vineyard cluster on kubernetes.

+
+
Parameters
+
    +
  • namespace – str +namespace in kubernetes

  • +
  • size

    int +The memory size limit for vineyard’s shared memory. The memory size +can be a plain integer or as a fixed-point number using one of these +suffixes:

    +
    E, P, T, G, M, K.
    +
    +
    +

    You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki.

    +

    For example, the following represent roughly the same value:

    +
    128974848, 129k, 129M, 123Mi, 1G, 10Gi, ...
    +
    +
    +

  • +
  • socket – str +The UNIX domain socket socket path that vineyard server will listen on.

  • +
  • rpc_socket_port – int +The port that vineyard will use to provide RPC service.

  • +
  • k8s_client – kubernetes.client.api.ApiClient +A kubernetes client. If not specified, vineyard will try to resolve the +kubernetes configuration from current context.

  • +
  • vineyard_image – str +The docker image of vineyardd to launch the daemonset.

  • +
  • vineyard_image_pull_policy – str +The docker image pull policy of vineyardd.

  • +
  • vineyard_image_pull_secrets – str +The docker image pull secrets of vineyardd.

  • +
+
+
Returns
+

A list of created kubernetes resources during the deploying process. The +resources can be later release using delete_kubernetes_objects().

+
+
+
+

See also

+

vineyard.deploy.kubernetes.delete_kubernetes_objects

+
+
+ +
+
+vineyard.deploy.kubernetes.delete_kubernetes_objects(targets, k8s_client=None, verbose=False, wait=False, timeout_seconds=60, **kwargs)[source]#
+

Delete the given kubernetes resources.

+
+
Parameters
+
    +
  • target – List +List of Kubernetes objects

  • +
  • k8s_client – The kubernetes client. If not specified, vineyard will try to resolve +the kubernetes configuration from current context.

  • +
  • verbose – bool +Whether to print the deletion logs.

  • +
  • wait – bool +Whether to wait for the deletion to complete.

  • +
  • timeout_seconds – int +The timeout in seconds for waiting for the deletion to complete.

  • +
+
+
+
+

See also

+

vineyard.deploy.kubernetes.start_vineyardd +vineyard.deploy.kubernetes.delete_kubernetes_object

+
+
+ +
+
+

I/O Drivers#

+
+
+vineyard.io.open(path, *args, mode='r', handlers=None, chunk_hook: Optional[Callable] = None, **kwargs)[source]#
+

Open a path as a reader or writer, depends on the parameter mode. +If mode is r, it will open a stream for read, and open a +stream for write when mode is w.

+
+
Parameters
+
    +
  • path (str) – Path to open.

  • +
  • mode (char) – Mode about how to open the path, r is for read and w for write.

  • +
  • handlers – A dict that will be filled with a handler that contains the process +handler of the underlying read/write process that can be joined using +join to capture the possible errors during the I/O proceeding.

  • +
  • chunk_hook (callable, optional) –

    If the read/write target is a global dataframe (e.g., csv, +orc, parquet, etc.), the hook will be called for each chunk +to be read or write (usually a pyarrow.RecordBatch). +The hook should return a pyarrow.RecordBatch object +and should be stateless as the invoke order is not guaranteed. +E.g.,

    +
    def exchange_column(batch):
    +    import pyarrow as pa
    +
    +    columns = batch.columns
    +    first = columns[0]
    +    second = columns[1]
    +    columns = [second, first] + columns[2:]
    +    return pa.RecordBatch.from_arrays(columns, schema=batch.schema)
    +
    +
    +

  • +
  • vineyard_ipc_socket (str) – Vineyard’s IPC socket location.

  • +
  • vineyard_endpoint (str) – Vineyard’s RPC socket address.

  • +
+
+
+ +
+ +
+
+vineyard.io.read(path, *args, handlers=None, accumulate=False, chunk_hook: Optional[Callable] = None, **kwargs)[source]#
+

Open a path and read it as a single stream.

+
+
Parameters
+
    +
  • path (str) – Path to read, the last reader registered for the scheme of +the path will be used.

  • +
  • handlers (list, optional) – If handlers is not None, launched worker processes will be +emplaced into the list for further customized job lifecycle +management. Default is None.

  • +
  • accumulate (bool, optional) – If accumulate is True, it will return a data frame, +rather than dataframe stream. Default is False.

  • +
  • chunk_hook (callable, optional) –

    If the read/write target is a global dataframe (e.g., csv, +orc, parquet, etc.), the hook will be called for each chunk +to be read or write (usually a pyarrow.RecordBatch). +The hook should return a pyarrow.RecordBatch object +and should be stateless as the invoke order is not guaranteed. +E.g.,

    +
    def exchange_column(batch):
    +    import pyarrow as pa
    +
    +    columns = batch.columns
    +    first = columns[0]
    +    second = columns[1]
    +    columns = [second, first] + columns[2:]
    +    return pa.RecordBatch.from_arrays(columns, schema=batch.schema)
    +
    +
    +

  • +
  • vineyard_ipc_socket (str) – The local or remote vineyard’s IPC socket location that the +remote readers will use to establish connections with the +vineyard server.

  • +
  • vineyard_endpoint (str, optional) – An optional address of vineyard’s RPC socket, which will be +used for retrieving server’s information on the client side. +If not provided, the vineyard_ipc_socket will be used, or +it will tries to discovery vineyard’s IPC or RPC endpoints +from environment variables.

  • +
+
+
+
+ +
+
+vineyard.io.write(path, stream, *args, handlers=None, chunk_hook: Optional[Callable] = None, **kwargs)[source]#
+

Write the stream to a given path.

+
+
Parameters
+
    +
  • path (str) – Path to write, the last writer registered for the scheme of the path +will be used.

  • +
  • stream (vineyard stream) – Stream that produces the data to write.

  • +
  • handlers (list, optional) – If handlers is not None, launched worker processes will be +emplaced into the list for further customized job lifecycle +management. Default is None.

  • +
  • chunk_hook (callable, optional) –

    If the read/write target is a global dataframe (e.g., csv, +orc, parquet, etc.), the hook will be called for each chunk +to be read or write (usually a pyarrow.RecordBatch). +The hook should return a pyarrow.RecordBatch object +and should be stateless as the invoke order is not guaranteed. +E.g.,

    +
    def exchange_column(batch):
    +    import pyarrow as pa
    +
    +    columns = batch.columns
    +    first = columns[0]
    +    second = columns[1]
    +    columns = [second, first] + columns[2:]
    +    return pa.RecordBatch.from_arrays(columns, schema=batch.schema)
    +
    +
    +

  • +
  • vineyard_ipc_socket (str) – The local or remote vineyard’s IPC socket location that the remote +readers will use to establish connections with the vineyard server.

  • +
  • vineyard_endpoint (str, optional) – An optional address of vineyard’s RPC socket, which will be used for +retrieving server’s information on the client side. If not provided, +the vineyard_ipc_socket will be used, or it will tries to discovery +vineyard’s IPC or RPC endpoints from environment variables.

  • +
+
+
+
+ +
+
+

Streams#

+
+
+class vineyard.io.byte.ByteStream(meta: ObjectMeta, params: Optional[Dict] = None)[source]#
+
+ +
+
+class vineyard.io.dataframe.DataframeStream(meta: ObjectMeta, params: Optional[Dict] = None)[source]#
+
+ +
+
+class vineyard.io.recordbatch.RecordBatchStream(meta: ObjectMeta, params: Optional[Dict[str, Any]] = None)[source]#
+
+ +
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 0000000000..2b0217c3ee Binary files /dev/null and b/objects.inv differ diff --git a/search.html b/search.html new file mode 100644 index 0000000000..63192f6492 --- /dev/null +++ b/search.html @@ -0,0 +1,389 @@ + + + + + + + Search - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 0000000000..831f17b422 --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["docs", "notes/architecture", "notes/cloud-native/deploy-kubernetes", "notes/cloud-native/vineyard-operator", "notes/cloud-native/vineyardctl", "notes/developers", "notes/developers/build-from-source", "notes/developers/contributing", "notes/developers/faq", "notes/developers/roadmap", "notes/developers/troubleshooting", "notes/getting-started", "notes/integration-bigdata", "notes/integration-orchestration", "notes/integration/airflow", "notes/integration/dask", "notes/integration/kedro", "notes/integration/ml", "notes/integration/ray", "notes/key-concepts", "notes/key-concepts/data-accessing", "notes/key-concepts/io-drivers", "notes/key-concepts/objects", "notes/key-concepts/streams", "notes/key-concepts/vcdl", "notes/references", "notes/references/cpp-api", "notes/references/ctl", "notes/references/python-api", "tutorials/data-processing", "tutorials/data-processing/accelerate-data-sharing-in-kedro", "tutorials/data-processing/distributed-learning", "tutorials/data-processing/python-sharedmemory", "tutorials/data-processing/using-objects-python", "tutorials/extending", "tutorials/extending/define-datatypes-cpp", "tutorials/extending/define-datatypes-python", "tutorials/kubernetes", "tutorials/kubernetes/data-sharing-with-vineyard-on-kubernetes", "tutorials/kubernetes/ml-pipeline-mars-pytorch", "tutorials/kubernetes/using-vineyard-operator", "tutorials/tutorials"], "filenames": ["docs.rst", "notes/architecture.rst", "notes/cloud-native/deploy-kubernetes.rst", "notes/cloud-native/vineyard-operator.rst", "notes/cloud-native/vineyardctl.md", "notes/developers.rst", "notes/developers/build-from-source.rst", "notes/developers/contributing.rst", "notes/developers/faq.rst", "notes/developers/roadmap.rst", "notes/developers/troubleshooting.rst", "notes/getting-started.rst", "notes/integration-bigdata.rst", "notes/integration-orchestration.rst", "notes/integration/airflow.rst", "notes/integration/dask.rst", "notes/integration/kedro.md", "notes/integration/ml.rst", "notes/integration/ray.rst", "notes/key-concepts.rst", "notes/key-concepts/data-accessing.rst", "notes/key-concepts/io-drivers.rst", "notes/key-concepts/objects.rst", "notes/key-concepts/streams.rst", "notes/key-concepts/vcdl.rst", "notes/references.rst", "notes/references/cpp-api.rst", "notes/references/ctl.rst", "notes/references/python-api.rst", "tutorials/data-processing.rst", "tutorials/data-processing/accelerate-data-sharing-in-kedro.rst", "tutorials/data-processing/distributed-learning.ipynb", "tutorials/data-processing/python-sharedmemory.rst", "tutorials/data-processing/using-objects-python.rst", "tutorials/extending.rst", "tutorials/extending/define-datatypes-cpp.rst", "tutorials/extending/define-datatypes-python.rst", "tutorials/kubernetes.rst", "tutorials/kubernetes/data-sharing-with-vineyard-on-kubernetes.rst", "tutorials/kubernetes/ml-pipeline-mars-pytorch.rst", "tutorials/kubernetes/using-vineyard-operator.rst", "tutorials/tutorials.rst"], "titles": ["Why bother?", "Architecture", "Deploy on Kubernetes", "Vineyard Operator", "vineyardctl", "Getting Involved", "Building from source", "Contributing to vineyard", "Frequently Asked Questions", "Roadmap", "Troubleshooting", "Getting Started", "Big-data on Vineyard", "Workflow orchestration", "Airflow on Vineyard", "Dask on Vineyard", "Kedro Vineyard Plugin", "Machine Learning with Vineyard", "Ray on Vineyard", "Key Concepts", "Data Accessing", "I/O Drivers", "Objects", "Streams in Vineyard", "Code Generation for Boilerplate", "API Reference", "C++ API Reference", "Vineyard Cli", "Python API Reference", "Data processing", "Accelerate Data Sharing in Kedro", "Distributed Learning with Vineyard", "multiprocessing.shared_memory in Python", "Sharing Python Objects with Vineyard", "Extending vineyard", "Defining Custom Data Types in C++", "Define Data Types in Python", "Vineyard on Kubernetes", "Data sharing with Vineyard on Kubernetes", "Machine learning with Vineyard on Kubernetes", "Use vineyard operator", "Data processing"], "terms": {"distributed-system": 0, "distribut": [0, 3, 4, 6, 7, 8, 9, 11, 12, 15, 27, 28, 29, 33, 36, 39, 41], "shared-memori": 0, "graph-analyt": 0, "in-memory-storag": 0, "big-data-analyt": 0, "distributed-comp": 0, "an": [0, 1, 2, 4, 5, 6, 7, 8, 9, 11, 14, 15, 16, 17, 19, 20, 23, 24, 26, 27, 28, 29, 35, 37, 39, 40, 41], "memori": [0, 3, 4, 8, 9, 10, 11, 14, 15, 16, 17, 20, 22, 26, 27, 30, 31, 32, 33, 35, 36], "immut": [0, 1, 8, 9, 11, 19, 23, 26, 28], "manag": [0, 1, 2, 3, 8, 9, 11, 14, 15, 20, 22, 28, 37, 39, 40, 41], "intermedi": [0, 3, 11, 13, 14, 16, 22, 30, 37, 41], "between": [0, 1, 2, 3, 4, 8, 9, 14, 16, 20, 22, 24, 29, 30, 31, 36, 41], "system": [0, 1, 2, 3, 4, 6, 7, 8, 11, 14, 16, 19, 22, 27, 30, 31, 39, 40], "modern": [0, 14, 20], "big": [0, 11, 14, 31, 37, 41], "ai": [0, 14], "workflow": [0, 2, 3, 11, 12, 14, 16, 29, 37, 40, 41], "can": [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41], "challeng": [0, 1, 8, 39], "often": [0, 1, 3, 14], "caus": [0, 4], "signific": [0, 14, 15, 20, 29, 35, 41], "bottleneck": 0, "job": [0, 1, 8, 9, 20, 28, 37, 39, 40, 41], "let": [0, 31, 35, 39, 40], "": [0, 1, 2, 3, 4, 6, 7, 8, 11, 14, 19, 21, 22, 23, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 38, 39, 40, 41], "consid": [0, 8, 14, 17, 22, 24, 27], "follow": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 21, 22, 24, 25, 26, 27, 28, 30, 31, 33, 35, 36, 37, 38, 39, 40, 41], "fraud": [0, 39], "detect": 0, "pipelin": [0, 1, 8, 13, 14, 16, 17, 23, 26, 29, 37, 41], "A": [0, 3, 6, 7, 8, 9, 11, 16, 17, 22, 23, 26, 27, 28, 31, 33, 36, 38, 40], "real": [0, 3, 14, 31, 33, 36], "life": 0, "from": [0, 1, 3, 4, 5, 7, 8, 9, 11, 14, 15, 16, 20, 22, 23, 25, 26, 27, 28, 30, 32, 33, 35, 36, 38, 40], "we": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 19, 20, 21, 22, 23, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 38, 39, 40, 41], "observ": [0, 3, 10, 30, 35], "user": [0, 1, 3, 4, 8, 9, 10, 11, 13, 14, 19, 20, 21, 22, 26, 28, 29, 31, 33, 34, 35, 36, 39, 41], "usual": [0, 1, 4, 16, 26, 28], "prefer": [0, 2], "program": [0, 1, 8, 11, 15, 22, 27, 28], "dedic": [0, 7, 14, 31, 40], "comput": [0, 1, 3, 9, 11, 12, 14, 15, 19, 20, 21, 22, 23, 26, 29, 31, 34, 36, 38, 41], "differ": [0, 1, 3, 8, 9, 10, 14, 15, 20, 21, 22, 28, 30, 31, 32, 35, 36, 39], "task": [0, 2, 3, 14, 15, 16, 20, 22, 25, 29, 30, 31, 34, 41], "same": [0, 1, 3, 4, 8, 15, 17, 20, 22, 26, 28, 31, 33, 36], "applic": [0, 1, 3, 8, 9, 14, 16, 22, 31, 38], "sql": 0, "python": [0, 4, 7, 9, 13, 14, 22, 25, 27, 29, 30, 31, 34, 35, 38, 40, 41], "integr": [0, 3, 7, 9, 11, 12, 13, 14, 15, 17, 19, 20, 22, 24, 29, 34, 35, 36, 37, 41], "new": [0, 1, 3, 4, 7, 16, 19, 23, 26, 28, 35, 39], "product": [0, 7, 39], "environ": [0, 3, 4, 5, 6, 7, 14, 16, 19, 26, 27, 28, 31, 36], "demand": 0, "high": [0, 3, 4, 8, 9, 11, 13, 22], "technic": 0, "effort": [0, 3, 4, 5], "align": [0, 8], "exist": [0, 1, 3, 4, 7, 19, 26, 27, 28, 29, 31, 35, 38, 41], "term": [0, 25], "failov": 0, "etc": [0, 4, 27, 28], "could": [0, 3, 4, 6, 7, 8, 9, 23, 26, 28, 35, 36, 40], "polymorph": 0, "non": [0, 16, 22, 26], "relat": [0, 4, 8, 9, 14, 26, 39, 40], "tensor": [0, 1, 3, 4, 7, 8, 14, 15, 20, 26, 28, 31, 33, 34, 35, 36, 40, 41], "datafram": [0, 1, 3, 4, 8, 11, 13, 14, 15, 16, 20, 23, 26, 27, 28, 31, 35, 38, 39], "panda": [0, 9, 11, 13, 14, 16, 17, 20, 23, 27, 31, 38], "graph": [0, 1, 6, 8, 14, 22, 26, 34, 35, 41], "network": [0, 1, 14, 20, 26, 28, 31], "graphscop": [0, 20, 22, 39], "ar": [0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 14, 15, 16, 19, 20, 21, 22, 24, 26, 28, 30, 31, 35, 38, 39, 40], "becom": [0, 1, 2, 3, 16, 22, 26, 28, 30, 31, 32, 35], "increasingli": 0, "preval": [0, 20], "tabl": [0, 4, 28, 34, 35, 39, 41], "mai": [0, 4, 5, 6, 7, 8, 9, 10, 22, 26, 28, 35, 36, 38], "best": [0, 3, 4], "wai": [0, 1, 8], "store": [0, 1, 3, 4, 8, 9, 14, 15, 17, 19, 22, 26, 31, 33, 35, 36, 39, 40], "exchang": 0, "process": [0, 1, 3, 7, 8, 9, 11, 12, 14, 15, 20, 21, 22, 24, 26, 28, 31, 33, 35, 36, 39], "them": [0, 3, 4, 11, 15, 22, 23, 31, 35, 38, 39], "transform": [0, 2, 3, 14, 32], "back": [0, 3, 4, 11, 26, 28], "forth": [0, 26], "result": [0, 1, 14, 15, 22, 26, 28, 35], "overhead": [0, 16, 20, 22, 23, 28, 31], "save": [0, 14, 16, 22, 31, 33, 36, 38], "load": [0, 2, 3, 13, 14, 15, 16, 22, 26, 30, 31], "extern": [0, 1, 2, 3, 11, 14, 16, 28, 31, 40], "storag": [0, 1, 3, 4, 9, 14, 16, 19, 23, 31, 37, 40, 41], "requir": [0, 1, 2, 3, 4, 6, 7, 8, 10, 14, 20, 21, 22, 23, 26, 28, 34, 35, 36, 39, 41], "numer": [0, 1, 17, 22, 31, 35, 39], "copi": [0, 1, 8, 9, 11, 14, 20, 23, 26, 28, 30, 33, 35, 36], "incur": [0, 8, 14, 15, 20], "io": [0, 2, 3, 4, 6, 7, 15, 16, 21, 23, 28, 30, 38, 39, 40], "cost": [0, 3, 8, 9, 11, 13, 14, 15, 16, 20, 22, 30], "v6d": [0, 2, 3, 4, 6, 7, 39, 40], "offer": [0, 1, 2, 3, 7, 8, 11, 19, 20, 22, 24, 25, 32, 34, 41], "level": [0, 8, 11, 20, 22, 28], "zero": [0, 8, 11, 14, 20, 26, 33, 35, 36, 40], "analyt": [0, 8, 11, 14], "e": [0, 1, 3, 4, 8, 9, 10, 11, 13, 16, 17, 21, 22, 23, 26, 27, 28, 31, 35], "g": [0, 1, 3, 4, 8, 9, 10, 11, 13, 16, 21, 22, 23, 26, 27, 28, 31, 35], "mar": [0, 20, 22, 39], "machin": [0, 1, 8, 12, 15, 22, 27, 28, 29, 30, 31, 33, 36, 37, 41], "learn": [0, 1, 8, 9, 11, 12, 29, 30, 37, 40, 41], "across": [0, 1, 3, 8, 13, 14, 15, 20, 22, 33, 35, 36, 39], "without": [0, 4, 8, 13, 14, 16, 22, 26, 28, 29, 30, 31, 41], "extra": [0, 11, 26, 28], "elimin": [0, 13, 15, 35], "serial": [0, 3, 8, 13, 14, 16, 22, 23, 28, 30], "deseri": [0, 3, 14, 22, 23], "when": [0, 1, 2, 3, 7, 8, 9, 10, 13, 14, 16, 20, 21, 22, 24, 26, 27, 28, 29, 30, 31, 35, 41], "defin": [0, 1, 3, 4, 14, 22, 23, 24, 31, 34, 41], "metadata": [0, 1, 2, 3, 8, 9, 24, 27, 33, 35, 36, 38, 40], "payload": [0, 1, 20, 26, 27, 28, 33, 35, 36], "separ": [0, 3, 31], "model": [0, 8, 11, 15, 39], "captur": [0, 28], "common": [0, 1, 6, 10, 26, 28], "method": [0, 2, 3, 11, 15, 17, 20, 21, 22, 24, 26, 28, 32, 35, 39, 40], "sharabl": [0, 11, 24], "object": [0, 2, 7, 8, 9, 10, 13, 14, 16, 17, 19, 24, 27, 29, 31, 37, 38, 40, 41], "languag": [0, 1, 11, 22, 24, 40], "unifi": 0, "The": [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 13, 16, 17, 19, 20, 21, 22, 24, 26, 27, 28, 30, 31, 33, 35, 36, 37, 38, 39, 40, 41], "code": [0, 5, 6, 9, 10, 11, 13, 16, 21, 26, 29, 31, 35, 36, 38, 39, 41], "gener": [0, 1, 3, 4, 6, 7, 8, 9, 11, 15, 16, 22, 23, 26, 27, 28, 30, 31, 35, 38], "boilerpl": [0, 2, 11, 26, 35], "compon": [0, 1, 2, 3, 4, 9, 16, 22, 36, 37, 40, 41], "descript": [0, 3, 7, 22], "specif": [0, 1, 3, 4, 8, 9, 16, 21, 22, 26, 28, 33, 35, 36], "design": [0, 1, 3, 7, 8, 9, 11, 14, 19, 20, 21, 22, 26, 31, 35, 40], "annot": [0, 1, 3, 24], "member": [0, 3, 5, 22, 24, 26, 27, 28, 35, 36], "enabl": [0, 1, 3, 4, 7, 8, 9, 11, 13, 14, 15, 17, 20, 22, 23, 27, 29, 36, 41], "automat": [0, 4, 7, 8, 24, 26, 28, 31, 35, 36], "minim": [0, 8, 11, 13, 22, 23], "In": [0, 1, 2, 3, 4, 8, 9, 10, 11, 14, 15, 17, 20, 22, 25, 26, 27, 28, 29, 31, 32, 33, 35, 36, 37, 38, 39, 40, 41], "mani": [0, 3, 10, 20, 26, 31], "substanti": 0, "portion": [0, 8, 14], "workload": [0, 1, 2, 3, 8, 9, 14, 28, 31, 38], "consist": [0, 1, 3, 7, 15, 22, 23, 31, 33, 35, 39, 40], "unrel": 0, "core": [0, 3, 10, 11, 15, 19, 22, 26, 28, 31], "These": [0, 8, 34, 35, 41], "includ": [0, 1, 3, 4, 7, 9, 12, 14, 22, 25, 26, 28, 31, 35, 40], "variou": [0, 3, 9, 11, 14, 17, 19, 20, 22, 28, 29, 35, 36, 40, 41], "adapt": [0, 14, 35], "partit": [0, 1, 3, 8, 15, 20, 22, 26], "strategi": [0, 3, 4, 15], "migrat": [0, 1, 3, 7, 8, 11, 14, 16, 20, 26, 28], "due": [0, 14, 20], "structur": [0, 1, 6, 9, 11, 17, 22, 24, 26, 31, 34, 35, 41], "easili": [0, 1, 6, 7, 13, 20, 22, 31, 34, 41], "reusabl": 0, "lead": [0, 22], "increas": [0, 10, 22, 26], "complex": [0, 1, 8, 11, 13, 14, 17, 22, 29, 41], "redund": 0, "provid": [0, 1, 3, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 26, 28, 31, 34, 35, 40, 41], "manipul": [0, 1, 26], "driver": [0, 1, 4, 11, 19, 22], "which": [0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 20, 21, 22, 26, 28, 31, 33, 36, 40], "extend": [0, 9, 31], "capabl": [0, 8, 9, 15, 20, 22, 29, 41], "regist": [0, 1, 8, 14, 15, 21, 22, 26, 27, 28, 31, 34, 36, 41], "appropri": [0, 3, 39], "thi": [0, 1, 2, 3, 4, 7, 8, 9, 10, 12, 14, 15, 16, 17, 20, 22, 23, 24, 26, 27, 28, 30, 31, 32, 33, 35, 36, 37, 38, 39, 40, 41], "reus": [0, 1], "divers": 0, "cloud": [0, 4, 8, 11, 14], "nativ": [0, 4, 8, 11, 14, 22], "embrac": 0, "help": [0, 3, 4, 5, 6, 7, 8, 9, 11, 26, 28, 31, 35, 36], "leverag": [0, 1, 16, 34, 41], "scale": [0, 1, 7, 13, 14, 16, 30], "schedul": [0, 1, 2, 8, 9, 11, 14, 15, 16, 20, 22, 31, 37, 38, 39, 40, 41], "abil": [0, 30], "put": [0, 1, 11, 15, 17, 20, 22, 23, 26, 28, 31, 33, 36, 38, 40], "arbitrari": [0, 11], "cross": [0, 1, 8, 24, 31], "larg": [0, 1, 8, 9, 10, 13, 14, 16, 20, 22, 30], "coordin": 0, "flow": [0, 14], "base": [0, 1, 3, 4, 6, 7, 8, 9, 14, 20, 22, 26, 28, 30, 35, 36, 39], "awar": [0, 9, 11, 20, 22, 32, 37, 41], "guid": [0, 2, 7, 8, 11, 19, 20, 35, 40], "deploi": [0, 3, 6, 8, 9, 11, 20, 28, 29, 37, 38, 39, 41], "acceler": [0, 3, 11, 29, 41], "infrastructur": [0, 1, 11, 14, 19], "tutori": [0, 14, 30, 35, 37, 38, 40, 41], "explor": [0, 3, 11, 23, 25, 40], "where": [0, 1, 3, 8, 10, 11, 14, 15, 16, 20, 26, 28, 31, 33, 35, 36, 37, 38, 41], "bring": [0, 9], "ad": [0, 1, 9, 17, 20, 26, 32, 35, 40], "valu": [0, 1, 3, 4, 8, 10, 11, 14, 15, 17, 20, 22, 26, 27, 28, 31, 32, 33, 36], "involv": [0, 1, 3, 14, 16, 20, 23, 24, 29, 35, 41], "part": [0, 1, 3, 9, 22, 31, 33, 35], "commun": [0, 1, 5, 7, 14, 20, 23, 26, 40], "faq": [0, 8], "frequent": 0, "ask": [0, 7], "question": [0, 40], "discuss": [0, 5, 8, 33, 36], "dure": [0, 3, 4, 5, 22, 26, 28], "adopt": [0, 1], "wenyuan": 0, "yu": 0, "tao": 0, "he": 0, "lei": 0, "wang": 0, "ke": 0, "meng": 0, "ye": [0, 8], "cao": 0, "diwen": 0, "zhu": 0, "sanhong": 0, "li": [0, 26], "jingren": 0, "zhou": 0, "optim": [0, 2, 14, 15, 22, 31], "intens": [0, 29, 34, 41], "acm": [0, 39], "sig": [0, 40], "confer": 0, "sigmod": 0, "industri": 0, "2023": [0, 38, 40], "cncf": [0, 5, 9], "sandbox": [0, 5, 9], "project": [0, 5, 7, 9, 16, 30], "made": [0, 26], "success": [0, 3, 7, 11, 26], "its": [0, 2, 3, 7, 8, 14, 15, 19, 20, 22, 26, 27, 28, 35, 36, 37, 41], "figur": [1, 3, 15, 20, 38], "illustr": [1, 15, 20], "vineyard": [1, 5, 8, 9, 13, 19, 20, 21, 22, 24, 25, 29, 32, 36], "On": [1, 33, 36], "daemon": [1, 2, 3, 8, 11, 15, 31, 35], "i": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 19, 20, 24, 25, 26, 27, 29, 30, 31, 32, 33, 35, 36, 38, 39, 40, 41], "aforement": [1, 8, 31], "instanc": [1, 3, 4, 8, 11, 17, 20, 22, 25, 26, 27, 28, 31, 33, 35, 36, 40], "three": [1, 3, 14, 20, 22, 31, 38, 39, 40], "primari": [1, 8], "space": [1, 19, 26], "via": [1, 4, 8, 11, 26, 27, 28, 38, 40], "unix": [1, 6, 8, 10, 11, 14, 26, 27, 28], "domain": [1, 8, 10, 11, 14, 26, 27, 28, 35], "socket": [1, 3, 4, 8, 10, 11, 14, 16, 26, 27, 28, 33, 36], "through": [1, 8, 20, 31, 32, 33, 35, 36, 37, 41], "map": [1, 3, 4, 8, 17, 20, 22, 26, 28, 31, 33, 35, 36], "As": [1, 3, 7, 14, 15, 20, 21, 22, 33, 35, 36, 38], "previous": [1, 15, 22], "mention": [1, 17, 22, 31], "resid": [1, 8, 26, 33, 36, 37, 41], "correspond": [1, 3, 8, 11, 17, 21, 22, 26, 28, 31, 33, 35, 36], "cluster": [1, 8, 9, 16, 20, 22, 26, 27, 31, 33, 36, 38, 39], "respons": [1, 5, 20, 26, 35], "maintain": [1, 5, 22, 35], "layout": [1, 22, 35], "properti": [1, 22, 28], "each": [1, 3, 8, 14, 15, 20, 28, 30, 31, 33, 36, 39], "other": [1, 3, 6, 7, 9, 11, 14, 20, 22, 23, 26, 27, 28, 30, 31, 32, 33, 36, 38, 39], "backend": [1, 3, 4, 13, 14, 22, 28, 29, 41], "kei": [1, 3, 4, 9, 11, 22, 26, 28, 30, 31, 35], "etcd": [1, 2, 3, 4, 7, 8, 10, 22, 26, 27, 28, 38, 40], "ensur": [1, 2, 3, 4, 7, 8, 9, 14, 22, 26, 31, 32, 39, 40], "ipc": [1, 3, 4, 8, 10, 11, 14, 20, 22, 26, 27, 28, 33, 40], "rpc": [1, 2, 3, 4, 8, 9, 20, 26, 27, 28, 38, 40], "connect": [1, 4, 8, 10, 15, 16, 20, 22, 23, 26, 28, 31, 33, 35, 36, 38], "obtain": [1, 3, 6, 11, 14, 15, 20, 26, 28, 39], "both": [1, 3, 8, 9, 15, 20, 26, 28, 29, 40, 41], "howev": [1, 8, 14, 20, 22, 31, 33, 35, 36], "must": [1, 3, 4, 22, 26, 28, 30, 31], "occur": [1, 26], "call": [1, 11, 17, 21, 26, 28], "low": [1, 3, 4, 8, 20, 31], "api": [1, 3, 6, 9, 11, 14, 20, 22, 23, 31], "precis": [1, 14, 22], "manner": [1, 3, 8, 20, 22, 26, 39], "routin": [1, 11], "o": [1, 3, 4, 6, 8, 9, 11, 13, 15, 16, 19, 30, 31, 38], "more": [1, 3, 4, 8, 9, 10, 11, 14, 16, 20, 22, 23, 25, 26, 28, 30, 32, 38, 39, 40], "local": [1, 3, 4, 6, 7, 8, 9, 14, 16, 21, 22, 25, 26, 27, 28, 30, 31, 33, 36, 39, 40], "us": [1, 2, 3, 4, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 19, 21, 22, 25, 26, 27, 28, 29, 30, 31, 33, 35, 36, 38, 39, 41], "establish": [1, 2, 3, 24, 28], "mmap": [1, 11, 26], "transfer": [1, 14, 16, 20, 28, 31], "file": [1, 3, 4, 7, 9, 16, 21, 26, 27, 30, 31, 38, 40], "descriptor": 1, "engin": [1, 3, 7, 8, 9, 11, 12, 13, 19, 20, 22, 23, 24, 29, 31, 34, 41], "tcp": [1, 2, 3, 4, 20, 26, 28, 31, 40], "port": [1, 2, 3, 4, 26, 27, 28, 30, 40], "bound": [1, 26], "unlik": [1, 26], "doesn": [1, 26, 28], "t": [1, 2, 3, 4, 7, 8, 11, 24, 26, 27, 28, 35, 40], "allow": [1, 3, 8, 14, 16, 20, 21, 22, 33, 36], "retriev": [1, 3, 15, 20, 22, 23, 26, 28, 33, 35, 36], "builder": [1, 11, 15, 20, 24, 26, 31, 34, 41], "resolv": [1, 7, 10, 11, 14, 15, 17, 24, 26, 31, 34, 35, 41], "consum": [1, 3, 8, 11, 20, 21, 38], "produc": [1, 3, 8, 11, 28, 35, 38], "extens": [1, 22, 35], "own": [1, 21, 26, 27, 28, 35], "newli": [1, 28], "type": [1, 2, 3, 4, 7, 13, 14, 16, 17, 20, 21, 22, 23, 24, 27, 28, 31, 34, 40, 41], "well": [1, 6, 7, 9, 16, 17, 20, 28, 31, 35, 40], "build": [1, 2, 4, 5, 11, 16, 17, 22, 26, 28, 30, 33, 35, 36, 39], "hoc": 1, "wrap": [1, 17], "registri": [1, 16, 22, 30, 34, 39, 41], "sdk": [1, 9, 25, 35], "current": [1, 2, 3, 4, 14, 26, 27, 28, 40], "c": [1, 2, 3, 4, 6, 7, 9, 11, 17, 22, 23, 24, 25, 28, 34, 38, 39, 40, 41], "offici": [1, 16, 39], "support": [1, 3, 4, 6, 7, 8, 9, 10, 14, 17, 20, 21, 26, 28, 40], "rust": [1, 9, 40], "go": [1, 6, 9, 16, 27, 39], "under": [1, 6, 7, 11, 27, 28, 39], "heavi": 1, "develop": [1, 3, 5, 8, 14, 22, 26, 30, 31, 35], "pluggabl": [1, 3, 4, 11], "assign": 1, "function": [1, 3, 9, 11, 14, 17, 21, 22, 26, 31, 35, 37, 41], "certain": [1, 3, 28, 31], "particular": [1, 31], "synchron": [1, 3, 20, 22, 26, 28], "databas": [1, 14], "read": [1, 3, 15, 26, 28, 31, 38, 39], "write": [1, 26, 28, 38, 39, 40], "while": [1, 2, 3, 4, 7, 8, 13, 14, 16, 17, 20, 22, 23, 31, 40], "re": [1, 15, 27, 36], "reorgan": 1, "balanc": 1, "typic": [1, 8, 10, 20, 23, 31, 35, 36], "emploi": [1, 3, 15, 20, 22, 26, 39], "oper": [1, 7, 8, 9, 10, 11, 13, 14, 16, 20, 22, 23, 24, 26, 30, 35, 37, 39, 41], "mechan": [1, 4, 11, 22, 24], "implement": [1, 7, 9, 11, 13, 15, 19, 22, 26, 34, 35, 41], "need": [1, 2, 3, 4, 5, 6, 7, 8, 13, 15, 16, 22, 26, 30, 35, 39, 40], "cannot": [1, 3, 8, 11, 14, 16, 26, 28, 32, 33, 36], "co": [1, 8, 9, 20], "locat": [1, 3, 4, 8, 10, 11, 14, 16, 20, 26, 27, 28, 35], "pair": [1, 22, 26, 28, 33, 36], "sender": 1, "receiv": [1, 17, 23], "move": [1, 14, 20, 26, 35], "don": [1, 2, 3, 4, 11, 40], "decoupl": [1, 22], "effici": [1, 2, 3, 11, 13, 14, 16, 20, 22, 23, 25, 29, 31, 34, 35, 37, 41], "deploy": [1, 2, 3, 7, 8, 9, 10, 26, 27, 30, 31, 38, 39, 40], "rdma": 1, "perform": [1, 3, 9, 10, 13, 14, 16, 20, 22, 23, 26, 29, 41], "technologi": 1, "creat": [1, 8, 9, 11, 16, 20, 22, 23, 26, 28, 30, 31, 33, 35, 38, 39, 40], "alloc": [1, 10, 11, 20, 22, 26, 28, 35], "blob": [1, 3, 9, 22, 24, 33, 35, 36, 40], "hand": [1, 33, 36], "inter": [1, 8, 23, 31], "techniqu": [1, 15, 20, 22], "By": [1, 10, 11, 22, 28, 29, 34, 41], "examin": [1, 8, 20], "practic": 1, "analysi": [1, 22, 35], "have": [1, 2, 3, 4, 5, 10, 11, 15, 16, 17, 20, 21, 26, 28, 30, 31, 32, 35, 36, 38, 39, 40], "identifi": [1, 3, 7, 11, 14, 24, 26, 28, 39], "four": [1, 40], "fragment": [1, 8, 22], "fit": [1, 4, 8, 9, 11, 14, 15, 22, 31], "never": [1, 22, 26], "modifi": [1, 3, 5, 7, 13, 26, 31, 32], "after": [1, 3, 4, 6, 7, 8, 9, 14, 16, 17, 26, 28, 30, 32, 40], "creation": [1, 3, 28], "With": [1, 2, 16, 31, 33, 36], "csr": [1, 22], "format": [1, 3, 4, 9, 22, 26, 28], "address": [1, 4, 7, 8, 9, 10, 22, 26, 28, 31], "compos": [1, 8, 26], "flexibl": [1, 8, 22, 36], "choic": [1, 22], "fulli": [1, 6, 9, 22], "determin": [1, 8, 22], "difficulti": 1, "handl": [1, 13, 14, 16, 21, 26, 30, 31, 36], "For": [1, 3, 4, 7, 8, 9, 10, 14, 15, 20, 22, 23, 25, 26, 28, 30, 31, 32, 35, 36, 38, 39, 40], "index": [1, 7, 16, 22, 23, 25, 26, 31, 35], "along": [1, 15, 22, 30, 35, 39], "vertic": [1, 22], "edg": [1, 14, 22], "like": [1, 3, 4, 6, 8, 9, 11, 13, 14, 16, 22, 26, 27, 28, 35], "iter": [1, 26, 28], "mean": [1, 4, 11, 20, 22, 26, 27, 28], "themselv": 1, "moreov": [1, 13, 22], "codegen": 1, "tool": [1, 2, 4, 8, 16, 25, 27, 38, 40], "transplant": 1, "onli": [1, 3, 4, 7, 8, 14, 17, 20, 22, 26, 27, 28, 31], "few": [1, 31], "throughout": 1, "end": [1, 8, 9, 14, 26, 30, 31], "hold": [1, 20, 22, 26, 33], "variabl": [1, 4, 6, 14, 16, 26, 27, 28, 31], "long": [1, 8], "modul": [1, 3, 6, 28, 32, 39], "down": [1, 28], "entir": [1, 8, 20, 22, 26, 33, 36], "run": [1, 2, 3, 4, 6, 8, 10, 11, 15, 16, 17, 27, 28, 30, 31, 33, 36, 38, 39, 40], "script": [1, 7], "trillion": 1, "background": [1, 28], "distributedli": [1, 15, 31], "onc": [1, 2, 6, 9, 11, 26, 32], "seal": [1, 7, 20, 26, 28, 35], "NOT": [1, 7], "anymor": [1, 16], "thu": [1, 26, 31], "suitabl": [1, 16], "cach": [1, 31], "chang": [1, 9, 11, 28, 30], "rapidli": 1, "order": [1, 14, 22, 26, 28, 39], "invok": [1, 21, 26, 28], "trigger": [1, 2, 8, 14, 26, 28], "There": [2, 3, 6, 8, 22], "two": [2, 3, 4, 8, 9, 11, 15, 17, 20, 23, 24, 26, 27, 28, 31, 33, 35, 36, 38, 40], "directli": [2, 15, 22, 26, 40], "prior": 2, "you": [2, 3, 4, 5, 6, 7, 8, 10, 11, 15, 16, 19, 20, 23, 27, 28, 30, 35, 37, 38, 39, 40, 41], "kubectl": [2, 3, 4, 16, 30, 38, 39, 40], "kind": [2, 3, 4, 9, 16, 17, 19, 26, 30, 38, 39, 40], "befor": [2, 3, 4, 7, 9, 14, 26, 30, 40], "proceed": [2, 28], "essenti": [2, 7, 8, 15, 35], "cert": [2, 39, 40], "webhook": [2, 3, 4, 39, 40], "within": [2, 3, 7, 8, 10, 14, 15, 19, 20, 22, 31, 33, 36, 40], "repo": [2, 3, 6, 30, 39, 40], "add": [2, 3, 4, 7, 22, 26, 27, 28, 30, 40], "http": [2, 3, 4, 6, 7, 8, 14, 16, 26, 30, 39, 40], "oss": [2, 30, 40], "ap": [2, 30, 40], "southeast": [2, 30, 40], "aliyunc": [2, 30, 40], "com": [2, 3, 4, 6, 7, 16, 30, 39, 40], "updat": [2, 3, 6, 7, 26, 30, 35, 40], "namespac": [2, 3, 4, 16, 28, 30, 38, 39, 40], "until": [2, 3, 23, 26, 28], "clone": [2, 6], "git": [2, 6], "github": [2, 3, 4, 5, 6, 7, 16, 30], "docker": [2, 16, 28, 39, 40], "imag": [2, 3, 4, 7, 15, 16, 28, 38, 39, 40], "cd": [2, 6, 7, 16, 30, 39], "k8": [2, 3, 4, 16, 30, 39, 40], "make": [2, 3, 6, 7, 8, 9, 14, 22, 25, 26, 28, 30, 31, 32, 33, 36, 39, 40], "first": [2, 3, 7, 9, 15, 20, 22, 23, 26, 27, 28, 30, 31, 33, 35, 36, 39, 40], "import": [2, 3, 4, 9, 11, 14, 15, 17, 20, 23, 28, 31, 32, 33, 36, 38, 40], "vineyardcloudn": [2, 3, 4, 7, 28, 40], "latest": [2, 3, 4, 6, 7, 16, 28, 30, 38, 39, 40], "appli": [2, 3, 4, 16, 24, 28, 30, 31, 38, 39, 40], "f": [2, 3, 4, 14, 15, 16, 20, 30, 31, 38, 39, 40], "releas": [2, 3, 6, 16, 26, 28, 30, 40], "download": [2, 6, 16, 30, 39], "v1": [2, 3, 4, 30, 38, 39, 40], "9": [2, 3, 4, 17, 30, 31, 38, 40], "yaml": [2, 3, 4, 16, 30, 38, 40], "pleas": [2, 3, 4, 6, 7, 8, 9, 10, 15, 16, 20, 23, 25, 32, 35, 38, 39, 40], "next": [2, 3, 4, 7, 8, 16, 23, 30, 31, 35], "check": [2, 3, 4, 7, 8, 10, 16, 26, 27, 28, 38, 39, 40], "get": [2, 3, 6, 9, 15, 16, 17, 19, 20, 21, 23, 26, 27, 28, 30, 31, 33, 36, 38, 39, 40], "all": [2, 3, 4, 6, 7, 8, 22, 25, 26, 27, 28, 30, 31, 38, 39, 40], "n": [2, 3, 4, 16, 27, 30, 38, 39, 40], "name": [2, 3, 4, 6, 11, 15, 16, 17, 22, 26, 27, 28, 30, 31, 32, 35, 38, 39, 40], "statu": [2, 3, 4, 16, 26, 27, 28, 30, 35, 38, 39, 40], "restart": [2, 3, 30, 38, 39, 40], "ag": [2, 3, 16, 30, 38, 39, 40], "pod": [2, 3, 4, 8, 10, 30, 39, 40], "control": [2, 3, 4, 9, 26, 30, 39, 40], "5c6f4bc454": [2, 3], "8xm8q": [2, 3], "0": [2, 3, 4, 6, 7, 8, 11, 15, 16, 17, 20, 22, 23, 26, 28, 30, 31, 35, 36, 38, 39], "62m": 2, "ip": [2, 3, 26, 38, 40], "servic": [2, 3, 4, 8, 16, 22, 26, 27, 28, 38, 39, 40], "metric": [2, 3, 4, 15, 27, 31, 39, 40], "clusterip": [2, 3, 4, 40], "10": [2, 3, 4, 15, 20, 23, 30, 31, 38, 40], "96": [2, 3, 40], "240": [2, 3], "173": [2, 3, 30], "none": [2, 3, 14, 15, 16, 21, 27, 28, 31, 33, 36, 38, 40], "8443": [2, 3, 40], "41": [2, 3, 40], "132": [2, 3], "443": [2, 3, 40], "up": [2, 3, 4, 5, 7, 9, 10, 28, 40], "TO": [2, 3, 40], "date": [2, 3, 7, 14, 40], "avail": [2, 3, 6, 7, 9, 14, 16, 20, 25, 26, 28, 30, 32, 40], "app": [2, 3, 4, 38, 39, 40], "desir": [2, 3, 40], "replicaset": [2, 3, 40], "vineyardd": [2, 7, 8, 9, 10, 11, 16, 25, 26, 27, 28, 30, 31, 38, 39, 40], "crd": [2, 3, 4, 9, 39, 40], "exampl": [2, 3, 7, 10, 11, 14, 15, 16, 20, 21, 24, 26, 27, 28, 33, 35, 36, 38, 40], "3": [2, 3, 4, 6, 10, 11, 15, 16, 17, 27, 28, 30, 31, 35, 38, 39], "replica": [2, 3, 4, 30, 38, 40], "cat": [2, 3, 4, 30, 38, 40], "eof": [2, 3, 30, 38, 40], "apivers": [2, 3, 4, 30, 38, 40], "v1alpha1": [2, 3, 40], "sampl": [2, 3, 4, 16, 21, 38, 39, 40], "default": [2, 3, 4, 8, 10, 11, 17, 22, 26, 28, 30, 36, 38, 39, 40], "spec": [2, 3, 4, 9, 38, 40], "9600": [2, 3, 4, 20, 28, 40], "alpin": [2, 4], "imagepullpolici": [2, 3, 4, 40], "ifnotpres": [2, 3, 4, 28, 40], "necessari": [2, 3, 7, 22, 31, 35], "depend": [2, 3, 9, 14, 16, 26, 28], "server": [2, 3, 4, 6, 8, 9, 10, 14, 16, 22, 27, 28, 30, 35], "configur": [2, 4, 7, 10, 14, 15, 27, 28, 30, 39, 40], "setup": [2, 6, 15, 16, 19, 28, 30, 33, 36], "complet": [2, 3, 7, 9, 14, 16, 22, 28, 39, 40], "conveni": [2, 20], "inspect": [2, 22, 25, 28], "command": [2, 3, 4, 7, 8, 10, 11, 14, 16, 20, 25, 30, 38, 40], "etcd0": [2, 3, 39], "48": [2, 3], "etcd1": [2, 3, 39], "etcd2": [2, 3, 39], "72": [2, 3], "5cc797668f": [2, 3], "9ggr9": [2, 3], "nhw7p": [2, 3], "r56h7": [2, 3], "174": [2, 3], "2379": [2, 3, 4, 8], "128": [2, 3, 10, 15], "87": [2, 3], "2380": [2, 3, 4], "116": [2, 3], "99": [2, 3], "182": [2, 3], "102": [2, 3], "183": [2, 3], "addit": [2, 6, 8, 14, 19, 22, 25, 31, 36, 39], "plai": 2, "crucial": 2, "role": [2, 4, 30, 39, 40], "data": [2, 3, 4, 6, 8, 9, 11, 13, 14, 15, 16, 19, 21, 23, 24, 27, 28, 33, 34, 37, 39, 40], "share": [2, 3, 6, 8, 9, 10, 12, 13, 14, 16, 17, 19, 20, 22, 23, 24, 26, 27, 29, 31, 32, 35, 36, 37, 41], "movement": [2, 14], "detail": [2, 3, 7, 8, 9, 11, 15, 16, 19, 20, 23, 25, 26, 27, 32, 38, 39, 40], "found": [2, 3, 7, 11, 26, 28, 35], "To": [2, 3, 5, 7, 8, 10, 11, 15, 22, 24, 26, 30, 31, 35, 36, 39, 40], "simplifi": [2, 14, 15, 35], "interact": [2, 4, 16, 22, 25, 28], "line": [2, 4, 7, 8, 10, 11, 16, 25, 26, 27, 31, 38], "vineyardctl": [2, 38], "autom": 2, "much": 2, "orchestr": [2, 3, 14, 30, 37, 41], "work": [2, 4, 8, 9, 10, 13, 14, 16, 27, 30, 35], "demonstr": [3, 9, 11, 14, 15, 16, 20, 21, 22, 29, 31, 32, 35, 36, 39, 40, 41], "successfulli": [3, 5, 6, 8, 16, 30, 35, 38, 40], "refer": [3, 4, 6, 8, 9, 10, 14, 15, 16, 20, 22, 23, 27, 35, 38, 39, 40], "kubernet": [3, 4, 8, 9, 11, 13, 28, 29], "effortlessli": [3, 11, 13, 20, 29, 41], "account": [3, 14, 20, 39], "set": [3, 4, 5, 6, 7, 8, 10, 11, 15, 20, 22, 26, 30, 31, 35, 39, 40], "ultim": 3, "upon": [3, 7, 11, 19, 20, 36], "readi": [3, 4, 28, 30, 38, 39, 40], "1": [3, 4, 7, 8, 11, 14, 15, 16, 17, 20, 21, 22, 23, 28, 30, 31, 33, 35, 36, 38, 39], "2": [3, 4, 7, 11, 14, 15, 16, 17, 20, 22, 23, 28, 30, 31, 35, 38, 39], "entri": [3, 22, 26, 28], "list": [3, 4, 9, 11, 15, 16, 17, 20, 22, 23, 26, 27, 28, 31, 38, 39], "option": [3, 6, 7, 11, 15, 26, 27, 28], "int": [3, 4, 23, 26, 28, 31, 35, 36], "etcdreplica": 3, "string": [3, 4, 22, 26, 27, 28, 31, 35], "contain": [3, 4, 7, 8, 15, 16, 17, 22, 26, 28, 31, 35, 36, 39, 40], "pull": [3, 26, 28], "polici": [3, 26, 28, 37, 41], "nil": 3, "synccrd": [3, 4], "bool": [3, 23, 26, 28], "persist": [3, 4, 10, 11, 15, 26, 28, 33, 36, 38, 40], "true": [3, 4, 11, 14, 15, 20, 22, 23, 26, 28, 31, 32, 38, 40], "size": [3, 4, 8, 22, 23, 24, 26, 27, 28, 30, 31, 33, 35, 36, 39], "reservememori": 3, "reserv": [3, 4, 26], "enough": [3, 4, 26], "physic": [3, 4], "page": [3, 4, 6, 8, 10, 19, 25], "fals": [3, 4, 15, 20, 22, 26, 28, 31, 32, 40], "streamthreshold": [3, 4], "int64": [3, 15], "threshold": [3, 4], "stream": [3, 4, 8, 11, 19, 21], "percentag": [3, 4], "total": [3, 4, 14, 26, 28, 31], "spill": [3, 4, 9, 26], "config": [3, 4, 30, 39, 40], "ll": [3, 16], "path": [3, 4, 11, 15, 16, 21, 26, 27, 28, 39, 40], "spilllowerr": [3, 4], "watermark": [3, 4], "spillupperr": [3, 4], "volumespec": 3, "corev1": 3, "pv": [3, 4], "volumeclaimspec": 3, "pvc": [3, 4], "env": [3, 4, 30], "envvar": 3, "pluginimag": [3, 4], "backupimag": [3, 4], "ghcr": [3, 4], "recoverimag": [3, 4], "daskrepartitionimag": [3, 4], "localassemblyimag": [3, 4], "distributedassemblyimag": [3, 4], "volum": [3, 4, 8, 39, 40], "pvcname": [3, 4], "mountpath": [3, 4, 40], "mount": [3, 4, 8], "seamlessli": [3, 11, 12, 13, 14, 15, 22, 29, 37, 41], "custom": [3, 4, 9, 17, 21, 22, 24, 28, 34, 40, 41], "resourc": [3, 4, 8, 9, 10, 22, 28, 38, 39, 40], "definit": [3, 9, 22, 26, 35], "similar": [3, 8, 20, 23], "present": [3, 8, 14, 28], "selector": [3, 4, 38, 40], "label": [3, 4, 8, 15, 17, 26, 31, 38, 39, 40], "your": [3, 4, 5, 8, 10, 11, 14, 16, 27, 30, 39, 40], "inject": [3, 14, 38], "request": [3, 4, 10, 26, 27, 28, 40], "cpu": [3, 4, 10], "besid": [3, 4], "some": [3, 4, 9, 16, 20, 22, 23, 26, 36, 38], "field": [3, 4, 24, 26, 28, 35], "cr": [3, 4, 40], "If": [3, 4, 5, 6, 7, 8, 10, 11, 17, 19, 26, 27, 28, 30, 38, 39, 40], "should": [3, 4, 8, 10, 11, 17, 22, 26, 28, 38], "demo": [3, 16, 40], "how": [3, 8, 11, 15, 16, 19, 22, 26, 28, 29, 30, 31, 35, 37, 38, 40, 41], "accord": [3, 21, 22], "previou": [3, 15, 38, 40], "step": [3, 6, 14, 15, 16, 24, 27, 31, 35, 38, 39], "bin": [3, 4, 6, 7, 27, 30, 39, 40], "sh": [3, 4, 39], "bash": [3, 4, 10, 27, 38, 40], "var": [3, 4, 10, 11, 27, 28, 33, 36, 40], "sock": [3, 4, 10, 11, 14, 16, 20, 23, 27, 28, 40], "do": [3, 4, 6, 7, 8, 9, 26, 28, 30, 38, 39], "sleep": [3, 4, 23, 38, 40], "done": [3, 4, 30, 39], "start": [3, 4, 8, 9, 19, 20, 21, 23, 31, 39, 40], "matchlabel": [3, 4, 38, 40], "templat": [3, 4, 16, 24, 26, 35, 38, 40], "python3": [3, 6, 8, 10, 11, 16, 30, 33, 36], "py": [3, 6, 7, 16, 27, 38], "job_nam": 3, "see": [3, 4, 6, 11, 14, 16, 20, 22, 24, 26, 28, 30, 31, 32, 38], "grok": [3, 4], "export": [3, 4, 6, 14, 16], "persistentvolumeclaimspec": 3, "persistentvolumespec": 3, "8": [3, 4, 11, 15, 16, 17, 27, 28, 30, 33, 36, 40], "80": [3, 4, 20], "here": [3, 4, 11, 15, 16, 17, 26, 28, 40], "show": [3, 4, 7, 30, 38], "l": [3, 16, 39, 40], "55664458f8": 3, "h4jzk": 3, "volumemount": [3, 4, 40], "usr": [3, 4, 6, 27, 30, 39], "wait": [3, 4, 8, 26, 27, 28, 38, 39, 40], "60": [3, 4, 28], "svc": [3, 4], "sync_crd": [3, 4], "stream_threshold": [3, 4], "etcd_cmd": [3, 4], "etcd_prefix": [3, 4, 28], "etcd_endpoint": [3, 4, 8, 27, 28], "vineyardd_uid": [3, 4], "7b0c2ec8": 3, "49f3": 3, "4f8f": 3, "9e5f": 3, "8576a4dc4321": 3, "vineyardd_nam": [3, 4], "vineyardd_namespac": [3, 4], "containerport": [3, 4], "protocol": [3, 4, 24], "emptydir": [3, 4], "number": [3, 4, 7, 26, 27, 28, 31], "want": [3, 4, 6, 27, 28, 38], "sure": [3, 26, 28, 39], "keep": 3, "1024mi": 3, "about": [3, 8, 9, 11, 14, 16, 23, 28, 30, 31, 40], "e2": [3, 39], "test": [3, 4, 6, 8, 9, 16, 23, 30, 31, 38, 39, 40], "inspir": [3, 4], "expos": [3, 8, 30], "panel": 3, "abstract": [3, 8, 11, 19, 22, 23], "global": [3, 4, 8, 15, 20, 22, 26, 27, 28, 31, 33, 36, 40], "repres": [3, 8, 9, 11, 22, 24, 26, 28, 31, 33, 36], "declar": [3, 35], "It": [3, 4, 5, 9, 14, 15, 16, 17, 19, 22, 26, 28, 35], "id": [3, 4, 6, 14, 17, 20, 22, 23, 26, 27, 28, 30, 35, 38, 39, 40], "signatur": [3, 20, 22, 26, 27, 28, 40], "typenam": [3, 4, 17, 20, 22, 24, 26, 27, 28, 33, 35, 36, 40], "300": 3, "o001bcbcea406acd0": 3, "s001bcbcea4069f60": 3, "globaldatafram": [3, 15, 26], "o001bcc19dbfc9c34": 3, "s001bcc19dbfc8d7a": 3, "instance_id": [3, 4, 20, 22, 26, 27, 28, 40], "hostnam": [3, 4, 28], "also": [3, 4, 5, 6, 11, 14, 15, 16, 20, 22, 24, 26, 27, 28, 31, 39, 40], "just": [3, 30, 31, 40], "o001bcbce202ab390": 3, "s001bcbce202aa6f6": 3, "worker2": [3, 38, 40], "o001bcbce21d273e4": 3, "s001bcbce21d269c2": 3, "worker": [3, 8, 14, 15, 16, 20, 28, 30, 31, 38, 39, 40], "o001bcbce24606f6a": 3, "s001bcbce246067fc": 3, "worker3": [3, 38, 40], "place": [3, 6, 8, 22, 28, 35], "close": [3, 26, 28, 38], "possibl": [3, 8, 26, 28, 31], "input": [3, 4, 8, 14, 16, 31, 35, 37, 41], "therebi": 3, "reduc": [3, 8, 22, 30], "framework": [3, 8, 9, 12, 17, 31, 36], "overal": [3, 22, 28, 35], "summar": 3, "node": [3, 4, 8, 13, 14, 16, 22, 26, 30, 38, 39, 40], "doe": [3, 4, 8, 10, 11, 26], "ani": [3, 4, 5, 7, 8, 9, 14, 16, 20, 22, 28, 30, 31, 39], "round": [3, 31], "robin": 3, "approach": [3, 19, 20, 29, 33, 36, 41], "ha": [3, 5, 6, 7, 8, 22, 23, 26, 28, 30, 35, 40], "second": [3, 4, 15, 26, 27, 28, 30, 33, 36, 40], "so": [3, 4, 8, 21, 26, 31, 39, 40], "assum": [3, 4, 20, 28, 36, 38], "chunk": [3, 8, 11, 15, 20, 22, 23, 26, 28], "lifecycl": [3, 28], "m": [3, 6, 7, 8, 10, 11, 14, 16, 27, 28, 30, 33, 36], "attempt": 3, "imagin": 3, "12": [3, 4, 16, 31, 38], "node1": 3, "node2": 3, "11": [3, 16, 30, 38, 40], "node3": 3, "replica1": 3, "replica2": 3, "4": [3, 11, 16, 17, 28, 30, 31, 32, 33, 36, 38], "7": [3, 11, 17, 28, 30, 31, 40], "replica3": 3, "alongsid": 3, "reli": [3, 14, 24], "inform": [3, 7, 8, 10, 11, 14, 19, 20, 22, 26, 28, 39], "below": [3, 5, 11, 14, 32, 39, 40], "clear": [3, 26, 28, 31, 35], "comprehens": [3, 7, 25, 29, 41], "than": [3, 4, 10, 26, 28, 30, 31], "concaten": [3, 15, 31], "job1": [3, 4, 40], "job2": [3, 4], "job3": 3, "schedulernam": [3, 40], "section": [3, 7, 8, 10, 15, 19, 20, 23, 30, 35, 38, 40], "begin": [3, 20, 26], "outlin": [3, 5], "earlier": 3, "Then": [3, 4, 6, 7, 20, 22, 31, 38], "proce": [3, 26, 40], "shown": [3, 7, 20, 21, 40], "hostpath": [3, 4, 40], "6f479d695b": 3, "698xb": 3, "3m16": 3, "7zrw6": 3, "o001c87014cf03c70": 3, "s001c87014cf03262": 3, "sequenc": [3, 8, 23, 26, 28], "o001c8729e49e06b8": 3, "s001c8729e49dfbb4": 3, "o001c87014ca81924": 3, "s001c87014ca80acc": 3, "o001c8729e4590626": 3, "s001c8729e458f47a": 3, "configmap": [3, 4, 39], "record": [3, 26, 30, 39], "pass": [3, 11, 17, 22, 26, 28], "nodenam": 3, "valuefrom": 3, "fieldref": 3, "fieldpath": 3, "notic": [3, 4, 21, 35, 39], "configmapref": 3, "envfrom": 3, "now": [3, 31, 35, 39, 40], "been": [3, 5, 6, 7, 8, 20, 26, 28, 40], "8m12": 3, "b5b58cbdc": 3, "4s7b2": 3, "6m24": 3, "cd5v2": 3, "n6zvm": 3, "abov": [3, 7, 8, 11, 14, 15, 20, 22, 28, 30, 31, 35, 38, 39, 40], "what": [3, 8, 9, 14, 22], "dig": 3, "happen": [3, 9, 32], "elegantli": 3, "primarili": [3, 39], "encompass": 3, "mainli": [3, 26], "built": [3, 4, 6, 7, 16, 17, 20, 23, 26, 28, 34, 35, 41], "target": [3, 4, 7, 11, 17, 22, 23, 26, 28, 31], "timeoutsecond": [3, 4], "timeout": [3, 4, 28, 39], "state": [3, 4, 9, 26, 31, 36], "bbf596bf4": 3, "985vc": 3, "brief": 3, "introduct": [3, 19], "activ": [3, 4, 14, 15, 27, 31], "temporari": [3, 27, 28, 36], "purpos": [3, 15], "note": [3, 4, 20, 26, 28, 40], "therefor": [3, 39], "passiv": 3, "exce": [3, 31], "capac": [3, 4], "surpass": 3, "excess": [3, 30], "reach": [3, 9, 26, 28], "persistentvolum": [3, 4, 8], "storageclassnam": [3, 4], "manual": [3, 4, 7], "1gi": [3, 4], "accessmod": [3, 4], "readwriteonc": [3, 4], "512mi": [3, 4, 28], "understand": [3, 11, 19, 20, 22, 35], "addition": [3, 8, 23], "valuabl": 3, "insight": 3, "effect": [3, 14, 15, 28, 36, 37, 40, 41], "world": [3, 11, 14, 28, 31, 33, 36], "scenario": [3, 8, 14, 15, 20, 33, 36], "seamless": [3, 7, 11, 13, 23, 34, 36, 37, 41], "convert": [3, 15, 26, 28, 31], "convers": [3, 36], "subsequ": [3, 8, 15, 20], "sever": [3, 4, 9, 21, 22, 39, 40], "assist": [3, 7, 8], "workload1": 3, "execut": [3, 4, 7, 12, 14, 15, 16, 17, 20, 30], "o001d1b280049b146": 3, "s001d1b280049a4d4": 3, "recordbatchstream": [3, 23, 28], "evid": [3, 22], "workload2": 3, "rememb": 3, "required_job_nam": 3, "remain": [3, 14], "pend": 3, "indic": [3, 7, 10, 26, 31, 39], "consequ": 3, "86c99c995f": 3, "nzns8": 3, "2m": 3, "646b78f494": 3, "cvz2w": 3, "53": [3, 30, 31, 40], "durat": [3, 16], "assembl": 3, "26": 3, "119": 3, "fzws7": 3, "5m55": 3, "4m": 3, "5m": 3, "podnam": 3, "o001d1b56f0ec01f8": 3, "s001d1b56f0ebf578": 3, "o001d1b5707c74e62": 3, "s001d1b5707c742e0": 3, "o001d1b571f47cfe2": 3, "s001d1b571f47c3c0": 3, "o001d1b5736a6fd6c": 3, "s001d1b5736a6f1cc": 3, "o001d1b574d9b94a": 3, "s001d1b574d9b8a9e": 3, "o001d1b5765629cbc": 3, "s001d1b57656290a8": 3, "o001d1b57809911c": 3, "s001d1b57809904e0": 3, "o001d1b5797a9f958": 3, "s001d1b5797a9ee82": 3, "o001d1b57add9581c": 3, "s001d1b57add94e62": 3, "o001d1b57c53875a": 3, "s001d1b57c5386a22": 3, "o001d1b57dc2c74e": 3, "s001d1b57dc2c6a4a": 3, "reschedul": 3, "9m55": 3, "8m": 3, "9m": 3, "further": [3, 9, 22, 28, 35, 39], "adjust": 3, "particularli": [3, 10], "accommod": [3, 34, 35, 36, 41], "redistribut": 3, "At": [3, 8, 26, 35], "helm": [3, 8, 9, 30, 40], "org": [3, 6, 14, 26], "main": [3, 4, 7, 16, 35, 39], "dockerfil": [3, 7], "tag": [3, 6, 14, 17, 30], "2022": [3, 9], "jupyt": 3, "repositori": [3, 7, 31, 39, 40], "vineyard_ipc_socket": [3, 4, 14, 16, 26, 28], "vineyard_rpc_socket": [3, 4], "my": [3, 4, 7], "8786": [3, 31], "dask_schedul": [3, 15, 31], "o001d2a6ae6c6e2e8": 3, "s001d2a6ae6c6d4f4": 3, "o001d2a6a6483ac44": 3, "s001d2a6a6483a3c": 3, "o001d2a6a64a29cf4": 3, "s001d2a6a64a28f2": 3, "o001d2a6a66709f20": 3, "s001d2a6a667092a2": 3, "o001d2a6ace0f6e30": 3, "s001d2a6ace0f65b8": 3, "finish": [3, 4, 23, 26, 31, 38], "5dbfc54997": 3, "7kghk": 3, "92": [3, 39], "cvrt2": 3, "49": 3, "5m43": 3, "4m30": 3, "79wcm": 3, "3m30": 3, "o001d2ab523e3fbd0": 3, "s001d2ab523e3f0e6": 3, "o001d2dc18d72a47": 3, "s001d2dc18d729ab6": 3, "whole": [3, 22], "directori": [3, 4, 6, 7, 16, 27, 28, 39], "describ": [3, 14, 22, 28, 40], "vineyarddnam": 3, "vineyarddnamespac": 3, "objectid": [3, 4, 11, 15, 20, 26, 28, 31, 40], "empti": [3, 20, 26, 28], "backuppath": 3, "restor": [3, 28, 31], "Its": 3, "backupnam": 3, "backupnamespac": 3, "dump": [3, 4, 13, 26, 28], "crash": [3, 7], "point": [3, 27, 28, 35], "relationship": 3, "recoveri": 3, "o000ef92379fd8850": 3, "o000ef9ea5189718d": 3, "o000ef9237a3a5432": 3, "o000ef9eb5d26ad5": 3, "o000ef97a8289973f": 3, "o000ef9ed586ef1d3": 3, "succe": [3, 26], "relev": [4, 7, 40], "sidecar": [4, 38, 39], "j": [4, 6, 7], "usag": [4, 7, 19, 26, 27, 28], "json": [4, 14, 26, 27, 28], "gen": [4, 39], "doc": [4, 6, 7, 14, 26, 40], "cmd": [4, 16], "readm": 4, "md": 4, "h": [4, 7, 26], "kubeconfig": [4, 16, 39], "home": [4, 30, 39], "kube": [4, 39, 40], "verbos": [4, 28, 31], "print": [4, 11, 14, 23, 27, 28, 31, 33, 36, 38, 39, 40], "log": [4, 27, 28, 30, 35, 38, 39], "v": [4, 6, 11, 15, 23, 26], "version": [4, 7, 8, 9, 25, 26, 28, 38, 40], "insert": [4, 23, 28, 35], "assembli": 4, "600": 4, "quickli": [4, 8], "specifi": [4, 7, 10, 14, 15, 26, 27, 28, 31, 35], "flag": [4, 8, 9], "limit": [4, 9, 10, 20, 26, 27, 28, 31], "1000": [4, 30], "instead": [4, 11, 26, 31, 40], "persistentvolumeclaim": 4, "repartit": [4, 8, 11], "dask": [4, 12, 20, 31], "deployvineyarddeploy": 4, "o000018d29207fd01": 4, "o000018d80d264010": 4, "alreadi": [4, 6, 7, 8, 26, 30], "instal": [4, 8, 14, 16, 27, 30, 38, 39, 40], "recommend": [4, 6, 7, 8, 10, 19, 30, 40], "becaus": [4, 28, 33], "error": [4, 10, 11, 26, 28], "old": 4, "ones": [4, 22, 33, 36], "left": 4, "column": [4, 11, 15, 16, 17, 23, 26, 27, 28, 31, 38], "right": 4, "stdin": 4, "v0": [4, 30, 40], "owner": [4, 14], "metic": 4, "reserve_memori": 4, "power": [4, 12, 27, 28], "equival": [4, 27, 28], "ei": [4, 27, 28], "pi": [4, 27, 28], "ti": [4, 27, 28], "gi": [4, 27, 28], "mi": [4, 27, 28], "ki": [4, 27, 28], "host": [4, 7, 8, 20, 26, 27, 28, 31, 39], "replac": [4, 31], "claim": [4, 26], "client": [4, 8, 9, 10, 11, 14, 20, 22, 27, 30, 31, 32, 33, 35, 36, 38, 40], "output": [4, 8, 11, 17, 31], "instanceid": [4, 26, 28], "forward": [4, 30, 31], "manifest": 4, "statefulset": 4, "time": [4, 8, 9, 20, 22, 23, 30, 36], "100000": [4, 14], "etcd_nod": 4, "null": 4, "ownerrefer": 4, "initi": [4, 8, 11, 15, 26, 28, 31, 35], "advertis": 4, "peer": 4, "url": 4, "listen": [4, 11, 27, 28, 33, 36], "restartpolici": 4, "alwai": [4, 8, 26], "targetport": 4, "creationtimestamp": 4, "introduc": [4, 9], "simpl": [4, 16, 17, 27], "nginx": 4, "14": [4, 6, 16, 28, 31, 40], "except": [4, 23, 26, 28, 31], "itself": [4, 20, 24], "remov": [4, 8, 28, 40], "unnecessari": 4, "access": [4, 8, 9, 11, 14, 19, 22, 26, 28, 30, 33, 35, 36, 40], "link": [4, 6, 22], "pkg": 4, "html": [4, 6, 7, 14, 26], "look": [4, 16, 28], "rpc_servic": 4, "etcd_servic": 4, "etcd_internal_servic": 4, "intern": [4, 8, 19, 26, 35], "etcd_pod": 4, "rather": [4, 26, 28], "final": [4, 7, 16, 23, 26, 28, 30, 31, 36, 39], "whether": [4, 7, 8, 26, 27, 28, 39], "injecti": 4, "pattern": [4, 20, 26, 27, 28], "regex": [4, 26, 27, 28], "127": [4, 8, 28], "prc": 4, "everi": [4, 9, 22, 26], "match": [4, 9, 26, 27, 28, 36], "maximum": [4, 26], "return": [4, 11, 14, 15, 16, 17, 20, 21, 23, 24, 26, 28, 31, 35, 36], "5": [4, 11, 16, 17, 26, 28, 30, 31, 40], "sort": 4, "p": [4, 15, 16, 27, 28, 30, 39], "against": [4, 26, 27, 28], "r": [4, 6, 16, 20, 21, 28, 36], "k": [4, 23, 26, 27, 28], "health": 4, "probe": 4, "bind": [4, 10, 27, 39], "endpoint": [4, 20, 26, 27, 28, 39], "8081": 4, "leader": [4, 39], "elect": [4, 39], "one": [4, 9, 17, 20, 23, 26, 27, 28, 31, 38, 39, 40], "8080": 4, "plugin": [4, 8, 9, 30, 39], "podaffin": 4, "especi": [4, 9], "globalobject": [4, 9, 39], "localobject": [4, 9, 39], "affin": 4, "requiredduringschedulingignoredduringexecut": 4, "labelselector": 4, "matchexpress": 4, "topologykei": 4, "web": 4, "podantiaffin": 4, "16": [4, 30, 38, 40], "open": [5, 6, 8, 9, 15, 21, 26, 28, 40], "sourc": [5, 9, 11, 12, 21, 26, 27, 28, 35], "wa": [5, 20, 33, 36], "accept": [5, 28], "april": [5, 9], "2021": [5, 9], "commit": 5, "engag": 5, "u": [5, 6, 7, 11, 40], "improv": [5, 7, 8, 9, 22, 29, 41], "find": [5, 6, 7, 8, 21, 26, 28, 39], "our": [5, 6, 7, 8, 9, 14, 16, 22, 30, 31, 35, 36], "welcom": [5, 7], "join": [5, 11, 23, 28, 39], "slack": 5, "channel": 5, "instruct": [5, 7, 19], "encount": [5, 7, 10, 11, 14, 23], "issu": [5, 7, 8, 9, 20, 22, 26, 27, 31], "journei": 5, "solut": [5, 14, 31, 37, 41], "troubleshoot": 5, "public": [5, 24, 26, 35], "roadmap": 5, "futur": [5, 40], "goal": 5, "highlight": 5, "ongo": 5, "packag": [6, 7, 9, 11, 14, 16, 17, 23, 40], "pip": [6, 7, 11, 38], "pip3": [6, 7, 11, 14, 16, 27], "submodul": 6, "init": [6, 31], "compil": [6, 8, 9, 15, 31], "softwar": [6, 7], "apach": [6, 7, 9, 13, 14], "arrow": [6, 7, 26, 35], "gflag": [6, 7], "glog": [6, 7], "boost": [6, 7], "mpi": 6, "librari": [6, 31, 36], "protobuf": [6, 7], "grpc": [6, 7], "And": [6, 31], "libclang": [6, 7], "20": [6, 15, 30], "04": 6, "apt": 6, "y": [6, 15], "ca": 6, "certif": [6, 39, 40], "cmake": [6, 7], "doxygen": [6, 7], "libboost": 6, "dev": [6, 7, 30], "libcurl4": 6, "openssl": 6, "libgflag": 6, "libgoogl": 6, "libgrpc": 6, "libmpich": 6, "libprotobuf": 6, "libssl": 6, "libunwind": [6, 9], "libz": 6, "wget": [6, 30], "jfrog": 6, "artifactori": 6, "lsb_releas": 6, "short": [6, 22], "tr": 6, "z": 6, "codenam": 6, "deb": 6, "tmp": [6, 10, 11, 14, 16, 20, 23, 27, 39], "libarrow": 6, "brew": [6, 7], "llvm": 6, "mpich": 6, "zlib": 6, "autoconf": 6, "out": [6, 7, 16, 31, 40], "accomplish": [6, 8], "cc": 6, "cxx": 6, "prefix": [6, 7, 28], "clang": [6, 7], "mkdir": [6, 7, 39], "nproc": [6, 7], "sudo": [6, 10, 11, 30], "binari": [6, 27, 28, 31], "static": [6, 26, 28, 35], "lib": [6, 36], "folder": 6, "bdist_wheel": 6, "latest_tag": 6, "curl": [6, 39], "jq": 6, "unam": 6, "upper": [6, 26], "lower": 6, "arch": [6, 7], "x86_64": 6, "amd64": [6, 30], "lo": 6, "chmod": [6, 30], "x": [6, 15, 30, 31, 40], "mv": [6, 30], "organ": [6, 14, 22], "sphinx": [6, 7], "txt": 6, "skip": [6, 30, 31], "continu": [6, 7, 23, 30], "ci": [6, 7], "cento": [6, 7, 9], "linux": [6, 7, 30], "team": 7, "research": 7, "warmli": 7, "enhanc": [7, 9, 13, 20, 22, 29, 35, 37, 41], "refin": [7, 9], "licens": 7, "17": [7, 30, 38], "parsec": 7, "streamlin": [7, 35], "platform": [7, 9, 12, 14], "ubuntu": 7, "maco": 7, "incorpor": [7, 13, 29, 41], "case": [7, 8, 10, 17, 20, 22, 23, 28, 29, 32, 36, 41], "vineyard_test": 7, "properli": 7, "etcd_distro": 7, "runner": [7, 16], "cpp": 7, "contrib": [7, 14, 15, 16, 17, 30, 31], "argument": [7, 10, 20, 26, 28], "messag": [7, 8, 16], "exit": [7, 26, 28, 36], "adaptor": 7, "ro": 7, "unittest": 7, "array_test": 7, "dataframe_test": 7, "navig": 7, "_build": 7, "most": [7, 21, 26], "visit": 7, "delv": 7, "adher": [7, 14], "syntax": 7, "convent": [7, 26], "markup": 7, "area": 7, "wish": 7, "feel": [7, 8], "free": [7, 8], "appreci": 7, "enthusiasm": 7, "util": [7, 8, 14, 15, 17, 22, 23, 26, 28, 29, 32, 39, 40, 41], "tracker": 7, "unexpect": 7, "behavior": [7, 26, 28], "search": [7, 25], "among": [7, 8, 14, 15, 16], "kindli": 7, "regard": 7, "problem": [7, 14], "greatli": [7, 9], "diagnos": 7, "fix": [7, 27, 28], "featur": [7, 9, 13, 15, 17, 19, 31, 39, 40], "guidelin": 7, "prevent": [7, 21, 26], "accident": 7, "inclus": 7, "secret": [7, 28, 30], "hook": [7, 14, 28], "dco": 7, "googl": 7, "style": [7, 27], "patch": [7, 9, 26, 28, 39], "makefil": 7, "vineyard_clformat": 7, "compli": 7, "cpplint": 7, "cmakefil": 7, "vineyard_cpplint": 7, "titl": 7, "bugfix": [7, 9], "bracket": 7, "1234": [7, 32], "vector": [7, 22, 26, 35, 39], "2345": [7, 38], "pytorch": [7, 26, 31, 39], "rebas": 7, "unless": 7, "merg": 7, "conflict": [7, 8, 28], "branch": 7, "top": [7, 12, 28, 34, 41], "recent": 7, "remot": [7, 8, 9, 14, 26, 27, 28, 38], "upstream": 7, "fetch": [7, 14, 20, 27, 28, 38], "mark": [7, 26, 28], "push": [7, 16, 26, 30, 39], "fork": [7, 23, 26], "forc": [7, 26, 27, 28], "manylinux1": 7, "reliabl": 7, "pypa": 7, "concis": 8, "answer": 8, "concern": 8, "post": 8, "multipl": [8, 14, 15, 20, 22, 26, 28, 29, 33, 36, 39, 41], "singl": [8, 10, 22, 28, 31], "vast": 8, "serv": [8, 9, 11, 12, 14, 23, 29, 35, 37, 39, 41], "parallel": [8, 14, 15, 31], "individu": [8, 14], "reader": [8, 21, 23, 26, 28, 39], "simultan": 8, "absolut": 8, "entiti": [8, 22], "safe": [8, 26], "concurr": [8, 9], "launch": [8, 10, 14, 15, 16, 20, 27, 28, 31, 33, 36], "simpli": [8, 11, 17, 40], "paramet": [8, 10, 16, 26, 27, 28, 35], "document": [8, 10, 14, 15, 16, 25], "necess": 8, "No": 8, "benefit": [8, 9, 16], "achiev": [8, 11, 14, 20, 26], "medium": [8, 16], "kafka": [8, 21], "small": [8, 22], "mini": 8, "batch": [8, 15, 17, 26, 28, 31, 39], "consecut": [8, 28], "train": [8, 29, 39, 41], "distinct": [8, 20], "tradit": 8, "still": [8, 16, 26, 28, 30], "normal": [8, 26, 28], "contrast": [8, 20], "would": [8, 9, 22, 26, 33, 36], "de": [8, 13, 16, 30, 31], "regardless": 8, "axi": [8, 15, 16, 17, 22, 26, 31], "decis": 8, "plan": [8, 9], "b": [8, 11, 14, 17, 20, 23, 32, 33, 36, 38], "h1": 8, "h2": 8, "h3": 8, "h4": 8, "o1": 8, "o2": 8, "respect": [8, 22, 26, 39], "b1": 8, "b2": 8, "sinc": [8, 26, 28, 31, 35], "situat": [8, 26, 35], "initcontain": 8, "although": 8, "priorit": 8, "whenev": 8, "24": [8, 39, 40], "highli": [8, 40], "why": 8, "try": [8, 14, 16, 23, 28, 30, 40], "again": 8, "aim": [9, 31], "cut": 9, "major": [9, 21, 26, 28], "year": 9, "minor": [9, 26, 28], "month": 9, "week": 9, "deliv": [9, 30], "hopefulli": 9, "later": [9, 14, 28, 33, 36], "aug": 9, "filesystem": 9, "view": [9, 22, 26, 39], "fashion": [9, 14, 26, 27, 28, 31], "Such": 9, "eas": [9, 19, 29, 35, 41], "realloc": [9, 26], "lineag": [9, 27], "mutat": [9, 39], "carefulli": 9, "transpar": [9, 14], "disk": [9, 15, 26], "thei": [9, 15, 21, 26, 30, 31], "too": [9, 10, 22, 26], "gpu": [9, 26], "devic": 9, "boarder": 9, "deep": [9, 15, 26, 27, 28], "gnn": 9, "juli": 9, "experiment": [9, 14, 15, 31, 40], "unseal": [9, 26], "unsaf": [9, 26, 28], "onlin": 9, "toler": [9, 28], "tne": 9, "june": 9, "better": [9, 30], "compat": [9, 26, 32], "archlinux": 9, "ld_library_path": 9, "backward": [9, 26], "third": 9, "parti": 9, "airflow": [9, 13], "homebrew": 9, "preliminari": 9, "expect": [9, 26, 31], "investig": 9, "opportun": [9, 14], "runtim": 9, "even": [9, 22, 26, 27, 28, 29, 30, 33, 36, 41], "mayb": 9, "csi": 9, "anoth": [9, 20, 23, 33, 36, 40], "robust": 9, "artifact": [9, 30, 39], "hub": 9, "chart": [9, 30, 40], "stabl": [9, 14, 26], "full": [9, 20], "far": 9, "ecosystem": [9, 11, 34, 41], "take": [9, 16, 20, 28, 31, 35], "half": 9, "sink": [9, 11, 12], "numpi": [9, 11, 14, 20, 23, 28, 33, 36, 38, 40], "basic": [9, 20, 22, 38], "daemonset": [9, 28], "prototyp": [9, 31], "brought": [9, 16], "criterion": 9, "friendli": 9, "pypi": 9, "dockerhub": 9, "guidanc": [10, 39], "aris": 10, "improp": 10, "send": [10, 20, 26], "etcdserv": 10, "txn": [10, 39], "correctli": 10, "transact": [10, 39], "startup": 10, "max": [10, 26], "op": 10, "102400": 10, "permiss": [10, 11, 39, 40], "deni": [10, 11], "root": [10, 11, 16, 22, 26], "either": [10, 11, 26, 36], "Or": [10, 11], "degrad": 10, "cgroup": 10, "tune": [10, 35], "hardwar": 10, "incom": 11, "stop": [11, 26], "press": [11, 27], "ctrl": 11, "termin": [11, 31, 40], "writabl": 11, "interoper": 11, "former": [11, 23], "latter": [11, 23], "ndarrai": [11, 28, 36], "arr": [11, 15, 17, 28], "object_id": [11, 26, 27, 28, 31], "uniqu": [11, 22, 26, 28], "given": [11, 16, 26, 28], "np": [11, 14, 15, 16, 17, 20, 23, 28, 33, 36, 38, 40], "random": [11, 14, 17, 20, 23, 27, 28, 31, 38], "rand": [11, 14, 17, 20], "o0015c78883eddf1c": 11, "shared_arrai": 11, "39736989": 11, "38047846": 11, "01948815": 11, "38332264": 11, "61671189": 11, "48903213": 11, "03875045": 11, "5873005": 11, "nest": [11, 28, 36], "df": [11, 15, 17, 20], "pd": [11, 14, 15, 16, 17, 20, 23, 31, 38], "weight": [11, 31], "shared_datafram": 11, "hood": 11, "multiprocess": [11, 28, 29, 41], "mp": 11, "def": [11, 14, 15, 16, 21, 23, 28, 31, 36], "randn": [11, 38], "100": [11, 22, 23, 30, 31, 38], "abcd": [11, 38], "sum": [11, 14, 16, 30, 38], "__name__": [11, 23], "__main__": [11, 23], "dataset": [11, 13, 15, 16, 17, 22, 29, 30, 31, 39, 41], "arg": [11, 21, 23, 26, 28], "529080": 11, "969152": 11, "067356": 11, "d": [11, 15, 31, 38], "003676": 11, "dtype": [11, 15, 22, 23, 31, 35, 36, 38], "float64": [11, 15, 20, 38, 40], "beyond": 11, "over": [11, 20, 23, 26, 28], "idl": 11, "glue": 11, "architectur": [11, 19, 20], "overview": 11, "concept": [11, 20, 22, 26], "vcdl": [11, 19, 24], "discov": [11, 29, 41], "natur": [11, 14, 22], "varieti": 12, "kedro": [13, 29, 41], "empow": 13, "cumbersom": 13, "pickl": [13, 14, 16, 28, 30], "xcom": [13, 14], "compar": [13, 26, 30], "altern": [13, 16, 29, 41], "aw": [13, 16, 30], "s3": [13, 14, 16], "minio": [13, 16, 30], "intrus": [13, 16, 29, 30, 41], "experi": [13, 29, 31, 41], "allevi": [14, 24], "programmat": 14, "author": [14, 39], "monitor": 14, "direct": [14, 17, 26, 28, 35], "acycl": 14, "dag": 14, "etl": 14, "schedule_interv": 14, "start_dat": 14, "days_ago": 14, "tutorial_taskflow_api_etl": 14, "extract": [14, 31, 35], "data_str": 14, "1001": 14, "301": 14, "27": 14, "1002": 14, "433": 14, "21": 14, "1003": 14, "502": 14, "22": [14, 30], "order_data_dict": 14, "multiple_output": 14, "dict": [14, 16, 17, 23, 26, 28], "total_order_valu": 14, "float": [14, 15, 22, 23, 26, 28], "2f": 14, "order_data": 14, "order_summari": 14, "tutorial_etl_dag": 14, "form": [14, 17, 22, 33, 36, 40], "sequenti": [14, 15], "excel": 14, "sqlite": 14, "mysql": 14, "postgresql": 14, "hdf": 14, "class": [14, 17, 24, 26, 28, 31, 32, 35], "vineyardxcom": 14, "basexcom": 14, "staticmethod": 14, "serialize_valu": 14, "deserialize_valu": 14, "underli": [14, 20, 26, 28], "celeryexecutor": 14, "might": [14, 16, 28], "necessit": 14, "action": [14, 26], "readili": [14, 40], "scientist": 14, "focu": 14, "logic": [14, 21, 22], "easier": [14, 16], "airflow__core__xcom_backend": 14, "airflow__vineyard__ipc_socket": 14, "decor": 14, "default_arg": 14, "taskflow_etl_panda": 14, "taskflow_etl_pandas_dag": 14, "deal": [14, 39], "taskflow": 14, "stage": 14, "potenti": 14, "flexibli": [14, 22], "believ": 14, "tutorial_taskflow_api": 14, "arrai": [15, 17, 24, 26, 28, 33, 35, 36], "showcas": [15, 39], "blog": 15, "tf_config": 15, "mnist": 15, "duplic": [15, 26], "simul": 15, "builder_context": [15, 28, 31], "dask_context": 15, "dask_preprocess": 15, "get_mnist": 15, "x_train": [15, 16], "y_train": [15, 16], "_": [15, 31], "tf": [15, 17, 31], "kera": 15, "load_data": 15, "uint8": 15, "255": 15, "rang": [15, 23, 31], "astyp": [15, 17, 23], "delai": 15, "dd": [15, 31], "from_delai": 15, "gdf": 15, "concat": [15, 31], "gdf_id": [15, 31], "ml": [15, 17, 31, 37, 41], "register_tf_typ": [15, 31], "resolver_context": [15, 28, 31, 36], "mnist_dataset": 15, "batch_siz": [15, 17, 31], "train_dataset": [15, 31], "repeat": 15, "experimental_distribut": 15, "auto_shard_polici": 15, "autoshardpolici": 15, "off": 15, "train_datasets_no_auto_shard": 15, "with_opt": 15, "build_and_compile_cnn_model": 15, "layer": [15, 31], "inputlay": 15, "input_shap": 15, "28": [15, 30, 33, 36], "reshap": 15, "target_shap": 15, "conv2d": 15, "32": [15, 31], "relu": [15, 31], "flatten": 15, "dens": [15, 31], "loss": [15, 31], "sparsecategoricalcrossentropi": [15, 31], "from_logit": 15, "sgd": 15, "learning_r": [15, 31], "001": [15, 31], "accuraci": [15, 31], "per_worker_batch_s": 15, "64": [15, 26, 28, 30, 40], "multiworkermirroredstrategi": 15, "scope": 15, "multi_worker_model": 15, "epoch": [15, 31], "steps_per_epoch": 15, "70": 15, "were": 15, "pre": 15, "downstream": 15, "advantag": [15, 22, 34, 41], "recomput": 15, "repeatedli": 15, "tf_flower": 15, "resnet50": 15, "400": [15, 22], "slot": 15, "get_imag": 15, "idx": [15, 23, 26, 31], "num": 15, "flower_photo": 15, "rglob": 15, "jpg": 15, "rb": 15, "img": 15, "bytesio": 15, "resiz": 15, "224": 15, "preprocess_input": 15, "img_to_arrai": 15, "append": [15, 23, 28, 31], "block_id": 15, "include_top": 15, "pred": 15, "predict": [15, 31], "stack": 15, "100352": 15, "da": 15, "shape": [15, 17, 22, 26, 31], "244": [15, 38], "map_block": 15, "drop_axi": 15, "global_tensor_id": 15, "18": 16, "tell": [16, 28], "prepar": [16, 26, 39, 40], "iri": 16, "starter": 16, "split_data": 16, "str": [16, 28], "tupl": [16, 26, 28], "seri": 16, "data_train": 16, "frac": 16, "train_fract": 16, "random_st": 16, "data_test": 16, "drop": [16, 17, 26, 28], "target_column": 16, "x_test": 16, "y_test": 16, "make_predict": 16, "x_train_numpi": 16, "to_numpi": [16, 31], "x_test_numpi": 16, "squared_dist": 16, "nearest_neighbour": 16, "argmin": 16, "y_pred": 16, "iloc": 16, "05": 16, "25": [16, 30, 38], "23": [16, 30], "38": [16, 40], "56": [16, 32], "info": [16, 35, 38, 39, 40], "session": [16, 26], "355": 16, "57": 16, "example_iris_data": 16, "csvdataset": 16, "data_catalog": 16, "343": 16, "memorydataset": 16, "split": [16, 22, 28], "329": 16, "382": 16, "sequential_runn": 16, "85": 16, "argo": 16, "those": [16, 20, 22, 26, 28, 30, 32], "csv": [16, 27, 28, 39], "filepath": 16, "02_intermedi": 16, "credenti": [16, 30], "ineffici": 16, "larger": [16, 22], "sequentialrunn": 16, "45": [16, 40], "34": 16, "vineyarddataset": 16, "modif": [16, 28, 29, 31, 35, 41], "longer": 16, "suffer": 16, "catalog": 16, "interfac": [16, 32], "rewrit": 16, "unspecifi": 16, "__default__": 16, "ds_name": 16, "argoproj": [16, 30], "v3": [16, 30], "walk": [16, 31], "minikub": [16, 30], "grep": [16, 30, 39], "3c92da8241c6": 16, "minut": 16, "ago": [16, 30], "690mb": 16, "yml": [16, 30], "rw": 16, "3685": 16, "jun": 16, "55": 16, "submit": [16, 30], "prioriti": 16, "sg6qf": 16, "succeed": [16, 26], "18m": 16, "30": [16, 38], "benchmark": [16, 30], "evalu": [16, 31], "gain": 16, "report": [16, 28], "from_tensor_slic": 17, "data_id": 17, "vineyard_cli": [17, 23, 28], "vin_data": 17, "6": [17, 28, 30, 31, 38, 40], "pop": 17, "bridg": 17, "dictionari": [17, 31], "pa": [17, 28, 36], "from_arrai": [17, 28], "f0": 17, "f1": 17, "row": [17, 22, 26, 27], "from_batch": 17, "inherit": [17, 35], "torch": 17, "customdataset": 17, "tensordataset": 17, "float32": [17, 31], "col": 17, "f2": 17, "gluon": 17, "mx": 17, "arraydataset": 17, "dmatrix": [17, 28, 36], "vin_tensor_id": 17, "vin_df_id": 17, "feature_nam": [17, 31], "sometim": 17, "kwarg": [17, 21, 28], "vin_rb_id": 17, "vin_tab_id": 17, "pipeline_def": 17, "pipe": [17, 23], "device_id": 17, "num_thread": 17, "pipe_out": 17, "vin_pip": 17, "tensorlist": 17, "depth": 19, "cover": [19, 31], "soon": 19, "smoother": 19, "builtin": 19, "depict": 20, "explain": [20, 22], "consider": 20, "globaltensor": [20, 26], "perspect": 20, "pictur": 20, "aggreg": [20, 23], "suit": [20, 25, 40], "commonli": [20, 22], "spark": 20, "presto": 20, "rai": 20, "vineyard_ipc_cli": 20, "o00053008257020f8": 20, "_c": [20, 40], "534487": 20, "261941": 20, "901056": 20, "441583": 20, "687568": 20, "671564": 20, "raw": [20, 39], "get_meta": [20, 28, 40], "objectmeta": [20, 26, 28, 35, 36], "meta": [20, 22, 26, 27, 28, 35, 36, 40], "nbyte": [20, 22, 26, 27, 28, 36, 40], "1460186430481176": 20, "transient": [20, 28, 40], "__values_": [20, 22], "o0005300822f54d1c": 20, "order_": [20, 40], "shape_": [20, 22, 40], "1460186388165810": 20, "doubl": [20, 22, 40], "value_type_": [20, 22, 40], "value_type_meta_": [20, 40], "f8": [20, 40], "buffer_": [20, 22, 24, 36, 40], "o8005300822d858df": 20, "create_blob": [20, 28], "blobbuild": [20, 28], "fill": [20, 26, 28], "get_blob": [20, 28], "mock": 20, "abcdefgh1234567890uvwxyz": 20, "buffer_build": [20, 35, 36], "len": [20, 26, 28, 31, 36], "o800532e4ab1f2087": 20, "byte": [20, 26, 27, 28], "memoryview": [20, 28], "facilit": [20, 22, 23, 25], "associ": [20, 23, 26, 28, 35], "vineyard_rpc_cli": [20, 28], "localhost": [20, 30, 31, 39], "absenc": 20, "feasibl": 20, "explicitli": [20, 22, 26, 28], "create_remote_blob": [20, 28], "remoteblobbuild": [20, 28], "get_remote_blob": [20, 28], "remoteblob": [20, 26, 28], "impli": [20, 22, 28], "remote_buffer_build": 20, "remote_blob_id": 20, "remote_blob": [20, 26], "0x142204870": 20, "subtl": 20, "buffer": [20, 26, 28, 33, 35, 36], "fly": 20, "head": [21, 40], "scheme": [21, 28], "actual": [21, 22, 28], "topic": 21, "dispatch": 21, "registr": 21, "register": 21, "urlpars": 21, "_factori": 21, "rais": [21, 26, 28], "runtimeerror": [21, 28], "unabl": 21, "proper": [21, 28], "local_driv": 21, "importantli": 21, "revis": [21, 40], "fulfil": 21, "compris": [22, 36], "collect": [22, 26, 34, 41], "hierarch": [22, 26, 33, 36], "tree": [22, 26, 27], "idea": [22, 38], "pointer": [22, 26, 28], "length": [22, 28, 35, 36, 40], "column_s": 22, "conform": 22, "simpler": 22, "semant": [22, 26, 32], "o800527ecdf05cff9": 22, "39": [22, 40], "o000527ecdffd95c4": 22, "partition_index_": [22, 40], "1451273207424436": 22, "o800527ecdeaf1015": 22, "o000527ece12e4f0a": 22, "800": 22, "1451273227452968": 22, "columns_": 22, "o000527ece15d374c": 22, "1200": [22, 39], "partition_index_column_": 22, "partition_index_row_": 22, "row_batch_index_": 22, "1451273231074538": 22, "sub": [22, 24, 40], "mere": 22, "piec": 22, "meaning": 22, "interpret": 22, "significantli": [22, 30], "self": [22, 26, 28], "exploit": 22, "amount": [22, 35], "composit": 22, "recurs": [22, 27, 28], "travers": [22, 28], "construct": [22, 26, 28, 35, 36], "behind": [22, 28], "shard": 22, "replic": 22, "billion": 22, "subset": 22, "todo": 22, "subsect": 22, "costli": 22, "burden": [22, 24], "categor": [22, 31], "known": [22, 24], "live": 22, "immedi": [22, 26, 28], "progress": 22, "visibl": [22, 26, 28, 32, 33, 36, 40], "paradigm": 22, "notabl": 22, "permit": 22, "plug": 22, "scan": 23, "filter": 23, "thread": 23, "recordbatch": [23, 26, 28], "generate_random_datafram": 23, "item": [23, 38, 39], "total_chunk": 23, "writer": [23, 26, 28], "randint": 23, "chunk_id": 23, "loop": 23, "stopiter": 23, "assert_frame_equ": 23, "break": 23, "test_recordbatch_stream": 23, "client1": [23, 33, 36], "client2": [23, 33, 36], "stream1": 23, "stream2": 23, "thread1": 23, "thread2": 23, "fundament": 24, "auto": [24, 35], "const": [24, 26, 35], "size_t": [24, 26, 35], "loc": [24, 26, 31], "size_": 24, "reinterpret_cast": [24, 35], "privat": [24, 35], "std": [24, 26, 35], "shared_ptr": [24, 26, 35], "synthes": 24, "treat": [24, 26, 28], "deem": 24, "ffi": 24, "wrapper": [24, 28], "ctl": [25, 27, 30], "debug": [25, 26, 28], "site": 25, "uint64_t": 26, "opaqu": [26, 28], "bit": [26, 28], "unsign": [26, 28], "integ": [26, 27, 28, 31], "objectbas": 26, "enable_shared_from_thi": 26, "scalar": 26, "subclass": 26, "arrowfragmentgroup": 26, "basebinaryarrai": 26, "arraytyp": 26, "baselistarrai": 26, "booleanarrai": 26, "fixedsizebinaryarrai": 26, "fixedsizelistarrai": 26, "hashmap": [26, 35], "prime_number_hash_wi": 26, "equal_to": 26, "hdatafram": 26, "nullarrai": 26, "numericarrai": [26, 36], "parallelstream": 26, "perfecthashmap": 26, "schemaproxi": 26, "arrowfragmentbas": 26, "itensor": 26, "virtual": [26, 35], "void": [26, 35], "come": 26, "getmetadata": 26, "inlin": 26, "postconstruct": 26, "noth": 26, "though": [26, 33, 36], "_seal": [26, 35], "clientbas": [26, 28], "isloc": [26, 28], "verb": [26, 39], "otherwis": [26, 28], "iff": 26, "ispersist": [26, 28], "isglob": [26, 28], "protect": 26, "attribut": [26, 28], "id_": [26, 35], "mutabl": [26, 28], "meta_": [26, 35], "friend": [26, 35], "plasmacli": 26, "rpcclient": [26, 28], "objectbuild": [26, 28], "collectionbuild": 26, "arrowfragmentgroupbuild": 26, "blobwrit": [26, 35], "booleanarraybasebuild": 26, "dataframebasebuild": 26, "fixedsizebinaryarraybasebuild": 26, "fixedsizelistarraybasebuild": 26, "nullarraybasebuild": 26, "parallelstreambasebuild": 26, "recordbatchbasebuild": 26, "schemaproxybasebuild": 26, "sequencebasebuild": 26, "tensorbasebuild": 26, "overrid": [26, 35], "set_seal": 26, "abl": 26, "readonli": [26, 28], "const_iter": 26, "nlohmann": 26, "iteration_proxy_valu": 26, "setclient": 26, "getclient": 26, "setid": 26, "getid": 26, "getsignatur": 26, "resetsignatur": 26, "reset": [26, 28], "setglob": 26, "settypenam": [26, 35], "type_nam": [26, 35], "objectfactori": 26, "gettypenam": 26, "setnbyt": [26, 35], "getnbyt": 26, "reflect": 26, "monopolist": 26, "bulk": [26, 33, 36], "getinstanceid": 26, "forceloc": 26, "haskei": 26, "resetkei": 26, "addkeyvalu": [26, 35], "unordered_map": 26, "unorderedmap": 26, "getkeyvalu": [26, 35], "deduct": 26, "addmemb": [26, 35], "member_id": 26, "getmemb": [26, 35], "getmembermeta": 26, "getbuff": 26, "blob_id": [26, 28, 33, 36], "indirect": 26, "setbuff": 26, "memoryusag": 26, "pretti": 26, "timestamp": [26, 28], "millisecond": 26, "insid": [26, 28], "unknown": 26, "tostr": 26, "printmeta": 26, "incomplet": 26, "mutmetadata": 26, "setmetadata": 26, "bufferset": 26, "getbufferset": 26, "unique_ptr": [26, 35], "nobject": 26, "uintptr_t": 26, "stuff": 26, "leav": [26, 39], "copyabl": 26, "basicipccli": 26, "delet": [26, 27, 28, 39, 40], "getdata": 26, "sync_remot": [26, 28], "block": [26, 28], "createdata": 26, "createmetadata": [26, 35], "meta_data": 26, "placehold": 26, "sync": 26, "syncmetadata": 26, "deldata": 26, "yield": [26, 28], "listdata": 26, "meta_tre": 26, "regular": 26, "express": [26, 27, 28], "glob": 26, "listnam": 26, "createstream": 26, "openstream": 26, "streamopenmod": 26, "mode": [26, 27, 28], "fail": [26, 28, 39], "pushnextstreamchunk": 26, "kstreamdrain": 26, "kstreamfinish": 26, "poll": 26, "pullnextstreamchunk": 26, "stopstream": 26, "abort": [26, 28], "dropstream": 26, "yet": [26, 28], "ifpersist": 26, "shallowcopi": 26, "target_id": 26, "shallow": [26, 27, 28], "extra_metadata": [26, 28], "feed": [26, 31], "putnam": 26, "assoici": 26, "getnam": 26, "queri": [26, 28], "dropnam": 26, "deregist": 26, "kept": 26, "won": [26, 28], "migrateobject": 26, "result_id": 26, "evict": 26, "pin": 26, "being": [26, 32], "reload": 26, "possibli": 26, "unpin": 26, "aliv": [26, 27, 28], "disconnect": 26, "ipc_socket": [26, 27, 28, 35, 36], "anonym": 26, "closesess": 26, "ipcsocket": 26, "rpcendpoint": 26, "remote_instance_id": [26, 28], "sessionid": 26, "session_id": 26, "clusterinfo": 26, "instancestatu": [26, 28], "struct": [26, 28], "semver": [26, 28], "sent": [26, 27, 28], "handler": [26, 27, 28], "dowrit": 26, "message_out": 26, "doread": 26, "message_in": 26, "connected_": 26, "ipc_socket_": 26, "rpc_endpoint_": 26, "vineyard_conn_": 26, "session_id_": 26, "instance_id_": 26, "server_version_": 26, "recursive_mutex": 26, "client_mutex_": 26, "usagetrack": 26, "talk": 26, "usernam": [26, 28], "password": [26, 28], "fetchandgetmetadata": 26, "createblob": [26, 35], "getblob": 26, "bypass": 26, "creatediskblob": 26, "filenam": 26, "smaller": 26, "enlarg": 26, "ftruncat": 26, "getnextstreamchunk": 26, "mutablebuff": 26, "satisfi": 26, "accumul": [26, 28], "getobject": [26, 35], "constructor": [26, 35], "cast": 26, "concret": 26, "runtime_error": 26, "fetchandgetobject": 26, "throw": 26, "dynamic_cast": 26, "deduc": 26, "int_arrai": 26, "listobjectmeta": 26, "nobuff": [26, 28], "listobject": 26, "issharedmemori": 26, "belong": [26, 28], "region": [26, 28, 30], "side": [26, 28, 36], "isinus": 26, "is_in_us": 26, "cold": 26, "isspil": 26, "is_spil": 26, "allocateds": 26, "createarena": 26, "fd": 26, "available_s": 26, "releasearena": 26, "offset": [26, 28, 36], "source_cli": 26, "select": [26, 28], "plasmaid": 26, "plasma_id": 26, "decreas": 26, "count": 26, "onreleas": 26, "creategpubuff": 26, "gpuunifiedaddress": 26, "gua": 26, "getgpubuff": 26, "cudaipcmemhandl": 26, "releaserequest": 26, "ondelet": 26, "postseal": 26, "getdepend": 26, "bid": 26, "createbuff": 26, "special": 26, "getbuffers": 26, "dropbuff": 26, "deleteobject": 26, "shrinkbuff": 26, "shrink": [26, 28], "shouldn": 26, "madvis": 26, "vineyard_rpc_endpoint": [26, 28], "rpc_endpoint": [26, 27, 28], "tpc": 26, "uint32_t": 26, "unaccess": 26, "createremoteblob": 26, "remoteblobwrit": 26, "getremoteblob": 26, "expens": 26, "explicit": 26, "memory_usag": [26, 27, 28], "memory_limit": [26, 27, 28], "deferred_request": [26, 27, 28], "defer": 26, "queue": 26, "ipc_connect": [26, 27, 28], "rpc_connect": [26, 27, 28], "unit": [26, 31, 33, 36, 38], "allocated_s": [26, 28], "char": [26, 28, 35], "arrowbuff": 26, "bufferorempti": 26, "valid": [26, 39], "arrowbufferorempti": 26, "makeempti": 26, "fromalloc": 26, "estim": 26, "frompoint": 26, "content": [26, 28], "bytestream": [26, 28], "bareregist": 26, "setbuffersizelimit": 26, "writebyt": 26, "ptr": [26, 28], "writelin": 26, "flushbuff": 26, "readlin": 26, "element": [26, 28, 33, 35, 36], "arraybuild": 26, "arraybasebuild": 26, "vec": [26, 35], "give": 26, "noexcept": 26, "hash": [26, 28], "keyhash": 26, "keyequ": 26, "ska": 26, "detailv3": 26, "sherwood_v3_entri": 26, "entrypoint": 26, "hasher": 26, "keyorvaluehash": 26, "equal": 26, "keyorvalueequ": 26, "value_typ": [26, 36], "size_typ": 26, "difference_typ": 26, "ptrdiff_t": 26, "key_equ": 26, "const_refer": 26, "const_point": 26, "flat_hash_table_typ": 26, "sherwood_v3_t": 26, "allocator_trait": 26, "rebind_alloc": 26, "bucket_count": 26, "cell": 26, "load_factor": 26, "factor": 26, "lh": 26, "rh": 26, "hashmapbuild": 26, "hashmapbasebuild": 26, "flat_hash_map": 26, "emplac": [26, 28], "cbegin": 26, "cend": 26, "associatedatabuff": 26, "data_buff": 26, "value_t": 26, "value_pointer_t": 26, "value_const_pointer_t": 26, "arrowtensort": 26, "arrowtensortyp": 26, "int64_t": 26, "stride": 26, "tensor_attribut": 26, "ith": 26, "partition_index": 26, "anytyp": 26, "auxiliary_buff": 26, "arrowtensor": 26, "origin": [26, 30, 35], "tensorbuild": 26, "itensorbuild": 26, "set_shap": 26, "set_partition_index": 26, "conncet": 26, "asbatch": 26, "dataframebuild": 26, "partition_index_row": 26, "partition_index_column": 26, "set_row_batch_index": 26, "row_batch_index": 26, "set_index": 26, "addcolumn": 26, "dropcolumn": 26, "bidirectional_iterator_tag": 26, "last": [26, 28, 31, 40], "sequencebuild": 26, "setsiz": 26, "setvalu": 26, "scalarbuild": 26, "scalarbasebuild": 26, "holder": [26, 28], "partition_shap": 26, "localpartit": 26, "globaltensorbuild": 26, "set_partition_shap": 26, "addpartit": 26, "partition_id": 26, "partition_shape_row": 26, "partition_shape_column": 26, "globaldataframebuild": 26, "number_of_partitions_on_row": 26, "number_of_partitions_on_column": 26, "rpc_host": 27, "rpc_port": 27, "pick": 27, "stdout": 27, "output_fil": 27, "memory_statu": 27, "00002ec13bc81226": [27, 28], "regex_pattern": 27, "deepli": [27, 28], "sep": 27, "delimit": 27, "header": [27, 31], "example_csv_fil": 27, "edit": [27, 39], "ipc_socket_valu": 27, "enter": [27, 30, 39, 40], "rpc_host_valu": 27, "rpc_port_valu": 27, "rpc_endpoint_valu": 27, "instance_statu": 27, "memory_s": 27, "vineyardd_path": [27, 28], "bundl": [27, 28], "plain": [27, 28], "suffix": [27, 28], "rpc_socket_port": [27, 28], "privod": [27, 28], "shell": [27, 40], "argcomplet": 27, "eval": 27, "bashrc": 27, "profil": 27, "That": 27, "good": [27, 38], "sta": 27, "tab": 27, "000043c5c6d5e646": 28, "repr": 28, "74516723525190": 28, "__eq__": 28, "__hash__": 28, "__init__": 28, "__repr__": 28, "__str__": 28, "word": 28, "seen": 28, "__getitem__": 28, "hashmap_id": 28, "0000347aebe92dd0": 28, "num_elements_": 28, "num_slots_minus_one_": 28, "max_lookups_": 28, "entries_": 28, "__contains__": 28, "global_": 28, "__setitem__": 28, "add_memb": [28, 36], "get_memb": 28, "set_glob": 28, "standalon": 28, "overload": 28, "ipcclient": 28, "login": 28, "tri": 28, "connectionfail": 28, "rare": 28, "resolut": [28, 36], "create_empty_blob": 28, "create_metadata": [28, 36], "forcedli": 28, "object_meta": 28, "drop_nam": 28, "objectnam": 28, "find_shared_memori": 28, "resolvercontext": 28, "kw": 28, "arr_id": 28, "ignor": [28, 31], "context": [28, 36, 39, 40], "code_remot": 28, "get_nam": [28, 38], "appear": [28, 35], "get_object": [28, 33, 36], "is_shared_memori": 28, "list_metadata": 28, "wildcard": 28, "list_nam": 28, "list_object": 28, "hostid": 28, "54058007061210": 28, "6882550126788354072": 28, "15": [28, 31], "48843417291806": 28, "6882568290204737414": 28, "buildercontext": 28, "arang": 28, "decid": 28, "put_nam": 28, "alia": [28, 30], "shallow_copi": 28, "primit": 28, "sync_meta": 28, "blob_build": 28, "signif": 28, "vineyard_endpoint": 28, "buffer_writ": 28, "ident": 28, "statist": 28, "360": 28, "268435456": 28, "is_empti": 28, "writeabl": 28, "th": 28, "parent_context": 28, "get_current_resolv": 28, "callabl": 28, "popul": [28, 35], "outsid": 28, "xgboost": [28, 36], "numpy_resolv": [28, 36], "obj": [28, 36], "default_resolver_context": [28, 36], "xgboost_resolv": [28, 36], "obvious": 28, "stackabl": [28, 36], "nestabl": 28, "driver_context": 28, "type_id": 28, "translat": 28, "mro": 28, "chain": 28, "get_current_build": 28, "drivercontext": 28, "get_current_driv": 28, "popult": 28, "shared_memori": [28, 29, 41], "sharedmemori": [28, 29, 32, 41], "buf": 28, "freez": [28, 32], "unlink": 28, "destroi": [28, 40], "shareablelist": [28, 32], "shareabl": 28, "pack": 28, "storabl": 28, "charact": 28, "slightli": [28, 32], "get_current_socket": 28, "try_init": 28, "valueerror": 28, "start_vineyardd": 28, "popen": [28, 31], "redi": 28, "roughli": 28, "128974848": 28, "129k": 28, "129m": 28, "123mi": 28, "1g": 28, "10gi": 28, "subprocess": [28, 31], "proc": 28, "vineyard_imag": 28, "vineyard_image_pull_polici": 28, "vineyard_image_pull_secret": 28, "k8s_client": 28, "apicli": 28, "delete_kubernetes_object": 28, "timeout_second": 28, "chunk_hook": 28, "w": 28, "orc": 28, "parquet": 28, "pyarrow": [28, 36], "stateless": 28, "guarante": 28, "exchange_column": 28, "schema": 28, "frame": [28, 34, 41], "discoveri": 28, "param": 28, "dataframestream": 28, "studi": [29, 41], "intuit": [29, 41], "eleg": [29, 41], "mlop": 30, "multi": [30, 31], "v1alpha4": [30, 40], "plane": [30, 39, 40], "kindest": [30, 39, 40], "7698c96655": 30, "jg2d": 30, "b888f4458": 30, "x4qf2": 30, "8g": 30, "8gi": 30, "less": [30, 31], "jump": 30, "minioadmin": 30, "bucket": 30, "s3api": 30, "9000": 30, "dl": 30, "min": 30, "mc": 30, "mb": 30, "conf": 30, "benchmark_aws_s3": 30, "client_kwarg": 30, "aws_access_key_id": 30, "aws_secret_access_kei": 30, "region_nam": 30, "fceaeb5a6688": 30, "07gb": 30, "multipli": 30, "500": 30, "watch": [30, 39], "similarli": [30, 31], "liter": 30, "access_key_id": 30, "secret_access_kei": 30, "2000": 30, "cloudpickl": 30, "calcul": 30, "13": [30, 31], "74": 30, "84": 30, "267": 30, "109": 30, "164": 30, "322": 30, "510": 30, "231": 30, "335": 30, "632": 30, "1069": 30, "comparison": 30, "impress": 30, "domin": 30, "outperform": 30, "margin": 30, "thank": [30, 39, 40], "avoid": 30, "zstd": 30, "compress": 30, "upload": 30, "growth": 31, "mimic": 31, "facto": 31, "standard": 31, "horovod": 31, "easi": 31, "tensorflow": 31, "mxnet": 31, "huge": 31, "principl": [31, 35], "covertyp": 31, "uci": 31, "forest": 31, "cartograph": 31, "506": 31, "011": 31, "accordingli": 31, "notebook": 31, "sp": 31, "dask_work": 31, "read_csv": 31, "raw_data": 31, "covtyp": 31, "encod": 31, "represent": 31, "warn": 31, "filterwarn": 31, "soil_type_valu": 31, "soil_type_": 31, "40": 31, "wilderness_area_valu": 31, "area_type_": 31, "soil_typ": 31, "lambda": 31, "nonzero": 31, "wilderness_area": 31, "csv_header": 31, "elev": 31, "aspect": 31, "slope": 31, "horizontal_distance_to_hydrologi": 31, "vertical_distance_to_hydrologi": 31, "horizontal_distance_to_roadwai": 31, "hillshade_9am": 31, "hillshade_noon": 31, "hillshade_3pm": 31, "horizontal_distance_to_fire_point": 31, "cover_typ": 31, "54": 31, "ignore_index": 31, "register_dask_typ": 31, "get_dataset_from_csv": 31, "csv_file_path": 31, "shuffl": 31, "make_csv_dataset": 31, "column_nam": 31, "column_default": 31, "label_nam": 31, "target_feature_nam": 31, "num_epoch": 31, "procedur": 31, "test_dataset": 31, "run_experi": 31, "adam": 31, "sparsecategoricalaccuraci": 31, "train_data_fil": 31, "test_data_fil": 31, "histori": 31, "get_dataset_from_vineyard": 31, "len_test": 31, "hvd": 31, "distributedoptim": 31, "callback": 31, "broadcast": 31, "rank": 31, "checkpoint": 31, "broadcastglobalvariablescallback": 31, "target_feature_label": 31, "numeric_feature_nam": 31, "categorical_features_with_vocabulari": 31, "categorical_feature_nam": 31, "num_class": 31, "dropout_r": 31, "265": 31, "hidden_unit": 31, "create_model_input": 31, "els": 31, "spars": 31, "hot": 31, "categoryencod": 31, "memor": 31, "dimension": 31, "embed": 31, "unseen": 31, "combin": [31, 39], "stringlookup": 31, "encode_input": 31, "use_embed": 31, "encoded_featur": 31, "vocabulari": 31, "lookup": 31, "mask": 31, "token": 31, "nor": 31, "oov": 31, "mask_token": 31, "num_oov_indic": 31, "output_mod": 31, "embedding_dim": 31, "math": 31, "sqrt": 31, "dimens": 31, "input_dim": 31, "output_dim": 31, "expand_dim": 31, "all_featur": 31, "baselin": 31, "create_baseline_model": 31, "batchnorm": 31, "dropout": 31, "softmax": 31, "baseline_model": 31, "shutdown": 31, "horovodrun": 31, "worri": 31, "bb": 32, "78": 32, "o8000000119aa10c0": 32, "frozen": 32, "aka": 32, "value1": 32, "shm": 32, "segment": [33, 36], "hello": [33, 36], "o800000011cfa7040": [33, 36], "sake": [33, 36], "simplic": [33, 36], "sock1": [33, 36], "sock2": [33, 36], "id1": [33, 36], "id2": [33, 36], "obj1": [33, 36], "obj2": [33, 36], "id_pair": [33, 36], "obj_pair": [33, 36], "value_pair": [33, 36], "tailor": [34, 41], "instantli": [34, 41], "craft": [34, 41], "snippet": 35, "grasp": 35, "nullptr": 35, "assert": 35, "__attribute__": 35, "static_pointer_cast": 35, "helper": 35, "stub": 35, "factori": 35, "human": 35, "readabl": 35, "int32": 35, "int32_t": 35, "dynamic_pointer_cast": 35, "vectorbuild": 35, "static_cast": 35, "malloc": 35, "sizeof": 35, "return_on_error": 35, "memcpi": 35, "ok": 35, "make_shar": 35, "buffer_object": 35, "argc": 35, "argv": 35, "vineyard_check_ok": 35, "ipcserv": 35, "cout": 35, "endl": 35, "java": [35, 40], "dsl": 35, "stai": 35, "sneak": 35, "peek": 35, "mod": [35, 39], "numeric_array_build": 36, "length_": 36, "null_count_": 36, "null_count": 36, "offset_": 36, "null_bitmap": 36, "null_bitmap_": 36, "numeric_array_resolv": 36, "normalize_dtyp": 36, "group": 36, "from_numpy_dtyp": 36, "as_arrow_buff": 36, "from_buff": 36, "builder_ctx": 36, "resolver_ctx": 36, "revert": 36, "rout": [37, 41], "central": [37, 41], "test_datafram": 38, "xxxxabcd": 38, "test_basic_data_unit": 38, "infin": [38, 40], "168469": 38, "19": [38, 40], "269489": 38, "332533": 38, "714950": 38, "2345000505447388": 38, "suppos": 38, "07": 38, "21t15": 38, "42": 38, "981": 38, "0800": 38, "lapp": 38, "owid": 38, "nomin": 38, "gate": 38, "5fd45fdd66": 38, "fq55z": 38, "3m37": 38, "qjr5c": 38, "35": 38, "ssqb7": 38, "29": 38, "3m53": 38, "dataframe_obj": 38, "unit_obj": 38, "jsonpath": 38, "587912": 38, "059792": 38, "863514": 38, "682567": 38, "quiet": 38, "fraudul": 39, "classifi": 39, "purchas": 39, "reproduc": 39, "a16c878c5091c1e5c9eff0a1fca065665f47edb4c8c75408b3d33e22f0ec0d05": 39, "cni": [39, 40], "storageclass": [39, 40], "customresourcedefinit": 39, "apiextens": 39, "certificaterequest": 39, "clusterissu": 39, "issuer": 39, "serviceaccount": 39, "cainjector": [39, 40], "clusterrol": [39, 40], "rbac": 39, "ingress": 39, "shim": 39, "approv": 39, "certificatesigningrequest": 39, "subjectaccessreview": 39, "clusterrolebind": 39, "leaderelect": 39, "dynam": 39, "rolebind": 39, "mutatingwebhookconfigur": 39, "admissionregistr": 39, "validatingwebhookconfigur": 39, "5dd59d9d9b": 39, "k9hkm": 39, "condit": 39, "met": 39, "8696fc9f89": 39, "bmjzh": 39, "7d4b5b8c56": 39, "fvmc2": 39, "5001": 39, "c3a672704524": 39, "b14a7037d2e7": 39, "8d7366c22fd8": 39, "digest": 39, "sha256": 39, "ea06c833351f19c5db28163406c55e2108676c27fdafea7652500c55ce333b9d": 39, "946": 39, "opt": 39, "caoy": 39, "gsbot": 39, "rolenam": 39, "maxdesclen": 39, "kustom": 39, "backup": 39, "recov": 39, "proxi": [39, 40], "selfsign": 39, "verifi": 39, "68": 39, "7f569b57c5": 39, "46tgq": 39, "6ffcb96cbc": 39, "gs2v9": 39, "67": 39, "n59gg": 39, "xwpzd": 39, "awk": [39, 40], "exec": [39, 40], "ol": 39, "githubusercont": 39, "gstest": 39, "master": [39, 40], "apigroup": 39, "lot": 39, "bug": 40, "know": 40, "coredn": 40, "6d4b75cb6d": 40, "k2sk2": 40, "xm4dt": 40, "52": 40, "kindnet": 40, "fp24b": 40, "h6swp": 40, "mtkd4": 40, "zxxpd": 40, "apiserv": 40, "6zgq2": 40, "8vghn": 40, "c7vz5": 40, "kd4zz": 40, "provision": 40, "9cd9bd544": 40, "2vrtq": 40, "2m30": 40, "114": 40, "newest": 40, "hang": 40, "tight": 40, "grab": 40, "got": 40, "happi": 40, "wed": 40, "jan": 40, "uninstal": 40, "fun": 40, "b865888cc": 40, "xj8x9": 40, "d99dcb884": 40, "gq9j5": 40, "5bc8fd5d48": 40, "vh4bg": 40, "5bcbb75fb6": 40, "cfdpk": 40, "166": 40, "147": 40, "9402": 40, "111": 40, "112": 40, "153": 40, "134": 40, "101": 40, "879798cb6": 40, "qpvtw": 40, "2m59": 40, "x4m2x": 40, "matur": 40, "golang": 40, "6fd8c47c98": 40, "7btkv": 40, "93": 40, "onam": 40, "objid": 40, "o001027d7c86a49f0": 40, "o801027d7c85c472": 40, "4547407361228035": 40, "tail": 40, "deprec": 40, "rpc_client": 40}, "objects": {"": [[26, 0, 1, "_CPPv4I0EN8vineyard5ArrayE", "vineyard::Array"], [26, 1, 1, "_CPPv4N8vineyard5Array9ConstructERK10ObjectMeta", "vineyard::Array::Construct"], [26, 2, 1, "_CPPv4N8vineyard5Array9ConstructERK10ObjectMeta", "vineyard::Array::Construct::meta"], [26, 1, 1, "_CPPv4N8vineyard5Array6CreateEv", "vineyard::Array::Create"], [26, 3, 1, "_CPPv4I0EN8vineyard5ArrayE", "vineyard::Array::T"], [26, 1, 1, "_CPPv4NK8vineyard5Array4dataEv", "vineyard::Array::data"], [26, 1, 1, "_CPPv4NK8vineyard5ArrayixE6size_t", "vineyard::Array::operator[]"], [26, 2, 1, "_CPPv4NK8vineyard5ArrayixE6size_t", "vineyard::Array::operator[]::loc"], [26, 1, 1, "_CPPv4NK8vineyard5Array4sizeEv", "vineyard::Array::size"], [26, 0, 1, "_CPPv4I0EN8vineyard12ArrayBuilderE", "vineyard::ArrayBuilder"], [26, 1, 1, "_CPPv4N8vineyard12ArrayBuilder12ArrayBuilderER6Client6size_t", "vineyard::ArrayBuilder::ArrayBuilder"], [26, 1, 1, "_CPPv4N8vineyard12ArrayBuilder12ArrayBuilderER6ClientPK1T6size_t", "vineyard::ArrayBuilder::ArrayBuilder"], [26, 1, 1, "_CPPv4N8vineyard12ArrayBuilder12ArrayBuilderER6ClientRKNSt6vectorI1TEE", "vineyard::ArrayBuilder::ArrayBuilder"], [26, 2, 1, "_CPPv4N8vineyard12ArrayBuilder12ArrayBuilderER6Client6size_t", "vineyard::ArrayBuilder::ArrayBuilder::client"], [26, 2, 1, "_CPPv4N8vineyard12ArrayBuilder12ArrayBuilderER6ClientPK1T6size_t", "vineyard::ArrayBuilder::ArrayBuilder::client"], [26, 2, 1, "_CPPv4N8vineyard12ArrayBuilder12ArrayBuilderER6ClientRKNSt6vectorI1TEE", "vineyard::ArrayBuilder::ArrayBuilder::client"], [26, 2, 1, "_CPPv4N8vineyard12ArrayBuilder12ArrayBuilderER6ClientPK1T6size_t", "vineyard::ArrayBuilder::ArrayBuilder::data"], [26, 2, 1, "_CPPv4N8vineyard12ArrayBuilder12ArrayBuilderER6Client6size_t", "vineyard::ArrayBuilder::ArrayBuilder::size"], [26, 2, 1, "_CPPv4N8vineyard12ArrayBuilder12ArrayBuilderER6ClientPK1T6size_t", "vineyard::ArrayBuilder::ArrayBuilder::size"], [26, 2, 1, "_CPPv4N8vineyard12ArrayBuilder12ArrayBuilderER6ClientRKNSt6vectorI1TEE", "vineyard::ArrayBuilder::ArrayBuilder::vec"], [26, 1, 1, "_CPPv4N8vineyard12ArrayBuilder5BuildER6Client", "vineyard::ArrayBuilder::Build"], [26, 2, 1, "_CPPv4N8vineyard12ArrayBuilder5BuildER6Client", "vineyard::ArrayBuilder::Build::client"], [26, 3, 1, "_CPPv4I0EN8vineyard12ArrayBuilderE", "vineyard::ArrayBuilder::T"], [26, 1, 1, "_CPPv4N8vineyard12ArrayBuilder4dataEv", "vineyard::ArrayBuilder::data"], [26, 1, 1, "_CPPv4NK8vineyard12ArrayBuilder4dataEv", "vineyard::ArrayBuilder::data"], [26, 1, 1, "_CPPv4N8vineyard12ArrayBuilderixE6size_t", "vineyard::ArrayBuilder::operator[]"], [26, 2, 1, "_CPPv4N8vineyard12ArrayBuilderixE6size_t", "vineyard::ArrayBuilder::operator[]::idx"], [26, 1, 1, "_CPPv4NK8vineyard12ArrayBuilder4sizeEv", "vineyard::ArrayBuilder::size"], [26, 1, 1, "_CPPv4N8vineyard12ArrayBuilderD0Ev", "vineyard::ArrayBuilder::~ArrayBuilder"], [26, 0, 1, "_CPPv4N8vineyard4BlobE", "vineyard::Blob"], [26, 1, 1, "_CPPv4NK8vineyard4Blob11ArrowBufferEv", "vineyard::Blob::ArrowBuffer"], [26, 1, 1, "_CPPv4NK8vineyard4Blob18ArrowBufferOrEmptyEv", "vineyard::Blob::ArrowBufferOrEmpty"], [26, 1, 1, "_CPPv4NK8vineyard4Blob6BufferEv", "vineyard::Blob::Buffer"], [26, 1, 1, "_CPPv4NK8vineyard4Blob13BufferOrEmptyEv", "vineyard::Blob::BufferOrEmpty"], [26, 1, 1, "_CPPv4N8vineyard4Blob9ConstructERK10ObjectMeta", "vineyard::Blob::Construct"], [26, 2, 1, "_CPPv4N8vineyard4Blob9ConstructERK10ObjectMeta", "vineyard::Blob::Construct::meta"], [26, 1, 1, "_CPPv4N8vineyard4Blob6CreateEv", "vineyard::Blob::Create"], [26, 1, 1, "_CPPv4NK8vineyard4Blob4DumpEv", "vineyard::Blob::Dump"], [26, 1, 1, "_CPPv4N8vineyard4Blob13FromAllocatorER6ClientK8ObjectIDK9uintptr_tK6size_t", "vineyard::Blob::FromAllocator"], [26, 2, 1, "_CPPv4N8vineyard4Blob13FromAllocatorER6ClientK8ObjectIDK9uintptr_tK6size_t", "vineyard::Blob::FromAllocator::client"], [26, 2, 1, "_CPPv4N8vineyard4Blob13FromAllocatorER6ClientK8ObjectIDK9uintptr_tK6size_t", "vineyard::Blob::FromAllocator::object_id"], [26, 2, 1, "_CPPv4N8vineyard4Blob13FromAllocatorER6ClientK8ObjectIDK9uintptr_tK6size_t", "vineyard::Blob::FromAllocator::pointer"], [26, 2, 1, "_CPPv4N8vineyard4Blob13FromAllocatorER6ClientK8ObjectIDK9uintptr_tK6size_t", "vineyard::Blob::FromAllocator::size"], [26, 1, 1, "_CPPv4N8vineyard4Blob11FromPointerER6ClientK9uintptr_tK6size_t", "vineyard::Blob::FromPointer"], [26, 2, 1, "_CPPv4N8vineyard4Blob11FromPointerER6ClientK9uintptr_tK6size_t", "vineyard::Blob::FromPointer::client"], [26, 2, 1, "_CPPv4N8vineyard4Blob11FromPointerER6ClientK9uintptr_tK6size_t", "vineyard::Blob::FromPointer::pointer"], [26, 2, 1, "_CPPv4N8vineyard4Blob11FromPointerER6ClientK9uintptr_tK6size_t", "vineyard::Blob::FromPointer::size"], [26, 1, 1, "_CPPv4N8vineyard4Blob9MakeEmptyER6Client", "vineyard::Blob::MakeEmpty"], [26, 2, 1, "_CPPv4N8vineyard4Blob9MakeEmptyER6Client", "vineyard::Blob::MakeEmpty::client"], [26, 1, 1, "_CPPv4NK8vineyard4Blob14allocated_sizeEv", "vineyard::Blob::allocated_size"], [26, 1, 1, "_CPPv4NK8vineyard4Blob4dataEv", "vineyard::Blob::data"], [26, 1, 1, "_CPPv4NK8vineyard4Blob4sizeEv", "vineyard::Blob::size"], [26, 0, 1, "_CPPv4N8vineyard10BlobWriterE", "vineyard::BlobWriter"], [26, 1, 1, "_CPPv4N8vineyard10BlobWriter5AbortER6Client", "vineyard::BlobWriter::Abort"], [26, 2, 1, "_CPPv4N8vineyard10BlobWriter5AbortER6Client", "vineyard::BlobWriter::Abort::client"], [26, 1, 1, "_CPPv4N8vineyard10BlobWriter11AddKeyValueERKNSt6stringERKNSt6stringE", "vineyard::BlobWriter::AddKeyValue"], [26, 1, 1, "_CPPv4N8vineyard10BlobWriter11AddKeyValueERKNSt6stringERRNSt6stringE", "vineyard::BlobWriter::AddKeyValue"], [26, 2, 1, "_CPPv4N8vineyard10BlobWriter11AddKeyValueERKNSt6stringERKNSt6stringE", "vineyard::BlobWriter::AddKeyValue::key"], [26, 2, 1, "_CPPv4N8vineyard10BlobWriter11AddKeyValueERKNSt6stringERRNSt6stringE", "vineyard::BlobWriter::AddKeyValue::key"], [26, 2, 1, "_CPPv4N8vineyard10BlobWriter11AddKeyValueERKNSt6stringERKNSt6stringE", "vineyard::BlobWriter::AddKeyValue::value"], [26, 2, 1, "_CPPv4N8vineyard10BlobWriter11AddKeyValueERKNSt6stringERRNSt6stringE", "vineyard::BlobWriter::AddKeyValue::value"], [26, 1, 1, "_CPPv4NK8vineyard10BlobWriter6BufferEv", "vineyard::BlobWriter::Buffer"], [26, 1, 1, "_CPPv4N8vineyard10BlobWriter5BuildER6Client", "vineyard::BlobWriter::Build"], [26, 2, 1, "_CPPv4N8vineyard10BlobWriter5BuildER6Client", "vineyard::BlobWriter::Build::client"], [26, 1, 1, "_CPPv4NK8vineyard10BlobWriter4DumpEv", "vineyard::BlobWriter::Dump"], [26, 1, 1, "_CPPv4N8vineyard10BlobWriter6ShrinkER6ClientK6size_t", "vineyard::BlobWriter::Shrink"], [26, 2, 1, "_CPPv4N8vineyard10BlobWriter6ShrinkER6ClientK6size_t", "vineyard::BlobWriter::Shrink::client"], [26, 2, 1, "_CPPv4N8vineyard10BlobWriter6ShrinkER6ClientK6size_t", "vineyard::BlobWriter::Shrink::size"], [26, 1, 1, "_CPPv4N8vineyard10BlobWriter4dataEv", "vineyard::BlobWriter::data"], [26, 1, 1, "_CPPv4NK8vineyard10BlobWriter4dataEv", "vineyard::BlobWriter::data"], [26, 1, 1, "_CPPv4NK8vineyard10BlobWriter2idEv", "vineyard::BlobWriter::id"], [26, 1, 1, "_CPPv4NK8vineyard10BlobWriter4sizeEv", "vineyard::BlobWriter::size"], [26, 0, 1, "_CPPv4N8vineyard10ByteStreamE", "vineyard::ByteStream"], [26, 1, 1, "_CPPv4N8vineyard10ByteStream6CreateEv", "vineyard::ByteStream::Create"], [26, 1, 1, "_CPPv4N8vineyard10ByteStream11FlushBufferEv", "vineyard::ByteStream::FlushBuffer"], [26, 1, 1, "_CPPv4N8vineyard10ByteStream8ReadLineERNSt6stringE", "vineyard::ByteStream::ReadLine"], [26, 2, 1, "_CPPv4N8vineyard10ByteStream8ReadLineERNSt6stringE", "vineyard::ByteStream::ReadLine::line"], [26, 1, 1, "_CPPv4N8vineyard10ByteStream18SetBufferSizeLimitE6size_t", "vineyard::ByteStream::SetBufferSizeLimit"], [26, 2, 1, "_CPPv4N8vineyard10ByteStream18SetBufferSizeLimitE6size_t", "vineyard::ByteStream::SetBufferSizeLimit::limit"], [26, 1, 1, "_CPPv4N8vineyard10ByteStream10WriteBytesEPKc6size_t", "vineyard::ByteStream::WriteBytes"], [26, 2, 1, "_CPPv4N8vineyard10ByteStream10WriteBytesEPKc6size_t", "vineyard::ByteStream::WriteBytes::len"], [26, 2, 1, "_CPPv4N8vineyard10ByteStream10WriteBytesEPKc6size_t", "vineyard::ByteStream::WriteBytes::ptr"], [26, 1, 1, "_CPPv4N8vineyard10ByteStream9WriteLineERKNSt6stringE", "vineyard::ByteStream::WriteLine"], [26, 2, 1, "_CPPv4N8vineyard10ByteStream9WriteLineERKNSt6stringE", "vineyard::ByteStream::WriteLine::line"], [26, 0, 1, "_CPPv4N8vineyard6ClientE", "vineyard::Client"], [26, 1, 1, "_CPPv4N8vineyard6Client13AllocatedSizeEK8ObjectIDR6size_t", "vineyard::Client::AllocatedSize"], [26, 2, 1, "_CPPv4N8vineyard6Client13AllocatedSizeEK8ObjectIDR6size_t", "vineyard::Client::AllocatedSize::id"], [26, 2, 1, "_CPPv4N8vineyard6Client13AllocatedSizeEK8ObjectIDR6size_t", "vineyard::Client::AllocatedSize::size"], [26, 1, 1, "_CPPv4N8vineyard6Client6ClientEv", "vineyard::Client::Client"], [26, 1, 1, "_CPPv4N8vineyard6Client7ConnectERKNSt6stringE", "vineyard::Client::Connect"], [26, 1, 1, "_CPPv4N8vineyard6Client7ConnectERKNSt6stringERKNSt6stringE", "vineyard::Client::Connect"], [26, 1, 1, "_CPPv4N8vineyard6Client7ConnectERKNSt6stringERKNSt6stringERKNSt6stringE", "vineyard::Client::Connect"], [26, 1, 1, "_CPPv4N8vineyard6Client7ConnectEv", "vineyard::Client::Connect"], [26, 2, 1, "_CPPv4N8vineyard6Client7ConnectERKNSt6stringE", "vineyard::Client::Connect::ipc_socket"], [26, 2, 1, "_CPPv4N8vineyard6Client7ConnectERKNSt6stringERKNSt6stringERKNSt6stringE", "vineyard::Client::Connect::ipc_socket"], [26, 2, 1, "_CPPv4N8vineyard6Client7ConnectERKNSt6stringERKNSt6stringE", "vineyard::Client::Connect::password"], [26, 2, 1, "_CPPv4N8vineyard6Client7ConnectERKNSt6stringERKNSt6stringERKNSt6stringE", "vineyard::Client::Connect::password"], [26, 2, 1, "_CPPv4N8vineyard6Client7ConnectERKNSt6stringERKNSt6stringE", "vineyard::Client::Connect::username"], [26, 2, 1, "_CPPv4N8vineyard6Client7ConnectERKNSt6stringERKNSt6stringERKNSt6stringE", "vineyard::Client::Connect::username"], [26, 1, 1, "_CPPv4N8vineyard6Client11CreateArenaEK6size_tRiR6size_tR9uintptr_tR9uintptr_t", "vineyard::Client::CreateArena"], [26, 2, 1, "_CPPv4N8vineyard6Client11CreateArenaEK6size_tRiR6size_tR9uintptr_tR9uintptr_t", "vineyard::Client::CreateArena::available_size"], [26, 2, 1, "_CPPv4N8vineyard6Client11CreateArenaEK6size_tRiR6size_tR9uintptr_tR9uintptr_t", "vineyard::Client::CreateArena::base"], [26, 2, 1, "_CPPv4N8vineyard6Client11CreateArenaEK6size_tRiR6size_tR9uintptr_tR9uintptr_t", "vineyard::Client::CreateArena::fd"], [26, 2, 1, "_CPPv4N8vineyard6Client11CreateArenaEK6size_tRiR6size_tR9uintptr_tR9uintptr_t", "vineyard::Client::CreateArena::size"], [26, 2, 1, "_CPPv4N8vineyard6Client11CreateArenaEK6size_tRiR6size_tR9uintptr_tR9uintptr_t", "vineyard::Client::CreateArena::space"], [26, 1, 1, "_CPPv4N8vineyard6Client10CreateBlobE6size_tRNSt10unique_ptrI10BlobWriterEE", "vineyard::Client::CreateBlob"], [26, 2, 1, "_CPPv4N8vineyard6Client10CreateBlobE6size_tRNSt10unique_ptrI10BlobWriterEE", "vineyard::Client::CreateBlob::blob"], [26, 2, 1, "_CPPv4N8vineyard6Client10CreateBlobE6size_tRNSt10unique_ptrI10BlobWriterEE", "vineyard::Client::CreateBlob::size"], [26, 1, 1, "_CPPv4N8vineyard6Client12CreateBufferEK6size_tR8ObjectIDR7PayloadRNSt10shared_ptrI13MutableBufferEE", "vineyard::Client::CreateBuffer"], [26, 2, 1, "_CPPv4N8vineyard6Client12CreateBufferEK6size_tR8ObjectIDR7PayloadRNSt10shared_ptrI13MutableBufferEE", "vineyard::Client::CreateBuffer::buffer"], [26, 2, 1, "_CPPv4N8vineyard6Client12CreateBufferEK6size_tR8ObjectIDR7PayloadRNSt10shared_ptrI13MutableBufferEE", "vineyard::Client::CreateBuffer::id"], [26, 2, 1, "_CPPv4N8vineyard6Client12CreateBufferEK6size_tR8ObjectIDR7PayloadRNSt10shared_ptrI13MutableBufferEE", "vineyard::Client::CreateBuffer::payload"], [26, 2, 1, "_CPPv4N8vineyard6Client12CreateBufferEK6size_tR8ObjectIDR7PayloadRNSt10shared_ptrI13MutableBufferEE", "vineyard::Client::CreateBuffer::size"], [26, 1, 1, "_CPPv4N8vineyard6Client14CreateDiskBlobE6size_tRKNSt6stringERNSt10unique_ptrI10BlobWriterEE", "vineyard::Client::CreateDiskBlob"], [26, 2, 1, "_CPPv4N8vineyard6Client14CreateDiskBlobE6size_tRKNSt6stringERNSt10unique_ptrI10BlobWriterEE", "vineyard::Client::CreateDiskBlob::blob"], [26, 2, 1, "_CPPv4N8vineyard6Client14CreateDiskBlobE6size_tRKNSt6stringERNSt10unique_ptrI10BlobWriterEE", "vineyard::Client::CreateDiskBlob::path"], [26, 2, 1, "_CPPv4N8vineyard6Client14CreateDiskBlobE6size_tRKNSt6stringERNSt10unique_ptrI10BlobWriterEE", "vineyard::Client::CreateDiskBlob::size"], [26, 1, 1, "_CPPv4N8vineyard6Client15CreateGPUBufferEK6size_tR8ObjectIDR7PayloadRNSt10shared_ptrI17GPUUnifiedAddressEE", "vineyard::Client::CreateGPUBuffer"], [26, 2, 1, "_CPPv4N8vineyard6Client15CreateGPUBufferEK6size_tR8ObjectIDR7PayloadRNSt10shared_ptrI17GPUUnifiedAddressEE", "vineyard::Client::CreateGPUBuffer::gua"], [26, 2, 1, "_CPPv4N8vineyard6Client15CreateGPUBufferEK6size_tR8ObjectIDR7PayloadRNSt10shared_ptrI17GPUUnifiedAddressEE", "vineyard::Client::CreateGPUBuffer::id"], [26, 2, 1, "_CPPv4N8vineyard6Client15CreateGPUBufferEK6size_tR8ObjectIDR7PayloadRNSt10shared_ptrI17GPUUnifiedAddressEE", "vineyard::Client::CreateGPUBuffer::payload"], [26, 2, 1, "_CPPv4N8vineyard6Client15CreateGPUBufferEK6size_tR8ObjectIDR7PayloadRNSt10shared_ptrI17GPUUnifiedAddressEE", "vineyard::Client::CreateGPUBuffer::size"], [26, 1, 1, "_CPPv4N8vineyard6Client7DefaultEv", "vineyard::Client::Default"], [26, 1, 1, "_CPPv4N8vineyard6Client7DelDataEK8ObjectIDKbKb", "vineyard::Client::DelData"], [26, 1, 1, "_CPPv4N8vineyard6Client7DelDataERKNSt6vectorI8ObjectIDEEKbKb", "vineyard::Client::DelData"], [26, 2, 1, "_CPPv4N8vineyard6Client7DelDataEK8ObjectIDKbKb", "vineyard::Client::DelData::deep"], [26, 2, 1, "_CPPv4N8vineyard6Client7DelDataERKNSt6vectorI8ObjectIDEEKbKb", "vineyard::Client::DelData::deep"], [26, 2, 1, "_CPPv4N8vineyard6Client7DelDataEK8ObjectIDKbKb", "vineyard::Client::DelData::force"], [26, 2, 1, "_CPPv4N8vineyard6Client7DelDataERKNSt6vectorI8ObjectIDEEKbKb", "vineyard::Client::DelData::force"], [26, 2, 1, "_CPPv4N8vineyard6Client7DelDataEK8ObjectIDKbKb", "vineyard::Client::DelData::id"], [26, 2, 1, "_CPPv4N8vineyard6Client7DelDataERKNSt6vectorI8ObjectIDEEKbKb", "vineyard::Client::DelData::ids"], [26, 1, 1, "_CPPv4N8vineyard6Client10DisconnectEv", "vineyard::Client::Disconnect"], [26, 1, 1, "_CPPv4N8vineyard6Client10DropBufferEK8ObjectIDKi", "vineyard::Client::DropBuffer"], [26, 2, 1, "_CPPv4N8vineyard6Client10DropBufferEK8ObjectIDKi", "vineyard::Client::DropBuffer::fd"], [26, 2, 1, "_CPPv4N8vineyard6Client10DropBufferEK8ObjectIDKi", "vineyard::Client::DropBuffer::id"], [26, 1, 1, "_CPPv4N8vineyard6Client19FetchAndGetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::Client::FetchAndGetMetaData"], [26, 2, 1, "_CPPv4N8vineyard6Client19FetchAndGetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::Client::FetchAndGetMetaData::id"], [26, 2, 1, "_CPPv4N8vineyard6Client19FetchAndGetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::Client::FetchAndGetMetaData::meta_data"], [26, 2, 1, "_CPPv4N8vineyard6Client19FetchAndGetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::Client::FetchAndGetMetaData::sync_remote"], [26, 1, 1, "_CPPv4I0EN8vineyard6Client17FetchAndGetObjectE6StatusK8ObjectIDRNSt10shared_ptrI1TEE", "vineyard::Client::FetchAndGetObject"], [26, 1, 1, "_CPPv4I0EN8vineyard6Client17FetchAndGetObjectENSt10shared_ptrI1TEEK8ObjectID", "vineyard::Client::FetchAndGetObject"], [26, 1, 1, "_CPPv4N8vineyard6Client17FetchAndGetObjectEK8ObjectID", "vineyard::Client::FetchAndGetObject"], [26, 1, 1, "_CPPv4N8vineyard6Client17FetchAndGetObjectEK8ObjectIDRNSt10shared_ptrI6ObjectEE", "vineyard::Client::FetchAndGetObject"], [26, 3, 1, "_CPPv4I0EN8vineyard6Client17FetchAndGetObjectE6StatusK8ObjectIDRNSt10shared_ptrI1TEE", "vineyard::Client::FetchAndGetObject::T"], [26, 3, 1, "_CPPv4I0EN8vineyard6Client17FetchAndGetObjectENSt10shared_ptrI1TEEK8ObjectID", "vineyard::Client::FetchAndGetObject::T"], [26, 2, 1, "_CPPv4I0EN8vineyard6Client17FetchAndGetObjectE6StatusK8ObjectIDRNSt10shared_ptrI1TEE", "vineyard::Client::FetchAndGetObject::id"], [26, 2, 1, "_CPPv4I0EN8vineyard6Client17FetchAndGetObjectENSt10shared_ptrI1TEEK8ObjectID", "vineyard::Client::FetchAndGetObject::id"], [26, 2, 1, "_CPPv4N8vineyard6Client17FetchAndGetObjectEK8ObjectID", "vineyard::Client::FetchAndGetObject::id"], [26, 2, 1, "_CPPv4N8vineyard6Client17FetchAndGetObjectEK8ObjectIDRNSt10shared_ptrI6ObjectEE", "vineyard::Client::FetchAndGetObject::id"], [26, 2, 1, "_CPPv4I0EN8vineyard6Client17FetchAndGetObjectE6StatusK8ObjectIDRNSt10shared_ptrI1TEE", "vineyard::Client::FetchAndGetObject::object"], [26, 2, 1, "_CPPv4N8vineyard6Client17FetchAndGetObjectEK8ObjectIDRNSt10shared_ptrI6ObjectEE", "vineyard::Client::FetchAndGetObject::object"], [26, 1, 1, "_CPPv4N8vineyard6Client4ForkER6Client", "vineyard::Client::Fork"], [26, 2, 1, "_CPPv4N8vineyard6Client4ForkER6Client", "vineyard::Client::Fork::client"], [26, 1, 1, "_CPPv4N8vineyard6Client7GetBlobEK8ObjectIDRNSt10shared_ptrI4BlobEE", "vineyard::Client::GetBlob"], [26, 1, 1, "_CPPv4N8vineyard6Client7GetBlobEK8ObjectIDbRNSt10shared_ptrI4BlobEE", "vineyard::Client::GetBlob"], [26, 2, 1, "_CPPv4N8vineyard6Client7GetBlobEK8ObjectIDRNSt10shared_ptrI4BlobEE", "vineyard::Client::GetBlob::blob"], [26, 2, 1, "_CPPv4N8vineyard6Client7GetBlobEK8ObjectIDbRNSt10shared_ptrI4BlobEE", "vineyard::Client::GetBlob::blob"], [26, 2, 1, "_CPPv4N8vineyard6Client7GetBlobEK8ObjectIDRNSt10shared_ptrI4BlobEE", "vineyard::Client::GetBlob::id"], [26, 2, 1, "_CPPv4N8vineyard6Client7GetBlobEK8ObjectIDbRNSt10shared_ptrI4BlobEE", "vineyard::Client::GetBlob::id"], [26, 2, 1, "_CPPv4N8vineyard6Client7GetBlobEK8ObjectIDbRNSt10shared_ptrI4BlobEE", "vineyard::Client::GetBlob::unsafe"], [26, 1, 1, "_CPPv4N8vineyard6Client8GetBlobsEKNSt6vectorI8ObjectIDEEKbRNSt6vectorINSt10shared_ptrI4BlobEEEE", "vineyard::Client::GetBlobs"], [26, 1, 1, "_CPPv4N8vineyard6Client8GetBlobsEKNSt6vectorI8ObjectIDEERNSt6vectorINSt10shared_ptrI4BlobEEEE", "vineyard::Client::GetBlobs"], [26, 2, 1, "_CPPv4N8vineyard6Client8GetBlobsEKNSt6vectorI8ObjectIDEEKbRNSt6vectorINSt10shared_ptrI4BlobEEEE", "vineyard::Client::GetBlobs::blobs"], [26, 2, 1, "_CPPv4N8vineyard6Client8GetBlobsEKNSt6vectorI8ObjectIDEERNSt6vectorINSt10shared_ptrI4BlobEEEE", "vineyard::Client::GetBlobs::blobs"], [26, 2, 1, "_CPPv4N8vineyard6Client8GetBlobsEKNSt6vectorI8ObjectIDEEKbRNSt6vectorINSt10shared_ptrI4BlobEEEE", "vineyard::Client::GetBlobs::ids"], [26, 2, 1, "_CPPv4N8vineyard6Client8GetBlobsEKNSt6vectorI8ObjectIDEERNSt6vectorINSt10shared_ptrI4BlobEEEE", "vineyard::Client::GetBlobs::ids"], [26, 2, 1, "_CPPv4N8vineyard6Client8GetBlobsEKNSt6vectorI8ObjectIDEEKbRNSt6vectorINSt10shared_ptrI4BlobEEEE", "vineyard::Client::GetBlobs::unsafe"], [26, 1, 1, "_CPPv4N8vineyard6Client9GetBufferEK8ObjectIDRNSt10shared_ptrI6BufferEE", "vineyard::Client::GetBuffer"], [26, 2, 1, "_CPPv4N8vineyard6Client9GetBufferEK8ObjectIDRNSt10shared_ptrI6BufferEE", "vineyard::Client::GetBuffer::buffer"], [26, 2, 1, "_CPPv4N8vineyard6Client9GetBufferEK8ObjectIDRNSt10shared_ptrI6BufferEE", "vineyard::Client::GetBuffer::id"], [26, 1, 1, "_CPPv4N8vineyard6Client14GetBufferSizesERKNSt3setI8ObjectIDEERNSt3mapI8ObjectID6size_tEE", "vineyard::Client::GetBufferSizes"], [26, 2, 1, "_CPPv4N8vineyard6Client14GetBufferSizesERKNSt3setI8ObjectIDEERNSt3mapI8ObjectID6size_tEE", "vineyard::Client::GetBufferSizes::ids"], [26, 2, 1, "_CPPv4N8vineyard6Client14GetBufferSizesERKNSt3setI8ObjectIDEERNSt3mapI8ObjectID6size_tEE", "vineyard::Client::GetBufferSizes::sizes"], [26, 1, 1, "_CPPv4N8vineyard6Client10GetBuffersERKNSt3setI8ObjectIDEERNSt3mapI8ObjectIDNSt10shared_ptrI6BufferEEEE", "vineyard::Client::GetBuffers"], [26, 2, 1, "_CPPv4N8vineyard6Client10GetBuffersERKNSt3setI8ObjectIDEERNSt3mapI8ObjectIDNSt10shared_ptrI6BufferEEEE", "vineyard::Client::GetBuffers::buffers"], [26, 2, 1, "_CPPv4N8vineyard6Client10GetBuffersERKNSt3setI8ObjectIDEERNSt3mapI8ObjectIDNSt10shared_ptrI6BufferEEEE", "vineyard::Client::GetBuffers::ids"], [26, 1, 1, "_CPPv4N8vineyard6Client13GetDependencyERK8ObjectIDRNSt3setI8ObjectIDEE", "vineyard::Client::GetDependency"], [26, 2, 1, "_CPPv4N8vineyard6Client13GetDependencyERK8ObjectIDRNSt3setI8ObjectIDEE", "vineyard::Client::GetDependency::bids"], [26, 2, 1, "_CPPv4N8vineyard6Client13GetDependencyERK8ObjectIDRNSt3setI8ObjectIDEE", "vineyard::Client::GetDependency::id"], [26, 1, 1, "_CPPv4N8vineyard6Client13GetGPUBuffersERKNSt3setI8ObjectIDEEKbRNSt3mapI8ObjectID17GPUUnifiedAddressEE", "vineyard::Client::GetGPUBuffers"], [26, 2, 1, "_CPPv4N8vineyard6Client13GetGPUBuffersERKNSt3setI8ObjectIDEEKbRNSt3mapI8ObjectID17GPUUnifiedAddressEE", "vineyard::Client::GetGPUBuffers::GUAs"], [26, 2, 1, "_CPPv4N8vineyard6Client13GetGPUBuffersERKNSt3setI8ObjectIDEEKbRNSt3mapI8ObjectID17GPUUnifiedAddressEE", "vineyard::Client::GetGPUBuffers::ids"], [26, 2, 1, "_CPPv4N8vineyard6Client13GetGPUBuffersERKNSt3setI8ObjectIDEEKbRNSt3mapI8ObjectID17GPUUnifiedAddressEE", "vineyard::Client::GetGPUBuffers::unsafe"], [26, 1, 1, "_CPPv4N8vineyard6Client11GetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::Client::GetMetaData"], [26, 1, 1, "_CPPv4N8vineyard6Client11GetMetaDataERKNSt6vectorI8ObjectIDEERNSt6vectorI10ObjectMetaEEKb", "vineyard::Client::GetMetaData"], [26, 2, 1, "_CPPv4N8vineyard6Client11GetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::Client::GetMetaData::id"], [26, 2, 1, "_CPPv4N8vineyard6Client11GetMetaDataERKNSt6vectorI8ObjectIDEERNSt6vectorI10ObjectMetaEEKb", "vineyard::Client::GetMetaData::ids"], [26, 2, 1, "_CPPv4N8vineyard6Client11GetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::Client::GetMetaData::meta_data"], [26, 2, 1, "_CPPv4N8vineyard6Client11GetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::Client::GetMetaData::sync_remote"], [26, 2, 1, "_CPPv4N8vineyard6Client11GetMetaDataERKNSt6vectorI8ObjectIDEERNSt6vectorI10ObjectMetaEEKb", "vineyard::Client::GetMetaData::sync_remote"], [26, 1, 1, "_CPPv4N8vineyard6Client18GetNextStreamChunkEK8ObjectIDK6size_tRNSt10unique_ptrI13MutableBufferEE", "vineyard::Client::GetNextStreamChunk"], [26, 2, 1, "_CPPv4N8vineyard6Client18GetNextStreamChunkEK8ObjectIDK6size_tRNSt10unique_ptrI13MutableBufferEE", "vineyard::Client::GetNextStreamChunk::blob"], [26, 2, 1, "_CPPv4N8vineyard6Client18GetNextStreamChunkEK8ObjectIDK6size_tRNSt10unique_ptrI13MutableBufferEE", "vineyard::Client::GetNextStreamChunk::id"], [26, 2, 1, "_CPPv4N8vineyard6Client18GetNextStreamChunkEK8ObjectIDK6size_tRNSt10unique_ptrI13MutableBufferEE", "vineyard::Client::GetNextStreamChunk::size"], [26, 1, 1, "_CPPv4I0EN8vineyard6Client9GetObjectE6StatusK8ObjectIDRNSt10shared_ptrI1TEE", "vineyard::Client::GetObject"], [26, 1, 1, "_CPPv4I0EN8vineyard6Client9GetObjectENSt10shared_ptrI1TEEK8ObjectID", "vineyard::Client::GetObject"], [26, 1, 1, "_CPPv4N8vineyard6Client9GetObjectEK8ObjectID", "vineyard::Client::GetObject"], [26, 1, 1, "_CPPv4N8vineyard6Client9GetObjectEK8ObjectIDRNSt10shared_ptrI6ObjectEE", "vineyard::Client::GetObject"], [26, 3, 1, "_CPPv4I0EN8vineyard6Client9GetObjectE6StatusK8ObjectIDRNSt10shared_ptrI1TEE", "vineyard::Client::GetObject::T"], [26, 3, 1, "_CPPv4I0EN8vineyard6Client9GetObjectENSt10shared_ptrI1TEEK8ObjectID", "vineyard::Client::GetObject::T"], [26, 2, 1, "_CPPv4I0EN8vineyard6Client9GetObjectE6StatusK8ObjectIDRNSt10shared_ptrI1TEE", "vineyard::Client::GetObject::id"], [26, 2, 1, "_CPPv4I0EN8vineyard6Client9GetObjectENSt10shared_ptrI1TEEK8ObjectID", "vineyard::Client::GetObject::id"], [26, 2, 1, "_CPPv4N8vineyard6Client9GetObjectEK8ObjectID", "vineyard::Client::GetObject::id"], [26, 2, 1, "_CPPv4N8vineyard6Client9GetObjectEK8ObjectIDRNSt10shared_ptrI6ObjectEE", "vineyard::Client::GetObject::id"], [26, 2, 1, "_CPPv4I0EN8vineyard6Client9GetObjectE6StatusK8ObjectIDRNSt10shared_ptrI1TEE", "vineyard::Client::GetObject::object"], [26, 2, 1, "_CPPv4N8vineyard6Client9GetObjectEK8ObjectIDRNSt10shared_ptrI6ObjectEE", "vineyard::Client::GetObject::object"], [26, 1, 1, "_CPPv4N8vineyard6Client10GetObjectsERKNSt6vectorI8ObjectIDEE", "vineyard::Client::GetObjects"], [26, 2, 1, "_CPPv4N8vineyard6Client10GetObjectsERKNSt6vectorI8ObjectIDEE", "vineyard::Client::GetObjects::ids"], [26, 1, 1, "_CPPv4N8vineyard6Client7IsInUseERK8ObjectIDRb", "vineyard::Client::IsInUse"], [26, 2, 1, "_CPPv4N8vineyard6Client7IsInUseERK8ObjectIDRb", "vineyard::Client::IsInUse::id"], [26, 2, 1, "_CPPv4N8vineyard6Client7IsInUseERK8ObjectIDRb", "vineyard::Client::IsInUse::is_in_use"], [26, 1, 1, "_CPPv4NK8vineyard6Client14IsSharedMemoryEK9uintptr_t", "vineyard::Client::IsSharedMemory"], [26, 1, 1, "_CPPv4NK8vineyard6Client14IsSharedMemoryEK9uintptr_tR8ObjectID", "vineyard::Client::IsSharedMemory"], [26, 1, 1, "_CPPv4NK8vineyard6Client14IsSharedMemoryEPKv", "vineyard::Client::IsSharedMemory"], [26, 1, 1, "_CPPv4NK8vineyard6Client14IsSharedMemoryEPKvR8ObjectID", "vineyard::Client::IsSharedMemory"], [26, 2, 1, "_CPPv4NK8vineyard6Client14IsSharedMemoryEK9uintptr_tR8ObjectID", "vineyard::Client::IsSharedMemory::object_id"], [26, 2, 1, "_CPPv4NK8vineyard6Client14IsSharedMemoryEPKvR8ObjectID", "vineyard::Client::IsSharedMemory::object_id"], [26, 2, 1, "_CPPv4NK8vineyard6Client14IsSharedMemoryEK9uintptr_t", "vineyard::Client::IsSharedMemory::target"], [26, 2, 1, "_CPPv4NK8vineyard6Client14IsSharedMemoryEK9uintptr_tR8ObjectID", "vineyard::Client::IsSharedMemory::target"], [26, 2, 1, "_CPPv4NK8vineyard6Client14IsSharedMemoryEPKv", "vineyard::Client::IsSharedMemory::target"], [26, 2, 1, "_CPPv4NK8vineyard6Client14IsSharedMemoryEPKvR8ObjectID", "vineyard::Client::IsSharedMemory::target"], [26, 1, 1, "_CPPv4N8vineyard6Client9IsSpilledERK8ObjectIDRb", "vineyard::Client::IsSpilled"], [26, 2, 1, "_CPPv4N8vineyard6Client9IsSpilledERK8ObjectIDRb", "vineyard::Client::IsSpilled::id"], [26, 2, 1, "_CPPv4N8vineyard6Client9IsSpilledERK8ObjectIDRb", "vineyard::Client::IsSpilled::is_spilled"], [26, 1, 1, "_CPPv4N8vineyard6Client14ListObjectMetaERKNSt6stringEKbK6size_tb", "vineyard::Client::ListObjectMeta"], [26, 2, 1, "_CPPv4N8vineyard6Client14ListObjectMetaERKNSt6stringEKbK6size_tb", "vineyard::Client::ListObjectMeta::limit"], [26, 2, 1, "_CPPv4N8vineyard6Client14ListObjectMetaERKNSt6stringEKbK6size_tb", "vineyard::Client::ListObjectMeta::nobuffer"], [26, 2, 1, "_CPPv4N8vineyard6Client14ListObjectMetaERKNSt6stringEKbK6size_tb", "vineyard::Client::ListObjectMeta::pattern"], [26, 2, 1, "_CPPv4N8vineyard6Client14ListObjectMetaERKNSt6stringEKbK6size_tb", "vineyard::Client::ListObjectMeta::regex"], [26, 1, 1, "_CPPv4N8vineyard6Client11ListObjectsERKNSt6stringEKbK6size_t", "vineyard::Client::ListObjects"], [26, 2, 1, "_CPPv4N8vineyard6Client11ListObjectsERKNSt6stringEKbK6size_t", "vineyard::Client::ListObjects::limit"], [26, 2, 1, "_CPPv4N8vineyard6Client11ListObjectsERKNSt6stringEKbK6size_t", "vineyard::Client::ListObjects::pattern"], [26, 2, 1, "_CPPv4N8vineyard6Client11ListObjectsERKNSt6stringEKbK6size_t", "vineyard::Client::ListObjects::regex"], [26, 1, 1, "_CPPv4N8vineyard6Client8OnDeleteERK8ObjectID", "vineyard::Client::OnDelete"], [26, 2, 1, "_CPPv4N8vineyard6Client8OnDeleteERK8ObjectID", "vineyard::Client::OnDelete::id"], [26, 1, 1, "_CPPv4N8vineyard6Client9OnReleaseERK8ObjectID", "vineyard::Client::OnRelease"], [26, 2, 1, "_CPPv4N8vineyard6Client9OnReleaseERK8ObjectID", "vineyard::Client::OnRelease::id"], [26, 1, 1, "_CPPv4N8vineyard6Client4OpenERKNSt6stringE", "vineyard::Client::Open"], [26, 1, 1, "_CPPv4N8vineyard6Client4OpenERKNSt6stringERKNSt6stringERKNSt6stringE", "vineyard::Client::Open"], [26, 2, 1, "_CPPv4N8vineyard6Client4OpenERKNSt6stringE", "vineyard::Client::Open::ipc_socket"], [26, 2, 1, "_CPPv4N8vineyard6Client4OpenERKNSt6stringERKNSt6stringERKNSt6stringE", "vineyard::Client::Open::ipc_socket"], [26, 2, 1, "_CPPv4N8vineyard6Client4OpenERKNSt6stringERKNSt6stringERKNSt6stringE", "vineyard::Client::Open::password"], [26, 2, 1, "_CPPv4N8vineyard6Client4OpenERKNSt6stringERKNSt6stringERKNSt6stringE", "vineyard::Client::Open::username"], [26, 1, 1, "_CPPv4N8vineyard6Client8PostSealERK10ObjectMeta", "vineyard::Client::PostSeal"], [26, 2, 1, "_CPPv4N8vineyard6Client8PostSealERK10ObjectMeta", "vineyard::Client::PostSeal::meta_data"], [26, 1, 1, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDR10ObjectMeta", "vineyard::Client::PullNextStreamChunk"], [26, 1, 1, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDR8ObjectID", "vineyard::Client::PullNextStreamChunk"], [26, 1, 1, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDRNSt10shared_ptrI6ObjectEE", "vineyard::Client::PullNextStreamChunk"], [26, 1, 1, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDRNSt10unique_ptrI6BufferEE", "vineyard::Client::PullNextStreamChunk"], [26, 2, 1, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDR10ObjectMeta", "vineyard::Client::PullNextStreamChunk::chunk"], [26, 2, 1, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDR8ObjectID", "vineyard::Client::PullNextStreamChunk::chunk"], [26, 2, 1, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDRNSt10shared_ptrI6ObjectEE", "vineyard::Client::PullNextStreamChunk::chunk"], [26, 2, 1, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDRNSt10unique_ptrI6BufferEE", "vineyard::Client::PullNextStreamChunk::chunk"], [26, 2, 1, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDR10ObjectMeta", "vineyard::Client::PullNextStreamChunk::id"], [26, 2, 1, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDR8ObjectID", "vineyard::Client::PullNextStreamChunk::id"], [26, 2, 1, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDRNSt10shared_ptrI6ObjectEE", "vineyard::Client::PullNextStreamChunk::id"], [26, 2, 1, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDRNSt10unique_ptrI6BufferEE", "vineyard::Client::PullNextStreamChunk::id"], [26, 1, 1, "_CPPv4N8vineyard6Client7ReleaseERK8ObjectID", "vineyard::Client::Release"], [26, 1, 1, "_CPPv4N8vineyard6Client7ReleaseERKNSt6vectorI8ObjectIDEE", "vineyard::Client::Release"], [26, 2, 1, "_CPPv4N8vineyard6Client7ReleaseERK8ObjectID", "vineyard::Client::Release::id"], [26, 2, 1, "_CPPv4N8vineyard6Client7ReleaseERKNSt6vectorI8ObjectIDEE", "vineyard::Client::Release::ids"], [26, 1, 1, "_CPPv4N8vineyard6Client12ReleaseArenaEKiRKNSt6vectorI6size_tEERKNSt6vectorI6size_tEE", "vineyard::Client::ReleaseArena"], [26, 2, 1, "_CPPv4N8vineyard6Client12ReleaseArenaEKiRKNSt6vectorI6size_tEERKNSt6vectorI6size_tEE", "vineyard::Client::ReleaseArena::fd"], [26, 2, 1, "_CPPv4N8vineyard6Client12ReleaseArenaEKiRKNSt6vectorI6size_tEERKNSt6vectorI6size_tEE", "vineyard::Client::ReleaseArena::offsets"], [26, 2, 1, "_CPPv4N8vineyard6Client12ReleaseArenaEKiRKNSt6vectorI6size_tEERKNSt6vectorI6size_tEE", "vineyard::Client::ReleaseArena::sizes"], [26, 1, 1, "_CPPv4N8vineyard6Client4SealERK8ObjectID", "vineyard::Client::Seal"], [26, 2, 1, "_CPPv4N8vineyard6Client4SealERK8ObjectID", "vineyard::Client::Seal::object_id"], [26, 1, 1, "_CPPv4N8vineyard6Client11ShallowCopyEK8ObjectIDR8ObjectIDR6Client", "vineyard::Client::ShallowCopy"], [26, 1, 1, "_CPPv4N8vineyard6Client11ShallowCopyEK8PlasmaIDR8ObjectIDR12PlasmaClient", "vineyard::Client::ShallowCopy"], [26, 2, 1, "_CPPv4N8vineyard6Client11ShallowCopyEK8ObjectIDR8ObjectIDR6Client", "vineyard::Client::ShallowCopy::id"], [26, 2, 1, "_CPPv4N8vineyard6Client11ShallowCopyEK8PlasmaIDR8ObjectIDR12PlasmaClient", "vineyard::Client::ShallowCopy::plasma_id"], [26, 2, 1, "_CPPv4N8vineyard6Client11ShallowCopyEK8ObjectIDR8ObjectIDR6Client", "vineyard::Client::ShallowCopy::source_client"], [26, 2, 1, "_CPPv4N8vineyard6Client11ShallowCopyEK8PlasmaIDR8ObjectIDR12PlasmaClient", "vineyard::Client::ShallowCopy::source_client"], [26, 2, 1, "_CPPv4N8vineyard6Client11ShallowCopyEK8ObjectIDR8ObjectIDR6Client", "vineyard::Client::ShallowCopy::target_id"], [26, 2, 1, "_CPPv4N8vineyard6Client11ShallowCopyEK8PlasmaIDR8ObjectIDR12PlasmaClient", "vineyard::Client::ShallowCopy::target_id"], [26, 1, 1, "_CPPv4N8vineyard6Client12ShrinkBufferEK8ObjectIDK6size_t", "vineyard::Client::ShrinkBuffer"], [26, 2, 1, "_CPPv4N8vineyard6Client12ShrinkBufferEK8ObjectIDK6size_t", "vineyard::Client::ShrinkBuffer::id"], [26, 2, 1, "_CPPv4N8vineyard6Client12ShrinkBufferEK8ObjectIDK6size_t", "vineyard::Client::ShrinkBuffer::size"], [26, 1, 1, "_CPPv4N8vineyard6ClientD0Ev", "vineyard::Client::~Client"], [26, 0, 1, "_CPPv4N8vineyard10ClientBaseE", "vineyard::ClientBase"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase5ClearEv", "vineyard::ClientBase::Clear"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase10ClientBaseERK10ClientBase", "vineyard::ClientBase::ClientBase"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase10ClientBaseERR10ClientBase", "vineyard::ClientBase::ClientBase"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase10ClientBaseEv", "vineyard::ClientBase::ClientBase"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase12CloseSessionEv", "vineyard::ClientBase::CloseSession"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase11ClusterInfoERNSt3mapI10InstanceID4jsonEE", "vineyard::ClientBase::ClusterInfo"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase11ClusterInfoERNSt3mapI10InstanceID4jsonEE", "vineyard::ClientBase::ClusterInfo::meta"], [26, 1, 1, "_CPPv4NK8vineyard10ClientBase9ConnectedEv", "vineyard::ClientBase::Connected"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase10CreateDataERK4jsonR8ObjectIDR9SignatureR10InstanceID", "vineyard::ClientBase::CreateData"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase10CreateDataERK4jsonR8ObjectIDR9SignatureR10InstanceID", "vineyard::ClientBase::CreateData::id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase10CreateDataERK4jsonR8ObjectIDR9SignatureR10InstanceID", "vineyard::ClientBase::CreateData::instance_id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase10CreateDataERK4jsonR8ObjectIDR9SignatureR10InstanceID", "vineyard::ClientBase::CreateData::signature"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase10CreateDataERK4jsonR8ObjectIDR9SignatureR10InstanceID", "vineyard::ClientBase::CreateData::tree"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase14CreateMetaDataER10ObjectMetaR8ObjectID", "vineyard::ClientBase::CreateMetaData"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase14CreateMetaDataER10ObjectMetaRK10InstanceIDR8ObjectID", "vineyard::ClientBase::CreateMetaData"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase14CreateMetaDataER10ObjectMetaR8ObjectID", "vineyard::ClientBase::CreateMetaData::id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase14CreateMetaDataER10ObjectMetaRK10InstanceIDR8ObjectID", "vineyard::ClientBase::CreateMetaData::id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase14CreateMetaDataER10ObjectMetaRK10InstanceIDR8ObjectID", "vineyard::ClientBase::CreateMetaData::instance_id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase14CreateMetaDataER10ObjectMetaR8ObjectID", "vineyard::ClientBase::CreateMetaData::meta_data"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase14CreateMetaDataER10ObjectMetaRK10InstanceIDR8ObjectID", "vineyard::ClientBase::CreateMetaData::meta_data"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase12CreateStreamERK8ObjectID", "vineyard::ClientBase::CreateStream"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase12CreateStreamERK8ObjectID", "vineyard::ClientBase::CreateStream::id"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase5DebugERK4jsonR4json", "vineyard::ClientBase::Debug"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase5DebugERK4jsonR4json", "vineyard::ClientBase::Debug::debug"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase5DebugERK4jsonR4json", "vineyard::ClientBase::Debug::tree"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase7DelDataEK8ObjectIDKbKb", "vineyard::ClientBase::DelData"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase7DelDataERKNSt6vectorI8ObjectIDEEKbKb", "vineyard::ClientBase::DelData"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7DelDataEK8ObjectIDKbKb", "vineyard::ClientBase::DelData::deep"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7DelDataERKNSt6vectorI8ObjectIDEEKbKb", "vineyard::ClientBase::DelData::deep"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7DelDataEK8ObjectIDKbKb", "vineyard::ClientBase::DelData::force"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7DelDataERKNSt6vectorI8ObjectIDEEKbKb", "vineyard::ClientBase::DelData::force"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7DelDataEK8ObjectIDKbKb", "vineyard::ClientBase::DelData::id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7DelDataERKNSt6vectorI8ObjectIDEEKbKb", "vineyard::ClientBase::DelData::ids"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase10DisconnectEv", "vineyard::ClientBase::Disconnect"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase8DropNameERKNSt6stringE", "vineyard::ClientBase::DropName"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase8DropNameERKNSt6stringE", "vineyard::ClientBase::DropName::name"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase10DropStreamEK8ObjectID", "vineyard::ClientBase::DropStream"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase10DropStreamEK8ObjectID", "vineyard::ClientBase::DropStream::id"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase5EvictERKNSt6vectorI8ObjectIDEE", "vineyard::ClientBase::Evict"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase5EvictERKNSt6vectorI8ObjectIDEE", "vineyard::ClientBase::Evict::objects"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase6ExistsEK8ObjectIDRb", "vineyard::ClientBase::Exists"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase6ExistsEK8ObjectIDRb", "vineyard::ClientBase::Exists::exists"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase6ExistsEK8ObjectIDRb", "vineyard::ClientBase::Exists::id"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase7GetDataEK8ObjectIDR4jsonKbKb", "vineyard::ClientBase::GetData"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase7GetDataERKNSt6vectorI8ObjectIDEERNSt6vectorI4jsonEEKbKb", "vineyard::ClientBase::GetData"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7GetDataEK8ObjectIDR4jsonKbKb", "vineyard::ClientBase::GetData::id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7GetDataERKNSt6vectorI8ObjectIDEERNSt6vectorI4jsonEEKbKb", "vineyard::ClientBase::GetData::ids"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7GetDataEK8ObjectIDR4jsonKbKb", "vineyard::ClientBase::GetData::sync_remote"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7GetDataERKNSt6vectorI8ObjectIDEERNSt6vectorI4jsonEEKbKb", "vineyard::ClientBase::GetData::sync_remote"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7GetDataEK8ObjectIDR4jsonKbKb", "vineyard::ClientBase::GetData::tree"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7GetDataERKNSt6vectorI8ObjectIDEERNSt6vectorI4jsonEEKbKb", "vineyard::ClientBase::GetData::trees"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7GetDataEK8ObjectIDR4jsonKbKb", "vineyard::ClientBase::GetData::wait"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7GetDataERKNSt6vectorI8ObjectIDEERNSt6vectorI4jsonEEKbKb", "vineyard::ClientBase::GetData::wait"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase11GetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::ClientBase::GetMetaData"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase11GetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::ClientBase::GetMetaData::id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase11GetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::ClientBase::GetMetaData::meta_data"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase11GetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::ClientBase::GetMetaData::sync_remote"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase7GetNameERKNSt6stringER8ObjectIDKb", "vineyard::ClientBase::GetName"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7GetNameERKNSt6stringER8ObjectIDKb", "vineyard::ClientBase::GetName::id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7GetNameERKNSt6stringER8ObjectIDKb", "vineyard::ClientBase::GetName::name"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7GetNameERKNSt6stringER8ObjectIDKb", "vineyard::ClientBase::GetName::wait"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase9IPCSocketEv", "vineyard::ClientBase::IPCSocket"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase9IfPersistEK8ObjectIDRb", "vineyard::ClientBase::IfPersist"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase9IfPersistEK8ObjectIDRb", "vineyard::ClientBase::IfPersist::id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase9IfPersistEK8ObjectIDRb", "vineyard::ClientBase::IfPersist::persist"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase14InstanceStatusERNSt10shared_ptrI14InstanceStatusEE", "vineyard::ClientBase::InstanceStatus"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase14InstanceStatusERNSt10shared_ptrI14InstanceStatusEE", "vineyard::ClientBase::InstanceStatus::status"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase9InstancesERNSt6vectorI10InstanceIDEE", "vineyard::ClientBase::Instances"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase9InstancesERNSt6vectorI10InstanceIDEE", "vineyard::ClientBase::Instances::instances"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase5LabelEK8ObjectIDRKNSt3mapINSt6stringENSt6stringEEE", "vineyard::ClientBase::Label"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase5LabelEK8ObjectIDRKNSt6stringERKNSt6stringE", "vineyard::ClientBase::Label"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase5LabelEK8ObjectIDRKNSt6stringERKNSt6stringE", "vineyard::ClientBase::Label::key"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase5LabelEK8ObjectIDRKNSt3mapINSt6stringENSt6stringEEE", "vineyard::ClientBase::Label::labels"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase5LabelEK8ObjectIDRKNSt3mapINSt6stringENSt6stringEEE", "vineyard::ClientBase::Label::object"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase5LabelEK8ObjectIDRKNSt6stringERKNSt6stringE", "vineyard::ClientBase::Label::object"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase5LabelEK8ObjectIDRKNSt6stringERKNSt6stringE", "vineyard::ClientBase::Label::value"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase8ListDataERKNSt6stringEKbK6size_tRNSt13unordered_mapI8ObjectID4jsonEE", "vineyard::ClientBase::ListData"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase8ListDataERKNSt6stringEKbK6size_tRNSt13unordered_mapI8ObjectID4jsonEE", "vineyard::ClientBase::ListData::limit"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase8ListDataERKNSt6stringEKbK6size_tRNSt13unordered_mapI8ObjectID4jsonEE", "vineyard::ClientBase::ListData::meta_trees"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase8ListDataERKNSt6stringEKbK6size_tRNSt13unordered_mapI8ObjectID4jsonEE", "vineyard::ClientBase::ListData::pattern"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase8ListDataERKNSt6stringEKbK6size_tRNSt13unordered_mapI8ObjectID4jsonEE", "vineyard::ClientBase::ListData::regex"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase9ListNamesERKNSt6stringEKbK6size_tRNSt3mapINSt6stringE8ObjectIDEE", "vineyard::ClientBase::ListNames"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase9ListNamesERKNSt6stringEKbK6size_tRNSt3mapINSt6stringE8ObjectIDEE", "vineyard::ClientBase::ListNames::limit"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase9ListNamesERKNSt6stringEKbK6size_tRNSt3mapINSt6stringE8ObjectIDEE", "vineyard::ClientBase::ListNames::names"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase9ListNamesERKNSt6stringEKbK6size_tRNSt3mapINSt6stringE8ObjectIDEE", "vineyard::ClientBase::ListNames::pattern"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase9ListNamesERKNSt6stringEKbK6size_tRNSt3mapINSt6stringE8ObjectIDEE", "vineyard::ClientBase::ListNames::regex"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase4LoadERKNSt6vectorI8ObjectIDEEKb", "vineyard::ClientBase::Load"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase4LoadERKNSt6vectorI8ObjectIDEEKb", "vineyard::ClientBase::Load::objects"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase4LoadERKNSt6vectorI8ObjectIDEEKb", "vineyard::ClientBase::Load::pin"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase13MigrateObjectEK8ObjectIDR8ObjectID", "vineyard::ClientBase::MigrateObject"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase13MigrateObjectEK8ObjectIDR8ObjectID", "vineyard::ClientBase::MigrateObject::object_id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase13MigrateObjectEK8ObjectIDR8ObjectID", "vineyard::ClientBase::MigrateObject::result_id"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase4OpenERKNSt6stringE", "vineyard::ClientBase::Open"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase4OpenERKNSt6stringE", "vineyard::ClientBase::Open::ipc_socket"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase10OpenStreamERK8ObjectID14StreamOpenMode", "vineyard::ClientBase::OpenStream"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase10OpenStreamERK8ObjectID14StreamOpenMode", "vineyard::ClientBase::OpenStream::id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase10OpenStreamERK8ObjectID14StreamOpenMode", "vineyard::ClientBase::OpenStream::mode"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase7PersistEK8ObjectID", "vineyard::ClientBase::Persist"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7PersistEK8ObjectID", "vineyard::ClientBase::Persist::id"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase19PullNextStreamChunkEK8ObjectIDR10ObjectMeta", "vineyard::ClientBase::PullNextStreamChunk"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase19PullNextStreamChunkEK8ObjectIDR8ObjectID", "vineyard::ClientBase::PullNextStreamChunk"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase19PullNextStreamChunkEK8ObjectIDRNSt10shared_ptrI6ObjectEE", "vineyard::ClientBase::PullNextStreamChunk"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase19PullNextStreamChunkEK8ObjectIDR10ObjectMeta", "vineyard::ClientBase::PullNextStreamChunk::chunk"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase19PullNextStreamChunkEK8ObjectIDR8ObjectID", "vineyard::ClientBase::PullNextStreamChunk::chunk"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase19PullNextStreamChunkEK8ObjectIDRNSt10shared_ptrI6ObjectEE", "vineyard::ClientBase::PullNextStreamChunk::chunk"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase19PullNextStreamChunkEK8ObjectIDR10ObjectMeta", "vineyard::ClientBase::PullNextStreamChunk::id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase19PullNextStreamChunkEK8ObjectIDR8ObjectID", "vineyard::ClientBase::PullNextStreamChunk::id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase19PullNextStreamChunkEK8ObjectIDRNSt10shared_ptrI6ObjectEE", "vineyard::ClientBase::PullNextStreamChunk::id"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase19PushNextStreamChunkEK8ObjectIDK8ObjectID", "vineyard::ClientBase::PushNextStreamChunk"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase19PushNextStreamChunkEK8ObjectIDK8ObjectID", "vineyard::ClientBase::PushNextStreamChunk::chunk"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase19PushNextStreamChunkEK8ObjectIDK8ObjectID", "vineyard::ClientBase::PushNextStreamChunk::id"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase7PutNameEK8ObjectIDRKNSt6stringE", "vineyard::ClientBase::PutName"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7PutNameEK8ObjectIDRKNSt6stringE", "vineyard::ClientBase::PutName::id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7PutNameEK8ObjectIDRKNSt6stringE", "vineyard::ClientBase::PutName::name"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase11RPCEndpointEv", "vineyard::ClientBase::RPCEndpoint"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase7ReleaseERK8ObjectID", "vineyard::ClientBase::Release"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7ReleaseERK8ObjectID", "vineyard::ClientBase::Release::id"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase11ShallowCopyEK8ObjectIDR8ObjectID", "vineyard::ClientBase::ShallowCopy"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase11ShallowCopyEK8ObjectIDRK4jsonR8ObjectID", "vineyard::ClientBase::ShallowCopy"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase11ShallowCopyEK8ObjectIDRK4jsonR8ObjectID", "vineyard::ClientBase::ShallowCopy::extra_metadata"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase11ShallowCopyEK8ObjectIDR8ObjectID", "vineyard::ClientBase::ShallowCopy::id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase11ShallowCopyEK8ObjectIDRK4jsonR8ObjectID", "vineyard::ClientBase::ShallowCopy::id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase11ShallowCopyEK8ObjectIDR8ObjectID", "vineyard::ClientBase::ShallowCopy::target_id"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase11ShallowCopyEK8ObjectIDRK4jsonR8ObjectID", "vineyard::ClientBase::ShallowCopy::target_id"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase10StopStreamEK8ObjectIDb", "vineyard::ClientBase::StopStream"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase10StopStreamEK8ObjectIDb", "vineyard::ClientBase::StopStream::failed"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase10StopStreamEK8ObjectIDb", "vineyard::ClientBase::StopStream::id"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase12SyncMetaDataEv", "vineyard::ClientBase::SyncMetaData"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase5UnpinERKNSt6vectorI8ObjectIDEE", "vineyard::ClientBase::Unpin"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase5UnpinERKNSt6vectorI8ObjectIDEE", "vineyard::ClientBase::Unpin::objects"], [26, 1, 1, "_CPPv4NK8vineyard10ClientBase7VersionEv", "vineyard::ClientBase::Version"], [26, 4, 1, "_CPPv4N8vineyard10ClientBase13client_mutex_E", "vineyard::ClientBase::client_mutex_"], [26, 4, 1, "_CPPv4N8vineyard10ClientBase10connected_E", "vineyard::ClientBase::connected_"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase6doReadER4json", "vineyard::ClientBase::doRead"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase6doReadERNSt6stringE", "vineyard::ClientBase::doRead"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase6doReadERNSt6stringE", "vineyard::ClientBase::doRead::message_in"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase6doReadER4json", "vineyard::ClientBase::doRead::root"], [26, 1, 1, "_CPPv4N8vineyard10ClientBase7doWriteERKNSt6stringE", "vineyard::ClientBase::doWrite"], [26, 2, 1, "_CPPv4N8vineyard10ClientBase7doWriteERKNSt6stringE", "vineyard::ClientBase::doWrite::message_out"], [26, 1, 1, "_CPPv4NK8vineyard10ClientBase11instance_idEv", "vineyard::ClientBase::instance_id"], [26, 4, 1, "_CPPv4N8vineyard10ClientBase12instance_id_E", "vineyard::ClientBase::instance_id_"], [26, 4, 1, "_CPPv4N8vineyard10ClientBase11ipc_socket_E", "vineyard::ClientBase::ipc_socket_"], [26, 1, 1, "_CPPv4N8vineyard10ClientBaseaSERK10ClientBase", "vineyard::ClientBase::operator="], [26, 1, 1, "_CPPv4N8vineyard10ClientBaseaSERR10ClientBase", "vineyard::ClientBase::operator="], [26, 1, 1, "_CPPv4NK8vineyard10ClientBase18remote_instance_idEv", "vineyard::ClientBase::remote_instance_id"], [26, 4, 1, "_CPPv4N8vineyard10ClientBase13rpc_endpoint_E", "vineyard::ClientBase::rpc_endpoint_"], [26, 4, 1, "_CPPv4N8vineyard10ClientBase15server_version_E", "vineyard::ClientBase::server_version_"], [26, 1, 1, "_CPPv4NK8vineyard10ClientBase10session_idEv", "vineyard::ClientBase::session_id"], [26, 4, 1, "_CPPv4N8vineyard10ClientBase11session_id_E", "vineyard::ClientBase::session_id_"], [26, 4, 1, "_CPPv4N8vineyard10ClientBase14vineyard_conn_E", "vineyard::ClientBase::vineyard_conn_"], [26, 1, 1, "_CPPv4N8vineyard10ClientBaseD0Ev", "vineyard::ClientBase::~ClientBase"], [26, 0, 1, "_CPPv4N8vineyard9DataFrameE", "vineyard::DataFrame"], [26, 1, 1, "_CPPv4NK8vineyard9DataFrame7AsBatchEb", "vineyard::DataFrame::AsBatch"], [26, 2, 1, "_CPPv4NK8vineyard9DataFrame7AsBatchEb", "vineyard::DataFrame::AsBatch::copy"], [26, 1, 1, "_CPPv4NK8vineyard9DataFrame6ColumnERK4json", "vineyard::DataFrame::Column"], [26, 2, 1, "_CPPv4NK8vineyard9DataFrame6ColumnERK4json", "vineyard::DataFrame::Column::column"], [26, 1, 1, "_CPPv4NK8vineyard9DataFrame7ColumnsEv", "vineyard::DataFrame::Columns"], [26, 1, 1, "_CPPv4N8vineyard9DataFrame9ConstructERK10ObjectMeta", "vineyard::DataFrame::Construct"], [26, 2, 1, "_CPPv4N8vineyard9DataFrame9ConstructERK10ObjectMeta", "vineyard::DataFrame::Construct::meta"], [26, 1, 1, "_CPPv4N8vineyard9DataFrame6CreateEv", "vineyard::DataFrame::Create"], [26, 1, 1, "_CPPv4NK8vineyard9DataFrame5IndexEv", "vineyard::DataFrame::Index"], [26, 1, 1, "_CPPv4NK8vineyard9DataFrame15partition_indexEv", "vineyard::DataFrame::partition_index"], [26, 1, 1, "_CPPv4NK8vineyard9DataFrame5shapeEv", "vineyard::DataFrame::shape"], [26, 0, 1, "_CPPv4N8vineyard16DataFrameBuilderE", "vineyard::DataFrameBuilder"], [26, 1, 1, "_CPPv4N8vineyard16DataFrameBuilder9AddColumnERK4jsonNSt10shared_ptrI14ITensorBuilderEE", "vineyard::DataFrameBuilder::AddColumn"], [26, 2, 1, "_CPPv4N8vineyard16DataFrameBuilder9AddColumnERK4jsonNSt10shared_ptrI14ITensorBuilderEE", "vineyard::DataFrameBuilder::AddColumn::builder"], [26, 2, 1, "_CPPv4N8vineyard16DataFrameBuilder9AddColumnERK4jsonNSt10shared_ptrI14ITensorBuilderEE", "vineyard::DataFrameBuilder::AddColumn::column"], [26, 1, 1, "_CPPv4N8vineyard16DataFrameBuilder5BuildER6Client", "vineyard::DataFrameBuilder::Build"], [26, 2, 1, "_CPPv4N8vineyard16DataFrameBuilder5BuildER6Client", "vineyard::DataFrameBuilder::Build::client"], [26, 1, 1, "_CPPv4NK8vineyard16DataFrameBuilder6ColumnERK4json", "vineyard::DataFrameBuilder::Column"], [26, 2, 1, "_CPPv4NK8vineyard16DataFrameBuilder6ColumnERK4json", "vineyard::DataFrameBuilder::Column::column"], [26, 1, 1, "_CPPv4N8vineyard16DataFrameBuilder16DataFrameBuilderER6Client", "vineyard::DataFrameBuilder::DataFrameBuilder"], [26, 2, 1, "_CPPv4N8vineyard16DataFrameBuilder16DataFrameBuilderER6Client", "vineyard::DataFrameBuilder::DataFrameBuilder::client"], [26, 1, 1, "_CPPv4N8vineyard16DataFrameBuilder10DropColumnERK4json", "vineyard::DataFrameBuilder::DropColumn"], [26, 2, 1, "_CPPv4N8vineyard16DataFrameBuilder10DropColumnERK4json", "vineyard::DataFrameBuilder::DropColumn::column"], [26, 1, 1, "_CPPv4NK8vineyard16DataFrameBuilder15partition_indexEv", "vineyard::DataFrameBuilder::partition_index"], [26, 1, 1, "_CPPv4N8vineyard16DataFrameBuilder9set_indexENSt10shared_ptrI14ITensorBuilderEE", "vineyard::DataFrameBuilder::set_index"], [26, 2, 1, "_CPPv4N8vineyard16DataFrameBuilder9set_indexENSt10shared_ptrI14ITensorBuilderEE", "vineyard::DataFrameBuilder::set_index::builder"], [26, 1, 1, "_CPPv4N8vineyard16DataFrameBuilder19set_partition_indexE6size_t6size_t", "vineyard::DataFrameBuilder::set_partition_index"], [26, 2, 1, "_CPPv4N8vineyard16DataFrameBuilder19set_partition_indexE6size_t6size_t", "vineyard::DataFrameBuilder::set_partition_index::partition_index_column"], [26, 2, 1, "_CPPv4N8vineyard16DataFrameBuilder19set_partition_indexE6size_t6size_t", "vineyard::DataFrameBuilder::set_partition_index::partition_index_row"], [26, 1, 1, "_CPPv4N8vineyard16DataFrameBuilder19set_row_batch_indexE6size_t", "vineyard::DataFrameBuilder::set_row_batch_index"], [26, 2, 1, "_CPPv4N8vineyard16DataFrameBuilder19set_row_batch_indexE6size_t", "vineyard::DataFrameBuilder::set_row_batch_index::row_batch_index"], [26, 0, 1, "_CPPv4N8vineyard15GlobalDataFrameE", "vineyard::GlobalDataFrame"], [26, 1, 1, "_CPPv4N8vineyard15GlobalDataFrame6CreateEv", "vineyard::GlobalDataFrame::Create"], [26, 1, 1, "_CPPv4NK8vineyard15GlobalDataFrame15LocalPartitionsER6Client", "vineyard::GlobalDataFrame::LocalPartitions"], [26, 2, 1, "_CPPv4NK8vineyard15GlobalDataFrame15LocalPartitionsER6Client", "vineyard::GlobalDataFrame::LocalPartitions::client"], [26, 1, 1, "_CPPv4N8vineyard15GlobalDataFrame13PostConstructERK10ObjectMeta", "vineyard::GlobalDataFrame::PostConstruct"], [26, 2, 1, "_CPPv4N8vineyard15GlobalDataFrame13PostConstructERK10ObjectMeta", "vineyard::GlobalDataFrame::PostConstruct::meta"], [26, 1, 1, "_CPPv4NK8vineyard15GlobalDataFrame15partition_shapeEv", "vineyard::GlobalDataFrame::partition_shape"], [26, 0, 1, "_CPPv4N8vineyard22GlobalDataFrameBuilderE", "vineyard::GlobalDataFrameBuilder"], [26, 1, 1, "_CPPv4N8vineyard22GlobalDataFrameBuilder12AddPartitionEK8ObjectID", "vineyard::GlobalDataFrameBuilder::AddPartition"], [26, 2, 1, "_CPPv4N8vineyard22GlobalDataFrameBuilder12AddPartitionEK8ObjectID", "vineyard::GlobalDataFrameBuilder::AddPartition::partition_id"], [26, 1, 1, "_CPPv4N8vineyard22GlobalDataFrameBuilder13AddPartitionsERKNSt6vectorI8ObjectIDEE", "vineyard::GlobalDataFrameBuilder::AddPartitions"], [26, 2, 1, "_CPPv4N8vineyard22GlobalDataFrameBuilder13AddPartitionsERKNSt6vectorI8ObjectIDEE", "vineyard::GlobalDataFrameBuilder::AddPartitions::partition_ids"], [26, 1, 1, "_CPPv4N8vineyard22GlobalDataFrameBuilder22GlobalDataFrameBuilderER6Client", "vineyard::GlobalDataFrameBuilder::GlobalDataFrameBuilder"], [26, 2, 1, "_CPPv4N8vineyard22GlobalDataFrameBuilder22GlobalDataFrameBuilderER6Client", "vineyard::GlobalDataFrameBuilder::GlobalDataFrameBuilder::client"], [26, 1, 1, "_CPPv4NK8vineyard22GlobalDataFrameBuilder15partition_shapeEv", "vineyard::GlobalDataFrameBuilder::partition_shape"], [26, 1, 1, "_CPPv4N8vineyard22GlobalDataFrameBuilder19set_partition_shapeEK6size_tK6size_t", "vineyard::GlobalDataFrameBuilder::set_partition_shape"], [26, 2, 1, "_CPPv4N8vineyard22GlobalDataFrameBuilder19set_partition_shapeEK6size_tK6size_t", "vineyard::GlobalDataFrameBuilder::set_partition_shape::partition_shape_column"], [26, 2, 1, "_CPPv4N8vineyard22GlobalDataFrameBuilder19set_partition_shapeEK6size_tK6size_t", "vineyard::GlobalDataFrameBuilder::set_partition_shape::partition_shape_row"], [26, 0, 1, "_CPPv4N8vineyard12GlobalTensorE", "vineyard::GlobalTensor"], [26, 1, 1, "_CPPv4N8vineyard12GlobalTensor6CreateEv", "vineyard::GlobalTensor::Create"], [26, 1, 1, "_CPPv4NK8vineyard12GlobalTensor15LocalPartitionsER6Client", "vineyard::GlobalTensor::LocalPartitions"], [26, 2, 1, "_CPPv4NK8vineyard12GlobalTensor15LocalPartitionsER6Client", "vineyard::GlobalTensor::LocalPartitions::client"], [26, 1, 1, "_CPPv4N8vineyard12GlobalTensor13PostConstructERK10ObjectMeta", "vineyard::GlobalTensor::PostConstruct"], [26, 2, 1, "_CPPv4N8vineyard12GlobalTensor13PostConstructERK10ObjectMeta", "vineyard::GlobalTensor::PostConstruct::meta"], [26, 1, 1, "_CPPv4NK8vineyard12GlobalTensor15partition_shapeEv", "vineyard::GlobalTensor::partition_shape"], [26, 1, 1, "_CPPv4NK8vineyard12GlobalTensor5shapeEv", "vineyard::GlobalTensor::shape"], [26, 0, 1, "_CPPv4N8vineyard19GlobalTensorBuilderE", "vineyard::GlobalTensorBuilder"], [26, 1, 1, "_CPPv4N8vineyard19GlobalTensorBuilder12AddPartitionEK8ObjectID", "vineyard::GlobalTensorBuilder::AddPartition"], [26, 2, 1, "_CPPv4N8vineyard19GlobalTensorBuilder12AddPartitionEK8ObjectID", "vineyard::GlobalTensorBuilder::AddPartition::partition_id"], [26, 1, 1, "_CPPv4N8vineyard19GlobalTensorBuilder13AddPartitionsERKNSt6vectorI8ObjectIDEE", "vineyard::GlobalTensorBuilder::AddPartitions"], [26, 2, 1, "_CPPv4N8vineyard19GlobalTensorBuilder13AddPartitionsERKNSt6vectorI8ObjectIDEE", "vineyard::GlobalTensorBuilder::AddPartitions::partition_ids"], [26, 1, 1, "_CPPv4N8vineyard19GlobalTensorBuilder19GlobalTensorBuilderER6Client", "vineyard::GlobalTensorBuilder::GlobalTensorBuilder"], [26, 2, 1, "_CPPv4N8vineyard19GlobalTensorBuilder19GlobalTensorBuilderER6Client", "vineyard::GlobalTensorBuilder::GlobalTensorBuilder::client"], [26, 1, 1, "_CPPv4NK8vineyard19GlobalTensorBuilder15partition_shapeEv", "vineyard::GlobalTensorBuilder::partition_shape"], [26, 1, 1, "_CPPv4N8vineyard19GlobalTensorBuilder19set_partition_shapeERKNSt6vectorI7int64_tEE", "vineyard::GlobalTensorBuilder::set_partition_shape"], [26, 2, 1, "_CPPv4N8vineyard19GlobalTensorBuilder19set_partition_shapeERKNSt6vectorI7int64_tEE", "vineyard::GlobalTensorBuilder::set_partition_shape::partition_shape"], [26, 1, 1, "_CPPv4N8vineyard19GlobalTensorBuilder9set_shapeERKNSt6vectorI7int64_tEE", "vineyard::GlobalTensorBuilder::set_shape"], [26, 2, 1, "_CPPv4N8vineyard19GlobalTensorBuilder9set_shapeERKNSt6vectorI7int64_tEE", "vineyard::GlobalTensorBuilder::set_shape::shape"], [26, 1, 1, "_CPPv4NK8vineyard19GlobalTensorBuilder5shapeEv", "vineyard::GlobalTensorBuilder::shape"], [26, 0, 1, "_CPPv4I0000EN8vineyard7HashmapE", "vineyard::Hashmap"], [26, 1, 1, "_CPPv4N8vineyard7Hashmap9ConstructERK10ObjectMeta", "vineyard::Hashmap::Construct"], [26, 2, 1, "_CPPv4N8vineyard7Hashmap9ConstructERK10ObjectMeta", "vineyard::Hashmap::Construct::meta"], [26, 1, 1, "_CPPv4N8vineyard7Hashmap6CreateEv", "vineyard::Hashmap::Create"], [26, 3, 1, "_CPPv4I0000EN8vineyard7HashmapE", "vineyard::Hashmap::E"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap5EntryE", "vineyard::Hashmap::Entry"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap12EntryPointerE", "vineyard::Hashmap::EntryPointer"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap5EqualE", "vineyard::Hashmap::Equal"], [26, 3, 1, "_CPPv4I0000EN8vineyard7HashmapE", "vineyard::Hashmap::H"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap6HasherE", "vineyard::Hashmap::Hasher"], [26, 3, 1, "_CPPv4I0000EN8vineyard7HashmapE", "vineyard::Hashmap::K"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap8KeyEqualE", "vineyard::Hashmap::KeyEqual"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap7KeyHashE", "vineyard::Hashmap::KeyHash"], [26, 1, 1, "_CPPv4N8vineyard7Hashmap13PostConstructERK10ObjectMeta", "vineyard::Hashmap::PostConstruct"], [26, 2, 1, "_CPPv4N8vineyard7Hashmap13PostConstructERK10ObjectMeta", "vineyard::Hashmap::PostConstruct::meta"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap1TE", "vineyard::Hashmap::T"], [26, 3, 1, "_CPPv4I0000EN8vineyard7HashmapE", "vineyard::Hashmap::V"], [26, 1, 1, "_CPPv4NK8vineyard7Hashmap2atERK1K", "vineyard::Hashmap::at"], [26, 2, 1, "_CPPv4NK8vineyard7Hashmap2atERK1K", "vineyard::Hashmap::at::key"], [26, 1, 1, "_CPPv4NK8vineyard7Hashmap5beginEv", "vineyard::Hashmap::begin"], [26, 1, 1, "_CPPv4NK8vineyard7Hashmap12bucket_countEv", "vineyard::Hashmap::bucket_count"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap13const_pointerE", "vineyard::Hashmap::const_pointer"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap15const_referenceE", "vineyard::Hashmap::const_reference"], [26, 1, 1, "_CPPv4NK8vineyard7Hashmap5countERK1K", "vineyard::Hashmap::count"], [26, 2, 1, "_CPPv4NK8vineyard7Hashmap5countERK1K", "vineyard::Hashmap::count::key"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap15difference_typeE", "vineyard::Hashmap::difference_type"], [26, 1, 1, "_CPPv4NK8vineyard7Hashmap5emptyEv", "vineyard::Hashmap::empty"], [26, 1, 1, "_CPPv4NK8vineyard7Hashmap3endEv", "vineyard::Hashmap::end"], [26, 1, 1, "_CPPv4N8vineyard7Hashmap4findERK1K", "vineyard::Hashmap::find"], [26, 1, 1, "_CPPv4NK8vineyard7Hashmap4findERK1K", "vineyard::Hashmap::find"], [26, 2, 1, "_CPPv4N8vineyard7Hashmap4findERK1K", "vineyard::Hashmap::find::key"], [26, 2, 1, "_CPPv4NK8vineyard7Hashmap4findERK1K", "vineyard::Hashmap::find::key"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap20flat_hash_table_typeE", "vineyard::Hashmap::flat_hash_table_type"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap6hasherE", "vineyard::Hashmap::hasher"], [26, 0, 1, "_CPPv4N8vineyard7Hashmap8iteratorE", "vineyard::Hashmap::iterator"], [26, 4, 1, "_CPPv4N8vineyard7Hashmap8iterator7currentE", "vineyard::Hashmap::iterator::current"], [26, 1, 1, "_CPPv4N8vineyard7Hashmap8iterator8iteratorE12EntryPointer", "vineyard::Hashmap::iterator::iterator"], [26, 1, 1, "_CPPv4N8vineyard7Hashmap8iterator8iteratorEv", "vineyard::Hashmap::iterator::iterator"], [26, 2, 1, "_CPPv4N8vineyard7Hashmap8iterator8iteratorE12EntryPointer", "vineyard::Hashmap::iterator::iterator::current"], [26, 1, 1, "_CPPv4N8vineyard7Hashmap8iteratorneERK8iteratorRK8iterator", "vineyard::Hashmap::iterator::operator!="], [26, 2, 1, "_CPPv4N8vineyard7Hashmap8iteratorneERK8iteratorRK8iterator", "vineyard::Hashmap::iterator::operator!=::lhs"], [26, 2, 1, "_CPPv4N8vineyard7Hashmap8iteratorneERK8iteratorRK8iterator", "vineyard::Hashmap::iterator::operator!=::rhs"], [26, 1, 1, "_CPPv4NK8vineyard7Hashmap8iteratormlEv", "vineyard::Hashmap::iterator::operator*"], [26, 1, 1, "_CPPv4N8vineyard7Hashmap8iteratorppEi", "vineyard::Hashmap::iterator::operator++"], [26, 1, 1, "_CPPv4N8vineyard7Hashmap8iteratorppEv", "vineyard::Hashmap::iterator::operator++"], [26, 1, 1, "_CPPv4NK8vineyard7Hashmap8iteratorptEv", "vineyard::Hashmap::iterator::operator->"], [26, 1, 1, "_CPPv4N8vineyard7Hashmap8iteratoreqERK8iteratorRK8iterator", "vineyard::Hashmap::iterator::operator=="], [26, 2, 1, "_CPPv4N8vineyard7Hashmap8iteratoreqERK8iteratorRK8iterator", "vineyard::Hashmap::iterator::operator==::lhs"], [26, 2, 1, "_CPPv4N8vineyard7Hashmap8iteratoreqERK8iteratorRK8iterator", "vineyard::Hashmap::iterator::operator==::rhs"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap9key_equalE", "vineyard::Hashmap::key_equal"], [26, 1, 1, "_CPPv4NK8vineyard7Hashmap11load_factorEv", "vineyard::Hashmap::load_factor"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap7pointerE", "vineyard::Hashmap::pointer"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap9referenceE", "vineyard::Hashmap::reference"], [26, 1, 1, "_CPPv4NK8vineyard7Hashmap4sizeEv", "vineyard::Hashmap::size"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap9size_typeE", "vineyard::Hashmap::size_type"], [26, 5, 1, "_CPPv4N8vineyard7Hashmap10value_typeE", "vineyard::Hashmap::value_type"], [26, 0, 1, "_CPPv4I0000EN8vineyard14HashmapBuilderE", "vineyard::HashmapBuilder"], [26, 1, 1, "_CPPv4N8vineyard14HashmapBuilder19AssociateDataBufferENSt10shared_ptrI4BlobEE", "vineyard::HashmapBuilder::AssociateDataBuffer"], [26, 2, 1, "_CPPv4N8vineyard14HashmapBuilder19AssociateDataBufferENSt10shared_ptrI4BlobEE", "vineyard::HashmapBuilder::AssociateDataBuffer::data_buffer"], [26, 1, 1, "_CPPv4N8vineyard14HashmapBuilder5BuildER6Client", "vineyard::HashmapBuilder::Build"], [26, 2, 1, "_CPPv4N8vineyard14HashmapBuilder5BuildER6Client", "vineyard::HashmapBuilder::Build::client"], [26, 3, 1, "_CPPv4I0000EN8vineyard14HashmapBuilderE", "vineyard::HashmapBuilder::E"], [26, 3, 1, "_CPPv4I0000EN8vineyard14HashmapBuilderE", "vineyard::HashmapBuilder::H"], [26, 1, 1, "_CPPv4N8vineyard14HashmapBuilder14HashmapBuilderER6Client", "vineyard::HashmapBuilder::HashmapBuilder"], [26, 1, 1, "_CPPv4N8vineyard14HashmapBuilder14HashmapBuilderER6ClientRRN3ska13flat_hash_mapI1K1V1H1EEE", "vineyard::HashmapBuilder::HashmapBuilder"], [26, 2, 1, "_CPPv4N8vineyard14HashmapBuilder14HashmapBuilderER6Client", "vineyard::HashmapBuilder::HashmapBuilder::client"], [26, 2, 1, "_CPPv4N8vineyard14HashmapBuilder14HashmapBuilderER6ClientRRN3ska13flat_hash_mapI1K1V1H1EEE", "vineyard::HashmapBuilder::HashmapBuilder::client"], [26, 2, 1, "_CPPv4N8vineyard14HashmapBuilder14HashmapBuilderER6ClientRRN3ska13flat_hash_mapI1K1V1H1EEE", "vineyard::HashmapBuilder::HashmapBuilder::hashmap"], [26, 3, 1, "_CPPv4I0000EN8vineyard14HashmapBuilderE", "vineyard::HashmapBuilder::K"], [26, 3, 1, "_CPPv4I0000EN8vineyard14HashmapBuilderE", "vineyard::HashmapBuilder::V"], [26, 1, 1, "_CPPv4N8vineyard14HashmapBuilder2atERK1K", "vineyard::HashmapBuilder::at"], [26, 1, 1, "_CPPv4NK8vineyard14HashmapBuilder2atERK1K", "vineyard::HashmapBuilder::at"], [26, 2, 1, "_CPPv4N8vineyard14HashmapBuilder2atERK1K", "vineyard::HashmapBuilder::at::key"], [26, 2, 1, "_CPPv4NK8vineyard14HashmapBuilder2atERK1K", "vineyard::HashmapBuilder::at::key"], [26, 1, 1, "_CPPv4N8vineyard14HashmapBuilder5beginEv", "vineyard::HashmapBuilder::begin"], [26, 1, 1, "_CPPv4NK8vineyard14HashmapBuilder5beginEv", "vineyard::HashmapBuilder::begin"], [26, 1, 1, "_CPPv4NK8vineyard14HashmapBuilder12bucket_countEv", "vineyard::HashmapBuilder::bucket_count"], [26, 1, 1, "_CPPv4NK8vineyard14HashmapBuilder6cbeginEv", "vineyard::HashmapBuilder::cbegin"], [26, 1, 1, "_CPPv4NK8vineyard14HashmapBuilder4cendEv", "vineyard::HashmapBuilder::cend"], [26, 1, 1, "_CPPv4IDpEN8vineyard14HashmapBuilder7emplaceEbDpRR4Args", "vineyard::HashmapBuilder::emplace"], [26, 3, 1, "_CPPv4IDpEN8vineyard14HashmapBuilder7emplaceEbDpRR4Args", "vineyard::HashmapBuilder::emplace::Args"], [26, 2, 1, "_CPPv4IDpEN8vineyard14HashmapBuilder7emplaceEbDpRR4Args", "vineyard::HashmapBuilder::emplace::args"], [26, 1, 1, "_CPPv4NK8vineyard14HashmapBuilder5emptyEv", "vineyard::HashmapBuilder::empty"], [26, 1, 1, "_CPPv4N8vineyard14HashmapBuilder3endEv", "vineyard::HashmapBuilder::end"], [26, 1, 1, "_CPPv4NK8vineyard14HashmapBuilder3endEv", "vineyard::HashmapBuilder::end"], [26, 1, 1, "_CPPv4N8vineyard14HashmapBuilder4findERK1K", "vineyard::HashmapBuilder::find"], [26, 2, 1, "_CPPv4N8vineyard14HashmapBuilder4findERK1K", "vineyard::HashmapBuilder::find::key"], [26, 1, 1, "_CPPv4NK8vineyard14HashmapBuilder11load_factorEv", "vineyard::HashmapBuilder::load_factor"], [26, 1, 1, "_CPPv4N8vineyard14HashmapBuilderixERK1K", "vineyard::HashmapBuilder::operator[]"], [26, 1, 1, "_CPPv4N8vineyard14HashmapBuilderixERR1K", "vineyard::HashmapBuilder::operator[]"], [26, 2, 1, "_CPPv4N8vineyard14HashmapBuilderixERK1K", "vineyard::HashmapBuilder::operator[]::key"], [26, 2, 1, "_CPPv4N8vineyard14HashmapBuilderixERR1K", "vineyard::HashmapBuilder::operator[]::key"], [26, 1, 1, "_CPPv4N8vineyard14HashmapBuilder7reserveE6size_t", "vineyard::HashmapBuilder::reserve"], [26, 2, 1, "_CPPv4N8vineyard14HashmapBuilder7reserveE6size_t", "vineyard::HashmapBuilder::reserve::size"], [26, 1, 1, "_CPPv4NK8vineyard14HashmapBuilder4sizeEv", "vineyard::HashmapBuilder::size"], [26, 0, 1, "_CPPv4N8vineyard14InstanceStatusE", "vineyard::InstanceStatus"], [26, 1, 1, "_CPPv4N8vineyard14InstanceStatus14InstanceStatusERK4json", "vineyard::InstanceStatus::InstanceStatus"], [26, 2, 1, "_CPPv4N8vineyard14InstanceStatus14InstanceStatusERK4json", "vineyard::InstanceStatus::InstanceStatus::tree"], [26, 4, 1, "_CPPv4N8vineyard14InstanceStatus17deferred_requestsE", "vineyard::InstanceStatus::deferred_requests"], [26, 4, 1, "_CPPv4N8vineyard14InstanceStatus10deploymentE", "vineyard::InstanceStatus::deployment"], [26, 4, 1, "_CPPv4N8vineyard14InstanceStatus11instance_idE", "vineyard::InstanceStatus::instance_id"], [26, 4, 1, "_CPPv4N8vineyard14InstanceStatus15ipc_connectionsE", "vineyard::InstanceStatus::ipc_connections"], [26, 4, 1, "_CPPv4N8vineyard14InstanceStatus12memory_limitE", "vineyard::InstanceStatus::memory_limit"], [26, 4, 1, "_CPPv4N8vineyard14InstanceStatus12memory_usageE", "vineyard::InstanceStatus::memory_usage"], [26, 4, 1, "_CPPv4N8vineyard14InstanceStatus15rpc_connectionsE", "vineyard::InstanceStatus::rpc_connections"], [26, 0, 1, "_CPPv4N8vineyard6ObjectE", "vineyard::Object"], [26, 1, 1, "_CPPv4N8vineyard6Object5BuildER6Client", "vineyard::Object::Build"], [26, 2, 1, "_CPPv4N8vineyard6Object5BuildER6Client", "vineyard::Object::Build::client"], [26, 1, 1, "_CPPv4N8vineyard6Object9ConstructERK10ObjectMeta", "vineyard::Object::Construct"], [26, 2, 1, "_CPPv4N8vineyard6Object9ConstructERK10ObjectMeta", "vineyard::Object::Construct::meta"], [26, 1, 1, "_CPPv4NK8vineyard6Object8IsGlobalEv", "vineyard::Object::IsGlobal"], [26, 1, 1, "_CPPv4NK8vineyard6Object7IsLocalEv", "vineyard::Object::IsLocal"], [26, 1, 1, "_CPPv4NK8vineyard6Object9IsPersistEv", "vineyard::Object::IsPersist"], [26, 1, 1, "_CPPv4N8vineyard6Object6ObjectEv", "vineyard::Object::Object"], [26, 1, 1, "_CPPv4NK8vineyard6Object7PersistER10ClientBase", "vineyard::Object::Persist"], [26, 2, 1, "_CPPv4NK8vineyard6Object7PersistER10ClientBase", "vineyard::Object::Persist::client"], [26, 1, 1, "_CPPv4N8vineyard6Object13PostConstructERK10ObjectMeta", "vineyard::Object::PostConstruct"], [26, 2, 1, "_CPPv4N8vineyard6Object13PostConstructERK10ObjectMeta", "vineyard::Object::PostConstruct::meta"], [26, 1, 1, "_CPPv4N8vineyard6Object5_SealER6Client", "vineyard::Object::_Seal"], [26, 2, 1, "_CPPv4N8vineyard6Object5_SealER6Client", "vineyard::Object::_Seal::client"], [26, 1, 1, "_CPPv4NK8vineyard6Object2idEv", "vineyard::Object::id"], [26, 4, 1, "_CPPv4N8vineyard6Object3id_E", "vineyard::Object::id_"], [26, 1, 1, "_CPPv4NK8vineyard6Object4metaEv", "vineyard::Object::meta"], [26, 4, 1, "_CPPv4N8vineyard6Object5meta_E", "vineyard::Object::meta_"], [26, 1, 1, "_CPPv4NK8vineyard6Object6nbytesEv", "vineyard::Object::nbytes"], [26, 1, 1, "_CPPv4N8vineyard6ObjectD0Ev", "vineyard::Object::~Object"], [26, 0, 1, "_CPPv4N8vineyard10ObjectBaseE", "vineyard::ObjectBase"], [26, 1, 1, "_CPPv4N8vineyard10ObjectBase5BuildER6Client", "vineyard::ObjectBase::Build"], [26, 2, 1, "_CPPv4N8vineyard10ObjectBase5BuildER6Client", "vineyard::ObjectBase::Build::client"], [26, 1, 1, "_CPPv4N8vineyard10ObjectBase5_SealER6Client", "vineyard::ObjectBase::_Seal"], [26, 2, 1, "_CPPv4N8vineyard10ObjectBase5_SealER6Client", "vineyard::ObjectBase::_Seal::client"], [26, 0, 1, "_CPPv4N8vineyard13ObjectBuilderE", "vineyard::ObjectBuilder"], [26, 1, 1, "_CPPv4N8vineyard13ObjectBuilder5BuildER6Client", "vineyard::ObjectBuilder::Build"], [26, 2, 1, "_CPPv4N8vineyard13ObjectBuilder5BuildER6Client", "vineyard::ObjectBuilder::Build::client"], [26, 1, 1, "_CPPv4N8vineyard13ObjectBuilder4SealER6Client", "vineyard::ObjectBuilder::Seal"], [26, 1, 1, "_CPPv4N8vineyard13ObjectBuilder4SealER6ClientRNSt10shared_ptrI6ObjectEE", "vineyard::ObjectBuilder::Seal"], [26, 2, 1, "_CPPv4N8vineyard13ObjectBuilder4SealER6Client", "vineyard::ObjectBuilder::Seal::client"], [26, 2, 1, "_CPPv4N8vineyard13ObjectBuilder4SealER6ClientRNSt10shared_ptrI6ObjectEE", "vineyard::ObjectBuilder::Seal::client"], [26, 2, 1, "_CPPv4N8vineyard13ObjectBuilder4SealER6ClientRNSt10shared_ptrI6ObjectEE", "vineyard::ObjectBuilder::Seal::object"], [26, 1, 1, "_CPPv4N8vineyard13ObjectBuilder5_SealER6Client", "vineyard::ObjectBuilder::_Seal"], [26, 1, 1, "_CPPv4N8vineyard13ObjectBuilder5_SealER6ClientRNSt10shared_ptrI6ObjectEE", "vineyard::ObjectBuilder::_Seal"], [26, 2, 1, "_CPPv4N8vineyard13ObjectBuilder5_SealER6Client", "vineyard::ObjectBuilder::_Seal::client"], [26, 2, 1, "_CPPv4N8vineyard13ObjectBuilder5_SealER6ClientRNSt10shared_ptrI6ObjectEE", "vineyard::ObjectBuilder::_Seal::client"], [26, 2, 1, "_CPPv4N8vineyard13ObjectBuilder5_SealER6ClientRNSt10shared_ptrI6ObjectEE", "vineyard::ObjectBuilder::_Seal::object"], [26, 1, 1, "_CPPv4NK8vineyard13ObjectBuilder6sealedEv", "vineyard::ObjectBuilder::sealed"], [26, 1, 1, "_CPPv4N8vineyard13ObjectBuilder10set_sealedEKb", "vineyard::ObjectBuilder::set_sealed"], [26, 2, 1, "_CPPv4N8vineyard13ObjectBuilder10set_sealedEKb", "vineyard::ObjectBuilder::set_sealed::sealed"], [26, 1, 1, "_CPPv4N8vineyard13ObjectBuilderD0Ev", "vineyard::ObjectBuilder::~ObjectBuilder"], [26, 5, 1, "_CPPv4N8vineyard8ObjectIDE", "vineyard::ObjectID"], [26, 0, 1, "_CPPv4N8vineyard10ObjectMetaE", "vineyard::ObjectMeta"], [26, 1, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK12UnorderedMapI4json5ValueE", "vineyard::ObjectMeta::AddKeyValue"], [26, 1, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK12UnorderedMapINSt6stringE5ValueE", "vineyard::ObjectMeta::AddKeyValue"], [26, 1, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK1T", "vineyard::ObjectMeta::AddKeyValue"], [26, 1, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK3MapI4json5ValueE", "vineyard::ObjectMeta::AddKeyValue"], [26, 1, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK3MapINSt6stringE5ValueE", "vineyard::ObjectMeta::AddKeyValue"], [26, 1, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK5TupleI1TE", "vineyard::ObjectMeta::AddKeyValue"], [26, 1, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt13unordered_mapI4json5ValueEE", "vineyard::ObjectMeta::AddKeyValue"], [26, 1, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt13unordered_mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::AddKeyValue"], [26, 1, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt3mapI4json5ValueEE", "vineyard::ObjectMeta::AddKeyValue"], [26, 1, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt3mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::AddKeyValue"], [26, 1, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt3setI1TEE", "vineyard::ObjectMeta::AddKeyValue"], [26, 1, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt6vectorI1TEE", "vineyard::ObjectMeta::AddKeyValue"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta11AddKeyValueERKNSt6stringERK4json", "vineyard::ObjectMeta::AddKeyValue"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta11AddKeyValueERKNSt6stringERKNSt6stringE", "vineyard::ObjectMeta::AddKeyValue"], [26, 3, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK1T", "vineyard::ObjectMeta::AddKeyValue::T"], [26, 3, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK5TupleI1TE", "vineyard::ObjectMeta::AddKeyValue::T"], [26, 3, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt3setI1TEE", "vineyard::ObjectMeta::AddKeyValue::T"], [26, 3, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt6vectorI1TEE", "vineyard::ObjectMeta::AddKeyValue::T"], [26, 3, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK12UnorderedMapI4json5ValueE", "vineyard::ObjectMeta::AddKeyValue::Value"], [26, 3, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK12UnorderedMapINSt6stringE5ValueE", "vineyard::ObjectMeta::AddKeyValue::Value"], [26, 3, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK3MapI4json5ValueE", "vineyard::ObjectMeta::AddKeyValue::Value"], [26, 3, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK3MapINSt6stringE5ValueE", "vineyard::ObjectMeta::AddKeyValue::Value"], [26, 3, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt13unordered_mapI4json5ValueEE", "vineyard::ObjectMeta::AddKeyValue::Value"], [26, 3, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt13unordered_mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::AddKeyValue::Value"], [26, 3, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt3mapI4json5ValueEE", "vineyard::ObjectMeta::AddKeyValue::Value"], [26, 3, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt3mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::AddKeyValue::Value"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK12UnorderedMapI4json5ValueE", "vineyard::ObjectMeta::AddKeyValue::key"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK12UnorderedMapINSt6stringE5ValueE", "vineyard::ObjectMeta::AddKeyValue::key"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK1T", "vineyard::ObjectMeta::AddKeyValue::key"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK3MapI4json5ValueE", "vineyard::ObjectMeta::AddKeyValue::key"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK3MapINSt6stringE5ValueE", "vineyard::ObjectMeta::AddKeyValue::key"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK5TupleI1TE", "vineyard::ObjectMeta::AddKeyValue::key"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt13unordered_mapI4json5ValueEE", "vineyard::ObjectMeta::AddKeyValue::key"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt13unordered_mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::AddKeyValue::key"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt3mapI4json5ValueEE", "vineyard::ObjectMeta::AddKeyValue::key"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt3mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::AddKeyValue::key"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt3setI1TEE", "vineyard::ObjectMeta::AddKeyValue::key"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt6vectorI1TEE", "vineyard::ObjectMeta::AddKeyValue::key"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta11AddKeyValueERKNSt6stringERK4json", "vineyard::ObjectMeta::AddKeyValue::key"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta11AddKeyValueERKNSt6stringERKNSt6stringE", "vineyard::ObjectMeta::AddKeyValue::key"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK1T", "vineyard::ObjectMeta::AddKeyValue::value"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta11AddKeyValueERKNSt6stringERKNSt6stringE", "vineyard::ObjectMeta::AddKeyValue::value"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK12UnorderedMapI4json5ValueE", "vineyard::ObjectMeta::AddKeyValue::values"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK12UnorderedMapINSt6stringE5ValueE", "vineyard::ObjectMeta::AddKeyValue::values"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK3MapI4json5ValueE", "vineyard::ObjectMeta::AddKeyValue::values"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK3MapINSt6stringE5ValueE", "vineyard::ObjectMeta::AddKeyValue::values"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK5TupleI1TE", "vineyard::ObjectMeta::AddKeyValue::values"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt13unordered_mapI4json5ValueEE", "vineyard::ObjectMeta::AddKeyValue::values"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt13unordered_mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::AddKeyValue::values"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt3mapI4json5ValueEE", "vineyard::ObjectMeta::AddKeyValue::values"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt3mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::AddKeyValue::values"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt3setI1TEE", "vineyard::ObjectMeta::AddKeyValue::values"], [26, 2, 1, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt6vectorI1TEE", "vineyard::ObjectMeta::AddKeyValue::values"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta11AddKeyValueERKNSt6stringERK4json", "vineyard::ObjectMeta::AddKeyValue::values"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringEK8ObjectID", "vineyard::ObjectMeta::AddMember"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringEPK6Object", "vineyard::ObjectMeta::AddMember"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringERK10ObjectMeta", "vineyard::ObjectMeta::AddMember"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringERK6Object", "vineyard::ObjectMeta::AddMember"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringERKNSt10shared_ptrI6ObjectEE", "vineyard::ObjectMeta::AddMember"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringEPK6Object", "vineyard::ObjectMeta::AddMember::member"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringERK10ObjectMeta", "vineyard::ObjectMeta::AddMember::member"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringERK6Object", "vineyard::ObjectMeta::AddMember::member"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringERKNSt10shared_ptrI6ObjectEE", "vineyard::ObjectMeta::AddMember::member"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringEK8ObjectID", "vineyard::ObjectMeta::AddMember::member_id"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringEK8ObjectID", "vineyard::ObjectMeta::AddMember::name"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringEPK6Object", "vineyard::ObjectMeta::AddMember::name"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringERK10ObjectMeta", "vineyard::ObjectMeta::AddMember::name"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringERK6Object", "vineyard::ObjectMeta::AddMember::name"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringERKNSt10shared_ptrI6ObjectEE", "vineyard::ObjectMeta::AddMember::name"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta10ForceLocalEv", "vineyard::ObjectMeta::ForceLocal"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta9GetBufferEK8ObjectIDRNSt10shared_ptrI6BufferEE", "vineyard::ObjectMeta::GetBuffer"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta9GetBufferEK8ObjectIDRNSt10shared_ptrI6BufferEE", "vineyard::ObjectMeta::GetBuffer::blob_id"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta9GetBufferEK8ObjectIDRNSt10shared_ptrI6BufferEE", "vineyard::ObjectMeta::GetBuffer::buffer"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta12GetBufferSetEv", "vineyard::ObjectMeta::GetBufferSet"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta9GetClientEv", "vineyard::ObjectMeta::GetClient"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta5GetIdEv", "vineyard::ObjectMeta::GetId"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta13GetInstanceIdEv", "vineyard::ObjectMeta::GetInstanceId"], [26, 1, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEK1TRKNSt6stringE", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER12UnorderedMapI4json5ValueE", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER12UnorderedMapINSt6stringE5ValueE", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER1T", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER3MapI4json5ValueE", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER3MapINSt6stringE5ValueE", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER5TupleI1TE", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt13unordered_mapI4json5ValueEE", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt13unordered_mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt3mapI4json5ValueEE", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt3mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt3setI1TEE", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt6vectorI1TEE", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4IENK8vineyard10ObjectMeta11GetKeyValueEK4jsonRKNSt6stringE", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4IENK8vineyard10ObjectMeta11GetKeyValueEK4jsonRKNSt6stringE", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta11GetKeyValueERKNSt6stringE", "vineyard::ObjectMeta::GetKeyValue"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta11GetKeyValueERKNSt6stringER4json", "vineyard::ObjectMeta::GetKeyValue"], [26, 3, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEK1TRKNSt6stringE", "vineyard::ObjectMeta::GetKeyValue::T"], [26, 3, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER1T", "vineyard::ObjectMeta::GetKeyValue::T"], [26, 3, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER5TupleI1TE", "vineyard::ObjectMeta::GetKeyValue::T"], [26, 3, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt3setI1TEE", "vineyard::ObjectMeta::GetKeyValue::T"], [26, 3, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt6vectorI1TEE", "vineyard::ObjectMeta::GetKeyValue::T"], [26, 3, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER12UnorderedMapI4json5ValueE", "vineyard::ObjectMeta::GetKeyValue::Value"], [26, 3, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER12UnorderedMapINSt6stringE5ValueE", "vineyard::ObjectMeta::GetKeyValue::Value"], [26, 3, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER3MapI4json5ValueE", "vineyard::ObjectMeta::GetKeyValue::Value"], [26, 3, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER3MapINSt6stringE5ValueE", "vineyard::ObjectMeta::GetKeyValue::Value"], [26, 3, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt13unordered_mapI4json5ValueEE", "vineyard::ObjectMeta::GetKeyValue::Value"], [26, 3, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt13unordered_mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::GetKeyValue::Value"], [26, 3, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt3mapI4json5ValueEE", "vineyard::ObjectMeta::GetKeyValue::Value"], [26, 3, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt3mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::GetKeyValue::Value"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEK1TRKNSt6stringE", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER12UnorderedMapI4json5ValueE", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER12UnorderedMapINSt6stringE5ValueE", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER1T", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER3MapI4json5ValueE", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER3MapINSt6stringE5ValueE", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER5TupleI1TE", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt13unordered_mapI4json5ValueEE", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt13unordered_mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt3mapI4json5ValueEE", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt3mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt3setI1TEE", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt6vectorI1TEE", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4IENK8vineyard10ObjectMeta11GetKeyValueEK4jsonRKNSt6stringE", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4IENK8vineyard10ObjectMeta11GetKeyValueEK4jsonRKNSt6stringE", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta11GetKeyValueERKNSt6stringE", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta11GetKeyValueERKNSt6stringER4json", "vineyard::ObjectMeta::GetKeyValue::key"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER1T", "vineyard::ObjectMeta::GetKeyValue::value"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta11GetKeyValueERKNSt6stringER4json", "vineyard::ObjectMeta::GetKeyValue::value"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER12UnorderedMapI4json5ValueE", "vineyard::ObjectMeta::GetKeyValue::values"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER12UnorderedMapINSt6stringE5ValueE", "vineyard::ObjectMeta::GetKeyValue::values"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER3MapI4json5ValueE", "vineyard::ObjectMeta::GetKeyValue::values"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER3MapINSt6stringE5ValueE", "vineyard::ObjectMeta::GetKeyValue::values"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER5TupleI1TE", "vineyard::ObjectMeta::GetKeyValue::values"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt13unordered_mapI4json5ValueEE", "vineyard::ObjectMeta::GetKeyValue::values"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt13unordered_mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::GetKeyValue::values"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt3mapI4json5ValueEE", "vineyard::ObjectMeta::GetKeyValue::values"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt3mapINSt6stringE5ValueEE", "vineyard::ObjectMeta::GetKeyValue::values"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt3setI1TEE", "vineyard::ObjectMeta::GetKeyValue::values"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt6vectorI1TEE", "vineyard::ObjectMeta::GetKeyValue::values"], [26, 1, 1, "_CPPv4I0ENK8vineyard10ObjectMeta9GetMemberE6StatusRKNSt6stringERNSt10shared_ptrI1TEE", "vineyard::ObjectMeta::GetMember"], [26, 1, 1, "_CPPv4I0ENK8vineyard10ObjectMeta9GetMemberENSt10shared_ptrI1TEERKNSt6stringE", "vineyard::ObjectMeta::GetMember"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta9GetMemberERKNSt6stringE", "vineyard::ObjectMeta::GetMember"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta9GetMemberERKNSt6stringERNSt10shared_ptrI6ObjectEE", "vineyard::ObjectMeta::GetMember"], [26, 3, 1, "_CPPv4I0ENK8vineyard10ObjectMeta9GetMemberE6StatusRKNSt6stringERNSt10shared_ptrI1TEE", "vineyard::ObjectMeta::GetMember::T"], [26, 3, 1, "_CPPv4I0ENK8vineyard10ObjectMeta9GetMemberENSt10shared_ptrI1TEERKNSt6stringE", "vineyard::ObjectMeta::GetMember::T"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta9GetMemberE6StatusRKNSt6stringERNSt10shared_ptrI1TEE", "vineyard::ObjectMeta::GetMember::name"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta9GetMemberENSt10shared_ptrI1TEERKNSt6stringE", "vineyard::ObjectMeta::GetMember::name"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta9GetMemberERKNSt6stringE", "vineyard::ObjectMeta::GetMember::name"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta9GetMemberERKNSt6stringERNSt10shared_ptrI6ObjectEE", "vineyard::ObjectMeta::GetMember::name"], [26, 2, 1, "_CPPv4I0ENK8vineyard10ObjectMeta9GetMemberE6StatusRKNSt6stringERNSt10shared_ptrI1TEE", "vineyard::ObjectMeta::GetMember::object"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta9GetMemberERKNSt6stringERNSt10shared_ptrI6ObjectEE", "vineyard::ObjectMeta::GetMember::object"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta13GetMemberMetaERKNSt6stringE", "vineyard::ObjectMeta::GetMemberMeta"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta13GetMemberMetaERKNSt6stringER10ObjectMeta", "vineyard::ObjectMeta::GetMemberMeta"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta13GetMemberMetaERKNSt6stringER10ObjectMeta", "vineyard::ObjectMeta::GetMemberMeta::meta"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta13GetMemberMetaERKNSt6stringE", "vineyard::ObjectMeta::GetMemberMeta::name"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta13GetMemberMetaERKNSt6stringER10ObjectMeta", "vineyard::ObjectMeta::GetMemberMeta::name"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta9GetNBytesEv", "vineyard::ObjectMeta::GetNBytes"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta12GetSignatureEv", "vineyard::ObjectMeta::GetSignature"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta11GetTypeNameEv", "vineyard::ObjectMeta::GetTypeName"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta6HasKeyERKNSt6stringE", "vineyard::ObjectMeta::HasKey"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta6HasKeyERKNSt6stringE", "vineyard::ObjectMeta::HasKey::key"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta6HaskeyERKNSt6stringE", "vineyard::ObjectMeta::Haskey"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta6HaskeyERKNSt6stringE", "vineyard::ObjectMeta::Haskey::key"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta8IsGlobalEv", "vineyard::ObjectMeta::IsGlobal"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta7IsLocalEv", "vineyard::ObjectMeta::IsLocal"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta5LabelERKNSt6stringE", "vineyard::ObjectMeta::Label"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta5LabelERKNSt6stringE", "vineyard::ObjectMeta::Label::key"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta6LabelsEv", "vineyard::ObjectMeta::Labels"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta11MemoryUsageER4jsonKb", "vineyard::ObjectMeta::MemoryUsage"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta11MemoryUsageEv", "vineyard::ObjectMeta::MemoryUsage"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta11MemoryUsageER4jsonKb", "vineyard::ObjectMeta::MemoryUsage::pretty"], [26, 2, 1, "_CPPv4NK8vineyard10ObjectMeta11MemoryUsageER4jsonKb", "vineyard::ObjectMeta::MemoryUsage::usages"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta8MetaDataEv", "vineyard::ObjectMeta::MetaData"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta11MutMetaDataEv", "vineyard::ObjectMeta::MutMetaData"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta10ObjectMetaERK10ObjectMeta", "vineyard::ObjectMeta::ObjectMeta"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta10ObjectMetaEv", "vineyard::ObjectMeta::ObjectMeta"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta9PrintMetaEv", "vineyard::ObjectMeta::PrintMeta"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta5ResetEv", "vineyard::ObjectMeta::Reset"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta8ResetKeyERKNSt6stringE", "vineyard::ObjectMeta::ResetKey"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta8ResetKeyERKNSt6stringE", "vineyard::ObjectMeta::ResetKey::key"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta14ResetSignatureEv", "vineyard::ObjectMeta::ResetSignature"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta9SetBufferERK8ObjectIDRKNSt10shared_ptrI6BufferEE", "vineyard::ObjectMeta::SetBuffer"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta9SetBufferERK8ObjectIDRKNSt10shared_ptrI6BufferEE", "vineyard::ObjectMeta::SetBuffer::buffer"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta9SetBufferERK8ObjectIDRKNSt10shared_ptrI6BufferEE", "vineyard::ObjectMeta::SetBuffer::id"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta9SetClientEP10ClientBase", "vineyard::ObjectMeta::SetClient"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta9SetClientEP10ClientBase", "vineyard::ObjectMeta::SetClient::client"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta9SetGlobalEb", "vineyard::ObjectMeta::SetGlobal"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta9SetGlobalEb", "vineyard::ObjectMeta::SetGlobal::global"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta5SetIdERK8ObjectID", "vineyard::ObjectMeta::SetId"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta5SetIdERK8ObjectID", "vineyard::ObjectMeta::SetId::id"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta11SetMetaDataEP10ClientBaseRK4json", "vineyard::ObjectMeta::SetMetaData"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta11SetMetaDataEP10ClientBaseRK4json", "vineyard::ObjectMeta::SetMetaData::client"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta11SetMetaDataEP10ClientBaseRK4json", "vineyard::ObjectMeta::SetMetaData::meta"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta9SetNBytesEK6size_t", "vineyard::ObjectMeta::SetNBytes"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta9SetNBytesEK6size_t", "vineyard::ObjectMeta::SetNBytes::nbytes"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta11SetTypeNameERKNSt6stringE", "vineyard::ObjectMeta::SetTypeName"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta11SetTypeNameERKNSt6stringE", "vineyard::ObjectMeta::SetTypeName::type_name"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta9TimestampEv", "vineyard::ObjectMeta::Timestamp"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta8ToStringEv", "vineyard::ObjectMeta::ToString"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta6UnsafeE4json6size_tP8ObjectIDP9uintptr_tP6size_t", "vineyard::ObjectMeta::Unsafe"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMeta6UnsafeENSt6stringE6size_tP8ObjectIDP9uintptr_tP6size_t", "vineyard::ObjectMeta::Unsafe"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta6UnsafeE4json6size_tP8ObjectIDP9uintptr_tP6size_t", "vineyard::ObjectMeta::Unsafe::meta"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta6UnsafeENSt6stringE6size_tP8ObjectIDP9uintptr_tP6size_t", "vineyard::ObjectMeta::Unsafe::meta"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta6UnsafeE4json6size_tP8ObjectIDP9uintptr_tP6size_t", "vineyard::ObjectMeta::Unsafe::nobjects"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta6UnsafeENSt6stringE6size_tP8ObjectIDP9uintptr_tP6size_t", "vineyard::ObjectMeta::Unsafe::nobjects"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta6UnsafeE4json6size_tP8ObjectIDP9uintptr_tP6size_t", "vineyard::ObjectMeta::Unsafe::objects"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta6UnsafeENSt6stringE6size_tP8ObjectIDP9uintptr_tP6size_t", "vineyard::ObjectMeta::Unsafe::objects"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta6UnsafeE4json6size_tP8ObjectIDP9uintptr_tP6size_t", "vineyard::ObjectMeta::Unsafe::pointers"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta6UnsafeENSt6stringE6size_tP8ObjectIDP9uintptr_tP6size_t", "vineyard::ObjectMeta::Unsafe::pointers"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta6UnsafeE4json6size_tP8ObjectIDP9uintptr_tP6size_t", "vineyard::ObjectMeta::Unsafe::sizes"], [26, 2, 1, "_CPPv4N8vineyard10ObjectMeta6UnsafeENSt6stringE6size_tP8ObjectIDP9uintptr_tP6size_t", "vineyard::ObjectMeta::Unsafe::sizes"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta5beginEv", "vineyard::ObjectMeta::begin"], [26, 5, 1, "_CPPv4N8vineyard10ObjectMeta14const_iteratorE", "vineyard::ObjectMeta::const_iterator"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta3endEv", "vineyard::ObjectMeta::end"], [26, 1, 1, "_CPPv4NK8vineyard10ObjectMeta10incompleteEv", "vineyard::ObjectMeta::incomplete"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMetaaSERK10ObjectMeta", "vineyard::ObjectMeta::operator="], [26, 2, 1, "_CPPv4N8vineyard10ObjectMetaaSERK10ObjectMeta", "vineyard::ObjectMeta::operator=::other"], [26, 1, 1, "_CPPv4N8vineyard10ObjectMetaD0Ev", "vineyard::ObjectMeta::~ObjectMeta"], [26, 0, 1, "_CPPv4N8vineyard9RPCClientE", "vineyard::RPCClient"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE", "vineyard::RPCClient::Connect"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_t", "vineyard::RPCClient::Connect"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_tK9SessionIDRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_tRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringEK9SessionIDRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringERKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient7ConnectEv", "vineyard::RPCClient::Connect"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_t", "vineyard::RPCClient::Connect::host"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_tK9SessionIDRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::host"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_tRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::host"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_tK9SessionIDRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::password"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_tRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::password"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringEK9SessionIDRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::password"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::password"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringERKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::password"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_t", "vineyard::RPCClient::Connect::port"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_tK9SessionIDRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::port"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_tRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::port"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE", "vineyard::RPCClient::Connect::rpc_endpoint"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringEK9SessionIDRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::rpc_endpoint"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringERKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::rpc_endpoint"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_tK9SessionIDRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::session_id"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringEK9SessionIDRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::session_id"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_tK9SessionIDRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::username"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_tRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::username"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringEK9SessionIDRKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::username"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::username"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringERKNSt6stringERKNSt6stringE", "vineyard::RPCClient::Connect::username"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient16CreateRemoteBlobERKNSt10shared_ptrI16RemoteBlobWriterEER8ObjectID", "vineyard::RPCClient::CreateRemoteBlob"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient16CreateRemoteBlobERKNSt10shared_ptrI16RemoteBlobWriterEER8ObjectID", "vineyard::RPCClient::CreateRemoteBlob::buffer"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient16CreateRemoteBlobERKNSt10shared_ptrI16RemoteBlobWriterEER8ObjectID", "vineyard::RPCClient::CreateRemoteBlob::id"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient4ForkER9RPCClient", "vineyard::RPCClient::Fork"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient4ForkER9RPCClient", "vineyard::RPCClient::Fork::client"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient11GetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::RPCClient::GetMetaData"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient11GetMetaDataERKNSt6vectorI8ObjectIDEERNSt6vectorI10ObjectMetaEEKb", "vineyard::RPCClient::GetMetaData"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient11GetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::RPCClient::GetMetaData::id"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient11GetMetaDataERKNSt6vectorI8ObjectIDEERNSt6vectorI10ObjectMetaEEKb", "vineyard::RPCClient::GetMetaData::id"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient11GetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::RPCClient::GetMetaData::meta_data"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient11GetMetaDataERKNSt6vectorI8ObjectIDEERNSt6vectorI10ObjectMetaEEKb", "vineyard::RPCClient::GetMetaData::meta_data"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient11GetMetaDataEK8ObjectIDR10ObjectMetaKb", "vineyard::RPCClient::GetMetaData::sync_remote"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient11GetMetaDataERKNSt6vectorI8ObjectIDEERNSt6vectorI10ObjectMetaEEKb", "vineyard::RPCClient::GetMetaData::sync_remote"], [26, 1, 1, "_CPPv4I0EN8vineyard9RPCClient9GetObjectE6StatusK8ObjectIDRNSt10shared_ptrI1TEE", "vineyard::RPCClient::GetObject"], [26, 1, 1, "_CPPv4I0EN8vineyard9RPCClient9GetObjectENSt10shared_ptrI1TEEK8ObjectID", "vineyard::RPCClient::GetObject"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient9GetObjectEK8ObjectID", "vineyard::RPCClient::GetObject"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient9GetObjectEK8ObjectIDRNSt10shared_ptrI6ObjectEE", "vineyard::RPCClient::GetObject"], [26, 3, 1, "_CPPv4I0EN8vineyard9RPCClient9GetObjectE6StatusK8ObjectIDRNSt10shared_ptrI1TEE", "vineyard::RPCClient::GetObject::T"], [26, 3, 1, "_CPPv4I0EN8vineyard9RPCClient9GetObjectENSt10shared_ptrI1TEEK8ObjectID", "vineyard::RPCClient::GetObject::T"], [26, 2, 1, "_CPPv4I0EN8vineyard9RPCClient9GetObjectE6StatusK8ObjectIDRNSt10shared_ptrI1TEE", "vineyard::RPCClient::GetObject::id"], [26, 2, 1, "_CPPv4I0EN8vineyard9RPCClient9GetObjectENSt10shared_ptrI1TEEK8ObjectID", "vineyard::RPCClient::GetObject::id"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient9GetObjectEK8ObjectID", "vineyard::RPCClient::GetObject::id"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient9GetObjectEK8ObjectIDRNSt10shared_ptrI6ObjectEE", "vineyard::RPCClient::GetObject::id"], [26, 2, 1, "_CPPv4I0EN8vineyard9RPCClient9GetObjectE6StatusK8ObjectIDRNSt10shared_ptrI1TEE", "vineyard::RPCClient::GetObject::object"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient9GetObjectEK8ObjectIDRNSt10shared_ptrI6ObjectEE", "vineyard::RPCClient::GetObject::object"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient10GetObjectsERKNSt6vectorI8ObjectIDEE", "vineyard::RPCClient::GetObjects"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient10GetObjectsERKNSt6vectorI8ObjectIDEE", "vineyard::RPCClient::GetObjects::ids"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient13GetRemoteBlobERK8ObjectIDKbRNSt10shared_ptrI10RemoteBlobEE", "vineyard::RPCClient::GetRemoteBlob"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient13GetRemoteBlobERK8ObjectIDRNSt10shared_ptrI10RemoteBlobEE", "vineyard::RPCClient::GetRemoteBlob"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient13GetRemoteBlobERK8ObjectIDKbRNSt10shared_ptrI10RemoteBlobEE", "vineyard::RPCClient::GetRemoteBlob::buffer"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient13GetRemoteBlobERK8ObjectIDRNSt10shared_ptrI10RemoteBlobEE", "vineyard::RPCClient::GetRemoteBlob::buffer"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient13GetRemoteBlobERK8ObjectIDKbRNSt10shared_ptrI10RemoteBlobEE", "vineyard::RPCClient::GetRemoteBlob::id"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient13GetRemoteBlobERK8ObjectIDRNSt10shared_ptrI10RemoteBlobEE", "vineyard::RPCClient::GetRemoteBlob::id"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient13GetRemoteBlobERK8ObjectIDKbRNSt10shared_ptrI10RemoteBlobEE", "vineyard::RPCClient::GetRemoteBlob::unsafe"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient14GetRemoteBlobsERKNSt6vectorI8ObjectIDEEKbRNSt6vectorINSt10shared_ptrI10RemoteBlobEEEE", "vineyard::RPCClient::GetRemoteBlobs"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient14GetRemoteBlobsERKNSt6vectorI8ObjectIDEERNSt6vectorINSt10shared_ptrI10RemoteBlobEEEE", "vineyard::RPCClient::GetRemoteBlobs"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient14GetRemoteBlobsERKNSt6vectorI8ObjectIDEEKbRNSt6vectorINSt10shared_ptrI10RemoteBlobEEEE", "vineyard::RPCClient::GetRemoteBlobs::ids"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient14GetRemoteBlobsERKNSt6vectorI8ObjectIDEERNSt6vectorINSt10shared_ptrI10RemoteBlobEEEE", "vineyard::RPCClient::GetRemoteBlobs::ids"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient14GetRemoteBlobsERKNSt6vectorI8ObjectIDEEKbRNSt6vectorINSt10shared_ptrI10RemoteBlobEEEE", "vineyard::RPCClient::GetRemoteBlobs::remote_blobs"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient14GetRemoteBlobsERKNSt6vectorI8ObjectIDEERNSt6vectorINSt10shared_ptrI10RemoteBlobEEEE", "vineyard::RPCClient::GetRemoteBlobs::remote_blobs"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient14GetRemoteBlobsERKNSt6vectorI8ObjectIDEEKbRNSt6vectorINSt10shared_ptrI10RemoteBlobEEEE", "vineyard::RPCClient::GetRemoteBlobs::unsafe"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient14ListObjectMetaERKNSt6stringEKbK6size_tb", "vineyard::RPCClient::ListObjectMeta"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient14ListObjectMetaERKNSt6stringEKbK6size_tb", "vineyard::RPCClient::ListObjectMeta::limit"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient14ListObjectMetaERKNSt6stringEKbK6size_tb", "vineyard::RPCClient::ListObjectMeta::nobuffer"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient14ListObjectMetaERKNSt6stringEKbK6size_tb", "vineyard::RPCClient::ListObjectMeta::pattern"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient14ListObjectMetaERKNSt6stringEKbK6size_tb", "vineyard::RPCClient::ListObjectMeta::regex"], [26, 1, 1, "_CPPv4N8vineyard9RPCClient11ListObjectsERKNSt6stringEKbK6size_t", "vineyard::RPCClient::ListObjects"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient11ListObjectsERKNSt6stringEKbK6size_t", "vineyard::RPCClient::ListObjects::limit"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient11ListObjectsERKNSt6stringEKbK6size_t", "vineyard::RPCClient::ListObjects::pattern"], [26, 2, 1, "_CPPv4N8vineyard9RPCClient11ListObjectsERKNSt6stringEKbK6size_t", "vineyard::RPCClient::ListObjects::regex"], [26, 1, 1, "_CPPv4NK8vineyard9RPCClient18remote_instance_idEv", "vineyard::RPCClient::remote_instance_id"], [26, 1, 1, "_CPPv4N8vineyard9RPCClientD0Ev", "vineyard::RPCClient::~RPCClient"], [26, 0, 1, "_CPPv4I0EN8vineyard6ScalarE", "vineyard::Scalar"], [26, 1, 1, "_CPPv4N8vineyard6Scalar9ConstructERK10ObjectMeta", "vineyard::Scalar::Construct"], [26, 2, 1, "_CPPv4N8vineyard6Scalar9ConstructERK10ObjectMeta", "vineyard::Scalar::Construct::meta"], [26, 1, 1, "_CPPv4N8vineyard6Scalar6CreateEv", "vineyard::Scalar::Create"], [26, 3, 1, "_CPPv4I0EN8vineyard6ScalarE", "vineyard::Scalar::T"], [26, 1, 1, "_CPPv4NK8vineyard6Scalar4TypeEv", "vineyard::Scalar::Type"], [26, 1, 1, "_CPPv4NK8vineyard6Scalar5ValueEv", "vineyard::Scalar::Value"], [26, 0, 1, "_CPPv4I0EN8vineyard13ScalarBuilderE", "vineyard::ScalarBuilder"], [26, 1, 1, "_CPPv4N8vineyard13ScalarBuilder13ScalarBuilderER6Client", "vineyard::ScalarBuilder::ScalarBuilder"], [26, 1, 1, "_CPPv4N8vineyard13ScalarBuilder13ScalarBuilderER6ClientRK1T", "vineyard::ScalarBuilder::ScalarBuilder"], [26, 2, 1, "_CPPv4N8vineyard13ScalarBuilder13ScalarBuilderER6Client", "vineyard::ScalarBuilder::ScalarBuilder::client"], [26, 2, 1, "_CPPv4N8vineyard13ScalarBuilder13ScalarBuilderER6ClientRK1T", "vineyard::ScalarBuilder::ScalarBuilder::client"], [26, 2, 1, "_CPPv4N8vineyard13ScalarBuilder13ScalarBuilderER6ClientRK1T", "vineyard::ScalarBuilder::ScalarBuilder::value"], [26, 1, 1, "_CPPv4N8vineyard13ScalarBuilder8SetValueERK1T", "vineyard::ScalarBuilder::SetValue"], [26, 2, 1, "_CPPv4N8vineyard13ScalarBuilder8SetValueERK1T", "vineyard::ScalarBuilder::SetValue::value"], [26, 3, 1, "_CPPv4I0EN8vineyard13ScalarBuilderE", "vineyard::ScalarBuilder::T"], [26, 0, 1, "_CPPv4N8vineyard8SequenceE", "vineyard::Sequence"], [26, 1, 1, "_CPPv4NK8vineyard8Sequence2AtE6size_t", "vineyard::Sequence::At"], [26, 2, 1, "_CPPv4NK8vineyard8Sequence2AtE6size_t", "vineyard::Sequence::At::index"], [26, 1, 1, "_CPPv4N8vineyard8Sequence9ConstructERK10ObjectMeta", "vineyard::Sequence::Construct"], [26, 2, 1, "_CPPv4N8vineyard8Sequence9ConstructERK10ObjectMeta", "vineyard::Sequence::Construct::meta"], [26, 1, 1, "_CPPv4N8vineyard8Sequence6CreateEv", "vineyard::Sequence::Create"], [26, 1, 1, "_CPPv4NK8vineyard8Sequence5FirstEv", "vineyard::Sequence::First"], [26, 1, 1, "_CPPv4NK8vineyard8Sequence6SecondEv", "vineyard::Sequence::Second"], [26, 1, 1, "_CPPv4NK8vineyard8Sequence4SizeEv", "vineyard::Sequence::Size"], [26, 1, 1, "_CPPv4NK8vineyard8Sequence5beginEv", "vineyard::Sequence::begin"], [26, 1, 1, "_CPPv4NK8vineyard8Sequence3endEv", "vineyard::Sequence::end"], [26, 0, 1, "_CPPv4N8vineyard8Sequence8iteratorE", "vineyard::Sequence::iterator"], [26, 1, 1, "_CPPv4N8vineyard8Sequence8iterator8iteratorEPK8Sequence6size_t", "vineyard::Sequence::iterator::iterator"], [26, 2, 1, "_CPPv4N8vineyard8Sequence8iterator8iteratorEPK8Sequence6size_t", "vineyard::Sequence::iterator::iterator::index"], [26, 2, 1, "_CPPv4N8vineyard8Sequence8iterator8iteratorEPK8Sequence6size_t", "vineyard::Sequence::iterator::iterator::sequence"], [26, 1, 1, "_CPPv4NK8vineyard8Sequence8iteratorneE8iterator", "vineyard::Sequence::iterator::operator!="], [26, 2, 1, "_CPPv4NK8vineyard8Sequence8iteratorneE8iterator", "vineyard::Sequence::iterator::operator!=::other"], [26, 1, 1, "_CPPv4NK8vineyard8Sequence8iteratormlEv", "vineyard::Sequence::iterator::operator*"], [26, 1, 1, "_CPPv4N8vineyard8Sequence8iteratorppEv", "vineyard::Sequence::iterator::operator++"], [26, 1, 1, "_CPPv4NK8vineyard8Sequence8iteratoreqE8iterator", "vineyard::Sequence::iterator::operator=="], [26, 2, 1, "_CPPv4NK8vineyard8Sequence8iteratoreqE8iterator", "vineyard::Sequence::iterator::operator==::other"], [26, 0, 1, "_CPPv4N8vineyard15SequenceBuilderE", "vineyard::SequenceBuilder"], [26, 1, 1, "_CPPv4N8vineyard15SequenceBuilder2AtE6size_t", "vineyard::SequenceBuilder::At"], [26, 2, 1, "_CPPv4N8vineyard15SequenceBuilder2AtE6size_t", "vineyard::SequenceBuilder::At::index"], [26, 1, 1, "_CPPv4N8vineyard15SequenceBuilder15SequenceBuilderER6Client", "vineyard::SequenceBuilder::SequenceBuilder"], [26, 1, 1, "_CPPv4N8vineyard15SequenceBuilder15SequenceBuilderER6ClientK6size_t", "vineyard::SequenceBuilder::SequenceBuilder"], [26, 2, 1, "_CPPv4N8vineyard15SequenceBuilder15SequenceBuilderER6Client", "vineyard::SequenceBuilder::SequenceBuilder::client"], [26, 2, 1, "_CPPv4N8vineyard15SequenceBuilder15SequenceBuilderER6ClientK6size_t", "vineyard::SequenceBuilder::SequenceBuilder::client"], [26, 2, 1, "_CPPv4N8vineyard15SequenceBuilder15SequenceBuilderER6ClientK6size_t", "vineyard::SequenceBuilder::SequenceBuilder::size"], [26, 1, 1, "_CPPv4N8vineyard15SequenceBuilder7SetSizeE6size_t", "vineyard::SequenceBuilder::SetSize"], [26, 2, 1, "_CPPv4N8vineyard15SequenceBuilder7SetSizeE6size_t", "vineyard::SequenceBuilder::SetSize::size"], [26, 1, 1, "_CPPv4N8vineyard15SequenceBuilder8SetValueE6size_tRKNSt10shared_ptrI13ObjectBuilderEE", "vineyard::SequenceBuilder::SetValue"], [26, 1, 1, "_CPPv4N8vineyard15SequenceBuilder8SetValueE6size_tRKNSt10shared_ptrI6ObjectEE", "vineyard::SequenceBuilder::SetValue"], [26, 2, 1, "_CPPv4N8vineyard15SequenceBuilder8SetValueE6size_tRKNSt10shared_ptrI13ObjectBuilderEE", "vineyard::SequenceBuilder::SetValue::idx"], [26, 2, 1, "_CPPv4N8vineyard15SequenceBuilder8SetValueE6size_tRKNSt10shared_ptrI6ObjectEE", "vineyard::SequenceBuilder::SetValue::idx"], [26, 2, 1, "_CPPv4N8vineyard15SequenceBuilder8SetValueE6size_tRKNSt10shared_ptrI13ObjectBuilderEE", "vineyard::SequenceBuilder::SetValue::value"], [26, 2, 1, "_CPPv4N8vineyard15SequenceBuilder8SetValueE6size_tRKNSt10shared_ptrI6ObjectEE", "vineyard::SequenceBuilder::SetValue::value"], [26, 1, 1, "_CPPv4NK8vineyard15SequenceBuilder4SizeEv", "vineyard::SequenceBuilder::Size"], [26, 0, 1, "_CPPv4I0EN8vineyard6TensorE", "vineyard::Tensor"], [26, 1, 1, "_CPPv4N8vineyard6Tensor11ArrowTensorEv", "vineyard::Tensor::ArrowTensor"], [26, 5, 1, "_CPPv4N8vineyard6Tensor12ArrowTensorTE", "vineyard::Tensor::ArrowTensorT"], [26, 1, 1, "_CPPv4N8vineyard6Tensor9ConstructERK10ObjectMeta", "vineyard::Tensor::Construct"], [26, 2, 1, "_CPPv4N8vineyard6Tensor9ConstructERK10ObjectMeta", "vineyard::Tensor::Construct::meta"], [26, 1, 1, "_CPPv4N8vineyard6Tensor6CreateEv", "vineyard::Tensor::Create"], [26, 3, 1, "_CPPv4I0EN8vineyard6TensorE", "vineyard::Tensor::T"], [26, 1, 1, "_CPPv4NK8vineyard6Tensor16auxiliary_bufferEv", "vineyard::Tensor::auxiliary_buffer"], [26, 1, 1, "_CPPv4NK8vineyard6Tensor6bufferEv", "vineyard::Tensor::buffer"], [26, 1, 1, "_CPPv4NK8vineyard6Tensor4dataEv", "vineyard::Tensor::data"], [26, 1, 1, "_CPPv4NK8vineyard6TensorixE6size_t", "vineyard::Tensor::operator[]"], [26, 2, 1, "_CPPv4NK8vineyard6TensorixE6size_t", "vineyard::Tensor::operator[]::index"], [26, 1, 1, "_CPPv4NK8vineyard6Tensor15partition_indexEv", "vineyard::Tensor::partition_index"], [26, 1, 1, "_CPPv4NK8vineyard6Tensor5shapeEv", "vineyard::Tensor::shape"], [26, 1, 1, "_CPPv4NK8vineyard6Tensor7stridesEv", "vineyard::Tensor::strides"], [26, 5, 1, "_CPPv4N8vineyard6Tensor21value_const_pointer_tE", "vineyard::Tensor::value_const_pointer_t"], [26, 5, 1, "_CPPv4N8vineyard6Tensor15value_pointer_tE", "vineyard::Tensor::value_pointer_t"], [26, 5, 1, "_CPPv4N8vineyard6Tensor7value_tE", "vineyard::Tensor::value_t"], [26, 1, 1, "_CPPv4NK8vineyard6Tensor10value_typeEv", "vineyard::Tensor::value_type"], [26, 0, 1, "_CPPv4I0EN8vineyard13TensorBuilderE", "vineyard::TensorBuilder"], [26, 1, 1, "_CPPv4N8vineyard13TensorBuilder5BuildER6Client", "vineyard::TensorBuilder::Build"], [26, 2, 1, "_CPPv4N8vineyard13TensorBuilder5BuildER6Client", "vineyard::TensorBuilder::Build::client"], [26, 3, 1, "_CPPv4I0EN8vineyard13TensorBuilderE", "vineyard::TensorBuilder::T"], [26, 1, 1, "_CPPv4N8vineyard13TensorBuilder13TensorBuilderER6ClientRKNSt6vectorI7int64_tEE", "vineyard::TensorBuilder::TensorBuilder"], [26, 1, 1, "_CPPv4N8vineyard13TensorBuilder13TensorBuilderER6ClientRKNSt6vectorI7int64_tEERKNSt6vectorI7int64_tEE", "vineyard::TensorBuilder::TensorBuilder"], [26, 2, 1, "_CPPv4N8vineyard13TensorBuilder13TensorBuilderER6ClientRKNSt6vectorI7int64_tEE", "vineyard::TensorBuilder::TensorBuilder::client"], [26, 2, 1, "_CPPv4N8vineyard13TensorBuilder13TensorBuilderER6ClientRKNSt6vectorI7int64_tEERKNSt6vectorI7int64_tEE", "vineyard::TensorBuilder::TensorBuilder::client"], [26, 2, 1, "_CPPv4N8vineyard13TensorBuilder13TensorBuilderER6ClientRKNSt6vectorI7int64_tEERKNSt6vectorI7int64_tEE", "vineyard::TensorBuilder::TensorBuilder::partition_index"], [26, 2, 1, "_CPPv4N8vineyard13TensorBuilder13TensorBuilderER6ClientRKNSt6vectorI7int64_tEE", "vineyard::TensorBuilder::TensorBuilder::shape"], [26, 2, 1, "_CPPv4N8vineyard13TensorBuilder13TensorBuilderER6ClientRKNSt6vectorI7int64_tEERKNSt6vectorI7int64_tEE", "vineyard::TensorBuilder::TensorBuilder::shape"], [26, 1, 1, "_CPPv4NK8vineyard13TensorBuilder4dataEv", "vineyard::TensorBuilder::data"], [26, 1, 1, "_CPPv4NK8vineyard13TensorBuilder15partition_indexEv", "vineyard::TensorBuilder::partition_index"], [26, 1, 1, "_CPPv4N8vineyard13TensorBuilder19set_partition_indexERKNSt6vectorI7int64_tEE", "vineyard::TensorBuilder::set_partition_index"], [26, 2, 1, "_CPPv4N8vineyard13TensorBuilder19set_partition_indexERKNSt6vectorI7int64_tEE", "vineyard::TensorBuilder::set_partition_index::partition_index"], [26, 1, 1, "_CPPv4N8vineyard13TensorBuilder9set_shapeERKNSt6vectorI7int64_tEE", "vineyard::TensorBuilder::set_shape"], [26, 2, 1, "_CPPv4N8vineyard13TensorBuilder9set_shapeERKNSt6vectorI7int64_tEE", "vineyard::TensorBuilder::set_shape::shape"], [26, 1, 1, "_CPPv4NK8vineyard13TensorBuilder5shapeEv", "vineyard::TensorBuilder::shape"], [26, 1, 1, "_CPPv4NK8vineyard13TensorBuilder7stridesEv", "vineyard::TensorBuilder::strides"], [26, 5, 1, "_CPPv4N8vineyard13TensorBuilder21value_const_pointer_tE", "vineyard::TensorBuilder::value_const_pointer_t"], [26, 5, 1, "_CPPv4N8vineyard13TensorBuilder15value_pointer_tE", "vineyard::TensorBuilder::value_pointer_t"], [26, 5, 1, "_CPPv4N8vineyard13TensorBuilder7value_tE", "vineyard::TensorBuilder::value_t"]], "vineyard": [[28, 6, 1, "", "Blob"], [28, 6, 1, "", "BlobBuilder"], [28, 6, 1, "", "IPCClient"], [28, 6, 1, "", "InstanceStatus"], [28, 6, 1, "", "Object"], [28, 6, 1, "", "ObjectBuilder"], [28, 6, 1, "", "ObjectID"], [28, 6, 1, "", "ObjectMeta"], [28, 6, 1, "", "RPCClient"], [28, 6, 1, "", "RemoteBlob"], [28, 6, 1, "", "RemoteBlobBuilder"], [28, 9, 1, "id0", "connect"], [28, 9, 1, "", "get_current_socket"]], "vineyard.Blob": [[28, 7, 1, "", "address"], [28, 7, 1, "", "buffer"], [28, 8, 1, "", "empty"], [28, 7, 1, "", "is_empty"], [28, 7, 1, "", "size"]], "vineyard.BlobBuilder": [[28, 8, 1, "", "abort"], [28, 7, 1, "", "address"], [28, 7, 1, "", "buffer"], [28, 8, 1, "", "copy"], [28, 7, 1, "", "id"], [28, 8, 1, "", "shrink"], [28, 7, 1, "", "size"]], "vineyard.IPCClient": [[28, 8, 1, "", "allocated_size"], [28, 8, 1, "", "clear"], [28, 8, 1, "", "close"], [28, 7, 1, "", "connected"], [28, 8, 1, "", "create_blob"], [28, 8, 1, "", "create_empty_blob"], [28, 8, 1, "", "create_metadata"], [28, 8, 1, "", "delete"], [28, 8, 1, "", "drop_name"], [28, 8, 1, "", "exists"], [28, 8, 1, "", "find_shared_memory"], [28, 8, 1, "", "get"], [28, 8, 1, "", "get_blob"], [28, 8, 1, "", "get_blobs"], [28, 8, 1, "", "get_meta"], [28, 8, 1, "", "get_metas"], [28, 8, 1, "", "get_name"], [28, 8, 1, "", "get_object"], [28, 8, 1, "", "get_objects"], [28, 7, 1, "", "instance_id"], [28, 7, 1, "", "ipc_socket"], [28, 8, 1, "", "is_shared_memory"], [28, 8, 1, "", "list_metadatas"], [28, 8, 1, "", "list_names"], [28, 8, 1, "", "list_objects"], [28, 7, 1, "", "meta"], [28, 8, 1, "", "persist"], [28, 8, 1, "", "put"], [28, 8, 1, "", "put_name"], [28, 8, 1, "", "reset"], [28, 7, 1, "", "rpc_endpoint"], [28, 8, 1, "", "shallow_copy"], [28, 7, 1, "", "status"], [28, 8, 1, "", "sync_meta"], [28, 7, 1, "", "version"]], "vineyard.InstanceStatus": [[28, 8, 1, "", "__init__"], [28, 8, 1, "", "__repr__"], [28, 8, 1, "", "__str__"], [28, 7, 1, "", "deferred_requests"], [28, 7, 1, "", "deployment"], [28, 7, 1, "", "instance_id"], [28, 7, 1, "", "ipc_connections"], [28, 7, 1, "", "memory_limit"], [28, 7, 1, "", "memory_usage"], [28, 7, 1, "", "rpc_connections"]], "vineyard.Object": [[28, 7, 1, "", "id"], [28, 7, 1, "", "isglobal"], [28, 7, 1, "", "islocal"], [28, 7, 1, "", "ispersist"], [28, 8, 1, "", "member"], [28, 7, 1, "", "meta"], [28, 7, 1, "", "nbytes"], [28, 7, 1, "", "signature"], [28, 7, 1, "", "typename"]], "vineyard.ObjectID": [[28, 8, 1, "", "__eq__"], [28, 8, 1, "", "__hash__"], [28, 8, 1, "", "__init__"], [28, 8, 1, "", "__repr__"], [28, 8, 1, "", "__str__"]], "vineyard.ObjectMeta": [[28, 8, 1, "", "__contains__"], [28, 8, 1, "", "__getitem__"], [28, 8, 1, "", "__init__"], [28, 8, 1, "", "__repr__"], [28, 8, 1, "", "__setitem__"], [28, 8, 1, "", "__str__"], [28, 8, 1, "", "add_member"], [28, 8, 1, "", "get"], [28, 8, 1, "", "get_member"], [28, 7, 1, "", "id"], [28, 7, 1, "", "instance_id"], [28, 7, 1, "", "isglobal"], [28, 7, 1, "", "islocal"], [28, 7, 1, "", "memory_usage"], [28, 7, 1, "", "nbytes"], [28, 8, 1, "", "set_global"], [28, 7, 1, "", "signature"], [28, 7, 1, "", "typename"]], "vineyard.RPCClient": [[28, 8, 1, "", "clear"], [28, 8, 1, "", "close"], [28, 7, 1, "", "connected"], [28, 8, 1, "", "create_metadata"], [28, 8, 1, "", "create_remote_blob"], [28, 8, 1, "", "delete"], [28, 8, 1, "", "drop_name"], [28, 8, 1, "", "exists"], [28, 8, 1, "", "get"], [28, 8, 1, "", "get_meta"], [28, 8, 1, "", "get_metas"], [28, 8, 1, "", "get_name"], [28, 8, 1, "", "get_object"], [28, 8, 1, "", "get_objects"], [28, 8, 1, "", "get_remote_blob"], [28, 8, 1, "", "get_remote_blobs"], [28, 7, 1, "", "instance_id"], [28, 7, 1, "", "ipc_socket"], [28, 8, 1, "", "list_metadatas"], [28, 8, 1, "", "list_names"], [28, 8, 1, "", "list_objects"], [28, 7, 1, "", "meta"], [28, 8, 1, "", "persist"], [28, 8, 1, "", "put"], [28, 8, 1, "", "put_name"], [28, 7, 1, "", "remote_instance_id"], [28, 8, 1, "", "reset"], [28, 7, 1, "", "rpc_endpoint"], [28, 8, 1, "", "shallow_copy"], [28, 7, 1, "", "status"], [28, 8, 1, "", "sync_meta"], [28, 7, 1, "", "version"]], "vineyard.RemoteBlob": [[28, 7, 1, "", "address"], [28, 7, 1, "", "buffer"], [28, 7, 1, "", "id"], [28, 7, 1, "", "instance_id"], [28, 7, 1, "", "is_empty"], [28, 7, 1, "", "size"]], "vineyard.RemoteBlobBuilder": [[28, 8, 1, "", "abort"], [28, 7, 1, "", "address"], [28, 7, 1, "", "buffer"], [28, 8, 1, "", "copy"], [28, 7, 1, "", "size"]], "vineyard.core.builder": [[28, 6, 1, "", "BuilderContext"], [28, 9, 1, "", "builder_context"], [28, 9, 1, "", "get_current_builders"]], "vineyard.core.builder.BuilderContext": [[28, 8, 1, "", "register"], [28, 8, 1, "", "run"]], "vineyard.core.driver": [[28, 6, 1, "", "DriverContext"], [28, 9, 1, "", "driver_context"], [28, 9, 1, "", "get_current_drivers"]], "vineyard.core.resolver": [[28, 6, 1, "", "ResolverContext"], [28, 9, 1, "", "get_current_resolvers"], [28, 9, 1, "", "resolver_context"]], "vineyard.deploy.distributed": [[28, 9, 1, "", "start_vineyardd"]], "vineyard.deploy.kubernetes": [[28, 9, 1, "", "delete_kubernetes_objects"], [28, 9, 1, "", "start_vineyardd"]], "vineyard.deploy.local": [[28, 9, 1, "", "start_vineyardd"]], "vineyard.io.byte": [[28, 6, 1, "", "ByteStream"]], "vineyard.io.dataframe": [[28, 6, 1, "", "DataframeStream"]], "vineyard.io": [[28, 9, 1, "", "open"], [28, 9, 1, "", "read"], [28, 9, 1, "", "write"]], "vineyard.io.recordbatch": [[28, 6, 1, "", "RecordBatchStream"]], "vineyard.shared_memory": [[28, 6, 1, "", "ShareableList"], [28, 6, 1, "", "SharedMemory"]], "vineyard.shared_memory.ShareableList": [[28, 8, 1, "", "freeze"]], "vineyard.shared_memory.SharedMemory": [[28, 7, 1, "", "buf"], [28, 8, 1, "", "freeze"], [28, 7, 1, "", "name"], [28, 7, 1, "", "size"], [28, 8, 1, "", "unlink"]]}, "objtypes": {"0": "cpp:class", "1": "cpp:function", "2": "cpp:functionParam", "3": "cpp:templateParam", "4": "cpp:member", "5": "cpp:type", "6": "py:class", "7": "py:property", "8": "py:method", "9": "py:function"}, "objnames": {"0": ["cpp", "class", "C++ class"], "1": ["cpp", "function", "C++ function"], "2": ["cpp", "functionParam", "C++ function parameter"], "3": ["cpp", "templateParam", "C++ template parameter"], "4": ["cpp", "member", "C++ member"], "5": ["cpp", "type", "C++ type"], "6": ["py", "class", "Python class"], "7": ["py", "property", "Python property"], "8": ["py", "method", "Python method"], "9": ["py", "function", "Python function"]}, "titleterms": {"why": 0, "bother": 0, "what": 0, "i": [0, 21, 22, 28], "vineyard": [0, 2, 3, 4, 6, 7, 10, 11, 12, 14, 15, 16, 17, 18, 23, 26, 27, 28, 30, 31, 33, 34, 35, 37, 38, 39, 40, 41], "featur": [0, 1], "effici": 0, "data": [0, 1, 12, 17, 20, 22, 26, 29, 30, 31, 35, 36, 38, 41], "share": [0, 1, 11, 28, 30, 33, 38], "out": [0, 1], "box": [0, 1], "abstract": [0, 1], "pluggabl": 0, "o": [0, 21, 28], "routin": 0, "orchestr": [0, 1, 13], "kubernet": [0, 2, 10, 16, 30, 37, 38, 39, 40, 41], "us": [0, 7, 17, 20, 23, 40], "case": 0, "get": [0, 4, 5, 11], "start": [0, 10, 11, 27], "now": 0, "read": 0, "paper": 0, "architectur": [1, 3], "overview": 1, "server": [1, 11, 26], "side": 1, "client": [1, 26, 28], "core": 1, "zero": 1, "cost": 1, "memori": [1, 28], "distribut": [1, 14, 20, 22, 26, 31], "big": [1, 12], "task": [1, 11], "high": 1, "level": 1, "conveni": 1, "integr": 1, "python": [1, 6, 11, 28, 32, 33, 36], "notebook": 1, "non": 1, "goal": 1, "limit": 1, "NO": 1, "mutabl": 1, "object": [1, 3, 4, 11, 20, 22, 26, 28, 33, 35, 36], "instant": 1, "remot": [1, 20], "access": [1, 20], "deploi": [2, 4, 16, 30, 40], "instal": [2, 3, 6, 7, 11], "oper": [2, 3, 4, 40], "option": [2, 4, 40], "1": [2, 9, 40], "from": [2, 6, 17, 31], "helm": 2, "chart": 2, "recommend": 2, "2": [2, 9, 40], "form": 2, "sourc": [2, 6, 7], "code": [2, 7, 24], "wait": 2, "readi": 2, "expect": [2, 3, 39, 40], "output": [2, 3, 39, 40], "creat": [2, 3, 4, 7, 36], "cluster": [2, 3, 4, 28, 30, 40], "refer": [2, 25, 26, 28], "vineyardd": [3, 4], "configur": [3, 16], "sidecar": 3, "globalobject": 3, "properti": 3, "localobject": 3, "schedul": [3, 4], "util": [3, 20, 35], "plugin": [3, 16], "driver": [3, 21, 28], "checkpoint": 3, "trigger": 3, "job": [3, 4], "assembli": 3, "an": [3, 22, 31], "repartit": 3, "initi": [3, 40], "dask": [3, 15], "failov": 3, "mechan": 3, "backup": [3, 4], "recov": [3, 4], "vineyardctl": [4, 6], "synopsi": 4, "exampl": [4, 22, 31], "delet": 4, "cert": 4, "manag": 4, "deploy": [4, 14, 15, 28], "info": 4, "inject": 4, "l": [4, 27], "blob": [4, 20, 26, 28], "metadata": [4, 20, 22, 26, 28], "workflow": [4, 7, 13, 30], "workload": 4, "involv": 5, "build": [6, 7], "etcd": 6, "prepar": [6, 30], "depend": [6, 7], "ubuntu": 6, "debian": 6, "maco": 6, "wheel": 6, "document": [6, 7], "variou": 6, "platform": 6, "contribut": 7, "develop": 7, "docker": [7, 30], "run": [7, 14], "unit": 7, "test": 7, "report": 7, "bug": 7, "submit": 7, "pull": 7, "request": 7, "pre": 7, "commit": 7, "sign": 7, "off": 7, "your": [7, 35], "format": 7, "open": 7, "git": 7, "newcom": 7, "releas": [7, 9], "frequent": 8, "ask": 8, "question": 8, "roadmap": 9, "v0": 9, "8": 9, "0": [9, 40], "7": 9, "6": 9, "5": 9, "4": [9, 40], "3": [9, 40], "note": 9, "troubleshoot": 10, "fail": 10, "issu": 10, "launch": 11, "connect": [11, 27, 40], "store": 11, "retriev": 11, "between": [11, 23, 38], "next": 11, "step": [11, 40], "airflow": 14, "introduc": 14, "The": [14, 15], "rational": 14, "how": 14, "enhanc": 14, "address": 14, "challeng": 14, "further": 14, "ahead": 14, "preprocess": [15, 31], "train": [15, 31], "tensorflow": [15, 17], "transfer": 15, "learn": [15, 17, 31, 39], "kedro": [16, 30], "requir": 16, "usag": 16, "machin": [17, 39], "numpi": 17, "datafram": [17, 22], "recordbatch": 17, "pyarrow": 17, "tabl": 17, "pytorch": 17, "mxnet": 17, "xgboost": 17, "tensor": [17, 22], "nvidia": 17, "dali": 17, "rai": 18, "kei": 19, "concept": 19, "ipcclient": 20, "v": [20, 22], "rpcclient": 20, "local": 20, "inspect": 20, "payload": 22, "two": 22, "column": 22, "where": 22, "each": 22, "separ": 22, "model": [22, 31], "compos": 22, "transient": 22, "persist": 22, "builder": [22, 28, 35, 36], "resolv": [22, 28, 36], "stream": [23, 26, 28], "produc": 23, "consum": 23, "process": [23, 29, 41], "gener": 24, "boilerpl": 24, "api": [25, 26, 28], "c": [26, 35], "basic": 26, "type": [26, 35, 36], "cli": 27, "support": 27, "command": 27, "queri": 27, "head": 27, "copi": 27, "del": 27, "stat": 27, "put": 27, "config": 27, "migrat": 27, "debug": 27, "autocomplet": 27, "acceler": 30, "argo": 30, "s3": 30, "servic": 30, "imag": 30, "pipelin": 30, "perform": 30, "kera": 31, "setup": 31, "conclus": 31, "multiprocess": 32, "shared_memori": 32, "extend": [34, 41], "defin": [35, 36], "custom": 35, "objectbuild": 35, "regist": 35, "cross": 35, "languag": 35, "compat": 35, "prerequisit": 38, "differ": 38, "contain": 38, "pod": 38, "cleanup": 40}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 8, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "nbsphinx": 4, "sphinx.ext.viewcode": 1, "sphinx": 57}, "alltitles": {"Why bother?": [[0, "why-bother"]], "What is Vineyard?": [[0, "what-is-vineyard"]], "Features": [[0, "features"]], "Efficient data sharing": [[0, "efficient-data-sharing"]], "Out-of-the-box data abstraction": [[0, "out-of-the-box-data-abstraction"]], "Pluggable I/O routines": [[0, "pluggable-i-o-routines"]], "Data orchestration on Kubernetes": [[0, "data-orchestration-on-kubernetes"]], "Use cases": [[0, "use-cases"]], "Get started now!": [[0, "get-started-now"]], "Read the Paper": [[0, "read-the-paper"]], "Architecture": [[1, "architecture"], [3, "architecture"]], "Overview": [[1, "overview"]], "Server side": [[1, "server-side"]], "Client side": [[1, "client-side"]], "Core features": [[1, "core-features"]], "Zero-cost in-memory data sharing": [[1, "zero-cost-in-memory-data-sharing"]], "Distributed data sharing in big data tasks": [[1, "distributed-data-sharing-in-big-data-tasks"]], "Out-of-the-box high-level data abstraction": [[1, "out-of-the-box-high-level-data-abstraction"]], "Convenient data integration": [[1, "convenient-data-integration"]], "Data orchestration in a Python notebook": [[1, "data-orchestration-in-a-python-notebook"]], "Non-goals and limitations": [[1, "non-goals-and-limitations"]], "NO mutable objects": [[1, "no-mutable-objects"]], "NO instant remote data accessing": [[1, "no-instant-remote-data-accessing"]], "Deploy on Kubernetes": [[2, "deploy-on-kubernetes"]], "Install vineyard-operator": [[2, "install-vineyard-operator"]], "Option #1: Install from helm chart (recommended)": [[2, "option-1-install-from-helm-chart-recommended"]], "Option #2: Install form source code": [[2, "option-2-install-form-source-code"]], "Wait vineyard-operator ready": [[2, "wait-vineyard-operator-ready"]], "Expected output": [[2, null], [2, null], [3, null], [3, null], [3, null], [39, null], [39, null], [39, null], [40, null], [40, null], [40, null], [40, null], [40, null], [40, null], [40, null], [40, null], [40, null], [40, null], [40, null], [40, null], [40, null], [40, null], [40, null]], "Create vineyard cluster": [[2, "create-vineyard-cluster"]], "References": [[2, "references"]], "Vineyard Operator": [[3, "vineyard-operator"]], "Create a vineyard Cluster": [[3, "create-a-vineyard-cluster"]], "Vineyardd Configurations": [[3, null]], "Installing vineyard as sidecar": [[3, "installing-vineyard-as-sidecar"]], "Sidecar Configurations": [[3, null], [3, "id3"]], "Objects in Vineyard": [[3, "objects-in-vineyard"]], "GlobalObject": [[3, "globalobject"]], "GlobalObject Properties": [[3, null]], "LocalObject": [[3, "localobject"]], "LocalObject Properties": [[3, null]], "Vineyard Scheduler": [[3, "vineyard-scheduler"]], "Utilizing the Vineyard Scheduler": [[3, "utilizing-the-vineyard-scheduler"]], "Scheduler Plugin Configurations": [[3, null]], "Operations and drivers": [[3, "operations-and-drivers"]], "Operation Configurations": [[3, null]], "Checkpoint": [[3, "checkpoint"]], "Triggering a checkpoint job": [[3, "triggering-a-checkpoint-job"]], "Assembly": [[3, "assembly"]], "Triggering an assembly job": [[3, "triggering-an-assembly-job"]], "Assembly Drivers Configurations": [[3, null]], "Repartitioning": [[3, "repartitioning"]], "Initiating a Repartition Job": [[3, "initiating-a-repartition-job"]], "Dask Repartition Drivers Configurations": [[3, null]], "Failover mechanism of vineyard cluster": [[3, "failover-mechanism-of-vineyard-cluster"]], "Backup Configurations": [[3, null]], "Recover Configurations": [[3, null]], "vineyardctl": [[4, "vineyardctl"]], "Synopsis": [[4, "synopsis"], [4, "id2"], [4, "id5"], [4, "id8"], [4, "id13"], [4, "id16"], [4, "id33"], [4, "id36"], [4, "id39"], [4, "id42"], [4, "id47"], [4, "id50"], [4, "id55"], [4, "id58"], [4, "id63"], [4, "id66"], [4, "id69"], [4, "id76"], [4, "id79"]], "Options": [[4, "options"], [4, "id1"], [4, "id4"], [4, "id7"], [4, "id10"], [4, "id12"], [4, "id15"], [4, "id18"], [4, "id20"], [4, "id22"], [4, "id24"], [4, "id26"], [4, "id28"], [4, "id30"], [4, "id32"], [4, "id35"], [4, "id38"], [4, "id41"], [4, "id44"], [4, "id46"], [4, "id49"], [4, "id52"], [4, "id54"], [4, "id57"], [4, "id60"], [4, "id62"], [4, "id65"], [4, "id68"], [4, "id71"], [4, "id73"], [4, "id75"], [4, "id78"], [4, "id81"]], "vineyardctl create": [[4, "vineyardctl-create"]], "Examples": [[4, "examples"], [4, "id3"], [4, "id6"], [4, "id9"], [4, "id11"], [4, "id14"], [4, "id17"], [4, "id19"], [4, "id21"], [4, "id23"], [4, "id25"], [4, "id27"], [4, "id29"], [4, "id31"], [4, "id34"], [4, "id37"], [4, "id40"], [4, "id43"], [4, "id45"], [4, "id48"], [4, "id51"], [4, "id53"], [4, "id56"], [4, "id59"], [4, "id61"], [4, "id64"], [4, "id67"], [4, "id70"], [4, "id72"], [4, "id74"], [4, "id77"], [4, "id80"]], "vineyardctl create backup": [[4, "vineyardctl-create-backup"]], "vineyardctl create operation": [[4, "vineyardctl-create-operation"]], "vineyardctl create recover": [[4, "vineyardctl-create-recover"]], "vineyardctl delete": [[4, "vineyardctl-delete"]], "vineyardctl delete backup": [[4, "vineyardctl-delete-backup"]], "vineyardctl delete cert-manager": [[4, "vineyardctl-delete-cert-manager"]], "vineyardctl delete operation": [[4, "vineyardctl-delete-operation"]], "vineyardctl delete operator": [[4, "vineyardctl-delete-operator"]], "vineyardctl delete recover": [[4, "vineyardctl-delete-recover"]], "vineyardctl delete vineyard-cluster": [[4, "vineyardctl-delete-vineyard-cluster"]], "vineyardctl delete vineyard-deployment": [[4, "vineyardctl-delete-vineyard-deployment"]], "vineyardctl delete vineyardd": [[4, "vineyardctl-delete-vineyardd"]], "vineyardctl deploy": [[4, "vineyardctl-deploy"]], "vineyardctl deploy backup-job": [[4, "vineyardctl-deploy-backup-job"]], "vineyardctl deploy cert-manager": [[4, "vineyardctl-deploy-cert-manager"]], "vineyardctl deploy operator": [[4, "vineyardctl-deploy-operator"]], "vineyardctl deploy recover-job": [[4, "vineyardctl-deploy-recover-job"]], "vineyardctl deploy vineyard-cluster": [[4, "vineyardctl-deploy-vineyard-cluster"]], "vineyardctl deploy vineyard-deployment": [[4, "vineyardctl-deploy-vineyard-deployment"]], "vineyardctl deploy vineyardd": [[4, "vineyardctl-deploy-vineyardd"]], "vineyardctl get": [[4, "vineyardctl-get"]], "vineyardctl get cluster-info": [[4, "vineyardctl-get-cluster-info"]], "vineyardctl inject": [[4, "vineyardctl-inject"]], "vineyardctl ls": [[4, "vineyardctl-ls"]], "vineyardctl ls blobs": [[4, "vineyardctl-ls-blobs"]], "vineyardctl ls metadatas": [[4, "vineyardctl-ls-metadatas"]], "vineyardctl ls objects": [[4, "vineyardctl-ls-objects"]], "vineyardctl manager": [[4, "vineyardctl-manager"]], "vineyardctl schedule": [[4, "vineyardctl-schedule"]], "vineyardctl schedule workflow": [[4, "vineyardctl-schedule-workflow"]], "vineyardctl schedule workload": [[4, "vineyardctl-schedule-workload"]], "Getting Involved": [[5, "getting-involved"]], "Building from source": [[6, "building-from-source"]], "Install vineyard": [[6, "install-vineyard"]], "Install etcd": [[6, "install-etcd"]], "Install from source": [[6, "install-from-source"]], "Prepare dependencies": [[6, "prepare-dependencies"]], "Dependencies": [[6, "dependencies"]], "Install on Ubuntu (or Debian)": [[6, "install-on-ubuntu-or-debian"]], "Dependencies on MacOS": [[6, "dependencies-on-macos"]], "Building vineyard": [[6, "building-vineyard"]], "Building python wheels": [[6, "building-python-wheels"]], "Install vineyardctl": [[6, "install-vineyardctl"]], "Building the documentation": [[6, "building-the-documentation"]], "Building on various platforms": [[6, "building-on-various-platforms"]], "Contributing to vineyard": [[7, "contributing-to-vineyard"]], "Install development dependencies": [[7, "install-development-dependencies"]], "Developing Vineyard Using Docker": [[7, "developing-vineyard-using-docker"]], "Build the source": [[7, "build-the-source"]], "Running Unit Tests": [[7, "running-unit-tests"]], "Documentation": [[7, "documentation"]], "Reporting Bugs": [[7, "reporting-bugs"]], "Submitting Pull Requests": [[7, "submitting-pull-requests"]], "Install Pre-commit": [[7, "install-pre-commit"]], "Sign Off Your Commits": [[7, "sign-off-your-commits"]], "Code Formatting": [[7, "code-formatting"]], "Open a Pull Request": [[7, "open-a-pull-request"]], "Git Workflow for Newcomers": [[7, "git-workflow-for-newcomers"]], "Creating a Release": [[7, "creating-a-release"]], "Frequently Asked Questions": [[8, "frequently-asked-questions"]], "Roadmap": [[9, "roadmap"]], "v0.8.0": [[9, "v0-8-0"]], "v0.7.0": [[9, "v0-7-0"]], "v0.6.0": [[9, "v0-6-0"]], "v0.5.0": [[9, "v0-5-0"]], "v0.4.0": [[9, "v0-4-0"]], "v0.3.0": [[9, "v0-3-0"]], "v0.2.0": [[9, "v0-2-0"]], "v0.1.0": [[9, "v0-1-0"]], "Release Notes": [[9, "release-notes"]], "Troubleshooting": [[10, "troubleshooting"]], "Vineyard Fails to Start": [[10, "vineyard-fails-to-start"]], "Vineyard Issues on Kubernetes": [[10, "vineyard-issues-on-kubernetes"]], "Getting Started": [[11, "getting-started"]], "Installing vineyard": [[11, "installing-vineyard"]], "Launching vineyard server": [[11, "launching-vineyard-server"]], "Connecting to vineyard": [[11, "connecting-to-vineyard"]], "Storing and Retrieving Python Objects": [[11, "storing-and-retrieving-python-objects"]], "Sharing objects between tasks": [[11, "sharing-objects-between-tasks"]], "Next steps": [[11, "next-steps"]], "Big-data on Vineyard": [[12, "big-data-on-vineyard"]], "Workflow orchestration": [[13, "workflow-orchestration"]], "Airflow on Vineyard": [[14, "airflow-on-vineyard"], [14, "id2"]], "Introducing Airflow": [[14, "introducing-airflow"]], "The Rationale for Airflow on Vineyard": [[14, "the-rationale-for-airflow-on-vineyard"]], "How Vineyard Enhances Airflow": [[14, "how-vineyard-enhances-airflow"]], "Addressing Distributed Deployment Challenges": [[14, "addressing-distributed-deployment-challenges"]], "Running Vineyard + Airflow": [[14, "running-vineyard-airflow"]], "Further Ahead": [[14, "further-ahead"]], "Dask on Vineyard": [[15, "dask-on-vineyard"]], "The Deployment": [[15, "the-deployment"]], "Preprocessing in Dask": [[15, "preprocessing-in-dask"]], "Training in Tensorflow": [[15, "training-in-tensorflow"]], "Transfer Learning": [[15, "transfer-learning"]], "Kedro Vineyard Plugin": [[16, "kedro-vineyard-plugin"]], "Kedro on Vineyard": [[16, "kedro-on-vineyard"]], "Requirements": [[16, "requirements"]], "Configuration": [[16, "configuration"]], "Usage": [[16, "usage"]], "Deploy to Kubernetes": [[16, "deploy-to-kubernetes"]], "Machine Learning with Vineyard": [[17, "machine-learning-with-vineyard"]], "TensorFlow": [[17, "tensorflow"]], "Using Numpy Data": [[17, "using-numpy-data"], [17, "id1"], [17, "id5"]], "Using Dataframe": [[17, "using-dataframe"], [17, "id2"], [17, "id6"]], "Using RecordBatch of Pyarrow": [[17, "using-recordbatch-of-pyarrow"], [17, "id3"], [17, "id7"]], "Using Tables of Pyarrow": [[17, "using-tables-of-pyarrow"], [17, "id4"], [17, "id8"]], "PyTorch": [[17, "pytorch"]], "MxNet": [[17, "mxnet"]], "XGBoost": [[17, "xgboost"]], "From Vineyard::Tensor": [[17, "from-vineyard-tensor"]], "From Vineyard::DataFrame": [[17, "from-vineyard-dataframe"]], "From Vineyard::RecordBatch": [[17, "from-vineyard-recordbatch"]], "From Vineyard::Table": [[17, "from-vineyard-table"]], "Nvidia-DALI": [[17, "nvidia-dali"]], "Ray on Vineyard": [[18, "ray-on-vineyard"]], "Key Concepts": [[19, "key-concepts"]], "Concepts": [[19, "concepts"]], "Data Accessing": [[20, "data-accessing"]], "IPCClient vs. RPCClient": [[20, "ipcclient-vs-rpcclient"]], "Local vs. Remote": [[20, "local-vs-remote"]], "Local Objects": [[20, "local-objects"]], "Accessing metadatas": [[20, "accessing-metadatas"]], "Using blobs": [[20, "using-blobs"]], "Remote Objects": [[20, "remote-objects"]], "Inspecting metadata": [[20, "inspecting-metadata"]], "Using remote blobs": [[20, "using-remote-blobs"]], "Utilizing Distributed Objects": [[20, "utilizing-distributed-objects"]], "I/O Drivers": [[21, "i-o-drivers"], [28, "i-o-drivers"]], "Objects": [[22, "objects"], [26, "objects"], [28, "objects"], [36, "objects"]], "Object = metadata + payloads": [[22, "object-metadata-payloads"]], "An example for the object metadata: a dataframe with two columns where each\n column is a tensor.": [[22, null]], "Separating metadata and payload": [[22, "separating-metadata-and-payload"]], "Data model": [[22, "data-model"]], "Composable": [[22, "composable"]], "Distributed objects": [[22, "distributed-objects"]], "Transient vs. Persistent": [[22, "transient-vs-persistent"]], "Builders and resolvers": [[22, "builders-and-resolvers"]], "Streams in Vineyard": [[23, "streams-in-vineyard"]], "Using streams": [[23, "using-streams"]], "Producer and consumer": [[23, "producer-and-consumer"]], "Streams between processes": [[23, "streams-between-processes"]], "Code Generation for Boilerplate": [[24, "code-generation-for-boilerplate"]], "API Reference": [[25, "api-reference"]], "C++ API Reference": [[26, "c-api-reference"]], "Metadata": [[26, "metadata"], [28, "metadata"]], "Vineyard Clients": [[26, "vineyard-clients"]], "Vineyard Server": [[26, "vineyard-server"]], "Blob": [[26, "blob"], [28, "blob"]], "Stream": [[26, "stream"]], "Basic Data Types": [[26, "basic-data-types"]], "Distributed Data Types": [[26, "distributed-data-types"]], "Vineyard Cli": [[27, "vineyard-cli"]], "Connect to vineyard": [[27, "connect-to-vineyard"]], "Supported Commands": [[27, "supported-commands"]], "ls": [[27, "ls"]], "query": [[27, "query"]], "head": [[27, "head"]], "copy": [[27, "copy"]], "del": [[27, "del"]], "stat": [[27, "stat"]], "put": [[27, "put"]], "config": [[27, "config"]], "migrate": [[27, "migrate"]], "debug": [[27, "debug"]], "start": [[27, "start"]], "Autocomplete": [[27, "autocomplete"]], "Python API Reference": [[28, "python-api-reference"]], "Vineyard client": [[28, "vineyard-client"]], "Vineyard cluster": [[28, "vineyard-cluster"]], "Resolvers and builders": [[28, "resolvers-and-builders"]], "Shared memory": [[28, "shared-memory"]], "Deployment": [[28, "deployment"]], "Streams": [[28, "streams"]], "Data processing": [[29, "data-processing"], [41, "data-processing"]], "Accelerate Data Sharing in Kedro": [[30, "accelerate-data-sharing-in-kedro"]], "Prepare the Kubernetes cluster": [[30, "prepare-the-kubernetes-cluster"]], "Deploy Argo Workflows": [[30, "deploy-argo-workflows"]], "Deploy Vineyard": [[30, "deploy-vineyard"]], "Prepare the S3 Service": [[30, "prepare-the-s3-service"]], "Prepare the Docker images": [[30, "prepare-the-docker-images"]], "Deploy the Kedro Pipelines": [[30, "deploy-the-kedro-pipelines"]], "Performance": [[30, "performance"]], "Distributed Learning with Vineyard": [[31, "Distributed-Learning-with-Vineyard"]], "An Example from Keras": [[31, "An-Example-from-Keras"]], "Setup": [[31, "Setup"]], "Preprocessing the data": [[31, "Preprocessing-the-data"]], "Training the model": [[31, "Training-the-model"]], "Conclusion": [[31, "Conclusion"]], "multiprocessing.shared_memory in Python": [[32, "multiprocessing-shared-memory-in-python"]], "Sharing Python Objects with Vineyard": [[33, "sharing-python-objects-with-vineyard"]], "Extending vineyard": [[34, "extending-vineyard"], [41, "extending-vineyard"]], "Defining Custom Data Types in C++": [[35, "defining-custom-data-types-in-c"]], "Object and ObjectBuilder": [[35, "object-and-objectbuilder"]], "Defining Your Custom Type": [[35, "defining-your-custom-type"]], "Registering C++ Types": [[35, "registering-c-types"]], "Builder": [[35, "builder"]], "Utilizing Custom Data Types with Vineyard": [[35, "utilizing-custom-data-types-with-vineyard"]], "Cross-Language Compatibility": [[35, "cross-language-compatibility"]], "Define Data Types in Python": [[36, "define-data-types-in-python"]], "Creating Builders and Resolvers": [[36, "creating-builders-and-resolvers"]], "Vineyard on Kubernetes": [[37, "vineyard-on-kubernetes"], [41, "vineyard-on-kubernetes"]], "Data sharing with Vineyard on Kubernetes": [[38, "data-sharing-with-vineyard-on-kubernetes"]], "Prerequisites": [[38, "prerequisites"]], "Data sharing between different containers": [[38, "data-sharing-between-different-containers"]], "Data sharing between different pods": [[38, "data-sharing-between-different-pods"]], "Machine learning with Vineyard on Kubernetes": [[39, "machine-learning-with-vineyard-on-kubernetes"]], "Use vineyard operator": [[40, "use-vineyard-operator"]], "Step 0: (optional) Initialize Kubernetes Cluster": [[40, "step-0-optional-initialize-kubernetes-cluster"]], "Step 1: Deploy the Vineyard Operator": [[40, "step-1-deploy-the-vineyard-operator"]], "Step 2: Deploy a Vineyard Cluster": [[40, "step-2-deploy-a-vineyard-cluster"]], "Step 3: Connect to Vineyard": [[40, "step-3-connect-to-vineyard"]], "Step 4: Cleanup": [[40, "step-4-cleanup"]]}, "indexentries": {"vineyard::array (c++ class)": [[26, "_CPPv4I0EN8vineyard5ArrayE"]], "vineyard::array::construct (c++ function)": [[26, "_CPPv4N8vineyard5Array9ConstructERK10ObjectMeta"]], "vineyard::array::create (c++ function)": [[26, "_CPPv4N8vineyard5Array6CreateEv"]], "vineyard::array::data (c++ function)": [[26, "_CPPv4NK8vineyard5Array4dataEv"]], "vineyard::array::operator[] (c++ function)": [[26, "_CPPv4NK8vineyard5ArrayixE6size_t"]], "vineyard::array::size (c++ function)": [[26, "_CPPv4NK8vineyard5Array4sizeEv"]], "vineyard::arraybuilder (c++ class)": [[26, "_CPPv4I0EN8vineyard12ArrayBuilderE"]], "vineyard::arraybuilder::arraybuilder (c++ function)": [[26, "_CPPv4N8vineyard12ArrayBuilder12ArrayBuilderER6Client6size_t"], [26, "_CPPv4N8vineyard12ArrayBuilder12ArrayBuilderER6ClientPK1T6size_t"], [26, "_CPPv4N8vineyard12ArrayBuilder12ArrayBuilderER6ClientRKNSt6vectorI1TEE"]], "vineyard::arraybuilder::build (c++ function)": [[26, "_CPPv4N8vineyard12ArrayBuilder5BuildER6Client"]], "vineyard::arraybuilder::data (c++ function)": [[26, "_CPPv4N8vineyard12ArrayBuilder4dataEv"], [26, "_CPPv4NK8vineyard12ArrayBuilder4dataEv"]], "vineyard::arraybuilder::operator[] (c++ function)": [[26, "_CPPv4N8vineyard12ArrayBuilderixE6size_t"]], "vineyard::arraybuilder::size (c++ function)": [[26, "_CPPv4NK8vineyard12ArrayBuilder4sizeEv"]], "vineyard::arraybuilder::~arraybuilder (c++ function)": [[26, "_CPPv4N8vineyard12ArrayBuilderD0Ev"]], "vineyard::blob (c++ class)": [[26, "_CPPv4N8vineyard4BlobE"]], "vineyard::blob::arrowbuffer (c++ function)": [[26, "_CPPv4NK8vineyard4Blob11ArrowBufferEv"]], "vineyard::blob::arrowbufferorempty (c++ function)": [[26, "_CPPv4NK8vineyard4Blob18ArrowBufferOrEmptyEv"]], "vineyard::blob::buffer (c++ function)": [[26, "_CPPv4NK8vineyard4Blob6BufferEv"]], "vineyard::blob::bufferorempty (c++ function)": [[26, "_CPPv4NK8vineyard4Blob13BufferOrEmptyEv"]], "vineyard::blob::construct (c++ function)": [[26, "_CPPv4N8vineyard4Blob9ConstructERK10ObjectMeta"]], "vineyard::blob::create (c++ function)": [[26, "_CPPv4N8vineyard4Blob6CreateEv"]], "vineyard::blob::dump (c++ function)": [[26, "_CPPv4NK8vineyard4Blob4DumpEv"]], "vineyard::blob::fromallocator (c++ function)": [[26, "_CPPv4N8vineyard4Blob13FromAllocatorER6ClientK8ObjectIDK9uintptr_tK6size_t"]], "vineyard::blob::frompointer (c++ function)": [[26, "_CPPv4N8vineyard4Blob11FromPointerER6ClientK9uintptr_tK6size_t"]], "vineyard::blob::makeempty (c++ function)": [[26, "_CPPv4N8vineyard4Blob9MakeEmptyER6Client"]], "vineyard::blob::allocated_size (c++ function)": [[26, "_CPPv4NK8vineyard4Blob14allocated_sizeEv"]], "vineyard::blob::data (c++ function)": [[26, "_CPPv4NK8vineyard4Blob4dataEv"]], "vineyard::blob::size (c++ function)": [[26, "_CPPv4NK8vineyard4Blob4sizeEv"]], "vineyard::blobwriter (c++ class)": [[26, "_CPPv4N8vineyard10BlobWriterE"]], "vineyard::blobwriter::abort (c++ function)": [[26, "_CPPv4N8vineyard10BlobWriter5AbortER6Client"]], "vineyard::blobwriter::addkeyvalue (c++ function)": [[26, "_CPPv4N8vineyard10BlobWriter11AddKeyValueERKNSt6stringERKNSt6stringE"], [26, "_CPPv4N8vineyard10BlobWriter11AddKeyValueERKNSt6stringERRNSt6stringE"]], "vineyard::blobwriter::buffer (c++ function)": [[26, "_CPPv4NK8vineyard10BlobWriter6BufferEv"]], "vineyard::blobwriter::build (c++ function)": [[26, "_CPPv4N8vineyard10BlobWriter5BuildER6Client"]], "vineyard::blobwriter::dump (c++ function)": [[26, "_CPPv4NK8vineyard10BlobWriter4DumpEv"]], "vineyard::blobwriter::shrink (c++ function)": [[26, "_CPPv4N8vineyard10BlobWriter6ShrinkER6ClientK6size_t"]], "vineyard::blobwriter::data (c++ function)": [[26, "_CPPv4N8vineyard10BlobWriter4dataEv"], [26, "_CPPv4NK8vineyard10BlobWriter4dataEv"]], "vineyard::blobwriter::id (c++ function)": [[26, "_CPPv4NK8vineyard10BlobWriter2idEv"]], "vineyard::blobwriter::size (c++ function)": [[26, "_CPPv4NK8vineyard10BlobWriter4sizeEv"]], "vineyard::bytestream (c++ class)": [[26, "_CPPv4N8vineyard10ByteStreamE"]], "vineyard::bytestream::create (c++ function)": [[26, "_CPPv4N8vineyard10ByteStream6CreateEv"]], "vineyard::bytestream::flushbuffer (c++ function)": [[26, "_CPPv4N8vineyard10ByteStream11FlushBufferEv"]], "vineyard::bytestream::readline (c++ function)": [[26, "_CPPv4N8vineyard10ByteStream8ReadLineERNSt6stringE"]], "vineyard::bytestream::setbuffersizelimit (c++ function)": [[26, "_CPPv4N8vineyard10ByteStream18SetBufferSizeLimitE6size_t"]], "vineyard::bytestream::writebytes (c++ function)": [[26, "_CPPv4N8vineyard10ByteStream10WriteBytesEPKc6size_t"]], "vineyard::bytestream::writeline (c++ function)": [[26, "_CPPv4N8vineyard10ByteStream9WriteLineERKNSt6stringE"]], "vineyard::client (c++ class)": [[26, "_CPPv4N8vineyard6ClientE"]], "vineyard::client::allocatedsize (c++ function)": [[26, "_CPPv4N8vineyard6Client13AllocatedSizeEK8ObjectIDR6size_t"]], "vineyard::client::client (c++ function)": [[26, "_CPPv4N8vineyard6Client6ClientEv"]], "vineyard::client::connect (c++ function)": [[26, "_CPPv4N8vineyard6Client7ConnectERKNSt6stringE"], [26, "_CPPv4N8vineyard6Client7ConnectERKNSt6stringERKNSt6stringE"], [26, "_CPPv4N8vineyard6Client7ConnectERKNSt6stringERKNSt6stringERKNSt6stringE"], [26, "_CPPv4N8vineyard6Client7ConnectEv"]], "vineyard::client::createarena (c++ function)": [[26, "_CPPv4N8vineyard6Client11CreateArenaEK6size_tRiR6size_tR9uintptr_tR9uintptr_t"]], "vineyard::client::createblob (c++ function)": [[26, "_CPPv4N8vineyard6Client10CreateBlobE6size_tRNSt10unique_ptrI10BlobWriterEE"]], "vineyard::client::createbuffer (c++ function)": [[26, "_CPPv4N8vineyard6Client12CreateBufferEK6size_tR8ObjectIDR7PayloadRNSt10shared_ptrI13MutableBufferEE"]], "vineyard::client::creatediskblob (c++ function)": [[26, "_CPPv4N8vineyard6Client14CreateDiskBlobE6size_tRKNSt6stringERNSt10unique_ptrI10BlobWriterEE"]], "vineyard::client::creategpubuffer (c++ function)": [[26, "_CPPv4N8vineyard6Client15CreateGPUBufferEK6size_tR8ObjectIDR7PayloadRNSt10shared_ptrI17GPUUnifiedAddressEE"]], "vineyard::client::default (c++ function)": [[26, "_CPPv4N8vineyard6Client7DefaultEv"]], "vineyard::client::deldata (c++ function)": [[26, "_CPPv4N8vineyard6Client7DelDataEK8ObjectIDKbKb"], [26, "_CPPv4N8vineyard6Client7DelDataERKNSt6vectorI8ObjectIDEEKbKb"]], "vineyard::client::disconnect (c++ function)": [[26, "_CPPv4N8vineyard6Client10DisconnectEv"]], "vineyard::client::dropbuffer (c++ function)": [[26, "_CPPv4N8vineyard6Client10DropBufferEK8ObjectIDKi"]], "vineyard::client::fetchandgetmetadata (c++ function)": [[26, "_CPPv4N8vineyard6Client19FetchAndGetMetaDataEK8ObjectIDR10ObjectMetaKb"]], "vineyard::client::fetchandgetobject (c++ function)": [[26, "_CPPv4I0EN8vineyard6Client17FetchAndGetObjectE6StatusK8ObjectIDRNSt10shared_ptrI1TEE"], [26, "_CPPv4I0EN8vineyard6Client17FetchAndGetObjectENSt10shared_ptrI1TEEK8ObjectID"], [26, "_CPPv4N8vineyard6Client17FetchAndGetObjectEK8ObjectID"], [26, "_CPPv4N8vineyard6Client17FetchAndGetObjectEK8ObjectIDRNSt10shared_ptrI6ObjectEE"]], "vineyard::client::fork (c++ function)": [[26, "_CPPv4N8vineyard6Client4ForkER6Client"]], "vineyard::client::getblob (c++ function)": [[26, "_CPPv4N8vineyard6Client7GetBlobEK8ObjectIDRNSt10shared_ptrI4BlobEE"], [26, "_CPPv4N8vineyard6Client7GetBlobEK8ObjectIDbRNSt10shared_ptrI4BlobEE"]], "vineyard::client::getblobs (c++ function)": [[26, "_CPPv4N8vineyard6Client8GetBlobsEKNSt6vectorI8ObjectIDEEKbRNSt6vectorINSt10shared_ptrI4BlobEEEE"], [26, "_CPPv4N8vineyard6Client8GetBlobsEKNSt6vectorI8ObjectIDEERNSt6vectorINSt10shared_ptrI4BlobEEEE"]], "vineyard::client::getbuffer (c++ function)": [[26, "_CPPv4N8vineyard6Client9GetBufferEK8ObjectIDRNSt10shared_ptrI6BufferEE"]], "vineyard::client::getbuffersizes (c++ function)": [[26, "_CPPv4N8vineyard6Client14GetBufferSizesERKNSt3setI8ObjectIDEERNSt3mapI8ObjectID6size_tEE"]], "vineyard::client::getbuffers (c++ function)": [[26, "_CPPv4N8vineyard6Client10GetBuffersERKNSt3setI8ObjectIDEERNSt3mapI8ObjectIDNSt10shared_ptrI6BufferEEEE"]], "vineyard::client::getdependency (c++ function)": [[26, "_CPPv4N8vineyard6Client13GetDependencyERK8ObjectIDRNSt3setI8ObjectIDEE"]], "vineyard::client::getgpubuffers (c++ function)": [[26, "_CPPv4N8vineyard6Client13GetGPUBuffersERKNSt3setI8ObjectIDEEKbRNSt3mapI8ObjectID17GPUUnifiedAddressEE"]], "vineyard::client::getmetadata (c++ function)": [[26, "_CPPv4N8vineyard6Client11GetMetaDataEK8ObjectIDR10ObjectMetaKb"], [26, "_CPPv4N8vineyard6Client11GetMetaDataERKNSt6vectorI8ObjectIDEERNSt6vectorI10ObjectMetaEEKb"]], "vineyard::client::getnextstreamchunk (c++ function)": [[26, "_CPPv4N8vineyard6Client18GetNextStreamChunkEK8ObjectIDK6size_tRNSt10unique_ptrI13MutableBufferEE"]], "vineyard::client::getobject (c++ function)": [[26, "_CPPv4I0EN8vineyard6Client9GetObjectE6StatusK8ObjectIDRNSt10shared_ptrI1TEE"], [26, "_CPPv4I0EN8vineyard6Client9GetObjectENSt10shared_ptrI1TEEK8ObjectID"], [26, "_CPPv4N8vineyard6Client9GetObjectEK8ObjectID"], [26, "_CPPv4N8vineyard6Client9GetObjectEK8ObjectIDRNSt10shared_ptrI6ObjectEE"]], "vineyard::client::getobjects (c++ function)": [[26, "_CPPv4N8vineyard6Client10GetObjectsERKNSt6vectorI8ObjectIDEE"]], "vineyard::client::isinuse (c++ function)": [[26, "_CPPv4N8vineyard6Client7IsInUseERK8ObjectIDRb"]], "vineyard::client::issharedmemory (c++ function)": [[26, "_CPPv4NK8vineyard6Client14IsSharedMemoryEK9uintptr_t"], [26, "_CPPv4NK8vineyard6Client14IsSharedMemoryEK9uintptr_tR8ObjectID"], [26, "_CPPv4NK8vineyard6Client14IsSharedMemoryEPKv"], [26, "_CPPv4NK8vineyard6Client14IsSharedMemoryEPKvR8ObjectID"]], "vineyard::client::isspilled (c++ function)": [[26, "_CPPv4N8vineyard6Client9IsSpilledERK8ObjectIDRb"]], "vineyard::client::listobjectmeta (c++ function)": [[26, "_CPPv4N8vineyard6Client14ListObjectMetaERKNSt6stringEKbK6size_tb"]], "vineyard::client::listobjects (c++ function)": [[26, "_CPPv4N8vineyard6Client11ListObjectsERKNSt6stringEKbK6size_t"]], "vineyard::client::ondelete (c++ function)": [[26, "_CPPv4N8vineyard6Client8OnDeleteERK8ObjectID"]], "vineyard::client::onrelease (c++ function)": [[26, "_CPPv4N8vineyard6Client9OnReleaseERK8ObjectID"]], "vineyard::client::open (c++ function)": [[26, "_CPPv4N8vineyard6Client4OpenERKNSt6stringE"], [26, "_CPPv4N8vineyard6Client4OpenERKNSt6stringERKNSt6stringERKNSt6stringE"]], "vineyard::client::postseal (c++ function)": [[26, "_CPPv4N8vineyard6Client8PostSealERK10ObjectMeta"]], "vineyard::client::pullnextstreamchunk (c++ function)": [[26, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDR10ObjectMeta"], [26, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDR8ObjectID"], [26, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDRNSt10shared_ptrI6ObjectEE"], [26, "_CPPv4N8vineyard6Client19PullNextStreamChunkEK8ObjectIDRNSt10unique_ptrI6BufferEE"]], "vineyard::client::release (c++ function)": [[26, "_CPPv4N8vineyard6Client7ReleaseERK8ObjectID"], [26, "_CPPv4N8vineyard6Client7ReleaseERKNSt6vectorI8ObjectIDEE"]], "vineyard::client::releasearena (c++ function)": [[26, "_CPPv4N8vineyard6Client12ReleaseArenaEKiRKNSt6vectorI6size_tEERKNSt6vectorI6size_tEE"]], "vineyard::client::seal (c++ function)": [[26, "_CPPv4N8vineyard6Client4SealERK8ObjectID"]], "vineyard::client::shallowcopy (c++ function)": [[26, "_CPPv4N8vineyard6Client11ShallowCopyEK8ObjectIDR8ObjectIDR6Client"], [26, "_CPPv4N8vineyard6Client11ShallowCopyEK8PlasmaIDR8ObjectIDR12PlasmaClient"]], "vineyard::client::shrinkbuffer (c++ function)": [[26, "_CPPv4N8vineyard6Client12ShrinkBufferEK8ObjectIDK6size_t"]], "vineyard::client::~client (c++ function)": [[26, "_CPPv4N8vineyard6ClientD0Ev"]], "vineyard::clientbase (c++ class)": [[26, "_CPPv4N8vineyard10ClientBaseE"]], "vineyard::clientbase::clear (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase5ClearEv"]], "vineyard::clientbase::clientbase (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase10ClientBaseERK10ClientBase"], [26, "_CPPv4N8vineyard10ClientBase10ClientBaseERR10ClientBase"], [26, "_CPPv4N8vineyard10ClientBase10ClientBaseEv"]], "vineyard::clientbase::closesession (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase12CloseSessionEv"]], "vineyard::clientbase::clusterinfo (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase11ClusterInfoERNSt3mapI10InstanceID4jsonEE"]], "vineyard::clientbase::connected (c++ function)": [[26, "_CPPv4NK8vineyard10ClientBase9ConnectedEv"]], "vineyard::clientbase::createdata (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase10CreateDataERK4jsonR8ObjectIDR9SignatureR10InstanceID"]], "vineyard::clientbase::createmetadata (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase14CreateMetaDataER10ObjectMetaR8ObjectID"], [26, "_CPPv4N8vineyard10ClientBase14CreateMetaDataER10ObjectMetaRK10InstanceIDR8ObjectID"]], "vineyard::clientbase::createstream (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase12CreateStreamERK8ObjectID"]], "vineyard::clientbase::debug (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase5DebugERK4jsonR4json"]], "vineyard::clientbase::deldata (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase7DelDataEK8ObjectIDKbKb"], [26, "_CPPv4N8vineyard10ClientBase7DelDataERKNSt6vectorI8ObjectIDEEKbKb"]], "vineyard::clientbase::disconnect (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase10DisconnectEv"]], "vineyard::clientbase::dropname (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase8DropNameERKNSt6stringE"]], "vineyard::clientbase::dropstream (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase10DropStreamEK8ObjectID"]], "vineyard::clientbase::evict (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase5EvictERKNSt6vectorI8ObjectIDEE"]], "vineyard::clientbase::exists (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase6ExistsEK8ObjectIDRb"]], "vineyard::clientbase::getdata (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase7GetDataEK8ObjectIDR4jsonKbKb"], [26, "_CPPv4N8vineyard10ClientBase7GetDataERKNSt6vectorI8ObjectIDEERNSt6vectorI4jsonEEKbKb"]], "vineyard::clientbase::getmetadata (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase11GetMetaDataEK8ObjectIDR10ObjectMetaKb"]], "vineyard::clientbase::getname (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase7GetNameERKNSt6stringER8ObjectIDKb"]], "vineyard::clientbase::ipcsocket (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase9IPCSocketEv"]], "vineyard::clientbase::ifpersist (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase9IfPersistEK8ObjectIDRb"]], "vineyard::clientbase::instancestatus (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase14InstanceStatusERNSt10shared_ptrI14InstanceStatusEE"]], "vineyard::clientbase::instances (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase9InstancesERNSt6vectorI10InstanceIDEE"]], "vineyard::clientbase::label (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase5LabelEK8ObjectIDRKNSt3mapINSt6stringENSt6stringEEE"], [26, "_CPPv4N8vineyard10ClientBase5LabelEK8ObjectIDRKNSt6stringERKNSt6stringE"]], "vineyard::clientbase::listdata (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase8ListDataERKNSt6stringEKbK6size_tRNSt13unordered_mapI8ObjectID4jsonEE"]], "vineyard::clientbase::listnames (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase9ListNamesERKNSt6stringEKbK6size_tRNSt3mapINSt6stringE8ObjectIDEE"]], "vineyard::clientbase::load (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase4LoadERKNSt6vectorI8ObjectIDEEKb"]], "vineyard::clientbase::migrateobject (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase13MigrateObjectEK8ObjectIDR8ObjectID"]], "vineyard::clientbase::open (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase4OpenERKNSt6stringE"]], "vineyard::clientbase::openstream (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase10OpenStreamERK8ObjectID14StreamOpenMode"]], "vineyard::clientbase::persist (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase7PersistEK8ObjectID"]], "vineyard::clientbase::pullnextstreamchunk (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase19PullNextStreamChunkEK8ObjectIDR10ObjectMeta"], [26, "_CPPv4N8vineyard10ClientBase19PullNextStreamChunkEK8ObjectIDR8ObjectID"], [26, "_CPPv4N8vineyard10ClientBase19PullNextStreamChunkEK8ObjectIDRNSt10shared_ptrI6ObjectEE"]], "vineyard::clientbase::pushnextstreamchunk (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase19PushNextStreamChunkEK8ObjectIDK8ObjectID"]], "vineyard::clientbase::putname (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase7PutNameEK8ObjectIDRKNSt6stringE"]], "vineyard::clientbase::rpcendpoint (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase11RPCEndpointEv"]], "vineyard::clientbase::release (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase7ReleaseERK8ObjectID"]], "vineyard::clientbase::shallowcopy (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase11ShallowCopyEK8ObjectIDR8ObjectID"], [26, "_CPPv4N8vineyard10ClientBase11ShallowCopyEK8ObjectIDRK4jsonR8ObjectID"]], "vineyard::clientbase::stopstream (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase10StopStreamEK8ObjectIDb"]], "vineyard::clientbase::syncmetadata (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase12SyncMetaDataEv"]], "vineyard::clientbase::unpin (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase5UnpinERKNSt6vectorI8ObjectIDEE"]], "vineyard::clientbase::version (c++ function)": [[26, "_CPPv4NK8vineyard10ClientBase7VersionEv"]], "vineyard::clientbase::client_mutex_ (c++ member)": [[26, "_CPPv4N8vineyard10ClientBase13client_mutex_E"]], "vineyard::clientbase::connected_ (c++ member)": [[26, "_CPPv4N8vineyard10ClientBase10connected_E"]], "vineyard::clientbase::doread (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase6doReadER4json"], [26, "_CPPv4N8vineyard10ClientBase6doReadERNSt6stringE"]], "vineyard::clientbase::dowrite (c++ function)": [[26, "_CPPv4N8vineyard10ClientBase7doWriteERKNSt6stringE"]], "vineyard::clientbase::instance_id (c++ function)": [[26, "_CPPv4NK8vineyard10ClientBase11instance_idEv"]], "vineyard::clientbase::instance_id_ (c++ member)": [[26, "_CPPv4N8vineyard10ClientBase12instance_id_E"]], "vineyard::clientbase::ipc_socket_ (c++ member)": [[26, "_CPPv4N8vineyard10ClientBase11ipc_socket_E"]], "vineyard::clientbase::operator= (c++ function)": [[26, "_CPPv4N8vineyard10ClientBaseaSERK10ClientBase"], [26, "_CPPv4N8vineyard10ClientBaseaSERR10ClientBase"]], "vineyard::clientbase::remote_instance_id (c++ function)": [[26, "_CPPv4NK8vineyard10ClientBase18remote_instance_idEv"]], "vineyard::clientbase::rpc_endpoint_ (c++ member)": [[26, "_CPPv4N8vineyard10ClientBase13rpc_endpoint_E"]], "vineyard::clientbase::server_version_ (c++ member)": [[26, "_CPPv4N8vineyard10ClientBase15server_version_E"]], "vineyard::clientbase::session_id (c++ function)": [[26, "_CPPv4NK8vineyard10ClientBase10session_idEv"]], "vineyard::clientbase::session_id_ (c++ member)": [[26, "_CPPv4N8vineyard10ClientBase11session_id_E"]], "vineyard::clientbase::vineyard_conn_ (c++ member)": [[26, "_CPPv4N8vineyard10ClientBase14vineyard_conn_E"]], "vineyard::clientbase::~clientbase (c++ function)": [[26, "_CPPv4N8vineyard10ClientBaseD0Ev"]], "vineyard::dataframe (c++ class)": [[26, "_CPPv4N8vineyard9DataFrameE"]], "vineyard::dataframe::asbatch (c++ function)": [[26, "_CPPv4NK8vineyard9DataFrame7AsBatchEb"]], "vineyard::dataframe::column (c++ function)": [[26, "_CPPv4NK8vineyard9DataFrame6ColumnERK4json"]], "vineyard::dataframe::columns (c++ function)": [[26, "_CPPv4NK8vineyard9DataFrame7ColumnsEv"]], "vineyard::dataframe::construct (c++ function)": [[26, "_CPPv4N8vineyard9DataFrame9ConstructERK10ObjectMeta"]], "vineyard::dataframe::create (c++ function)": [[26, "_CPPv4N8vineyard9DataFrame6CreateEv"]], "vineyard::dataframe::index (c++ function)": [[26, "_CPPv4NK8vineyard9DataFrame5IndexEv"]], "vineyard::dataframe::partition_index (c++ function)": [[26, "_CPPv4NK8vineyard9DataFrame15partition_indexEv"]], "vineyard::dataframe::shape (c++ function)": [[26, "_CPPv4NK8vineyard9DataFrame5shapeEv"]], "vineyard::dataframebuilder (c++ class)": [[26, "_CPPv4N8vineyard16DataFrameBuilderE"]], "vineyard::dataframebuilder::addcolumn (c++ function)": [[26, "_CPPv4N8vineyard16DataFrameBuilder9AddColumnERK4jsonNSt10shared_ptrI14ITensorBuilderEE"]], "vineyard::dataframebuilder::build (c++ function)": [[26, "_CPPv4N8vineyard16DataFrameBuilder5BuildER6Client"]], "vineyard::dataframebuilder::column (c++ function)": [[26, "_CPPv4NK8vineyard16DataFrameBuilder6ColumnERK4json"]], "vineyard::dataframebuilder::dataframebuilder (c++ function)": [[26, "_CPPv4N8vineyard16DataFrameBuilder16DataFrameBuilderER6Client"]], "vineyard::dataframebuilder::dropcolumn (c++ function)": [[26, "_CPPv4N8vineyard16DataFrameBuilder10DropColumnERK4json"]], "vineyard::dataframebuilder::partition_index (c++ function)": [[26, "_CPPv4NK8vineyard16DataFrameBuilder15partition_indexEv"]], "vineyard::dataframebuilder::set_index (c++ function)": [[26, "_CPPv4N8vineyard16DataFrameBuilder9set_indexENSt10shared_ptrI14ITensorBuilderEE"]], "vineyard::dataframebuilder::set_partition_index (c++ function)": [[26, "_CPPv4N8vineyard16DataFrameBuilder19set_partition_indexE6size_t6size_t"]], "vineyard::dataframebuilder::set_row_batch_index (c++ function)": [[26, "_CPPv4N8vineyard16DataFrameBuilder19set_row_batch_indexE6size_t"]], "vineyard::globaldataframe (c++ class)": [[26, "_CPPv4N8vineyard15GlobalDataFrameE"]], "vineyard::globaldataframe::create (c++ function)": [[26, "_CPPv4N8vineyard15GlobalDataFrame6CreateEv"]], "vineyard::globaldataframe::localpartitions (c++ function)": [[26, "_CPPv4NK8vineyard15GlobalDataFrame15LocalPartitionsER6Client"]], "vineyard::globaldataframe::postconstruct (c++ function)": [[26, "_CPPv4N8vineyard15GlobalDataFrame13PostConstructERK10ObjectMeta"]], "vineyard::globaldataframe::partition_shape (c++ function)": [[26, "_CPPv4NK8vineyard15GlobalDataFrame15partition_shapeEv"]], "vineyard::globaldataframebuilder (c++ class)": [[26, "_CPPv4N8vineyard22GlobalDataFrameBuilderE"]], "vineyard::globaldataframebuilder::addpartition (c++ function)": [[26, "_CPPv4N8vineyard22GlobalDataFrameBuilder12AddPartitionEK8ObjectID"]], "vineyard::globaldataframebuilder::addpartitions (c++ function)": [[26, "_CPPv4N8vineyard22GlobalDataFrameBuilder13AddPartitionsERKNSt6vectorI8ObjectIDEE"]], "vineyard::globaldataframebuilder::globaldataframebuilder (c++ function)": [[26, "_CPPv4N8vineyard22GlobalDataFrameBuilder22GlobalDataFrameBuilderER6Client"]], "vineyard::globaldataframebuilder::partition_shape (c++ function)": [[26, "_CPPv4NK8vineyard22GlobalDataFrameBuilder15partition_shapeEv"]], "vineyard::globaldataframebuilder::set_partition_shape (c++ function)": [[26, "_CPPv4N8vineyard22GlobalDataFrameBuilder19set_partition_shapeEK6size_tK6size_t"]], "vineyard::globaltensor (c++ class)": [[26, "_CPPv4N8vineyard12GlobalTensorE"]], "vineyard::globaltensor::create (c++ function)": [[26, "_CPPv4N8vineyard12GlobalTensor6CreateEv"]], "vineyard::globaltensor::localpartitions (c++ function)": [[26, "_CPPv4NK8vineyard12GlobalTensor15LocalPartitionsER6Client"]], "vineyard::globaltensor::postconstruct (c++ function)": [[26, "_CPPv4N8vineyard12GlobalTensor13PostConstructERK10ObjectMeta"]], "vineyard::globaltensor::partition_shape (c++ function)": [[26, "_CPPv4NK8vineyard12GlobalTensor15partition_shapeEv"]], "vineyard::globaltensor::shape (c++ function)": [[26, "_CPPv4NK8vineyard12GlobalTensor5shapeEv"]], "vineyard::globaltensorbuilder (c++ class)": [[26, "_CPPv4N8vineyard19GlobalTensorBuilderE"]], "vineyard::globaltensorbuilder::addpartition (c++ function)": [[26, "_CPPv4N8vineyard19GlobalTensorBuilder12AddPartitionEK8ObjectID"]], "vineyard::globaltensorbuilder::addpartitions (c++ function)": [[26, "_CPPv4N8vineyard19GlobalTensorBuilder13AddPartitionsERKNSt6vectorI8ObjectIDEE"]], "vineyard::globaltensorbuilder::globaltensorbuilder (c++ function)": [[26, "_CPPv4N8vineyard19GlobalTensorBuilder19GlobalTensorBuilderER6Client"]], "vineyard::globaltensorbuilder::partition_shape (c++ function)": [[26, "_CPPv4NK8vineyard19GlobalTensorBuilder15partition_shapeEv"]], "vineyard::globaltensorbuilder::set_partition_shape (c++ function)": [[26, "_CPPv4N8vineyard19GlobalTensorBuilder19set_partition_shapeERKNSt6vectorI7int64_tEE"]], "vineyard::globaltensorbuilder::set_shape (c++ function)": [[26, "_CPPv4N8vineyard19GlobalTensorBuilder9set_shapeERKNSt6vectorI7int64_tEE"]], "vineyard::globaltensorbuilder::shape (c++ function)": [[26, "_CPPv4NK8vineyard19GlobalTensorBuilder5shapeEv"]], "vineyard::hashmap (c++ class)": [[26, "_CPPv4I0000EN8vineyard7HashmapE"]], "vineyard::hashmap::construct (c++ function)": [[26, "_CPPv4N8vineyard7Hashmap9ConstructERK10ObjectMeta"]], "vineyard::hashmap::create (c++ function)": [[26, "_CPPv4N8vineyard7Hashmap6CreateEv"]], "vineyard::hashmap::entry (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap5EntryE"]], "vineyard::hashmap::entrypointer (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap12EntryPointerE"]], "vineyard::hashmap::equal (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap5EqualE"]], "vineyard::hashmap::hasher (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap6HasherE"], [26, "_CPPv4N8vineyard7Hashmap6hasherE"]], "vineyard::hashmap::keyequal (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap8KeyEqualE"]], "vineyard::hashmap::keyhash (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap7KeyHashE"]], "vineyard::hashmap::postconstruct (c++ function)": [[26, "_CPPv4N8vineyard7Hashmap13PostConstructERK10ObjectMeta"]], "vineyard::hashmap::t (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap1TE"]], "vineyard::hashmap::at (c++ function)": [[26, "_CPPv4NK8vineyard7Hashmap2atERK1K"]], "vineyard::hashmap::begin (c++ function)": [[26, "_CPPv4NK8vineyard7Hashmap5beginEv"]], "vineyard::hashmap::bucket_count (c++ function)": [[26, "_CPPv4NK8vineyard7Hashmap12bucket_countEv"]], "vineyard::hashmap::const_pointer (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap13const_pointerE"]], "vineyard::hashmap::const_reference (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap15const_referenceE"]], "vineyard::hashmap::count (c++ function)": [[26, "_CPPv4NK8vineyard7Hashmap5countERK1K"]], "vineyard::hashmap::difference_type (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap15difference_typeE"]], "vineyard::hashmap::empty (c++ function)": [[26, "_CPPv4NK8vineyard7Hashmap5emptyEv"]], "vineyard::hashmap::end (c++ function)": [[26, "_CPPv4NK8vineyard7Hashmap3endEv"]], "vineyard::hashmap::find (c++ function)": [[26, "_CPPv4N8vineyard7Hashmap4findERK1K"], [26, "_CPPv4NK8vineyard7Hashmap4findERK1K"]], "vineyard::hashmap::flat_hash_table_type (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap20flat_hash_table_typeE"]], "vineyard::hashmap::iterator (c++ struct)": [[26, "_CPPv4N8vineyard7Hashmap8iteratorE"]], "vineyard::hashmap::iterator::current (c++ member)": [[26, "_CPPv4N8vineyard7Hashmap8iterator7currentE"]], "vineyard::hashmap::iterator::iterator (c++ function)": [[26, "_CPPv4N8vineyard7Hashmap8iterator8iteratorE12EntryPointer"], [26, "_CPPv4N8vineyard7Hashmap8iterator8iteratorEv"]], "vineyard::hashmap::iterator::operator!= (c++ function)": [[26, "_CPPv4N8vineyard7Hashmap8iteratorneERK8iteratorRK8iterator"]], "vineyard::hashmap::iterator::operator* (c++ function)": [[26, "_CPPv4NK8vineyard7Hashmap8iteratormlEv"]], "vineyard::hashmap::iterator::operator++ (c++ function)": [[26, "_CPPv4N8vineyard7Hashmap8iteratorppEi"], [26, "_CPPv4N8vineyard7Hashmap8iteratorppEv"]], "vineyard::hashmap::iterator::operator-> (c++ function)": [[26, "_CPPv4NK8vineyard7Hashmap8iteratorptEv"]], "vineyard::hashmap::iterator::operator== (c++ function)": [[26, "_CPPv4N8vineyard7Hashmap8iteratoreqERK8iteratorRK8iterator"]], "vineyard::hashmap::key_equal (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap9key_equalE"]], "vineyard::hashmap::load_factor (c++ function)": [[26, "_CPPv4NK8vineyard7Hashmap11load_factorEv"]], "vineyard::hashmap::pointer (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap7pointerE"]], "vineyard::hashmap::reference (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap9referenceE"]], "vineyard::hashmap::size (c++ function)": [[26, "_CPPv4NK8vineyard7Hashmap4sizeEv"]], "vineyard::hashmap::size_type (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap9size_typeE"]], "vineyard::hashmap::value_type (c++ type)": [[26, "_CPPv4N8vineyard7Hashmap10value_typeE"]], "vineyard::hashmapbuilder (c++ class)": [[26, "_CPPv4I0000EN8vineyard14HashmapBuilderE"]], "vineyard::hashmapbuilder::associatedatabuffer (c++ function)": [[26, "_CPPv4N8vineyard14HashmapBuilder19AssociateDataBufferENSt10shared_ptrI4BlobEE"]], "vineyard::hashmapbuilder::build (c++ function)": [[26, "_CPPv4N8vineyard14HashmapBuilder5BuildER6Client"]], "vineyard::hashmapbuilder::hashmapbuilder (c++ function)": [[26, "_CPPv4N8vineyard14HashmapBuilder14HashmapBuilderER6Client"], [26, "_CPPv4N8vineyard14HashmapBuilder14HashmapBuilderER6ClientRRN3ska13flat_hash_mapI1K1V1H1EEE"]], "vineyard::hashmapbuilder::at (c++ function)": [[26, "_CPPv4N8vineyard14HashmapBuilder2atERK1K"], [26, "_CPPv4NK8vineyard14HashmapBuilder2atERK1K"]], "vineyard::hashmapbuilder::begin (c++ function)": [[26, "_CPPv4N8vineyard14HashmapBuilder5beginEv"], [26, "_CPPv4NK8vineyard14HashmapBuilder5beginEv"]], "vineyard::hashmapbuilder::bucket_count (c++ function)": [[26, "_CPPv4NK8vineyard14HashmapBuilder12bucket_countEv"]], "vineyard::hashmapbuilder::cbegin (c++ function)": [[26, "_CPPv4NK8vineyard14HashmapBuilder6cbeginEv"]], "vineyard::hashmapbuilder::cend (c++ function)": [[26, "_CPPv4NK8vineyard14HashmapBuilder4cendEv"]], "vineyard::hashmapbuilder::emplace (c++ function)": [[26, "_CPPv4IDpEN8vineyard14HashmapBuilder7emplaceEbDpRR4Args"]], "vineyard::hashmapbuilder::empty (c++ function)": [[26, "_CPPv4NK8vineyard14HashmapBuilder5emptyEv"]], "vineyard::hashmapbuilder::end (c++ function)": [[26, "_CPPv4N8vineyard14HashmapBuilder3endEv"], [26, "_CPPv4NK8vineyard14HashmapBuilder3endEv"]], "vineyard::hashmapbuilder::find (c++ function)": [[26, "_CPPv4N8vineyard14HashmapBuilder4findERK1K"]], "vineyard::hashmapbuilder::load_factor (c++ function)": [[26, "_CPPv4NK8vineyard14HashmapBuilder11load_factorEv"]], "vineyard::hashmapbuilder::operator[] (c++ function)": [[26, "_CPPv4N8vineyard14HashmapBuilderixERK1K"], [26, "_CPPv4N8vineyard14HashmapBuilderixERR1K"]], "vineyard::hashmapbuilder::reserve (c++ function)": [[26, "_CPPv4N8vineyard14HashmapBuilder7reserveE6size_t"]], "vineyard::hashmapbuilder::size (c++ function)": [[26, "_CPPv4NK8vineyard14HashmapBuilder4sizeEv"]], "vineyard::instancestatus (c++ struct)": [[26, "_CPPv4N8vineyard14InstanceStatusE"]], "vineyard::instancestatus::instancestatus (c++ function)": [[26, "_CPPv4N8vineyard14InstanceStatus14InstanceStatusERK4json"]], "vineyard::instancestatus::deferred_requests (c++ member)": [[26, "_CPPv4N8vineyard14InstanceStatus17deferred_requestsE"]], "vineyard::instancestatus::deployment (c++ member)": [[26, "_CPPv4N8vineyard14InstanceStatus10deploymentE"]], "vineyard::instancestatus::instance_id (c++ member)": [[26, "_CPPv4N8vineyard14InstanceStatus11instance_idE"]], "vineyard::instancestatus::ipc_connections (c++ member)": [[26, "_CPPv4N8vineyard14InstanceStatus15ipc_connectionsE"]], "vineyard::instancestatus::memory_limit (c++ member)": [[26, "_CPPv4N8vineyard14InstanceStatus12memory_limitE"]], "vineyard::instancestatus::memory_usage (c++ member)": [[26, "_CPPv4N8vineyard14InstanceStatus12memory_usageE"]], "vineyard::instancestatus::rpc_connections (c++ member)": [[26, "_CPPv4N8vineyard14InstanceStatus15rpc_connectionsE"]], "vineyard::object (c++ class)": [[26, "_CPPv4N8vineyard6ObjectE"]], "vineyard::object::build (c++ function)": [[26, "_CPPv4N8vineyard6Object5BuildER6Client"]], "vineyard::object::construct (c++ function)": [[26, "_CPPv4N8vineyard6Object9ConstructERK10ObjectMeta"]], "vineyard::object::isglobal (c++ function)": [[26, "_CPPv4NK8vineyard6Object8IsGlobalEv"]], "vineyard::object::islocal (c++ function)": [[26, "_CPPv4NK8vineyard6Object7IsLocalEv"]], "vineyard::object::ispersist (c++ function)": [[26, "_CPPv4NK8vineyard6Object9IsPersistEv"]], "vineyard::object::object (c++ function)": [[26, "_CPPv4N8vineyard6Object6ObjectEv"]], "vineyard::object::persist (c++ function)": [[26, "_CPPv4NK8vineyard6Object7PersistER10ClientBase"]], "vineyard::object::postconstruct (c++ function)": [[26, "_CPPv4N8vineyard6Object13PostConstructERK10ObjectMeta"]], "vineyard::object::_seal (c++ function)": [[26, "_CPPv4N8vineyard6Object5_SealER6Client"]], "vineyard::object::id (c++ function)": [[26, "_CPPv4NK8vineyard6Object2idEv"]], "vineyard::object::id_ (c++ member)": [[26, "_CPPv4N8vineyard6Object3id_E"]], "vineyard::object::meta (c++ function)": [[26, "_CPPv4NK8vineyard6Object4metaEv"]], "vineyard::object::meta_ (c++ member)": [[26, "_CPPv4N8vineyard6Object5meta_E"]], "vineyard::object::nbytes (c++ function)": [[26, "_CPPv4NK8vineyard6Object6nbytesEv"]], "vineyard::object::~object (c++ function)": [[26, "_CPPv4N8vineyard6ObjectD0Ev"]], "vineyard::objectbase (c++ class)": [[26, "_CPPv4N8vineyard10ObjectBaseE"]], "vineyard::objectbase::build (c++ function)": [[26, "_CPPv4N8vineyard10ObjectBase5BuildER6Client"]], "vineyard::objectbase::_seal (c++ function)": [[26, "_CPPv4N8vineyard10ObjectBase5_SealER6Client"]], "vineyard::objectbuilder (c++ class)": [[26, "_CPPv4N8vineyard13ObjectBuilderE"]], "vineyard::objectbuilder::build (c++ function)": [[26, "_CPPv4N8vineyard13ObjectBuilder5BuildER6Client"]], "vineyard::objectbuilder::seal (c++ function)": [[26, "_CPPv4N8vineyard13ObjectBuilder4SealER6Client"], [26, "_CPPv4N8vineyard13ObjectBuilder4SealER6ClientRNSt10shared_ptrI6ObjectEE"]], "vineyard::objectbuilder::_seal (c++ function)": [[26, "_CPPv4N8vineyard13ObjectBuilder5_SealER6Client"], [26, "_CPPv4N8vineyard13ObjectBuilder5_SealER6ClientRNSt10shared_ptrI6ObjectEE"]], "vineyard::objectbuilder::sealed (c++ function)": [[26, "_CPPv4NK8vineyard13ObjectBuilder6sealedEv"]], "vineyard::objectbuilder::set_sealed (c++ function)": [[26, "_CPPv4N8vineyard13ObjectBuilder10set_sealedEKb"]], "vineyard::objectbuilder::~objectbuilder (c++ function)": [[26, "_CPPv4N8vineyard13ObjectBuilderD0Ev"]], "vineyard::objectid (c++ type)": [[26, "_CPPv4N8vineyard8ObjectIDE"]], "vineyard::objectmeta (c++ class)": [[26, "_CPPv4N8vineyard10ObjectMetaE"]], "vineyard::objectmeta::addkeyvalue (c++ function)": [[26, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK12UnorderedMapI4json5ValueE"], [26, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK12UnorderedMapINSt6stringE5ValueE"], [26, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK1T"], [26, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK3MapI4json5ValueE"], [26, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK3MapINSt6stringE5ValueE"], [26, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERK5TupleI1TE"], [26, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt13unordered_mapI4json5ValueEE"], [26, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt13unordered_mapINSt6stringE5ValueEE"], [26, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt3mapI4json5ValueEE"], [26, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt3mapINSt6stringE5ValueEE"], [26, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt3setI1TEE"], [26, "_CPPv4I0EN8vineyard10ObjectMeta11AddKeyValueEvRKNSt6stringERKNSt6vectorI1TEE"], [26, "_CPPv4N8vineyard10ObjectMeta11AddKeyValueERKNSt6stringERK4json"], [26, "_CPPv4N8vineyard10ObjectMeta11AddKeyValueERKNSt6stringERKNSt6stringE"]], "vineyard::objectmeta::addmember (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringEK8ObjectID"], [26, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringEPK6Object"], [26, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringERK10ObjectMeta"], [26, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringERK6Object"], [26, "_CPPv4N8vineyard10ObjectMeta9AddMemberERKNSt6stringERKNSt10shared_ptrI6ObjectEE"]], "vineyard::objectmeta::forcelocal (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta10ForceLocalEv"]], "vineyard::objectmeta::getbuffer (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta9GetBufferEK8ObjectIDRNSt10shared_ptrI6BufferEE"]], "vineyard::objectmeta::getbufferset (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta12GetBufferSetEv"]], "vineyard::objectmeta::getclient (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta9GetClientEv"]], "vineyard::objectmeta::getid (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta5GetIdEv"]], "vineyard::objectmeta::getinstanceid (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta13GetInstanceIdEv"]], "vineyard::objectmeta::getkeyvalue (c++ function)": [[26, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEK1TRKNSt6stringE"], [26, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER12UnorderedMapI4json5ValueE"], [26, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER12UnorderedMapINSt6stringE5ValueE"], [26, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER1T"], [26, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER3MapI4json5ValueE"], [26, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER3MapINSt6stringE5ValueE"], [26, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringER5TupleI1TE"], [26, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt13unordered_mapI4json5ValueEE"], [26, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt13unordered_mapINSt6stringE5ValueEE"], [26, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt3mapI4json5ValueEE"], [26, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt3mapINSt6stringE5ValueEE"], [26, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt3setI1TEE"], [26, "_CPPv4I0ENK8vineyard10ObjectMeta11GetKeyValueEvRKNSt6stringERNSt6vectorI1TEE"], [26, "_CPPv4IENK8vineyard10ObjectMeta11GetKeyValueEK4jsonRKNSt6stringE"], [26, "_CPPv4NK8vineyard10ObjectMeta11GetKeyValueERKNSt6stringE"], [26, "_CPPv4NK8vineyard10ObjectMeta11GetKeyValueERKNSt6stringER4json"]], "vineyard::objectmeta::getmember (c++ function)": [[26, "_CPPv4I0ENK8vineyard10ObjectMeta9GetMemberE6StatusRKNSt6stringERNSt10shared_ptrI1TEE"], [26, "_CPPv4I0ENK8vineyard10ObjectMeta9GetMemberENSt10shared_ptrI1TEERKNSt6stringE"], [26, "_CPPv4NK8vineyard10ObjectMeta9GetMemberERKNSt6stringE"], [26, "_CPPv4NK8vineyard10ObjectMeta9GetMemberERKNSt6stringERNSt10shared_ptrI6ObjectEE"]], "vineyard::objectmeta::getmembermeta (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta13GetMemberMetaERKNSt6stringE"], [26, "_CPPv4NK8vineyard10ObjectMeta13GetMemberMetaERKNSt6stringER10ObjectMeta"]], "vineyard::objectmeta::getnbytes (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta9GetNBytesEv"]], "vineyard::objectmeta::getsignature (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta12GetSignatureEv"]], "vineyard::objectmeta::gettypename (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta11GetTypeNameEv"]], "vineyard::objectmeta::haskey (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta6HasKeyERKNSt6stringE"], [26, "_CPPv4NK8vineyard10ObjectMeta6HaskeyERKNSt6stringE"]], "vineyard::objectmeta::isglobal (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta8IsGlobalEv"]], "vineyard::objectmeta::islocal (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta7IsLocalEv"]], "vineyard::objectmeta::label (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta5LabelERKNSt6stringE"]], "vineyard::objectmeta::labels (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta6LabelsEv"]], "vineyard::objectmeta::memoryusage (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta11MemoryUsageER4jsonKb"], [26, "_CPPv4NK8vineyard10ObjectMeta11MemoryUsageEv"]], "vineyard::objectmeta::metadata (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta8MetaDataEv"]], "vineyard::objectmeta::mutmetadata (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMeta11MutMetaDataEv"]], "vineyard::objectmeta::objectmeta (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMeta10ObjectMetaERK10ObjectMeta"], [26, "_CPPv4N8vineyard10ObjectMeta10ObjectMetaEv"]], "vineyard::objectmeta::printmeta (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta9PrintMetaEv"]], "vineyard::objectmeta::reset (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMeta5ResetEv"]], "vineyard::objectmeta::resetkey (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMeta8ResetKeyERKNSt6stringE"]], "vineyard::objectmeta::resetsignature (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMeta14ResetSignatureEv"]], "vineyard::objectmeta::setbuffer (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMeta9SetBufferERK8ObjectIDRKNSt10shared_ptrI6BufferEE"]], "vineyard::objectmeta::setclient (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMeta9SetClientEP10ClientBase"]], "vineyard::objectmeta::setglobal (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMeta9SetGlobalEb"]], "vineyard::objectmeta::setid (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMeta5SetIdERK8ObjectID"]], "vineyard::objectmeta::setmetadata (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMeta11SetMetaDataEP10ClientBaseRK4json"]], "vineyard::objectmeta::setnbytes (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMeta9SetNBytesEK6size_t"]], "vineyard::objectmeta::settypename (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMeta11SetTypeNameERKNSt6stringE"]], "vineyard::objectmeta::timestamp (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta9TimestampEv"]], "vineyard::objectmeta::tostring (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta8ToStringEv"]], "vineyard::objectmeta::unsafe (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMeta6UnsafeE4json6size_tP8ObjectIDP9uintptr_tP6size_t"], [26, "_CPPv4N8vineyard10ObjectMeta6UnsafeENSt6stringE6size_tP8ObjectIDP9uintptr_tP6size_t"]], "vineyard::objectmeta::begin (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta5beginEv"]], "vineyard::objectmeta::const_iterator (c++ type)": [[26, "_CPPv4N8vineyard10ObjectMeta14const_iteratorE"]], "vineyard::objectmeta::end (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta3endEv"]], "vineyard::objectmeta::incomplete (c++ function)": [[26, "_CPPv4NK8vineyard10ObjectMeta10incompleteEv"]], "vineyard::objectmeta::operator= (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMetaaSERK10ObjectMeta"]], "vineyard::objectmeta::~objectmeta (c++ function)": [[26, "_CPPv4N8vineyard10ObjectMetaD0Ev"]], "vineyard::rpcclient (c++ class)": [[26, "_CPPv4N8vineyard9RPCClientE"]], "vineyard::rpcclient::connect (c++ function)": [[26, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE"], [26, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_t"], [26, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_tK9SessionIDRKNSt6stringERKNSt6stringE"], [26, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringE8uint32_tRKNSt6stringERKNSt6stringE"], [26, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringEK9SessionIDRKNSt6stringERKNSt6stringE"], [26, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringERKNSt6stringE"], [26, "_CPPv4N8vineyard9RPCClient7ConnectERKNSt6stringERKNSt6stringERKNSt6stringE"], [26, "_CPPv4N8vineyard9RPCClient7ConnectEv"]], "vineyard::rpcclient::createremoteblob (c++ function)": [[26, "_CPPv4N8vineyard9RPCClient16CreateRemoteBlobERKNSt10shared_ptrI16RemoteBlobWriterEER8ObjectID"]], "vineyard::rpcclient::fork (c++ function)": [[26, "_CPPv4N8vineyard9RPCClient4ForkER9RPCClient"]], "vineyard::rpcclient::getmetadata (c++ function)": [[26, "_CPPv4N8vineyard9RPCClient11GetMetaDataEK8ObjectIDR10ObjectMetaKb"], [26, "_CPPv4N8vineyard9RPCClient11GetMetaDataERKNSt6vectorI8ObjectIDEERNSt6vectorI10ObjectMetaEEKb"]], "vineyard::rpcclient::getobject (c++ function)": [[26, "_CPPv4I0EN8vineyard9RPCClient9GetObjectE6StatusK8ObjectIDRNSt10shared_ptrI1TEE"], [26, "_CPPv4I0EN8vineyard9RPCClient9GetObjectENSt10shared_ptrI1TEEK8ObjectID"], [26, "_CPPv4N8vineyard9RPCClient9GetObjectEK8ObjectID"], [26, "_CPPv4N8vineyard9RPCClient9GetObjectEK8ObjectIDRNSt10shared_ptrI6ObjectEE"]], "vineyard::rpcclient::getobjects (c++ function)": [[26, "_CPPv4N8vineyard9RPCClient10GetObjectsERKNSt6vectorI8ObjectIDEE"]], "vineyard::rpcclient::getremoteblob (c++ function)": [[26, "_CPPv4N8vineyard9RPCClient13GetRemoteBlobERK8ObjectIDKbRNSt10shared_ptrI10RemoteBlobEE"], [26, "_CPPv4N8vineyard9RPCClient13GetRemoteBlobERK8ObjectIDRNSt10shared_ptrI10RemoteBlobEE"]], "vineyard::rpcclient::getremoteblobs (c++ function)": [[26, "_CPPv4N8vineyard9RPCClient14GetRemoteBlobsERKNSt6vectorI8ObjectIDEEKbRNSt6vectorINSt10shared_ptrI10RemoteBlobEEEE"], [26, "_CPPv4N8vineyard9RPCClient14GetRemoteBlobsERKNSt6vectorI8ObjectIDEERNSt6vectorINSt10shared_ptrI10RemoteBlobEEEE"]], "vineyard::rpcclient::listobjectmeta (c++ function)": [[26, "_CPPv4N8vineyard9RPCClient14ListObjectMetaERKNSt6stringEKbK6size_tb"]], "vineyard::rpcclient::listobjects (c++ function)": [[26, "_CPPv4N8vineyard9RPCClient11ListObjectsERKNSt6stringEKbK6size_t"]], "vineyard::rpcclient::remote_instance_id (c++ function)": [[26, "_CPPv4NK8vineyard9RPCClient18remote_instance_idEv"]], "vineyard::rpcclient::~rpcclient (c++ function)": [[26, "_CPPv4N8vineyard9RPCClientD0Ev"]], "vineyard::scalar (c++ class)": [[26, "_CPPv4I0EN8vineyard6ScalarE"]], "vineyard::scalar::construct (c++ function)": [[26, "_CPPv4N8vineyard6Scalar9ConstructERK10ObjectMeta"]], "vineyard::scalar::create (c++ function)": [[26, "_CPPv4N8vineyard6Scalar6CreateEv"]], "vineyard::scalar::type (c++ function)": [[26, "_CPPv4NK8vineyard6Scalar4TypeEv"]], "vineyard::scalar::value (c++ function)": [[26, "_CPPv4NK8vineyard6Scalar5ValueEv"]], "vineyard::scalarbuilder (c++ class)": [[26, "_CPPv4I0EN8vineyard13ScalarBuilderE"]], "vineyard::scalarbuilder::scalarbuilder (c++ function)": [[26, "_CPPv4N8vineyard13ScalarBuilder13ScalarBuilderER6Client"], [26, "_CPPv4N8vineyard13ScalarBuilder13ScalarBuilderER6ClientRK1T"]], "vineyard::scalarbuilder::setvalue (c++ function)": [[26, "_CPPv4N8vineyard13ScalarBuilder8SetValueERK1T"]], "vineyard::sequence (c++ class)": [[26, "_CPPv4N8vineyard8SequenceE"]], "vineyard::sequence::at (c++ function)": [[26, "_CPPv4NK8vineyard8Sequence2AtE6size_t"]], "vineyard::sequence::construct (c++ function)": [[26, "_CPPv4N8vineyard8Sequence9ConstructERK10ObjectMeta"]], "vineyard::sequence::create (c++ function)": [[26, "_CPPv4N8vineyard8Sequence6CreateEv"]], "vineyard::sequence::first (c++ function)": [[26, "_CPPv4NK8vineyard8Sequence5FirstEv"]], "vineyard::sequence::second (c++ function)": [[26, "_CPPv4NK8vineyard8Sequence6SecondEv"]], "vineyard::sequence::size (c++ function)": [[26, "_CPPv4NK8vineyard8Sequence4SizeEv"]], "vineyard::sequence::begin (c++ function)": [[26, "_CPPv4NK8vineyard8Sequence5beginEv"]], "vineyard::sequence::end (c++ function)": [[26, "_CPPv4NK8vineyard8Sequence3endEv"]], "vineyard::sequence::iterator (c++ class)": [[26, "_CPPv4N8vineyard8Sequence8iteratorE"]], "vineyard::sequence::iterator::iterator (c++ function)": [[26, "_CPPv4N8vineyard8Sequence8iterator8iteratorEPK8Sequence6size_t"]], "vineyard::sequence::iterator::operator!= (c++ function)": [[26, "_CPPv4NK8vineyard8Sequence8iteratorneE8iterator"]], "vineyard::sequence::iterator::operator* (c++ function)": [[26, "_CPPv4NK8vineyard8Sequence8iteratormlEv"]], "vineyard::sequence::iterator::operator++ (c++ function)": [[26, "_CPPv4N8vineyard8Sequence8iteratorppEv"]], "vineyard::sequence::iterator::operator== (c++ function)": [[26, "_CPPv4NK8vineyard8Sequence8iteratoreqE8iterator"]], "vineyard::sequencebuilder (c++ class)": [[26, "_CPPv4N8vineyard15SequenceBuilderE"]], "vineyard::sequencebuilder::at (c++ function)": [[26, "_CPPv4N8vineyard15SequenceBuilder2AtE6size_t"]], "vineyard::sequencebuilder::sequencebuilder (c++ function)": [[26, "_CPPv4N8vineyard15SequenceBuilder15SequenceBuilderER6Client"], [26, "_CPPv4N8vineyard15SequenceBuilder15SequenceBuilderER6ClientK6size_t"]], "vineyard::sequencebuilder::setsize (c++ function)": [[26, "_CPPv4N8vineyard15SequenceBuilder7SetSizeE6size_t"]], "vineyard::sequencebuilder::setvalue (c++ function)": [[26, "_CPPv4N8vineyard15SequenceBuilder8SetValueE6size_tRKNSt10shared_ptrI13ObjectBuilderEE"], [26, "_CPPv4N8vineyard15SequenceBuilder8SetValueE6size_tRKNSt10shared_ptrI6ObjectEE"]], "vineyard::sequencebuilder::size (c++ function)": [[26, "_CPPv4NK8vineyard15SequenceBuilder4SizeEv"]], "vineyard::tensor (c++ class)": [[26, "_CPPv4I0EN8vineyard6TensorE"]], "vineyard::tensor::arrowtensor (c++ function)": [[26, "_CPPv4N8vineyard6Tensor11ArrowTensorEv"]], "vineyard::tensor::arrowtensort (c++ type)": [[26, "_CPPv4N8vineyard6Tensor12ArrowTensorTE"]], "vineyard::tensor::construct (c++ function)": [[26, "_CPPv4N8vineyard6Tensor9ConstructERK10ObjectMeta"]], "vineyard::tensor::create (c++ function)": [[26, "_CPPv4N8vineyard6Tensor6CreateEv"]], "vineyard::tensor::auxiliary_buffer (c++ function)": [[26, "_CPPv4NK8vineyard6Tensor16auxiliary_bufferEv"]], "vineyard::tensor::buffer (c++ function)": [[26, "_CPPv4NK8vineyard6Tensor6bufferEv"]], "vineyard::tensor::data (c++ function)": [[26, "_CPPv4NK8vineyard6Tensor4dataEv"]], "vineyard::tensor::operator[] (c++ function)": [[26, "_CPPv4NK8vineyard6TensorixE6size_t"]], "vineyard::tensor::partition_index (c++ function)": [[26, "_CPPv4NK8vineyard6Tensor15partition_indexEv"]], "vineyard::tensor::shape (c++ function)": [[26, "_CPPv4NK8vineyard6Tensor5shapeEv"]], "vineyard::tensor::strides (c++ function)": [[26, "_CPPv4NK8vineyard6Tensor7stridesEv"]], "vineyard::tensor::value_const_pointer_t (c++ type)": [[26, "_CPPv4N8vineyard6Tensor21value_const_pointer_tE"]], "vineyard::tensor::value_pointer_t (c++ type)": [[26, "_CPPv4N8vineyard6Tensor15value_pointer_tE"]], "vineyard::tensor::value_t (c++ type)": [[26, "_CPPv4N8vineyard6Tensor7value_tE"]], "vineyard::tensor::value_type (c++ function)": [[26, "_CPPv4NK8vineyard6Tensor10value_typeEv"]], "vineyard::tensorbuilder (c++ class)": [[26, "_CPPv4I0EN8vineyard13TensorBuilderE"]], "vineyard::tensorbuilder::build (c++ function)": [[26, "_CPPv4N8vineyard13TensorBuilder5BuildER6Client"]], "vineyard::tensorbuilder::tensorbuilder (c++ function)": [[26, "_CPPv4N8vineyard13TensorBuilder13TensorBuilderER6ClientRKNSt6vectorI7int64_tEE"], [26, "_CPPv4N8vineyard13TensorBuilder13TensorBuilderER6ClientRKNSt6vectorI7int64_tEERKNSt6vectorI7int64_tEE"]], "vineyard::tensorbuilder::data (c++ function)": [[26, "_CPPv4NK8vineyard13TensorBuilder4dataEv"]], "vineyard::tensorbuilder::partition_index (c++ function)": [[26, "_CPPv4NK8vineyard13TensorBuilder15partition_indexEv"]], "vineyard::tensorbuilder::set_partition_index (c++ function)": [[26, "_CPPv4N8vineyard13TensorBuilder19set_partition_indexERKNSt6vectorI7int64_tEE"]], "vineyard::tensorbuilder::set_shape (c++ function)": [[26, "_CPPv4N8vineyard13TensorBuilder9set_shapeERKNSt6vectorI7int64_tEE"]], "vineyard::tensorbuilder::shape (c++ function)": [[26, "_CPPv4NK8vineyard13TensorBuilder5shapeEv"]], "vineyard::tensorbuilder::strides (c++ function)": [[26, "_CPPv4NK8vineyard13TensorBuilder7stridesEv"]], "vineyard::tensorbuilder::value_const_pointer_t (c++ type)": [[26, "_CPPv4N8vineyard13TensorBuilder21value_const_pointer_tE"]], "vineyard::tensorbuilder::value_pointer_t (c++ type)": [[26, "_CPPv4N8vineyard13TensorBuilder15value_pointer_tE"]], "vineyard::tensorbuilder::value_t (c++ type)": [[26, "_CPPv4N8vineyard13TensorBuilder7value_tE"]], "blob (class in vineyard)": [[28, "vineyard.Blob"]], "blobbuilder (class in vineyard)": [[28, "vineyard.BlobBuilder"]], "buildercontext (class in vineyard.core.builder)": [[28, "vineyard.core.builder.BuilderContext"]], "bytestream (class in vineyard.io.byte)": [[28, "vineyard.io.byte.ByteStream"]], "dataframestream (class in vineyard.io.dataframe)": [[28, "vineyard.io.dataframe.DataframeStream"]], "drivercontext (class in vineyard.core.driver)": [[28, "vineyard.core.driver.DriverContext"]], "ipcclient (class in vineyard)": [[28, "vineyard.IPCClient"]], "instancestatus (class in vineyard)": [[28, "vineyard.InstanceStatus"]], "object (class in vineyard)": [[28, "vineyard.Object"]], "objectbuilder (class in vineyard)": [[28, "vineyard.ObjectBuilder"]], "objectid (class in vineyard)": [[28, "vineyard.ObjectID"]], "objectmeta (class in vineyard)": [[28, "vineyard.ObjectMeta"]], "rpcclient (class in vineyard)": [[28, "vineyard.RPCClient"]], "recordbatchstream (class in vineyard.io.recordbatch)": [[28, "vineyard.io.recordbatch.RecordBatchStream"]], "remoteblob (class in vineyard)": [[28, "vineyard.RemoteBlob"]], "remoteblobbuilder (class in vineyard)": [[28, "vineyard.RemoteBlobBuilder"]], "resolvercontext (class in vineyard.core.resolver)": [[28, "vineyard.core.resolver.ResolverContext"]], "shareablelist (class in vineyard.shared_memory)": [[28, "vineyard.shared_memory.ShareableList"]], "sharedmemory (class in vineyard.shared_memory)": [[28, "vineyard.shared_memory.SharedMemory"]], "__contains__() (vineyard.objectmeta method)": [[28, "vineyard.ObjectMeta.__contains__"]], "__eq__() (vineyard.objectid method)": [[28, "vineyard.ObjectID.__eq__"]], "__getitem__() (vineyard.objectmeta method)": [[28, "vineyard.ObjectMeta.__getitem__"]], "__hash__() (vineyard.objectid method)": [[28, "vineyard.ObjectID.__hash__"]], "__init__() (vineyard.instancestatus method)": [[28, "vineyard.InstanceStatus.__init__"]], "__init__() (vineyard.objectid method)": [[28, "vineyard.ObjectID.__init__"]], "__init__() (vineyard.objectmeta method)": [[28, "vineyard.ObjectMeta.__init__"]], "__repr__() (vineyard.instancestatus method)": [[28, "vineyard.InstanceStatus.__repr__"]], "__repr__() (vineyard.objectid method)": [[28, "vineyard.ObjectID.__repr__"]], "__repr__() (vineyard.objectmeta method)": [[28, "vineyard.ObjectMeta.__repr__"]], "__setitem__() (vineyard.objectmeta method)": [[28, "vineyard.ObjectMeta.__setitem__"]], "__str__() (vineyard.instancestatus method)": [[28, "vineyard.InstanceStatus.__str__"]], "__str__() (vineyard.objectid method)": [[28, "vineyard.ObjectID.__str__"]], "__str__() (vineyard.objectmeta method)": [[28, "vineyard.ObjectMeta.__str__"]], "abort() (vineyard.blobbuilder method)": [[28, "vineyard.BlobBuilder.abort"]], "abort() (vineyard.remoteblobbuilder method)": [[28, "vineyard.RemoteBlobBuilder.abort"]], "add_member() (vineyard.objectmeta method)": [[28, "vineyard.ObjectMeta.add_member"]], "address (vineyard.blob property)": [[28, "vineyard.Blob.address"]], "address (vineyard.blobbuilder property)": [[28, "vineyard.BlobBuilder.address"]], "address (vineyard.remoteblob property)": [[28, "vineyard.RemoteBlob.address"]], "address (vineyard.remoteblobbuilder property)": [[28, "vineyard.RemoteBlobBuilder.address"]], "allocated_size() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.allocated_size"]], "buf (vineyard.shared_memory.sharedmemory property)": [[28, "vineyard.shared_memory.SharedMemory.buf"]], "buffer (vineyard.blob property)": [[28, "vineyard.Blob.buffer"]], "buffer (vineyard.blobbuilder property)": [[28, "vineyard.BlobBuilder.buffer"]], "buffer (vineyard.remoteblob property)": [[28, "vineyard.RemoteBlob.buffer"]], "buffer (vineyard.remoteblobbuilder property)": [[28, "vineyard.RemoteBlobBuilder.buffer"]], "builder_context() (in module vineyard.core.builder)": [[28, "vineyard.core.builder.builder_context"]], "clear() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.clear"]], "clear() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.clear"]], "close() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.close"]], "close() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.close"]], "connect() (in module vineyard)": [[28, "id0"], [28, "vineyard.connect"]], "connected (vineyard.ipcclient property)": [[28, "vineyard.IPCClient.connected"]], "connected (vineyard.rpcclient property)": [[28, "vineyard.RPCClient.connected"]], "copy() (vineyard.blobbuilder method)": [[28, "vineyard.BlobBuilder.copy"]], "copy() (vineyard.remoteblobbuilder method)": [[28, "vineyard.RemoteBlobBuilder.copy"]], "create_blob() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.create_blob"]], "create_empty_blob() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.create_empty_blob"]], "create_metadata() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.create_metadata"]], "create_metadata() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.create_metadata"]], "create_remote_blob() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.create_remote_blob"]], "deferred_requests (vineyard.instancestatus property)": [[28, "vineyard.InstanceStatus.deferred_requests"]], "delete() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.delete"]], "delete() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.delete"]], "delete_kubernetes_objects() (in module vineyard.deploy.kubernetes)": [[28, "vineyard.deploy.kubernetes.delete_kubernetes_objects"]], "deployment (vineyard.instancestatus property)": [[28, "vineyard.InstanceStatus.deployment"]], "driver_context() (in module vineyard.core.driver)": [[28, "vineyard.core.driver.driver_context"]], "drop_name() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.drop_name"]], "drop_name() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.drop_name"]], "empty() (vineyard.blob static method)": [[28, "vineyard.Blob.empty"]], "exists() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.exists"]], "exists() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.exists"]], "find_shared_memory() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.find_shared_memory"]], "freeze() (vineyard.shared_memory.shareablelist method)": [[28, "vineyard.shared_memory.ShareableList.freeze"]], "freeze() (vineyard.shared_memory.sharedmemory method)": [[28, "vineyard.shared_memory.SharedMemory.freeze"]], "get() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.get"]], "get() (vineyard.objectmeta method)": [[28, "vineyard.ObjectMeta.get"]], "get() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.get"]], "get_blob() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.get_blob"]], "get_blobs() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.get_blobs"]], "get_current_builders() (in module vineyard.core.builder)": [[28, "vineyard.core.builder.get_current_builders"]], "get_current_drivers() (in module vineyard.core.driver)": [[28, "vineyard.core.driver.get_current_drivers"]], "get_current_resolvers() (in module vineyard.core.resolver)": [[28, "vineyard.core.resolver.get_current_resolvers"]], "get_current_socket() (in module vineyard)": [[28, "vineyard.get_current_socket"]], "get_member() (vineyard.objectmeta method)": [[28, "vineyard.ObjectMeta.get_member"]], "get_meta() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.get_meta"]], "get_meta() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.get_meta"]], "get_metas() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.get_metas"]], "get_metas() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.get_metas"]], "get_name() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.get_name"]], "get_name() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.get_name"]], "get_object() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.get_object"]], "get_object() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.get_object"]], "get_objects() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.get_objects"]], "get_objects() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.get_objects"]], "get_remote_blob() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.get_remote_blob"]], "get_remote_blobs() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.get_remote_blobs"]], "id (vineyard.blobbuilder property)": [[28, "vineyard.BlobBuilder.id"]], "id (vineyard.object property)": [[28, "vineyard.Object.id"]], "id (vineyard.objectmeta property)": [[28, "vineyard.ObjectMeta.id"]], "id (vineyard.remoteblob property)": [[28, "vineyard.RemoteBlob.id"]], "instance_id (vineyard.ipcclient property)": [[28, "vineyard.IPCClient.instance_id"]], "instance_id (vineyard.instancestatus property)": [[28, "vineyard.InstanceStatus.instance_id"]], "instance_id (vineyard.objectmeta property)": [[28, "vineyard.ObjectMeta.instance_id"]], "instance_id (vineyard.rpcclient property)": [[28, "vineyard.RPCClient.instance_id"]], "instance_id (vineyard.remoteblob property)": [[28, "vineyard.RemoteBlob.instance_id"]], "ipc_connections (vineyard.instancestatus property)": [[28, "vineyard.InstanceStatus.ipc_connections"]], "ipc_socket (vineyard.ipcclient property)": [[28, "vineyard.IPCClient.ipc_socket"]], "ipc_socket (vineyard.rpcclient property)": [[28, "vineyard.RPCClient.ipc_socket"]], "is_empty (vineyard.blob property)": [[28, "vineyard.Blob.is_empty"]], "is_empty (vineyard.remoteblob property)": [[28, "vineyard.RemoteBlob.is_empty"]], "is_shared_memory() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.is_shared_memory"]], "isglobal (vineyard.object property)": [[28, "vineyard.Object.isglobal"]], "isglobal (vineyard.objectmeta property)": [[28, "vineyard.ObjectMeta.isglobal"]], "islocal (vineyard.object property)": [[28, "vineyard.Object.islocal"]], "islocal (vineyard.objectmeta property)": [[28, "vineyard.ObjectMeta.islocal"]], "ispersist (vineyard.object property)": [[28, "vineyard.Object.ispersist"]], "list_metadatas() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.list_metadatas"]], "list_metadatas() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.list_metadatas"]], "list_names() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.list_names"]], "list_names() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.list_names"]], "list_objects() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.list_objects"]], "list_objects() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.list_objects"]], "member() (vineyard.object method)": [[28, "vineyard.Object.member"]], "memory_limit (vineyard.instancestatus property)": [[28, "vineyard.InstanceStatus.memory_limit"]], "memory_usage (vineyard.instancestatus property)": [[28, "vineyard.InstanceStatus.memory_usage"]], "memory_usage (vineyard.objectmeta property)": [[28, "vineyard.ObjectMeta.memory_usage"]], "meta (vineyard.ipcclient property)": [[28, "vineyard.IPCClient.meta"]], "meta (vineyard.object property)": [[28, "vineyard.Object.meta"]], "meta (vineyard.rpcclient property)": [[28, "vineyard.RPCClient.meta"]], "name (vineyard.shared_memory.sharedmemory property)": [[28, "vineyard.shared_memory.SharedMemory.name"]], "nbytes (vineyard.object property)": [[28, "vineyard.Object.nbytes"]], "nbytes (vineyard.objectmeta property)": [[28, "vineyard.ObjectMeta.nbytes"]], "open() (in module vineyard.io)": [[28, "vineyard.io.open"]], "persist() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.persist"]], "persist() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.persist"]], "put() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.put"]], "put() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.put"]], "put_name() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.put_name"]], "put_name() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.put_name"]], "read() (in module vineyard.io)": [[28, "vineyard.io.read"]], "register() (vineyard.core.builder.buildercontext method)": [[28, "vineyard.core.builder.BuilderContext.register"]], "remote_instance_id (vineyard.rpcclient property)": [[28, "vineyard.RPCClient.remote_instance_id"]], "reset() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.reset"]], "reset() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.reset"]], "resolver_context() (in module vineyard.core.resolver)": [[28, "vineyard.core.resolver.resolver_context"]], "rpc_connections (vineyard.instancestatus property)": [[28, "vineyard.InstanceStatus.rpc_connections"]], "rpc_endpoint (vineyard.ipcclient property)": [[28, "vineyard.IPCClient.rpc_endpoint"]], "rpc_endpoint (vineyard.rpcclient property)": [[28, "vineyard.RPCClient.rpc_endpoint"]], "run() (vineyard.core.builder.buildercontext method)": [[28, "vineyard.core.builder.BuilderContext.run"]], "set_global() (vineyard.objectmeta method)": [[28, "vineyard.ObjectMeta.set_global"]], "shallow_copy() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.shallow_copy"]], "shallow_copy() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.shallow_copy"]], "shrink() (vineyard.blobbuilder method)": [[28, "vineyard.BlobBuilder.shrink"]], "signature (vineyard.object property)": [[28, "vineyard.Object.signature"]], "signature (vineyard.objectmeta property)": [[28, "vineyard.ObjectMeta.signature"]], "size (vineyard.blob property)": [[28, "vineyard.Blob.size"]], "size (vineyard.blobbuilder property)": [[28, "vineyard.BlobBuilder.size"]], "size (vineyard.remoteblob property)": [[28, "vineyard.RemoteBlob.size"]], "size (vineyard.remoteblobbuilder property)": [[28, "vineyard.RemoteBlobBuilder.size"]], "size (vineyard.shared_memory.sharedmemory property)": [[28, "vineyard.shared_memory.SharedMemory.size"]], "start_vineyardd() (in module vineyard.deploy.distributed)": [[28, "vineyard.deploy.distributed.start_vineyardd"]], "start_vineyardd() (in module vineyard.deploy.kubernetes)": [[28, "vineyard.deploy.kubernetes.start_vineyardd"]], "start_vineyardd() (in module vineyard.deploy.local)": [[28, "vineyard.deploy.local.start_vineyardd"]], "status (vineyard.ipcclient property)": [[28, "vineyard.IPCClient.status"]], "status (vineyard.rpcclient property)": [[28, "vineyard.RPCClient.status"]], "sync_meta() (vineyard.ipcclient method)": [[28, "vineyard.IPCClient.sync_meta"]], "sync_meta() (vineyard.rpcclient method)": [[28, "vineyard.RPCClient.sync_meta"]], "typename (vineyard.object property)": [[28, "vineyard.Object.typename"]], "typename (vineyard.objectmeta property)": [[28, "vineyard.ObjectMeta.typename"]], "unlink() (vineyard.shared_memory.sharedmemory method)": [[28, "vineyard.shared_memory.SharedMemory.unlink"]], "version (vineyard.ipcclient property)": [[28, "vineyard.IPCClient.version"]], "version (vineyard.rpcclient property)": [[28, "vineyard.RPCClient.version"]], "write() (in module vineyard.io)": [[28, "vineyard.io.write"]]}}) \ No newline at end of file diff --git a/summer.html b/summer.html new file mode 100644 index 0000000000..87128c0439 --- /dev/null +++ b/summer.html @@ -0,0 +1,7 @@ + + + + Vineyard • Summer of Code + + + diff --git a/tutorials/data-processing.html b/tutorials/data-processing.html new file mode 100644 index 0000000000..5645302f79 --- /dev/null +++ b/tutorials/data-processing.html @@ -0,0 +1,489 @@ + + + + + + + + + + + + + + + + + + + Data processing - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Data processing#

+
+
+

In these comprehensive case studies, we demonstrate how to seamlessly integrate vineyard’s +capabilities with existing data-intensive tasks. By incorporating vineyard into complex +workflows involving multiple computing engines, users can experience significant +improvements in both performance and ease of use.

+
+
+
+
+ +
+

Effortlessly share Python objects between processes using vineyard’s intuitive and efficient approach.

+
+
+
+
+
+ +
+

Utilize vineyard as an elegant alternative to multiprocessing.shared_memory in Python.

+
+
+
+
+
+ +
+

Discover how vineyard enhances distributed machine learning training workflows by +seamlessly integrating with various computing engines for improved efficiency and elegance.

+
+
+
+
+
+ +
+

Vineyard serves as the DataSet backend for Kedro pipelines, enabling +efficient data sharing between tasks without intrusive code modification, even +when the pipeline is deployed to Kubernetes.

+
+
+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/tutorials/data-processing/accelerate-data-sharing-in-kedro.html b/tutorials/data-processing/accelerate-data-sharing-in-kedro.html new file mode 100644 index 0000000000..176f760f76 --- /dev/null +++ b/tutorials/data-processing/accelerate-data-sharing-in-kedro.html @@ -0,0 +1,784 @@ + + + + + + + + + + + + + + + + + + + Accelerate Data Sharing in Kedro - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Accelerate Data Sharing in Kedro#

+

This is a tutorial that shows how Vineyard accelerate the intermediate data +sharing between tasks in Kedro pipelines using our +vineyard-kedro plugin, when data +scales and the pipeline are deployed on Kubernetes.

+
+

Note

+

This tutorial is based on the Developing and Learning MLOps at Home project, +a tutorial about orchestrating a machine learning pipeline with Kedro.

+
+
+

Prepare the Kubernetes cluster#

+

To deploy Kedro pipelines on Kubernetes, you must have a kubernetes cluster.

+
+

Tip

+

If you already have a K8s cluster, just skip this section and continue +on deploying.

+
+

We recommend kind v0.20.0 to create a multi-node +Kubernetes cluster on your local machine as follows:

+
$ cat <<EOF | kind create cluster --config=-
+kind: Cluster
+apiVersion: kind.x-k8s.io/v1alpha4
+nodes:
+- role: control-plane
+  image: kindest/node:v1.25.11
+- role: worker
+  image: kindest/node:v1.25.11
+- role: worker
+  image: kindest/node:v1.25.11
+- role: worker
+  image: kindest/node:v1.25.11
+EOF
+
+
+
+
+

Deploy Argo Workflows#

+

Install the argo operator on Kubernetes:

+
$ kubectl create namespace argo
+$ kubectl apply -n argo -f https://github.com/argoproj/argo-workflows/releases/download/v3.4.8/install.yaml
+
+
+

When the deployment becomes ready, you can see the following pods:

+
$ kubectl get pod -n argo
+NAME                                READY   STATUS    RESTARTS   AGE
+argo-server-7698c96655-jg2ds        1/1     Running   0          11s
+workflow-controller-b888f4458-x4qf2 1/1     Running   0          11s
+
+
+
+
+

Deploy Vineyard#

+
    +
  1. Install the vineyard operator:

    +
    $ helm repo add vineyard https://vineyard.oss-ap-southeast-1.aliyuncs.com/charts/
    +$ helm repo update
    +$ helm install vineyard-operator vineyard/vineyard-operator \
    +    --namespace vineyard-system \
    +    --create-namespace
    +
    +
    +
  2. +
  3. Create a vineyard cluster:

    +
    +

    Tip

    +
    +
    To handle the large data, we set the memory of vineyard cluster to 8G and

    the shared memory to 8G.

    +
    +
    +
    +
    $ python3 -m vineyard.ctl deploy vineyardd --vineyardd.memory=8Gi --vineyardd.size=8Gi
    +
    +
    +
    +

    Note

    +

    The above command will try to create a vineyard cluster with 3 replicas +by default. If you are working with Minikube, Kind, or other Kubernetes +that has less nodes available, try reduce the replicas by

    +
    $ python3 -m vineyard.ctl deploy vineyardd --replicas=1 --vineyardd.memory=8Gi --vineyardd.size=8Gi
    +
    +
    +
    +
  4. +
+
+
+

Prepare the S3 Service#

+
    +
  1. Deploy the Minio cluster:

    +
    +

    Tip

    +

    If you already have the AWS S3 service, just skip this section and jump to +the next section.

    +
    +
    $ kubectl apply -f python/vineyard/contrib/kedro/benchmark/mlops/minio-dev.yaml
    +
    +
    +
    +

    Tip

    +

    The default access key and secret key of the minio cluster are minioadmin +and minioadmin.

    +
    +
  2. +
  3. Create the S3 bucket:

    +
      +
    • If you are working with AWS S3, you can create a bucket named +aws-s3-benchmark-bucket with the following command:

      +
      $ aws s3api create-bucket --bucket aws-s3-benchmark-bucket --region <Your AWS Region Name>
      +
      +
      +
    • +
    • If you are working with Minio, you first need to expose the services +and then create the bucket:

      +
        +
      • Forward minio-artifacts service:

        +
        $ kubectl port-forward service/minio -n minio-dev 9000:9000
        +
        +
        +
      • +
      • Install the minio client:

        +
        $ wget https://dl.min.io/client/mc/release/linux-amd64/mc
        +$ chmod +x mc
        +$ sudo mv mc /usr/local/bin
        +
        +
        +
      • +
      • Configure the minio client:

        +
        $ mc alias set minio http://localhost:9000
        +Enter Access Key: <Your Access Key>
        +Enter Secret Key: <Your Secret Key>
        +
        +
        +
      • +
      • Finally, create the bucket minio-s3-benchmark-bucket:

        +
        $ mc mb minio/minio-s3-benchmark-bucket
        +Bucket created successfully `minio/minio-s3-benchmark-bucket`.
        +
        +
        +
      • +
      +
    • +
    +
  4. +
+
+
+

Prepare the Docker images#

+
    +
  1. Vineyard has delivered a benchmark project +to test Kedro pipelines on Vineyard and S3:

    +
    $ cd python/vineyard/contrib/kedro/benchmark/mlops
    +
    +
    +
  2. +
  3. Configure the credentials configurations of AWS S3:

    +
    $ cat conf/aws-s3/credentials.yml
    +benchmark_aws_s3:
    +    client_kwargs:
    +        aws_access_key_id: Your AWS/Minio Access Key ID
    +        aws_secret_access_key: Your AWS/Minio Secret Access Key
    +        region_name: Your AWS Region Name
    +
    +
    +
  4. +
  5. To deploy pipelines to Kubernetes, you first need to build the Docker image for the +benchmark project.

    +

    To show how vineyard can accelerate the data sharing along with the dataset +scales, Docker images for different data size will be generated:

    +
      +
    • For running Kedro on vineyard:

      +
      $ make docker-build
      +
      +
      +

      You will see Docker images for different data size are generated:

      +
      $ docker images | grep mlops
      +mlops-benchmark    latest    fceaeb5a6688   17 seconds ago   1.07GB
      +
      +
      +
    • +
    +
  6. +
  7. To make those images available for your Kubernetes cluster, they need to be +pushed to your registry (or load to kind cluster if you setup your Kubernetes +cluster using kind):

    +
      +
    • Push to registry:

      +
      $ docker tag mlops-benchmark:latest <Your Registry>/mlops-benchmark:latest
      +$ docker push <Your Registry>/mlops-benchmark:latest
      +
      +
      +
    • +
    • Load to kind cluster:

      +
      $ kind load docker-image mlops-benchmark:latest
      +
      +
      +
    • +
    +
  8. +
+
+
+

Deploy the Kedro Pipelines#

+
    +
  1. Deploy the Kedro pipeline with vineyard for intermediate data sharing:

    +
    $ kubectl create namespace vineyard
    +$ for multiplier in 1 10 100 500; do \
    +     argo submit -n vineyard --watch argo-vineyard-benchmark.yml -p multiplier=${multiplier}; \
    +  done
    +
    +
    +
  2. +
  3. Similarly, using AWS S3 or Minio for intermediate data sharing:

    +
      +
    • Using AWS S3:

      +
      $ kubectl create namespace aws-s3
      +# create the aws secrets from your ENV
      +$ kubectl create secret generic aws-secrets -n aws-s3 \
      +     --from-literal=access_key_id=$AWS_ACCESS_KEY_ID \
      +     --from-literal=secret_access_key=$AWS_SECRET_ACCESS_KEY
      +$ for multiplier in 1 10 100 500 1000 2000; do \
      +     argo submit -n aws-s3 --watch argo-aws-s3-benchmark.yml -p multiplier=${multiplier}; \
      +  done
      +
      +
      +
    • +
    • Using Cloudpickle dataset:

      +
      $ kubectl create namespace cloudpickle
      +# create the aws secrets from your ENV
      +$ kubectl create secret generic aws-secrets -n cloudpickle \
      +     --from-literal=access_key_id=$AWS_ACCESS_KEY_ID \
      +     --from-literal=secret_access_key=$AWS_SECRET_ACCESS_KEY
      +$ for multiplier in 1 10 100 500 1000 2000; do \
      +     argo submit -n cloudpickle --watch argo-cloudpickle-benchmark.yml -p multiplier=${multiplier}; \
      +  done
      +
      +
      +
    • +
    • Using Minio:

      +
      $ kubectl create namespace minio-s3
      +$ for multiplier in 1 10 100 500 1000 2000; do \
      +     argo submit -n minio-s3 --watch argo-minio-s3-benchmark.yml -p multiplier=${multiplier}; \
      +  done
      +
      +
      +
    • +
    +
  4. +
+
+
+

Performance#

+

After running the benchmark above on Kubernetes, we recorded each node’s execution time from the logs +of the argo workflow and calculated the sum of all nodes as the following end-to-end execution time +for each data scale:

+
+ +++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Data Scale

Vineyard

Minio S3

Cloudpickle S3

AWS S3

1

4.2s

4.3s

22.5s

16.9s

10

4.9s

5.5s

28.6s

23.3s

100

13.2s

20.3s

64.4s

74s

500

53.6s

84.5s

173.2s

267.9s

1000

109.8s

164.2s

322.7s

510.6s

2000

231.6s

335.9s

632.8s

1069.7s

+
+

We have the following observations from above comparison:

+
    +
  • Vineyard can significantly accelerate the data sharing between tasks in Kedro pipelines, without the +need for any intrusive changes to the original Kedro pipelines;

  • +
  • When data scales, the performance of Vineyard is more impressive, as the intermediate data sharing +cost becomes more dominant in end-to-end execution;

  • +
  • Even compared with local Minio, Vineyard still outperforms it by a large margin, thanks to the ability +of Vineyard to avoid (de)serialization, file I/O and excessive memory copies.

  • +
  • When using the Cloudpickle dataset(pickle + zstd), the performance is better than AWS S3, as the dataset +will be compressed before uploading to S3.

  • +
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/tutorials/data-processing/distributed-learning.html b/tutorials/data-processing/distributed-learning.html new file mode 100644 index 0000000000..30ee6288a3 --- /dev/null +++ b/tutorials/data-processing/distributed-learning.html @@ -0,0 +1,852 @@ + + + + + + + + + + + + + + + + + + + Distributed Learning with Vineyard - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Distributed Learning with Vineyard#

+

With the growth of data, distributed learning is becoming a must in real-world machine learning applications, as the data size can easily exceed the memory limit of a single machine. Thus, many distributed systems addressing different workloads are developed and they share the same objective of extending users’ single machine prototypes to distributed settings with as few modifications to the code as possible.

+

For example, dask.dataframe mimics the API of pandas which is the de-facto standard library for single-machine structured data processing, so that users can apply their pandas code for data preprocessing in the dask cluster with few modifications. Similarly, horovod provides easy-to-use APIs for users to transfer their single-machine code in machine learning frameworks (e.g., TensorFlow, PyTorch, MXNet) to the distributed settings with only a few additional lines of code.

+

However, when extending to distributed learning, the data sharing between libraries within the same python process (e.g., pandas and tensorflow) becomes inter-process sharing between engines (e.g., dask and horovod), not to mention in the distributed fashion. Existing solutions using external distributed file systems are less than optimal for the huge I/O overheads.

+

Vineyard shares the same design principle with the aforementioned distributed systems, which aims to provide efficient cross-engine data sharing with few modifications to the existing code. Next, we demonstrate how to transfer a single-machine learning example in keras to distributed learning with dask, horovod and Vineyard.

+
+

An Example from Keras#

+

This example uses the Covertype dataset from the UCI Machine Learning Repository. The task is to predict forest cover type from cartographic variables. The dataset includes 506,011 instances with 12 input features: 10 numerical features and 2 categorical features. Each instance is categorized into 1 of 7 classes.

+

The solution contains three steps:

+
    +
  1. preprocess the data in pandas to extract the 12 features and the label

  2. +
  3. store the preprocessed data in files

  4. +
  5. define and train the model in keras

  6. +
+

Mapping the solution to distributed learning, we have:

+
    +
  1. preprocess the data in dask.dataframe

  2. +
  3. share the preprocessed data using Vineyard

  4. +
  5. train the model in horovod.keras

  6. +
+

We will walk through the code as follows.

+
+
+

Setup#

+

The distributed deployment of vineyard and dask is as follows: on each machine, we launch a vineyard daemon process to handle the local data storage on that machine; and we also launch a dask worker on that machine for the computation accordingly. In this notebook, we limit the machine number as 1 (i.e., the local machine) just for demonstration.

+
+
[ ]:
+
+
+
import vineyard
+import subprocess as sp
+
+# launch local vineyardd
+client = vineyard.connect()
+
+# launch dask scheduler and worker
+dask_scheduler = sp.Popen(['dask-scheduler', '--host', 'localhost'])
+dask_worker = sp.Popen(['dask-worker', 'tcp://localhost:8786'])
+
+
+
+
+
+

Preprocessing the data#

+

To read the data, we replace pd.read_csv by dd.read_csv, which will automatically read the data in parallel.

+
+
[ ]:
+
+
+
import dask.dataframe as dd
+raw_data = dd.read_csv('covtype.data', header=None)
+
+
+
+

Then we preprocess the data using the same code from the example, except the replacement of pd.concat to dd.concat only.

+
+
[ ]:
+
+
+
"""
+The two categorical features in the dataset are binary-encoded.
+We will convert this dataset representation to the typical representation, where each
+categorical feature is represented as a single integer value.
+"""
+import warnings
+warnings.filterwarnings('ignore')
+
+soil_type_values = [f"soil_type_{idx+1}" for idx in range(40)]
+wilderness_area_values = [f"area_type_{idx+1}" for idx in range(4)]
+
+soil_type = raw_data.loc[:, 14:53].apply(
+    lambda x: soil_type_values[0::1][x.to_numpy().nonzero()[0][0]], axis=1
+)
+wilderness_area = raw_data.loc[:, 10:13].apply(
+    lambda x: wilderness_area_values[0::1][x.to_numpy().nonzero()[0][0]], axis=1
+)
+
+CSV_HEADER = [
+    "Elevation",
+    "Aspect",
+    "Slope",
+    "Horizontal_Distance_To_Hydrology",
+    "Vertical_Distance_To_Hydrology",
+    "Horizontal_Distance_To_Roadways",
+    "Hillshade_9am",
+    "Hillshade_Noon",
+    "Hillshade_3pm",
+    "Horizontal_Distance_To_Fire_Points",
+    "Wilderness_Area",
+    "Soil_Type",
+    "Cover_Type",
+]
+
+data = dd.concat(
+    [raw_data.loc[:, 0:9], wilderness_area, soil_type, raw_data.loc[:, 54]],
+    axis=1,
+    ignore_index=True,
+)
+data.columns = CSV_HEADER
+
+# Convert the target label indices into a range from 0 to 6 (there are 7 labels in total).
+data["Cover_Type"] = data["Cover_Type"] - 1
+
+
+
+

Finally, instead of saving the preprocessed data into files, we store them in Vineyard.

+
+
[ ]:
+
+
+
import vineyard
+from vineyard.core.builder import builder_context
+from vineyard.contrib.dask.dask import register_dask_types
+
+with builder_context() as builder:
+    register_dask_types(builder, None) # register dask builders
+    gdf_id = client.put(data, dask_scheduler='tcp://localhost:8786')
+    print(gdf_id)
+
+
+
+

We saved the preprocessed data as a global dataframe in Vineyard with the ObjectID above.

+
+
+

Training the model#

+

In the single machine solution from the example. A get_dataset_from_csv function is defined to load the dataset from the files of the preprocessed data as follows:

+
def get_dataset_from_csv(csv_file_path, batch_size, shuffle=False):
+
+    dataset = tf.data.experimental.make_csv_dataset(
+        csv_file_path,
+        batch_size=batch_size,
+        column_names=CSV_HEADER,
+        column_defaults=COLUMN_DEFAULTS,
+        label_name=TARGET_FEATURE_NAME,
+        num_epochs=1,
+        header=True,
+        shuffle=shuffle,
+    )
+    return dataset.cache()
+
+
+

while in the training procedure, it loads the train_dataset and test_dataset separately from two files as:

+
def run_experiment(model):
+
+    model.compile(
+        optimizer=keras.optimizers.Adam(learning_rate=learning_rate),
+        loss=keras.losses.SparseCategoricalCrossentropy(),
+        metrics=[keras.metrics.SparseCategoricalAccuracy()],
+    )
+
+    train_dataset = get_dataset_from_csv(train_data_file, batch_size, shuffle=True)
+
+    test_dataset = get_dataset_from_csv(test_data_file, batch_size)
+
+    print("Start training the model...")
+    history = model.fit(train_dataset, epochs=num_epochs)
+    print("Model training finished")
+
+    _, accuracy = model.evaluate(test_dataset, verbose=0)
+
+    print(f"Test accuracy: {round(accuracy * 100, 2)}%")
+
+
+

In our solution, we provide a function to load dataset from the global dataframe generated in the last step.

+
+
[ ]:
+
+
+
from vineyard.core.resolver import resolver_context
+from vineyard.contrib.ml.tensorflow import register_tf_types
+
+def get_dataset_from_vineyard(object_id, batch_size, shuffle=False):
+    with resolver_context() as resolver:
+        register_tf_types(None, resolver) # register tf resolvers
+        ds = vineyard.connect().get(object_id, label=TARGET_FEATURE_NAME) # specify the label column
+
+    if shuffle:
+        ds = ds.shuffle(len(ds))
+
+    len_test = int(len(ds) * 0.15)
+    test_dataset = ds.take(len_test).batch(batch_size)
+    train_dataset = ds.skip(len_test).batch(batch_size)
+
+    return train_dataset, test_dataset
+
+
+
+

And modify the training procedure with a few lines of horovod code.

+
+
[ ]:
+
+
+
import horovod.keras as hvd
+
+def run_experiment(model):
+
+    hvd.init()
+
+    model.compile(
+        optimizer=hvd.DistributedOptimizer(keras.optimizers.Adam(learning_rate=learning_rate)),
+        loss=keras.losses.SparseCategoricalCrossentropy(),
+        metrics=[keras.metrics.SparseCategoricalAccuracy()],
+    )
+
+    callbacks = [
+        # Horovod: broadcast initial variable states from rank 0 to all other processes.
+        # This is necessary to ensure consistent initialization of all workers when
+        # training is started with random weights or restored from a checkpoint.
+        hvd.callbacks.BroadcastGlobalVariablesCallback(0),
+    ]
+
+    train_dataset, test_dataset = get_dataset_from_vineyard(gdf_id, batch_size, shuffle=True)
+
+    print("Start training the model...")
+    history = model.fit(train_dataset, epochs=num_epochs, callbacks=callbacks)
+    print("Model training finished")
+
+    _, accuracy = model.evaluate(test_dataset, verbose=0)
+
+    print(f"Test accuracy: {round(accuracy * 100, 2)}%")
+
+
+
+

All the other parts of training procedure are the same as the single machine solution.

+
+
[ ]:
+
+
+
TARGET_FEATURE_NAME = "Cover_Type"
+
+TARGET_FEATURE_LABELS = ["0", "1", "2", "3", "4", "5", "6"]
+
+NUMERIC_FEATURE_NAMES = [
+    "Aspect",
+    "Elevation",
+    "Hillshade_3pm",
+    "Hillshade_9am",
+    "Hillshade_Noon",
+    "Horizontal_Distance_To_Fire_Points",
+    "Horizontal_Distance_To_Hydrology",
+    "Horizontal_Distance_To_Roadways",
+    "Slope",
+    "Vertical_Distance_To_Hydrology",
+]
+
+CATEGORICAL_FEATURES_WITH_VOCABULARY = {
+    "Soil_Type": soil_type_values,
+    "Wilderness_Area": wilderness_area_values,
+}
+
+CATEGORICAL_FEATURE_NAMES = list(CATEGORICAL_FEATURES_WITH_VOCABULARY.keys())
+
+FEATURE_NAMES = NUMERIC_FEATURE_NAMES + CATEGORICAL_FEATURE_NAMES
+
+NUM_CLASSES = len(TARGET_FEATURE_LABELS)
+
+learning_rate = 0.001
+dropout_rate = 0.1
+batch_size = 265
+num_epochs = 5
+
+hidden_units = [32, 32]
+
+"""
+## Create model inputs
+Now, define the inputs for the models as a dictionary, where the key is the feature name,
+and the value is a `keras.layers.Input` tensor with the corresponding feature shape
+and data type.
+"""
+import tensorflow as tf
+
+def create_model_inputs():
+    inputs = {}
+    for feature_name in FEATURE_NAMES:
+        if feature_name in NUMERIC_FEATURE_NAMES:
+            inputs[feature_name] = layers.Input(
+                name=feature_name, shape=(), dtype=tf.float32
+            )
+        else:
+            inputs[feature_name] = layers.Input(
+                name=feature_name, shape=(), dtype=tf.string
+            )
+    return inputs
+
+
+"""
+## Encode features
+We create two representations of our input features: sparse and dense:
+1. In the **sparse** representation, the categorical features are encoded with one-hot
+encoding using the `CategoryEncoding` layer. This representation can be useful for the
+model to *memorize* particular feature values to make certain predictions.
+2. In the **dense** representation, the categorical features are encoded with
+low-dimensional embeddings using the `Embedding` layer. This representation helps
+the model to *generalize* well to unseen feature combinations.
+"""
+
+
+from tensorflow.keras.layers import StringLookup
+
+
+def encode_inputs(inputs, use_embedding=False):
+    encoded_features = []
+    for feature_name in inputs:
+        if feature_name in CATEGORICAL_FEATURE_NAMES:
+            vocabulary = CATEGORICAL_FEATURES_WITH_VOCABULARY[feature_name]
+            # Create a lookup to convert string values to an integer indices.
+            # Since we are not using a mask token nor expecting any out of vocabulary
+            # (oov) token, we set mask_token to None and  num_oov_indices to 0.
+            lookup = StringLookup(
+                vocabulary=vocabulary,
+                mask_token=None,
+                num_oov_indices=0,
+                output_mode="int" if use_embedding else "binary",
+            )
+            if use_embedding:
+                # Convert the string input values into integer indices.
+                encoded_feature = lookup(inputs[feature_name])
+                embedding_dims = int(math.sqrt(len(vocabulary)))
+                # Create an embedding layer with the specified dimensions.
+                embedding = layers.Embedding(
+                    input_dim=len(vocabulary), output_dim=embedding_dims
+                )
+                # Convert the index values to embedding representations.
+                encoded_feature = embedding(encoded_feature)
+            else:
+                # Convert the string input values into a one hot encoding.
+                encoded_feature = lookup(tf.expand_dims(inputs[feature_name], -1))
+        else:
+            # Use the numerical features as-is.
+            encoded_feature = tf.expand_dims(inputs[feature_name], -1)
+
+        encoded_features.append(encoded_feature)
+
+    all_features = layers.concatenate(encoded_features)
+    return all_features
+
+
+"""
+## Experiment 1: a baseline model
+In the first experiment, let's create a multi-layer feed-forward network,
+where the categorical features are one-hot encoded.
+"""
+from tensorflow import keras
+from tensorflow.keras import layers
+
+def create_baseline_model():
+    inputs = create_model_inputs()
+    features = encode_inputs(inputs)
+
+    for units in hidden_units:
+        features = layers.Dense(units)(features)
+        features = layers.BatchNormalization()(features)
+        features = layers.ReLU()(features)
+        features = layers.Dropout(dropout_rate)(features)
+
+    outputs = layers.Dense(units=NUM_CLASSES, activation="softmax")(features)
+    model = keras.Model(inputs=inputs, outputs=outputs)
+    return model
+
+
+baseline_model = create_baseline_model()
+
+
+
+

Let’s run it:

+
+
[ ]:
+
+
+
run_experiment(baseline_model)
+
+
+
+

We clear the environments in the end.

+
+
[ ]:
+
+
+
dask_worker.terminate()
+dask_scheduler.terminate()
+
+vineyard.shutdown()
+
+
+
+

Finally, we can use horovodrun to run the above code distributedly in a cluster for distributed learning on big datasets.

+
+
+

Conclusion#

+

From this example, we can see that with the help of Vineyard, users can easily extend their single machine solutions to distributed learning using dedicated systems without worrying about the cross-system data sharing issues.

+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/tutorials/data-processing/distributed-learning.ipynb b/tutorials/data-processing/distributed-learning.ipynb new file mode 100644 index 0000000000..d428eda05b --- /dev/null +++ b/tutorials/data-processing/distributed-learning.ipynb @@ -0,0 +1,536 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Distributed Learning with Vineyard\n", + "==================================\n", + "\n", + "With the growth of data, distributed learning is becoming a must in real-world machine learning\n", + "applications, as the data size can easily exceed the memory limit of a single machine.\n", + "Thus, many distributed systems addressing different workloads are developed\n", + "and they share the same objective of extending users' single machine prototypes \n", + "to distributed settings with as few modifications to the code as possible.\n", + "\n", + "For example, **dask.dataframe** mimics the API of **pandas** which is the de-facto standard\n", + "library for single-machine structured data processing, so that users can apply their\n", + "pandas code for data preprocessing in the dask cluster with few modifications.\n", + "Similarly, **horovod** provides easy-to-use APIs for users to transfer their single-machine\n", + "code in machine learning frameworks (e.g., TensorFlow, PyTorch, MXNet) to the distributed settings\n", + "with only a few additional lines of code.\n", + "\n", + "However, when extending to distributed learning, the data sharing between libraries within the same\n", + "python process (e.g., pandas and tensorflow) becomes inter-process sharing between engines (e.g.,\n", + "dask and horovod), not to mention in the distributed fashion. Existing solutions using external\n", + "distributed file systems are less than optimal for the huge I/O overheads.\n", + "\n", + "Vineyard shares the same design principle with the aforementioned distributed systems, which aims to\n", + "provide efficient cross-engine data sharing with few modifications to the existing code.\n", + "Next, we demonstrate how to transfer a single-machine learning example in **keras** to\n", + "distributed learning with dask, horovod and Vineyard.\n", + "\n", + "An Example from Keras\n", + "---------------------\n", + "\n", + "This [example](https://keras.io/examples/structured_data/wide_deep_cross_networks/)\n", + "uses the Covertype dataset from the UCI Machine Learning Repository.\n", + "The task is to predict forest cover type from cartographic variables.\n", + "The dataset includes 506,011 instances with 12 input features:\n", + "10 numerical features and 2 categorical features.\n", + "Each instance is categorized into 1 of 7 classes.\n", + "\n", + "The solution contains three steps:\n", + "\n", + "1. preprocess the data in pandas to extract the 12 features and the label\n", + "2. store the preprocessed data in files\n", + "3. define and train the model in keras\n", + "\n", + "\n", + "Mapping the solution to distributed learning, we have:\n", + "\n", + "1. preprocess the data in dask.dataframe\n", + "2. share the preprocessed data using Vineyard\n", + "3. train the model in horovod.keras\n", + "\n", + "\n", + "We will walk through the code as follows.\n", + "\n", + "Setup\n", + "-------\n", + "\n", + "The distributed deployment of vineyard and dask is as follows: on each machine, we launch a vineyard daemon process to handle the local data storage on that machine; and we also launch a dask worker on that machine for the computation accordingly. In this notebook, we limit the machine number as 1 (i.e., the local machine) just for demonstration." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import vineyard\n", + "import subprocess as sp\n", + "\n", + "# launch local vineyardd\n", + "client = vineyard.connect()\n", + "\n", + "# launch dask scheduler and worker\n", + "dask_scheduler = sp.Popen(['dask-scheduler', '--host', 'localhost'])\n", + "dask_worker = sp.Popen(['dask-worker', 'tcp://localhost:8786'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Preprocessing the data\n", + "----------------------\n", + "\n", + "To read the data, we replace\n", + "**pd.read_csv** by **dd.read_csv**, which will automatically\n", + "read the data in parallel." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import dask.dataframe as dd\n", + "raw_data = dd.read_csv('covtype.data', header=None)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then we preprocess the data using the same code from the example,\n", + "except the replacement of **pd.concat** to **dd.concat** only." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"\n", + "The two categorical features in the dataset are binary-encoded.\n", + "We will convert this dataset representation to the typical representation, where each\n", + "categorical feature is represented as a single integer value.\n", + "\"\"\"\n", + "import warnings\n", + "warnings.filterwarnings('ignore')\n", + "\n", + "soil_type_values = [f\"soil_type_{idx+1}\" for idx in range(40)]\n", + "wilderness_area_values = [f\"area_type_{idx+1}\" for idx in range(4)]\n", + "\n", + "soil_type = raw_data.loc[:, 14:53].apply(\n", + " lambda x: soil_type_values[0::1][x.to_numpy().nonzero()[0][0]], axis=1\n", + ")\n", + "wilderness_area = raw_data.loc[:, 10:13].apply(\n", + " lambda x: wilderness_area_values[0::1][x.to_numpy().nonzero()[0][0]], axis=1\n", + ")\n", + "\n", + "CSV_HEADER = [\n", + " \"Elevation\",\n", + " \"Aspect\",\n", + " \"Slope\",\n", + " \"Horizontal_Distance_To_Hydrology\",\n", + " \"Vertical_Distance_To_Hydrology\",\n", + " \"Horizontal_Distance_To_Roadways\",\n", + " \"Hillshade_9am\",\n", + " \"Hillshade_Noon\",\n", + " \"Hillshade_3pm\",\n", + " \"Horizontal_Distance_To_Fire_Points\",\n", + " \"Wilderness_Area\",\n", + " \"Soil_Type\",\n", + " \"Cover_Type\",\n", + "]\n", + "\n", + "data = dd.concat(\n", + " [raw_data.loc[:, 0:9], wilderness_area, soil_type, raw_data.loc[:, 54]],\n", + " axis=1,\n", + " ignore_index=True,\n", + ")\n", + "data.columns = CSV_HEADER\n", + "\n", + "# Convert the target label indices into a range from 0 to 6 (there are 7 labels in total).\n", + "data[\"Cover_Type\"] = data[\"Cover_Type\"] - 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, instead of saving the preprocessed data into files, we store them in Vineyard.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import vineyard\n", + "from vineyard.core.builder import builder_context\n", + "from vineyard.contrib.dask.dask import register_dask_types\n", + "\n", + "with builder_context() as builder:\n", + " register_dask_types(builder, None) # register dask builders\n", + " gdf_id = client.put(data, dask_scheduler='tcp://localhost:8786')\n", + " print(gdf_id)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We saved the preprocessed data as a global dataframe\n", + "in Vineyard with the ObjectID above." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Training the model\n", + "------------------\n", + "\n", + "In the single machine solution from the example. A **get_dataset_from_csv** function \n", + "is defined to load the dataset from the files of the preprocessed data as follows:\n", + "```python\n", + "def get_dataset_from_csv(csv_file_path, batch_size, shuffle=False):\n", + "\n", + " dataset = tf.data.experimental.make_csv_dataset(\n", + " csv_file_path,\n", + " batch_size=batch_size,\n", + " column_names=CSV_HEADER,\n", + " column_defaults=COLUMN_DEFAULTS,\n", + " label_name=TARGET_FEATURE_NAME,\n", + " num_epochs=1,\n", + " header=True,\n", + " shuffle=shuffle,\n", + " )\n", + " return dataset.cache()\n", + "```\n", + "while in the training procedure, it loads the train_dataset and test_dataset\n", + "separately from two files as:\n", + "```python\n", + "def run_experiment(model):\n", + "\n", + " model.compile(\n", + " optimizer=keras.optimizers.Adam(learning_rate=learning_rate),\n", + " loss=keras.losses.SparseCategoricalCrossentropy(),\n", + " metrics=[keras.metrics.SparseCategoricalAccuracy()],\n", + " )\n", + "\n", + " train_dataset = get_dataset_from_csv(train_data_file, batch_size, shuffle=True)\n", + "\n", + " test_dataset = get_dataset_from_csv(test_data_file, batch_size)\n", + "\n", + " print(\"Start training the model...\")\n", + " history = model.fit(train_dataset, epochs=num_epochs)\n", + " print(\"Model training finished\")\n", + "\n", + " _, accuracy = model.evaluate(test_dataset, verbose=0)\n", + "\n", + " print(f\"Test accuracy: {round(accuracy * 100, 2)}%\")\n", + "```\n", + "In our solution, we provide a function to load dataset from the global dataframe\n", + "generated in the last step." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from vineyard.core.resolver import resolver_context\n", + "from vineyard.contrib.ml.tensorflow import register_tf_types\n", + "\n", + "def get_dataset_from_vineyard(object_id, batch_size, shuffle=False):\n", + " with resolver_context() as resolver:\n", + " register_tf_types(None, resolver) # register tf resolvers\n", + " ds = vineyard.connect().get(object_id, label=TARGET_FEATURE_NAME) # specify the label column\n", + "\n", + " if shuffle:\n", + " ds = ds.shuffle(len(ds))\n", + "\n", + " len_test = int(len(ds) * 0.15)\n", + " test_dataset = ds.take(len_test).batch(batch_size)\n", + " train_dataset = ds.skip(len_test).batch(batch_size)\n", + "\n", + " return train_dataset, test_dataset" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And modify the training procedure with a few lines of horovod code." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import horovod.keras as hvd\n", + "\n", + "def run_experiment(model):\n", + "\n", + " hvd.init()\n", + "\n", + " model.compile(\n", + " optimizer=hvd.DistributedOptimizer(keras.optimizers.Adam(learning_rate=learning_rate)),\n", + " loss=keras.losses.SparseCategoricalCrossentropy(),\n", + " metrics=[keras.metrics.SparseCategoricalAccuracy()],\n", + " )\n", + "\n", + " callbacks = [\n", + " # Horovod: broadcast initial variable states from rank 0 to all other processes.\n", + " # This is necessary to ensure consistent initialization of all workers when\n", + " # training is started with random weights or restored from a checkpoint.\n", + " hvd.callbacks.BroadcastGlobalVariablesCallback(0),\n", + " ]\n", + "\n", + " train_dataset, test_dataset = get_dataset_from_vineyard(gdf_id, batch_size, shuffle=True)\n", + "\n", + " print(\"Start training the model...\")\n", + " history = model.fit(train_dataset, epochs=num_epochs, callbacks=callbacks)\n", + " print(\"Model training finished\")\n", + "\n", + " _, accuracy = model.evaluate(test_dataset, verbose=0)\n", + "\n", + " print(f\"Test accuracy: {round(accuracy * 100, 2)}%\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All the other parts of training procedure are the same as the single machine solution." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "TARGET_FEATURE_NAME = \"Cover_Type\"\n", + "\n", + "TARGET_FEATURE_LABELS = [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\"]\n", + "\n", + "NUMERIC_FEATURE_NAMES = [\n", + " \"Aspect\",\n", + " \"Elevation\",\n", + " \"Hillshade_3pm\",\n", + " \"Hillshade_9am\",\n", + " \"Hillshade_Noon\",\n", + " \"Horizontal_Distance_To_Fire_Points\",\n", + " \"Horizontal_Distance_To_Hydrology\",\n", + " \"Horizontal_Distance_To_Roadways\",\n", + " \"Slope\",\n", + " \"Vertical_Distance_To_Hydrology\",\n", + "]\n", + "\n", + "CATEGORICAL_FEATURES_WITH_VOCABULARY = {\n", + " \"Soil_Type\": soil_type_values,\n", + " \"Wilderness_Area\": wilderness_area_values,\n", + "}\n", + "\n", + "CATEGORICAL_FEATURE_NAMES = list(CATEGORICAL_FEATURES_WITH_VOCABULARY.keys())\n", + "\n", + "FEATURE_NAMES = NUMERIC_FEATURE_NAMES + CATEGORICAL_FEATURE_NAMES\n", + "\n", + "NUM_CLASSES = len(TARGET_FEATURE_LABELS)\n", + "\n", + "learning_rate = 0.001\n", + "dropout_rate = 0.1\n", + "batch_size = 265\n", + "num_epochs = 5\n", + "\n", + "hidden_units = [32, 32]\n", + "\n", + "\"\"\"\n", + "## Create model inputs\n", + "Now, define the inputs for the models as a dictionary, where the key is the feature name,\n", + "and the value is a `keras.layers.Input` tensor with the corresponding feature shape\n", + "and data type.\n", + "\"\"\"\n", + "import tensorflow as tf\n", + "\n", + "def create_model_inputs():\n", + " inputs = {}\n", + " for feature_name in FEATURE_NAMES:\n", + " if feature_name in NUMERIC_FEATURE_NAMES:\n", + " inputs[feature_name] = layers.Input(\n", + " name=feature_name, shape=(), dtype=tf.float32\n", + " )\n", + " else:\n", + " inputs[feature_name] = layers.Input(\n", + " name=feature_name, shape=(), dtype=tf.string\n", + " )\n", + " return inputs\n", + "\n", + "\n", + "\"\"\"\n", + "## Encode features\n", + "We create two representations of our input features: sparse and dense:\n", + "1. In the **sparse** representation, the categorical features are encoded with one-hot\n", + "encoding using the `CategoryEncoding` layer. This representation can be useful for the\n", + "model to *memorize* particular feature values to make certain predictions.\n", + "2. In the **dense** representation, the categorical features are encoded with\n", + "low-dimensional embeddings using the `Embedding` layer. This representation helps\n", + "the model to *generalize* well to unseen feature combinations.\n", + "\"\"\"\n", + "\n", + "\n", + "from tensorflow.keras.layers import StringLookup\n", + "\n", + "\n", + "def encode_inputs(inputs, use_embedding=False):\n", + " encoded_features = []\n", + " for feature_name in inputs:\n", + " if feature_name in CATEGORICAL_FEATURE_NAMES:\n", + " vocabulary = CATEGORICAL_FEATURES_WITH_VOCABULARY[feature_name]\n", + " # Create a lookup to convert string values to an integer indices.\n", + " # Since we are not using a mask token nor expecting any out of vocabulary\n", + " # (oov) token, we set mask_token to None and num_oov_indices to 0.\n", + " lookup = StringLookup(\n", + " vocabulary=vocabulary,\n", + " mask_token=None,\n", + " num_oov_indices=0,\n", + " output_mode=\"int\" if use_embedding else \"binary\",\n", + " )\n", + " if use_embedding:\n", + " # Convert the string input values into integer indices.\n", + " encoded_feature = lookup(inputs[feature_name])\n", + " embedding_dims = int(math.sqrt(len(vocabulary)))\n", + " # Create an embedding layer with the specified dimensions.\n", + " embedding = layers.Embedding(\n", + " input_dim=len(vocabulary), output_dim=embedding_dims\n", + " )\n", + " # Convert the index values to embedding representations.\n", + " encoded_feature = embedding(encoded_feature)\n", + " else:\n", + " # Convert the string input values into a one hot encoding.\n", + " encoded_feature = lookup(tf.expand_dims(inputs[feature_name], -1))\n", + " else:\n", + " # Use the numerical features as-is.\n", + " encoded_feature = tf.expand_dims(inputs[feature_name], -1)\n", + "\n", + " encoded_features.append(encoded_feature)\n", + "\n", + " all_features = layers.concatenate(encoded_features)\n", + " return all_features\n", + "\n", + "\n", + "\"\"\"\n", + "## Experiment 1: a baseline model\n", + "In the first experiment, let's create a multi-layer feed-forward network,\n", + "where the categorical features are one-hot encoded.\n", + "\"\"\"\n", + "from tensorflow import keras\n", + "from tensorflow.keras import layers\n", + "\n", + "def create_baseline_model():\n", + " inputs = create_model_inputs()\n", + " features = encode_inputs(inputs)\n", + "\n", + " for units in hidden_units:\n", + " features = layers.Dense(units)(features)\n", + " features = layers.BatchNormalization()(features)\n", + " features = layers.ReLU()(features)\n", + " features = layers.Dropout(dropout_rate)(features)\n", + "\n", + " outputs = layers.Dense(units=NUM_CLASSES, activation=\"softmax\")(features)\n", + " model = keras.Model(inputs=inputs, outputs=outputs)\n", + " return model\n", + "\n", + "\n", + "baseline_model = create_baseline_model()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's run it:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "run_experiment(baseline_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We clear the environments in the end." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dask_worker.terminate()\n", + "dask_scheduler.terminate()\n", + "\n", + "vineyard.shutdown()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we can use **horovodrun** to run the above code distributedly in a cluster for distributed learning on big datasets." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Conclusion\n", + "----------\n", + "\n", + "From this example, we can see that with the help of Vineyard, users can easily extend\n", + "their single machine solutions to distributed learning using dedicated systems without\n", + "worrying about the cross-system data sharing issues." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/tutorials/data-processing/python-sharedmemory.html b/tutorials/data-processing/python-sharedmemory.html new file mode 100644 index 0000000000..065ed3a805 --- /dev/null +++ b/tutorials/data-processing/python-sharedmemory.html @@ -0,0 +1,466 @@ + + + + + + + + + + + + + + + + + + + multiprocessing.shared_memory in Python - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

multiprocessing.shared_memory in Python#

+

Vineyard offers a shared memory interface through SharedMemory and +ShareableList classes, ensuring compatibility with Python’s multiprocessing.shared_memory.

+

Utilize the shared memory interface as demonstrated below:

+
>>> from vineyard import shared_memory
+>>> value = shared_memory.ShareableList(client, [b"a", "bb", 1234, 56.78, True])
+>>> value
+ShareableList([b'a', 'bb', 1234, 56.78, True], name='o8000000119aa10c0')
+>>> value[4] = False
+>>> value
+ShareableList([b'a', 'bb', 1234, 56.78, False], name='o8000000119aa10c0')
+
+
+
+

Caution

+

Please be aware that the semantics of Vineyard’s shared_memory differ slightly +from those of Python’s multiprocessing module’s shared_memory. In Vineyard, +shared memory cannot be modified once it becomes visible to other clients.

+
+

We have added a freeze method to make such transformation happen:

+
>>> value.freeze()
+
+
+

After being frozen, the shared memory (aka. the ShareableList in this case) +is available for other clients:

+
>>> value1 = shared_memory.ShareableList(client, name=value.shm.name)
+>>> value1
+ShareableList([b'a', 'bb', 1234, 56.78, False], name='o8000000119aa10c0')
+
+
+

For more details, see Shared memory.

+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/tutorials/data-processing/using-objects-python.html b/tutorials/data-processing/using-objects-python.html new file mode 100644 index 0000000000..386f18df12 --- /dev/null +++ b/tutorials/data-processing/using-objects-python.html @@ -0,0 +1,508 @@ + + + + + + + + + + + + + + + + + + + Sharing Python Objects with Vineyard - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Sharing Python Objects with Vineyard#

+

As discussed in Objects, each object in Vineyard consists of two parts:

+
    +
  1. The data payload, which is stored locally in the corresponding Vineyard instance

  2. +
  3. The hierarchical metadata, which is shared across the entire Vineyard cluster

  4. +
+

Specifically, a Blob represents the unit where the data payload resides within a +Vineyard instance. A blob object holds a segment of memory in the bulk store of the +Vineyard instance, allowing users to save their local buffer into a blob and later +retrieve the blob in another process using a zero-copy approach through memory mapping.

+
>>> payload = b"Hello, World!"
+>>> blob_id = client.put(payload)
+>>> blob = client.get_object(blob_id)
+>>> print(blob.typename, blob.size, blob)
+
+
+
vineyard::Blob 28 Object <"o800000011cfa7040": vineyard::Blob>
+
+
+

On the other hand, the hierarchical metadata of Vineyard objects is shared across +the entire cluster. In the following example, for the sake of simplicity, we +launch a Vineyard cluster consisting of two Vineyard instances on the same machine. +However, in real-world scenarios, these Vineyard instances would be distributed +across multiple machines within the cluster.

+
$ python3 -m vineyard --socket /var/run/vineyard.sock1
+$ python3 -m vineyard --socket /var/run/vineyard.sock2
+
+
+

With this setup, we can create a distributed pair of arrays in Vineyard, where +the first array is stored in the first Vineyard instance listening to the IPC socket +/var/run/vineyard.sock1, and the second array is stored in the second instance +listening to the IPC socket /var/run/vineyard.sock2.

+
>>> import numpy as np
+>>> import vineyard
+>>> import vineyard.data.tensor
+
+>>> # build the first array in the first vineyard instance
+>>> client1 = vineyard.connect('/var/run/vineyard.sock1')
+>>> id1 = client1.put(np.zeros(8))
+>>> # persist the object to make it visible to form the global object
+>>> client1.persist(id1)
+
+>>> # build the second array in the second vineyard instance
+>>> client2 = vineyard.connect('/var/run/vineyard.sock2')
+>>> id2 = client2.put(np.ones(4))
+>>> # persist the object to make it visible to form the global object
+>>> client2.persist(id2)
+
+>>> # build the pair from client1
+>>> obj1 = client1.get_object(id1)
+>>> obj2 = client2.get_object(id2)
+>>> id_pair = client1.put((obj1, obj2))
+
+>>> # get the pair object from client2
+>>> obj_pair = client2.get_object(id_pair)
+>>> print(obj_pair.first.typename, obj_pair.first.size(), obj_pair.second.size())
+
+
+
vineyard::Array 8 4
+
+
+
>>> # get the pair value from client2
+>>> value_pair = client2.get(id_pair)
+>>> print(value_pair)
+
+
+
(None, [1, 1, 1, 1])
+
+
+

In this example, we can access the metadata of the pair object from client2 +even though it was created by client1. However, we cannot retrieve the payload +of the first element of the pair from client2 because it is stored locally +in the first Vineyard instance.

+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/tutorials/extending.html b/tutorials/extending.html new file mode 100644 index 0000000000..c445706b38 --- /dev/null +++ b/tutorials/extending.html @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + Extending vineyard - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Extending vineyard#

+
+
+

Vineyard offers a collection of efficient data structures tailored for data-intensive tasks, +such as tensors, data frames, tables, and graphs. These data types can be easily extended +to accommodate custom requirements. By registering user-defined types in the vineyard type +registry, computing engines built on top of vineyard can instantly leverage the advantages +provided by these custom data structures.

+
+
+
+
+ +
+

Craft builders and resolvers for custom Python data types.

+
+
+
+
+
+ +
+

Implement and register custom data types in C++ for seamless integration with vineyard’s ecosystem.

+
+
+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/tutorials/extending/define-datatypes-cpp.html b/tutorials/extending/define-datatypes-cpp.html new file mode 100644 index 0000000000..686bdf266f --- /dev/null +++ b/tutorials/extending/define-datatypes-cpp.html @@ -0,0 +1,736 @@ + + + + + + + + + + + + + + + + + + + Defining Custom Data Types in C++ - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Defining Custom Data Types in C++#

+

Vineyard provides an extensive set of efficient built-in data types in +its C++ SDK, such as Vector, HashMap, Tensor, +DataFrame, Table, and Graph (refer to Objects). +However, there may be situations where users need to develop their +own data structures and share the data efficiently with Vineyard. This +step-by-step tutorial guides you through the process of adding custom +C++ data types with ease.

+
+

Note

+

This tutorial includes code snippets that could be auto-generated to +provide a clear understanding of the design internals and to help +developers grasp the overall functionality of the Vineyard client.

+
+
+

Object and ObjectBuilder#

+

Vineyard has a base class vineyard::Objects, and a corresponding +base class Vineyard::ObjectBuilder for builders as follows,

+
class Object {
+  public:
+    static std::unique_ptr<Object> Create() {
+        ...
+    }
+
+    virtual void Construct(const ObjectMeta& meta);
+}
+
+
+

and the builder

+
class ObjectBuilder {
+    virtual Status Build(Client& client) override = 0;
+
+    virtual std::shared_ptr<Object> _Seal(Client& client) = 0;
+}
+
+
+

Where the object is the base class for user-defined data types, and the +builders is responsible for placing the data into vineyard.

+
+
+

Defining Your Custom Type#

+

Let’s take the example of defining a custom Vector type. Essentially, +a Vector consists of a vineyard::Blob as its payload, along with +metadata such as dtype and size.

+

The class definition for the Vector type typically appears as follows:

+
template <typename T>
+class Vector {
+private:
+    size_t size;
+    const T *data = nullptr;
+public:
+    Vector(): size(0), data(nullptr) {
+    }
+
+    Vector(const int size, const T *data): size(size), data(data) {
+    }
+
+    size_t length() const {
+        return size;
+    }
+
+    const T& operator[](size_t index) {
+        assert(index < size);
+        return data[index];
+    }
+};
+
+
+
+
+

Registering C++ Types#

+

First, we need to adapt the existing Vector<T> to become a Vineyard +Object,

+
 template <typename T>
+-class Vector {
++class Vector: public vineyard::Registered<Vector<T>> {
+   private:
+     size_t size;
+     T *data = nullptr;
+   public:
++    static std::unique_ptr<Object> Create() __attribute__((used)) {
++        return std::static_pointer_cast<Object>(
++            std::unique_ptr<Vector<T>>{
++                new Vector<T>()});
++    }
++
+     Vector(): size(0), data(nullptr) {
+     }
+
+     Vector(const int size, const T *data): size(size), data(data) {
+     }
+
+     ...
+ }
+
+
+

Observe the two key modifications above:

+
    +
  • Inheriting from vineyard::Registered<Vector<T>>:

    +

    vineyard::Registered<T> serves as a helper to generate static +initialization stubs, registering the data type T with the type +resolving factory and associating the type T with its typename. +The typename is an auto-generated, human-readable name for C++ types, e.g., +"Vector<int32>" for Vector<int32_t>.

    +
  • +
  • Implementing the zero-parameter static constructor Create():

    +

    Create() is a static function registered with the +resolving factory by the helper vineyard::Registered<T>. It is +used to construct an instance of type T when retrieving objects +from Vineyard.

    +

    The Vineyard client locates the static constructor using the typename +found in the metadata of Vineyard objects stored in the daemon server.

    +
  • +
+

To retrieve the object Vector<T> from Vineyard’s metadata, we need to +implement a Construct method as well. The Construct method takes +a vineyard::ObjectMeta as input and extracts metadata and +members from it to populate its own data members. The memory in the member +buffer (a vineyard::Blob) is shared using memory mapping, +eliminating the need for copying.

+
 template <typename T>
+ class Vector: public vineyard::Registered<Vector<T>> {
+   public:
+     ...
+
++    void Construct(const ObjectMeta& meta) override {
++      this->size = meta.GetKeyValue<size_t>("size");
++
++      auto buffer = std::dynamic_pointer_cast<Blob>(meta.GetMember("buffer"));
++      this->data = reinterpret_cast<const T *>(buffer->data());
++    }
++
+     ...
+ }
+
+
+
+
+

Builder#

+

Moving on to the builder section, the vineyard::ObjectBuilder consists of two parts:

+
    +
  • Build(): This method is responsible for storing the blobs of custom data +structures into Vineyard.

  • +
  • _Seal(): This method is responsible for generating the corresponding metadata +and inserting the metadata into Vineyard.

  • +
+

For our Vector<T> type, let’s first define a general vector builder:

+
template <typename T>
+class VectorBuilder {
+  private:
+    std::unique_ptr<BlobWriter> buffer_builder;
+    std::size_t size;
+    T *data;
+
+  public:
+    VectorBuilder(size_t size): size(size) {
+      data = static_cast<T *>(malloc(sizeof(T) * size));
+    }
+
+    T& operator[](size_t index) {
+      assert(index < size);
+      return data[index];
+    }
+};
+
+
+

The builder allocates the necessary memory based on the specified size to accommodate +the elements and provides a [] operator to populate the data.

+

Next, we adapt the above builder as a ObjectBuilder in Vineyard,

+
 template <typename T>
+-class VectorBuilder {
++class VectorBuilder: public vineyard::ObjectBuilder {
+   private:
+     std::unique_ptr<BlobWriter> buffer_builder;
+     std::size_t size;
+     T *data;
+
+   public:
+     VectorBuilder(size_t size): size(size) {
+       data = static_cast<T *>(malloc(sizeof(T) * size));
+     }
+
++    Status Build(Client& client) override {
++      RETURN_ON_ERROR(client.CreateBlob(size * sizeof(T), buffer_builder));
++      memcpy(buffer_builder->data(), data, size * sizeof(T));
++      return Status::OK();
++    }
++
++    Status _Seal(Client& client, std::shared_ptr<Object> &object) override {
++      RETURN_ON_ERROR(this->Build(client));
++
++      auto vec = std::make_shared<Vector<int>>();
+       object = vec;
++      std::shared_ptr<Object> buffer_object;
++      RETURN_ON_ERROR(this->buffer_builder->Seal(client, buffer_object));
++      auto buffer = std::dynamic_pointer_cast<Blob>(buffer_object);
++      vec->size = size;
++      vec->data = reinterpret_cast<const T *>(buffer->data());
++
++      vec->meta_.SetTypeName(vineyard::type_name<Vector<T>>());
++      vec->meta_.SetNBytes(size * sizeof(T));
++      vec->meta_.AddKeyValue("size", size);
++      vec->meta_.AddMember("buffer", buffer);
++      return client.CreateMetaData(vec->meta_, vec->id_);
++    }
++
+     T& operator[](size_t index) {
+       assert(index < size);
+       return data[index];
+     }
+ };
+
+
+

To access private member fields and methods, the builder may need to be +added as a friend class of the original type declaration.

+
+

Note

+

Since the builder requires direct access to the private data members of +Vector<T>, it is necessary to declare the builder as a friend class +of our vector type,

+
+
 template <typename T>
+ class Vector: public vineyard::Registered<Vector<T>> {
+
+     const T& operator[](size_t index) {
+       assert(index < size);
+       return data[index];
+     }
++
++  friend class VectorBuilder<T>;
+ };
+
+
+

In the example above, you may notice that the builder and constructor contain numerous +boilerplate snippets. These can be auto-generated based on the layout of the class +Vector<T> through static analysis of the user’s source code, streamlining +the process and enhancing readability.

+
+
+

Utilizing Custom Data Types with Vineyard#

+

At this point, we have successfully defined our custom data types and integrated them +with Vineyard. Now, we can demonstrate how to build these custom data types using the +Vineyard client and retrieve them for further processing.

+
int main(int argc, char** argv) {
+    std::string ipc_socket = std::string(argv[1]);
+
+    Client client;
+    VINEYARD_CHECK_OK(client.Connect(ipc_socket));
+    LOG(INFO) << "Connected to IPCServer: " << ipc_socket;
+
+    auto builder = VectorBuilder<int>(3);
+    builder[0] = 1;
+    builder[1] = 2;
+    builder[2] = 3;
+    auto result = builder.Seal(client);
+
+    auto vec = std::dynamic_pointer_cast<Vector<int>>(client.GetObject(result->id()));
+    for (size_t index = 0; index < vec->length(); ++index) {
+        std::cout << "element at " << index << " is: " << (*vec)[index] << std::endl;
+    }
+}
+
+
+
+
+

Cross-Language Compatibility#

+

Vineyard maintains consistent design principles across SDKs in various languages, +such as Java and Python. For an example of Vineyard objects and their builders in +Python, please refer to Builders and resolvers.

+

As demonstrated in the example above, there is a significant amount of boilerplate +code involved in defining constructors and builders. To simplify the integration +with Vineyard, we are developing a code generator that will automatically produce +SDKs in different languages based on a C++-like Domain Specific Language (DSL). +Stay tuned for updates!

+

For a sneak peek at how the code generator works, please refer to array.vineyard-mod +and arrow.vineyard-mod.

+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/tutorials/extending/define-datatypes-python.html b/tutorials/extending/define-datatypes-python.html new file mode 100644 index 0000000000..94c0f50ddd --- /dev/null +++ b/tutorials/extending/define-datatypes-python.html @@ -0,0 +1,599 @@ + + + + + + + + + + + + + + + + + + + Define Data Types in Python - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Define Data Types in Python#

+
+

Objects#

+

As discussed in Objects, each object in vineyard comprises two components:

+
    +
  1. The data payload, which is stored locally within the corresponding vineyard instance

  2. +
  3. The hierarchical meta data, which is shared across the entire vineyard cluster

  4. +
+

Specifically, a Blob represents the unit where the data payload resides in a vineyard +instance. A blob object contains a segment of memory in the bulk store of the vineyard +instance, allowing users to save their local buffer into a blob and later retrieve the +blob in another process using a zero-copy approach through memory mapping.

+
>>> payload = b"Hello, World!"
+>>> blob_id = client.put(payload)
+>>> blob = client.get_object(blob_id)
+>>> print(blob.typename, blob.size, blob)
+
+
+
vineyard::Blob 28 Object <"o800000011cfa7040": vineyard::Blob>
+
+
+

On the other hand, vineyard objects’ hierarchical meta data is shared across the entire +cluster. In the following example, for the sake of simplicity, we will launch a vineyard +cluster with two vineyard instances on the same machine. However, in real-world scenarios, +these vineyard instances would typically be distributed across multiple machines within +the cluster.

+
$ python3 -m vineyard --socket /var/run/vineyard.sock1
+$ python3 -m vineyard --socket /var/run/vineyard.sock2
+
+
+

With this setup, we can create a distributed pair of arrays in vineyard, where the first +array is stored in the first vineyard instance (listening to ipc_socket at /var/run/vineyard.sock1), +and the second array is stored in the second instance (listening to ipc_socket at +/var/run/vineyard.sock2).

+
>>> import numpy as np
+>>> import vineyard
+>>> import vineyard.data.tensor
+
+>>> # build the first array in the first vineyard instance
+>>> client1 = vineyard.connect('/var/run/vineyard.sock1')
+>>> id1 = client1.put(np.zeros(8))
+>>> # persist the object to make it visible to form the global object
+>>> client1.persist(id1)
+
+>>> # build the second array in the second vineyard instance
+>>> client2 = vineyard.connect('/var/run/vineyard.sock2')
+>>> id2 = client2.put(np.ones(4))
+>>> # persist the object to make it visible to form the global object
+>>> client2.persist(id2)
+
+>>> # build the pair from client1
+>>> obj1 = client1.get_object(id1)
+>>> obj2 = client2.get_object(id2)
+>>> id_pair = client1.put((obj1, obj2))
+
+>>> # get the pair object from client2
+>>> obj_pair = client2.get_object(id_pair)
+>>> print(obj_pair.first.typename, obj_pair.first.size(), obj_pair.second.size())
+
+
+
vineyard::Array 8 4
+
+
+
>>> # get the pair value from client2
+>>> value_pair = client2.get(id_pair)
+>>> print(value_pair)
+
+
+
(None, [1, 1, 1, 1])
+
+
+

In this example, we can access the metadata of the pair object from client2 even +though it was created by client1. However, we cannot retrieve the payload of the +first element of the pair from client2, as it is stored locally within the first +vineyard instance.

+
+
+

Creating Builders and Resolvers#

+

As demonstrated in Builders and resolvers, vineyard enables users to register +builders and resolvers for constructing and resolving vineyard objects from/to +client-side data types based on specific computational requirements.

+

For instance, if we use pyarrow types in our context, we can define the builder and +resolver for the conversion between vineyard::NumericArray and pyarrow.NumericArray +as follows:

+
>>> def numeric_array_builder(client, array, builder):
+>>>     meta = ObjectMeta()
+>>>     meta['typename'] = 'vineyard::NumericArray<%s>' % array.type
+>>>     meta['length_'] = len(array)
+>>>     meta['null_count_'] = array.null_count
+>>>     meta['offset_'] = array.offset
+>>>
+>>>     null_bitmap = buffer_builder(client, array.buffers()[0], builder)
+>>>     buffer = buffer_builder(client, array.buffers()[1], builder)
+>>>
+>>>     meta.add_member('buffer_', buffer)
+>>>     meta.add_member('null_bitmap_', null_bitmap)
+>>>     meta['nbytes'] = array.nbytes
+>>>     return client.create_metadata(meta)
+
+>>> def numeric_array_resolver(obj):
+>>>     meta = obj.meta
+>>>     typename = obj.typename
+>>>     value_type = normalize_dtype(re.match(r'vineyard::NumericArray<([^>]+)>', typename).groups()[0])
+>>>     dtype = pa.from_numpy_dtype(value_type)
+>>>     buffer = as_arrow_buffer(obj.member('buffer_'))
+>>>     null_bitmap = as_arrow_buffer(obj.member('null_bitmap_'))
+>>>     length = int(meta['length_'])
+>>>     null_count = int(meta['null_count_'])
+>>>     offset = int(meta['offset_'])
+>>>     return pa.lib.Array.from_buffers(dtype, length, [null_bitmap, buffer], null_count, offset)
+
+
+

Finally, we register the builder and resolver for automatic building and resolving: +.. code:: python

+
>>> builder_ctx.register(pa.NumericArray, numeric_array_builder)
+>>> resolver_ctx.register('vineyard::NumericArray', numeric_array_resolver)
+
+
+

In some cases, we may have multiple resolvers or builders for a specific type. +For instance, the vineyard::Tensor object can be resolved as either numpy.ndarray or +xgboost::DMatrix. To accommodate this, we could have:

+
>>> resolver_ctx.register('vineyard::Tensor', numpy_resolver)
+>>> resolver_ctx.register('vineyard::Tensor', xgboost_resolver)
+
+
+

This flexibility enables seamless integration with various libraries and frameworks by +effectively handling different data types and their corresponding resolvers or builders.

+
def xgboost_resolver(obj):
+    ...
+
+default_resolver_context.register('vineyard::Tensor', xgboost_resolver)
+
+
+

at the same time. The stackable resolver_context could help there,

+
with resolver_context({'vineyard::Tensor', xgboost_resolver}):
+    ...
+
+
+

Assuming the default context resolves vineyard::Tensor to numpy.ndarray, the +with resolver_context allows for temporary resolution of vineyard::Tensor to +xgboost::DMatrix. Upon exiting the context, the global environment reverts to +its default state.

+

The with resolver_context can be nested for additional flexibility.

+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/tutorials/kubernetes.html b/tutorials/kubernetes.html new file mode 100644 index 0000000000..fc6aefd7c3 --- /dev/null +++ b/tutorials/kubernetes.html @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + Vineyard on Kubernetes - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Vineyard on Kubernetes#

+
+
+

Vineyard can be seamlessly deployed on Kubernetes, managed by the Vineyard Operator, +to enhance big-data workflows through its data-aware scheduling policy. This policy +orchestrates shared objects and routes jobs to where their input data resides. In the +following tutorials, you will learn how to deploy Vineyard and effectively integrate it +with Kubernetes.

+
+
+
+
+ +
+

The Vineyard operator serves as the central component for seamless integration with Kubernetes.

+
+
+
+
+
+ +
+

Vineyard functions as an efficient intermediate data storage solution for machine learning pipelines on Kubernetes.

+
+
+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/tutorials/kubernetes/data-sharing-with-vineyard-on-kubernetes.html b/tutorials/kubernetes/data-sharing-with-vineyard-on-kubernetes.html new file mode 100644 index 0000000000..f1761f8f7f --- /dev/null +++ b/tutorials/kubernetes/data-sharing-with-vineyard-on-kubernetes.html @@ -0,0 +1,692 @@ + + + + + + + + + + + + + + + + + + + Data sharing with Vineyard on Kubernetes - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Data sharing with Vineyard on Kubernetes#

+

If you want to share data between different workloads(pods or containers) on kubernetes, it’s a good idea to +use vineyard as the data-sharing service. In this tutorial, we will show you how to +share data between different containers or pods on kubernetes step by step.

+
+Data sharing between containers +

Data sharing between containers#

+
+

From the above figure, the vineyardctl inject command will inject vineyard container into the app pod and +the app containers will connect to the vineyard container to share the vineyard data.

+
+Data sharing on the vineyard deployment +

Data sharing on the vineyard deployment#

+
+

From the above figure, the vineyardctl deploy vineyard-deployment command will deploy a vineyard deployment +on the kubernetes cluster (default is 3 replicas) and the app pods will be scheduled to the vineyard deployment +to share the vineyard data via the command vineyardctl schedule workload.

+
+

Prerequisites#

+
    +
  • A kubernetes cluster with version >= 1.25.10.

  • +
  • Install the latest vineyardctl command line tool refer to vineyardctl installation.

  • +
+
+
+

Data sharing between different containers#

+

In this section, we will show you how to share data between different containers on kubernetes. +Assuming you have a pod with two containers, one is a producer and the other is a consumer. +The producer will generate some data and write it to vineyard, and the consumer will read the data +from vineyard and do some computation.

+

Save the following yaml as pod.yaml.

+
$ cat << EOF >> pod.yaml
+apiVersion: v1
+kind: Pod
+metadata:
+  name: vineyard-producer-consumer
+  namespace: vineyard-test
+spec:
+  containers:
+  - name: producer
+    image: python:3.10
+    command:
+    - bash
+    - -c
+    - |
+      pip install vineyard numpy pandas;
+      cat << EOF >> producer.py
+      import vineyard;
+      import numpy as np;
+      import pandas as pd;
+      client = vineyard.connect();
+      # put a pandas dataframe to vineyard
+      client.put(pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD')), persist=True, name="test_dataframe");
+      # put a basic data unit to vineyard
+      client.put((1, 1.2345, 'xxxxabcd'), persist=True, name="test_basic_data_unit");
+      client.close()
+      EOF
+      python producer.py;
+      sleep infinity;
+  - name: consumer
+    image: python:3.10
+    command:
+    - bash
+    - -c
+    - |
+      # wait for the producer to finish
+      sleep 10;
+      pip install vineyard numpy pandas;
+      cat << EOF >> consumer.py
+      import vineyard;
+      client = vineyard.connect();
+      # get the pandas dataframe from vineyard
+      print(client.get(name="test_dataframe").sum())
+      # get the basic data unit from vineyard
+      print(client.get(name="test_basic_data_unit"))
+      client.close()
+      EOF
+      python consumer.py;
+      sleep infinity;
+EOF
+
+
+

Use the vineyardctl to inject vineyard into the pod and apply them to the kubernetes cluster +as follows.

+
# create the namespace
+$ kubectl create ns vineyard-test
+# get all injected resources
+$ vineyardctl inject -f pod.yaml | kubectl apply -f -
+pod/vineyard-sidecar-etcd-0 created
+service/vineyard-sidecar-etcd-0 created
+service/vineyard-sidecar-etcd-service created
+service/vineyard-sidecar-rpc created
+pod/vineyard-producer-consumer created
+
+
+

Then you can get the logs of the consumer containers as follows.

+
# get the logs of the consumer container
+$ kubectl logs -f vineyard-producer-consumer -n test -c consumer
+A   -30.168469
+B   -19.269489
+C     6.332533
+D    -9.714950
+dtype: float64
+(1, 1.2345000505447388, 'xxxxabcd')
+
+
+
+
+

Data sharing between different pods#

+

In this section, we will show you how to share data between different workloads on kubernetes. +You are supposed to create a vineyard deployment and then deploy the application pods on +the nodes where the vineyard deployment is running.

+

Deploy the vineyard deployment (default is 3 replicas) as follows.

+
# create the namespace if not exists
+$ kubectl create ns vineyard-test
+# create the vineyard deployment
+$ vineyardctl deploy vineyard-deployment --name vineyardd-sample -n vineyard-test
+2023-07-21T15:42:25.981+0800    INFO    vineyard cluster deployed successfully
+
+
+

Check the vineyard deployment status and the three vineyardd pods should run on the different nodes.

+
# check the pods status
+$ kubectl get pod -lapp.vineyard.io/name=vineyardd-sample -n vineyard-test -owide
+NAME                                READY   STATUS    RESTARTS   AGE     IP            NODE           NOMINATED NODE   READINESS GATES
+vineyardd-sample-5fd45fdd66-fq55z   1/1     Running   0          3m37s   10.244.1.17   kind-worker3   <none>           <none>
+vineyardd-sample-5fd45fdd66-qjr5c   1/1     Running   0          3m37s   10.244.3.35   kind-worker    <none>           <none>
+vineyardd-sample-5fd45fdd66-ssqb7   1/1     Running   0          3m37s   10.244.2.29   kind-worker2   <none>           <none>
+vineyardd-sample-etcd-0             1/1     Running   0          3m53s   10.244.1.16   kind-worker3   <none>           <none>
+
+
+

Assume we have two pods, one is a producer and the other is a consumer.

+

The producer yaml file is as follows.

+
$ cat << EOF >> producer.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: producer
+  namespace: vineyard-test
+spec:
+  selector:
+    matchLabels:
+      app: producer
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: producer
+    spec:
+      containers:
+      - name: producer
+        image: python:3.10
+        command:
+        - bash
+        - -c
+        - |
+          pip install vineyard numpy pandas;
+          cat << EOF >> producer.py
+          import vineyard
+          import numpy as np
+          import pandas as pd
+          client = vineyard.connect()
+          client.put(pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD')), persist=True, name="test_dataframe")
+          client.put((1, 1.2345, 'xxxxabcd'), persist=True, name="test_basic_data_unit");
+          client.close()
+          EOF
+          python producer.py;
+          sleep infinity;
+EOF
+
+
+

The consumer yaml file is as follows.

+
$ cat << EOF >> consumer.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: consumer
+  namespace: vineyard-test
+spec:
+  selector:
+    matchLabels:
+      app: consumer
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: consumer
+    spec:
+      containers:
+      - name: consumer
+        image: python:3.10
+        command:
+        - bash
+        - -c
+        - |
+          pip install vineyard numpy pandas;
+          cat << EOF >> consumer.py
+          import vineyard
+          client = vineyard.connect()
+          dataframe_obj = client.get_name("test_dataframe")
+          print(client.get(dataframe_obj,fetch=True).sum())
+          unit_obj = client.get_name("test_basic_data_unit")
+          print(client.get(unit_obj,fetch=True))
+          client.close()
+          EOF
+          python consumer.py;
+          sleep infinity;
+EOF
+
+
+

Use the vineyardctl to schedule the two workloads on the vineyard cluster.

+
# schedule the producer workload to the vineyard cluster and apply it to the kubernetes cluster
+$ vineyardctl schedule workload -f producer.yaml --vineyardd-name vineyardd-sample \
+--vineyardd-namespace vineyard-test -o yaml | kubectl apply -f -
+deployment.apps/producer created
+
+# schedule the consumer workload to the vineyard cluster and apply it to the kubernetes cluster
+$ vineyardctl schedule workload -f consumer.yaml --vineyardd-name vineyardd-sample \
+--vineyardd-namespace vineyard-test -o yaml | kubectl apply -f -
+deployment.apps/consumer created
+
+
+

Check the logs of the consumer pods as follows.

+
$ kubectl logs -f $(kubectl get pod -lapp=consumer -n vineyard-test -o jsonpath='{.items[0].metadata.name}') -n vineyard-test
+A    11.587912
+B    12.059792
+C     4.863514
+D    -2.682567
+dtype: float64
+(1, 1.2345000505447388, 'xxxxabcd')
+
+
+

From the above example, we can see the code of the consumer is quiet different from the previous sidecar example. +As the consumer may be scheduled to different node from the producer with the default kubernetes scheduler, the client +should get the remote object id by name and then fetch it from other vineyard nodes. For more details, please refer to +the vineyard objects.

+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/tutorials/kubernetes/ml-pipeline-mars-pytorch.html b/tutorials/kubernetes/ml-pipeline-mars-pytorch.html new file mode 100644 index 0000000000..006fa461eb --- /dev/null +++ b/tutorials/kubernetes/ml-pipeline-mars-pytorch.html @@ -0,0 +1,677 @@ + + + + + + + + + + + + + + + + + + + Machine learning with Vineyard on Kubernetes - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Machine learning with Vineyard on Kubernetes#

+

In this demonstration, we will build a fraudulent transaction classifier for +fraudulent transaction data. The process consists of the following +three main steps:

+
    +
  • prepare-data: Utilize Vineyard to read and store data in a distributed manner.

  • +
  • process-data: Employ Mars to process the data across multiple nodes.

  • +
  • train-data: Use Pytorch to train the model on the distributed data.

  • +
+

We have three tables: user table, product table, and transaction table. +The user and product tables primarily contain user and product IDs, along with +their respective Feature vectors. Each record in the transaction table indicates +a user purchasing a product, with a Fraud label identifying whether the +transaction is fraudulent. Additional features related to these transactions are also +stored in the transaction table. You can find the three tables in the dataset repo. +Follow the steps below to reproduce the demonstration. First, create a vineyard cluster +with 3 worker nodes.

+
$ cd k8s && make install-vineyard
+
+
+
+

Expected output

+
+
the kubeconfig path is /tmp/e2e-k8s.config
+Creating the kind cluster with local registry
+a16c878c5091c1e5c9eff0a1fca065665f47edb4c8c75408b3d33e22f0ec0d05
+Creating cluster "kind" ...
+✓ Ensuring node image (kindest/node:v1.24.0) 🖼
+✓ Preparing nodes 📦 📦 📦 📦
+✓ Writing configuration 📜
+✓ Starting control-plane 🕹️
+✓ Installing CNI 🔌
+✓ Installing StorageClass 💾
+✓ Joining worker nodes 🚜
+Set kubectl context to "kind-kind"
+You can now use your cluster with:
+
+kubectl cluster-info --context kind-kind --kubeconfig /tmp/e2e-k8s.config
+
+Thanks for using kind! 😊
+configmap/local-registry-hosting created
+Installing cert-manager...
+namespace/cert-manager created
+customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
+customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
+customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created
+customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created
+customresourcedefinition.apiextensions.k8s.io/issuers.cert-manager.io created
+customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manager.io created
+serviceaccount/cert-manager-cainjector created
+serviceaccount/cert-manager created
+serviceaccount/cert-manager-webhook created
+configmap/cert-manager-webhook created
+clusterrole.rbac.authorization.k8s.io/cert-manager-cainjector created
+clusterrole.rbac.authorization.k8s.io/cert-manager-controller-issuers created
+clusterrole.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers created
+clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificates created
+clusterrole.rbac.authorization.k8s.io/cert-manager-controller-orders created
+clusterrole.rbac.authorization.k8s.io/cert-manager-controller-challenges created
+clusterrole.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim created
+clusterrole.rbac.authorization.k8s.io/cert-manager-view created
+clusterrole.rbac.authorization.k8s.io/cert-manager-edit created
+clusterrole.rbac.authorization.k8s.io/cert-manager-controller-approve:cert-manager-io created
+clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificatesigningrequests created
+clusterrole.rbac.authorization.k8s.io/cert-manager-webhook:subjectaccessreviews created
+clusterrolebinding.rbac.authorization.k8s.io/cert-manager-cainjector created
+clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-issuers created
+clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers created
+clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificates created
+clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-orders created
+clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-challenges created
+clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim created
+clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-approve:cert-manager-io created
+clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificatesigningrequests created
+clusterrolebinding.rbac.authorization.k8s.io/cert-manager-webhook:subjectaccessreviews created
+role.rbac.authorization.k8s.io/cert-manager-cainjector:leaderelection created
+role.rbac.authorization.k8s.io/cert-manager:leaderelection created
+role.rbac.authorization.k8s.io/cert-manager-webhook:dynamic-serving created
+rolebinding.rbac.authorization.k8s.io/cert-manager-cainjector:leaderelection created
+rolebinding.rbac.authorization.k8s.io/cert-manager:leaderelection created
+rolebinding.rbac.authorization.k8s.io/cert-manager-webhook:dynamic-serving created
+service/cert-manager created
+service/cert-manager-webhook created
+deployment.apps/cert-manager-cainjector created
+deployment.apps/cert-manager created
+deployment.apps/cert-manager-webhook created
+mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
+validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
+pod/cert-manager-5dd59d9d9b-k9hkm condition met
+pod/cert-manager-cainjector-8696fc9f89-bmjzh condition met
+pod/cert-manager-webhook-7d4b5b8c56-fvmc2 condition met
+Cert-Manager ready.
+Installing vineyard-operator...
+The push refers to repository [localhost:5001/vineyard-operator]
+c3a672704524: Pushed
+b14a7037d2e7: Pushed
+8d7366c22fd8: Pushed
+latest: digest: sha256:ea06c833351f19c5db28163406c55e2108676c27fdafea7652500c55ce333b9d size: 946
+make[1]: Entering directory '/opt/caoye/v6d/k8s'
+go: creating new go.mod: module tmp
+/home/gsbot/go/bin/controller-gen rbac:roleName=manager-role crd:maxDescLen=0 webhook paths="./..." output:crd:artifacts:config=config/crd/bases
+cd config/manager && /usr/local/bin/kustomize edit set image controller=localhost:5001/vineyard-operator:latest
+/usr/local/bin/kustomize build config/default | kubectl apply -f -
+namespace/vineyard-system created
+customresourcedefinition.apiextensions.k8s.io/backups.k8s.v6d.io created
+customresourcedefinition.apiextensions.k8s.io/globalobjects.k8s.v6d.io created
+customresourcedefinition.apiextensions.k8s.io/localobjects.k8s.v6d.io created
+customresourcedefinition.apiextensions.k8s.io/operations.k8s.v6d.io created
+customresourcedefinition.apiextensions.k8s.io/recovers.k8s.v6d.io created
+customresourcedefinition.apiextensions.k8s.io/sidecars.k8s.v6d.io created
+customresourcedefinition.apiextensions.k8s.io/vineyardds.k8s.v6d.io created
+serviceaccount/vineyard-manager created
+role.rbac.authorization.k8s.io/vineyard-leader-election-role created
+clusterrole.rbac.authorization.k8s.io/vineyard-manager-role created
+clusterrole.rbac.authorization.k8s.io/vineyard-metrics-reader created
+clusterrole.rbac.authorization.k8s.io/vineyard-proxy-role created
+clusterrole.rbac.authorization.k8s.io/vineyard-scheduler-plugin-role created
+rolebinding.rbac.authorization.k8s.io/vineyard-leader-election-rolebinding created
+clusterrolebinding.rbac.authorization.k8s.io/vineyard-kube-scheduler-rolebinding created
+clusterrolebinding.rbac.authorization.k8s.io/vineyard-manager-rolebinding created
+clusterrolebinding.rbac.authorization.k8s.io/vineyard-proxy-rolebinding created
+clusterrolebinding.rbac.authorization.k8s.io/vineyard-scheduler-plugin-rolebinding created
+clusterrolebinding.rbac.authorization.k8s.io/vineyard-scheduler-rolebinding created
+clusterrolebinding.rbac.authorization.k8s.io/vineyard-volume-scheduler-rolebinding created
+service/vineyard-controller-manager-metrics-service created
+service/vineyard-webhook-service created
+deployment.apps/vineyard-controller-manager created
+certificate.cert-manager.io/vineyard-serving-cert created
+issuer.cert-manager.io/vineyard-selfsigned-issuer created
+mutatingwebhookconfiguration.admissionregistration.k8s.io/vineyard-mutating-webhook-configuration created
+validatingwebhookconfiguration.admissionregistration.k8s.io/vineyard-validating-webhook-configuration created
+make[1]: Leaving directory '/opt/caoye/v6d/k8s'
+deployment.apps/vineyard-controller-manager condition met
+Vineyard-Operator Ready
+Installing vineyard cluster...
+vineyardd.k8s.v6d.io/vineyardd-sample created
+vineyardd.k8s.v6d.io/vineyardd-sample condition met
+Vineyard cluster Ready
+
+
+
+
+

Verify that all Vineyard pods are running.

+
$ KUBECONFIG=/tmp/e2e-k8s.config kubectl get pod -n vineyard-system
+
+
+
+

Expected output

+
+
NAME                                           READY   STATUS    RESTARTS   AGE
+etcd0                                          1/1     Running   0          68s
+etcd1                                          1/1     Running   0          68s
+etcd2                                          1/1     Running   0          68s
+vineyard-controller-manager-7f569b57c5-46tgq   2/2     Running   0          92s
+vineyardd-sample-6ffcb96cbc-gs2v9              1/1     Running   0          67s
+vineyardd-sample-6ffcb96cbc-n59gg              1/1     Running   0          67s
+vineyardd-sample-6ffcb96cbc-xwpzd              1/1     Running   0          67s
+
+
+
+
+

First, let’s prepare the dataset and download it into the kind worker nodes as follows.

+
$ worker=($(docker ps | grep kind-worker | awk -F ' ' '{print $1}'))
+$ for c in ${worker[@]}; do \
+    docker exec $c sh -c "\
+        mkdir -p /datasets; \
+        cd /datasets/; \
+        curl -OL https://raw.githubusercontent.com/GraphScope/gstest/master/vineyard-mars-showcase-dataset/{item,txn,user}.csv" \
+  done
+
+
+

The prepare-data job primarily reads the datasets and distributes them across different +Vineyard nodes. For more information, please refer to the prepare data code. To apply +the job, follow the steps below:

+
+

Note

+

The prepare-data job needs to exec into the other pods. Therefore, you need to +create a service account and bind it to the role under the namespace. +Please make sure you can have permission to create the following role.

+
- apiGroups: [""]
+  resources: ["pods", "pods/log", "pods/exec"]
+  verbs: ["get", "patch", "delete", "create", "watch", "list"]
+
+
+
+
$ kubectl create ns vineyard-job && \
+kubectl apply -f showcase/vineyard-mars-pytorch/prepare-data/resources && \
+kubectl wait job -n vineyard-job -l app=prepare-data --for condition=complete --timeout=1200s
+
+
+
+

Expected output

+
+
namespace/vineyard-job created
+clusterrolebinding.rbac.authorization.k8s.io/prepare-data-rolebinding created
+clusterrole.rbac.authorization.k8s.io/prepare-data-role created
+job.batch/prepare-data created
+serviceaccount/prepare-data created
+job.batch/prepare-data condition met
+
+
+
+
+
+

Note

+

The process-data job needs to create a new namespace and deploy several kubernetes +resources in it. Please make sure you can have permission to create the following role.

+
- apiGroups: [""]
+  resources: ["pods", "pods/exec", "pods/log", "endpoints", "services"]
+  verbs: ["get", "patch", "delete", "create", "watch", "list"]
+- apiGroups: [""]
+  resources: ["namespaces"]
+  verbs: ["get", "create", "delete"]
+- apiGroups: [""]
+  resources: ["nodes"]
+  verbs: ["get", "list"]
+- apiGroups: ["rbac.authorization.k8s.io"]
+  resources: ["roles", "rolebindings"]
+  verbs: ["patch", "get", "create", "delete"]
+- apiGroups: ["apps"]
+  resources: ["deployments"]
+  verbs: ["create"]
+
+
+

Notice, the process-data job will require lots of permissions to deal +kubernetes resources, so please check the image of process-data job +if it is an official one.

+
+

The prepare-data job creates numerous dataframes in Vineyard. To combine these dataframes, +we use the appropriate join method in mars. For more details, refer to the process data +code. Apply the process-data job as follows:

+
$ kubectl apply -f showcase/vineyard-mars-pytorch/process-data/resources && \
+  kubectl wait job -n vineyard-job -l app=process-data --for condition=complete --timeout=1200s
+
+
+

Finally, apply the train-data job to obtain the fraudulent transaction classifier. You can +also view the train data code.

+
$ kubectl apply -f k8s/showcase/vineyard-mars-pytorch/train-data/resources && \
+  kubectl wait pods -n vineyard-job -l app=train-data --for condition=Ready --timeout=1200s
+
+
+

If any of the above steps fail, please refer to the mars showcase e2e test for further guidance.

+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/tutorials/kubernetes/using-vineyard-operator.html b/tutorials/kubernetes/using-vineyard-operator.html new file mode 100644 index 0000000000..a89cbb5c54 --- /dev/null +++ b/tutorials/kubernetes/using-vineyard-operator.html @@ -0,0 +1,909 @@ + + + + + + + + + + + + + + + + + + + Use vineyard operator - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Use vineyard operator#

+

Vineyard operator has been designed to manage vineyard components within Kubernetes. +This tutorial provides a step-by-step guide on how to effectively utilize the vineyard +operator. For more details, please refer to Vineyard Operator.

+
+

Step 0: (optional) Initialize Kubernetes Cluster#

+

If you don’t have a Kubernetes cluster readily available, we highly recommend using kind to +create one. Before setting up the Kubernetes cluster, please ensure you have the following +tools installed:

+
    +
  • kubectl: version >= 1.19.2

  • +
  • kind: version >= 0.14.0

  • +
  • docker: version >= 0.19.0

  • +
+

Utilize kind (v0.14.0) to create a Kubernetes cluster consisting of 4 nodes (1 master node and 3 +worker nodes):

+
$ cat > kind-config.yaml <<EOF
+# four node (three workers) cluster config
+kind: Cluster
+apiVersion: kind.x-k8s.io/v1alpha4
+nodes:
+- role: control-plane
+- role: worker
+- role: worker
+- role: worker
+EOF
+$ kind create cluster --config kind-config.yaml
+
+
+
+

Expected output

+
+
Creating cluster "kind" ...
+  Ensuring node image (kindest/node:v1.24.0) 🖼
+  Preparing nodes 📦
+  Writing configuration 📜
+  Starting control-plane 🕹️
+  Installing CNI 🔌
+  Installing StorageClass 💾
+ Set kubectl context to "kind-kind"
+ You can now use your cluster with:
+
+ kubectl cluster-info --context kind-kind
+
+ Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community 🙂
+
+
+
+
+
+

Note

+

The kind cluster’s config file is stored in ~/.kube/config, so you can use +the kubectl directly as it’s the default config path.

+
+

Check all kubernetes pods.

+
$ kubectl get pod -A
+
+
+
+

Expected output

+
+
NAMESPACE            NAME                                         READY   STATUS    RESTARTS   AGE
+kube-system          coredns-6d4b75cb6d-k2sk2                     1/1     Running   0          38s
+kube-system          coredns-6d4b75cb6d-xm4dt                     1/1     Running   0          38s
+kube-system          etcd-kind-control-plane                      1/1     Running   0          52s
+kube-system          kindnet-fp24b                                1/1     Running   0          19s
+kube-system          kindnet-h6swp                                1/1     Running   0          39s
+kube-system          kindnet-mtkd4                                1/1     Running   0          19s
+kube-system          kindnet-zxxpd                                1/1     Running   0          19s
+kube-system          kube-apiserver-kind-control-plane            1/1     Running   0          52s
+kube-system          kube-controller-manager-kind-control-plane   1/1     Running   0          53s
+kube-system          kube-proxy-6zgq2                             1/1     Running   0          19s
+kube-system          kube-proxy-8vghn                             1/1     Running   0          39s
+kube-system          kube-proxy-c7vz5                             1/1     Running   0          19s
+kube-system          kube-proxy-kd4zz                             1/1     Running   0          19s
+kube-system          kube-scheduler-kind-control-plane            1/1     Running   0          52s
+local-path-storage   local-path-provisioner-9cd9bd544-2vrtq       1/1     Running   0          38s
+
+
+
+
+

Check all kubernetes nodes.

+
$ kubectl get nodes -A
+
+
+
+

Expected output

+
+
NAME                 STATUS   ROLES           AGE     VERSION
+kind-control-plane   Ready    control-plane   2m30s   v1.24.0
+kind-worker          Ready    <none>          114s    v1.24.0
+kind-worker2         Ready    <none>          114s    v1.24.0
+kind-worker3         Ready    <none>          114s    v1.24.0
+
+
+
+
+
+
+

Step 1: Deploy the Vineyard Operator#

+

Create a dedicated namespace for the Vineyard Operator.

+
$ kubectl create namespace vineyard-system
+
+
+
+

Expected output

+
+
namespace/vineyard-system created
+
+
+
+
+

The operator needs a certificate created by cert-manager for webhook(https), +and the cert-manager is a sub chart of the vineyard operator chart. Also, the +Vineyard CRDs、Controllers、Webhooks and Scheduler are packaged by helm, you could +deploy all resources as follows.

+
+

Note

+

The vineyard operator needs permission to create several CRDs and kubernetes +resources, before deploying the vineyard operator, please ensure you can create +the clusterrole.

+
+
$ helm repo add vineyard https://vineyard.oss-ap-southeast-1.aliyuncs.com/charts/
+
+
+
+

Expected output

+
+
"vineyard" has been added to your repositories
+
+
+
+
+

Update the vineyard operator chart to the newest one.

+
$ helm repo update
+
+
+
+

Expected output

+
+
Hang tight while we grab the latest from your chart repositories...
+ ...Successfully got an update from the "vineyard" chart repository
+Update Complete. ⎈Happy Helming!⎈
+
+
+
+
+

Deploy the vineyard operator in the namespace vineyard-system.

+
$ helm install vineyard-operator vineyard/vineyard-operator -n vineyard-system
+
+
+
+

Expected output

+
+
NAME: vineyard-operator
+LAST DEPLOYED: Wed Jan  4 16:41:45 2023
+NAMESPACE: vineyard-system
+STATUS: deployed
+REVISION: 1
+TEST SUITE: None
+NOTES:
+Thanks for installing VINEYARD-OPERATOR, release at namespace: vineyard-system, name: vineyard-operator.
+
+To learn more about the release, try:
+
+$ helm status vineyard-operator -n vineyard-system   # get status of running vineyard operator
+$ helm get all vineyard-operator -n vineyard-system  # get all deployment yaml of vineyard operator
+
+To uninstall the release, try:
+
+$ helm uninstall vineyard-operator -n vineyard-system
+
+
+
+
+

You could get all details about vineyard operator in the doc Vineyard Operator, just have fun with vineyard operator!

+

Check the status of all vineyard resources created by helm:

+
$ kubectl get all -n vineyard-system
+
+
+
+

Expected output

+
+
NAME                                                            READY   STATUS    RESTARTS   AGE
+pod/vineyard-operator-cert-manager-cainjector-b865888cc-xj8x9   1/1     Running   0          2m30s
+pod/vineyard-operator-cert-manager-d99dcb884-gq9j5              1/1     Running   0          2m30s
+pod/vineyard-operator-cert-manager-webhook-5bc8fd5d48-vh4bg     1/1     Running   0          2m30s
+pod/vineyard-operator-controller-manager-5bcbb75fb6-cfdpk       2/2     Running   0          2m30s
+
+NAME                                                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
+service/vineyard-operator-cert-manager                         ClusterIP   10.96.166.147   <none>        9402/TCP   2m30s
+service/vineyard-operator-cert-manager-webhook                 ClusterIP   10.96.111.112   <none>        443/TCP    2m30s
+service/vineyard-operator-controller-manager-metrics-service   ClusterIP   10.96.153.134   <none>        8443/TCP   2m30s
+service/vineyard-operator-webhook-service                      ClusterIP   10.96.9.101     <none>        443/TCP    2m30s
+
+NAME                                                        READY   UP-TO-DATE   AVAILABLE   AGE
+deployment.apps/vineyard-operator-cert-manager              1/1     1            1           2m30s
+deployment.apps/vineyard-operator-cert-manager-cainjector   1/1     1            1           2m30s
+deployment.apps/vineyard-operator-cert-manager-webhook      1/1     1            1           2m30s
+deployment.apps/vineyard-operator-controller-manager        1/1     1            1           2m30s
+
+NAME                                                                  DESIRED   CURRENT   READY   AGE
+replicaset.apps/vineyard-operator-cert-manager-cainjector-b865888cc   1         1         1       2m30s
+replicaset.apps/vineyard-operator-cert-manager-d99dcb884              1         1         1       2m30s
+replicaset.apps/vineyard-operator-cert-manager-webhook-5bc8fd5d48     1         1         1       2m30s
+replicaset.apps/vineyard-operator-controller-manager-5bcbb75fb6       1         1         1       2m30s
+
+
+
+
+
+
+

Step 2: Deploy a Vineyard Cluster#

+

After successfully installing the Vineyard operator as described in the previous step, +you can now proceed to deploy a Vineyard cluster. To create a cluster with two Vineyard +instances, simply create a Vineyardd Custom Resource (CR) as shown below.

+
$ cat <<EOF | kubectl apply -f -
+apiVersion: k8s.v6d.io/v1alpha1
+kind: Vineyardd
+metadata:
+  name: vineyardd-sample
+  namespace: vineyard-system
+spec:
+  # vineyard instances
+  replicas: 2
+EOF
+
+
+
+

Expected output

+
+
vineyardd.k8s.v6d.io/vineyardd-sample created
+
+
+
+
+

Check the status of all relevant resources managed by the vineyardd-sample cr.

+
$ kubectl get all -l app.kubernetes.io/instance=vineyardd -n vineyard-system
+
+
+
+

Expected output

+
+
NAME                                   READY   STATUS    RESTARTS   AGE
+pod/vineyardd-sample-879798cb6-qpvtw   1/1     Running   0          2m59s
+pod/vineyardd-sample-879798cb6-x4m2x   1/1     Running   0          2m59s
+
+NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
+deployment.apps/vineyardd-sample   2/2     2            2           2m59s
+
+NAME                                         DESIRED   CURRENT   READY   AGE
+replicaset.apps/vineyardd-sample-879798cb6   2         2         2       2m59s
+
+
+
+
+
+
+

Step 3: Connect to Vineyard#

+

Vineyard currently supports clients in various languages, including mature support +for C++ and Python, as well as experimental support for Java, Golang, and Rust. In +this tutorial, we will demonstrate how to connect to a Vineyard cluster using the +Python client. Vineyard provides two connection methods: IPC and RPC. In the +following sections, we will explore both methods.

+

First, let’s deploy the Python client on two Vineyard nodes as follows.

+
$ cat <<EOF | kubectl apply -f -
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: vineyard-python-client
+  namespace:  vineyard-system
+spec:
+  selector:
+    matchLabels:
+      app: vineyard-python-client
+  replicas: 2
+  template:
+    metadata:
+      labels:
+        app: vineyard-python-client
+        # related to which vineyard cluster
+        scheduling.k8s.v6d.io/vineyardd-namespace: vineyard-system
+        scheduling.k8s.v6d.io/vineyardd: vineyardd-sample
+        scheduling.k8s.v6d.io/job: v6d-workflow-demo-job1
+    spec:
+      # use the vineyard scheduler to deploy the pod on the vineyard cluster.
+      schedulerName: vineyard-scheduler
+      containers:
+      - name: vineyard-python
+        imagePullPolicy: IfNotPresent
+        image: vineyardcloudnative/vineyard-python:v0.11.4
+        command:
+        - /bin/bash
+        - -c
+        - sleep infinity
+        volumeMounts:
+        - mountPath: /var/run
+          name: vineyard-sock
+      volumes:
+      - name: vineyard-sock
+        hostPath:
+          path: /var/run/vineyard-kubernetes/vineyard-system/vineyardd-sample
+EOF
+
+
+
+

Expected output

+
+
pod/vineyard-python-client created
+
+
+
+
+

Wait for the vineyard python client pod ready.

+
$ kubectl get pod -l app=vineyard-python-client -n vineyard-system
+
+
+
+

Expected output

+
+
NAME                                      READY   STATUS    RESTARTS   AGE
+vineyard-python-client-6fd8c47c98-7btkv   1/1     Running   0          93s
+
+
+
+
+

Use the kubectl exec command to enter the first vineyard python client pod.

+
$ kubectl exec -it $(kubectl get pod -l app=vineyard-python-client -n vineyard-system -oname | head -n 1 | awk -F '/' '{print $2}') -n vineyard-system /bin/bash
+
+
+

After entering the shell, you can connect to the vineyard cluster,

+
In [1]: import numpy as np
+In [2]: import vineyard
+
+In [3]: client = vineyard.connect('/var/run/vineyard.sock')
+
+In [4]: objid = client.put(np.zeros(8))
+
+In [5]: # persist the object to make it visible to form the global object
+In [6]: client.persist(objid)
+
+In [7]: objid
+Out[7]: o001027d7c86a49f0
+
+In [8]: # get meta info
+In [9]: meta = client.get_meta(objid)
+In [10]: meta
+Out[10]:
+{
+    "buffer_": {
+        "id": "o801027d7c85c472e",
+        "instance_id": 1,
+        "length": 0,
+        "nbytes": 0,
+        "transient": true,
+        "typename": "vineyard::Blob"
+    },
+    "global": false,
+    "id": "o001027d7c86a49f0",
+    "instance_id": 1,
+    "nbytes": 64,
+    "order_": "\"C\"",
+    "partition_index_": "[]",
+    "shape_": "[8]",
+    "signature": 4547407361228035,
+    "transient": false,
+    "typename": "vineyard::Tensor<double>",
+    "value_type_": "float64",
+    "value_type_meta_": "<f8"
+}
+
+
+

Open another terminal and enter the second vineyard python client pod.

+
$ kubectl exec -it $(kubectl get pod -l app=vineyard-python-client -n vineyard-system -oname | tail -n 1 | awk -F '/' '{print $2}') -n vineyard-system /bin/bash
+
+
+
+

Expected output

+
+
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
+
+
+
+
+

Also, you can connect to the vineyard cluster by RPC and get the metadata of +above object as follows.

+
In [1]: import vineyard
+
+In [2]: rpc_client = vineyard.connect('vineyardd-sample-rpc.vineyard-system',9600)
+
+In [3]: # use the object id created by another vineyard instance here
+In [4]: meta = rpc_client.get_meta(vineyard._C.ObjectID('o001027d7c86a49f0'))
+In [5]: meta
+Out[5]:
+{
+    "buffer_": {
+        "id": "o801027d7c85c472e",
+        "instance_id": 1,
+        "length": 0,
+        "nbytes": 0,
+        "transient": true,
+        "typename": "vineyard::Blob"
+    },
+    "global": false,
+    "id": "o001027d7c86a49f0",
+    "instance_id": 1,
+    "nbytes": 64,
+    "order_": "\"C\"",
+    "partition_index_": "[]",
+    "shape_": "[8]",
+    "signature": 4547407361228035,
+    "transient": false,
+    "typename": "vineyard::Tensor<double>",
+    "value_type_": "float64",
+    "value_type_meta_": "<f8"
+}
+
+
+

For more examples, please refer the vineyard data accessing.

+
+
+

Step 4: Cleanup#

+
    +
  • Destroy the vineyard operator via helm:

  • +
+
$ helm uninstall vineyard-operator -n vineyard-system
+
+
+
+

Expected output

+
+
release "vineyard-operator" uninstalled
+
+
+
+
+
    +
  • Delete the namespace:

  • +
+
$ kubectl delete namespace vineyard-system
+
+
+
+

Expected output

+
+
namespace "vineyard-system" deleted
+
+
+
+
+
+
+ +
+
+ +
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/tutorials/tutorials.html b/tutorials/tutorials.html new file mode 100644 index 0000000000..663729aad2 --- /dev/null +++ b/tutorials/tutorials.html @@ -0,0 +1,521 @@ + + + + + + + + + + + + + + + + + + + Data processing - Vineyard + + + + + + + + + + + + + + + + + + + + + + + + + + + Contents + + + + + + Menu + + + + + + + + Expand + + + + + + Light mode + + + + + + + + + + + + + + Dark mode + + + + + + + Auto light/dark mode + + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
+
Vineyard
+
+
+
+ +
+ +
+
+ +
+
+
+ + + + + Back to top + +
+
+ +
+ +
+
+
+

Data processing#

+
+
+

In these comprehensive case studies, we demonstrate how to seamlessly integrate vineyard’s +capabilities with existing data-intensive tasks. By incorporating vineyard into complex +workflows involving multiple computing engines, users can experience significant +improvements in both performance and ease of use.

+
+
+
+
+ +
+

Effortlessly share Python objects between processes using vineyard’s intuitive and efficient approach.

+
+
+
+
+
+ +
+

Utilize vineyard as an elegant alternative to multiprocessing.shared_memory in Python.

+
+
+
+
+
+ +
+

Discover how vineyard enhances distributed machine learning training workflows by +seamlessly integrating with various computing engines for improved efficiency and elegance.

+
+
+
+
+
+ +
+

Vineyard serves as the DataSet backend for Kedro pipelines, enabling +efficient data sharing between tasks without intrusive code modification, even +when the pipeline is deployed to Kubernetes.

+
+
+
+
+
+
+
+

Vineyard on Kubernetes#

+
+
+

Vineyard can be seamlessly deployed on Kubernetes, managed by the Vineyard Operator, +to enhance big-data workflows through its data-aware scheduling policy. This policy +orchestrates shared objects and routes jobs to where their input data resides. In the +following tutorials, you will learn how to deploy Vineyard and effectively integrate it +with Kubernetes.

+
+
+
+
+ +
+

The Vineyard operator serves as the central component for seamless integration with Kubernetes.

+
+
+
+
+
+ +
+

Vineyard functions as an efficient intermediate data storage solution for machine learning pipelines on Kubernetes.

+
+
+
+
+
+
+
+

Extending vineyard#

+
+
+

Vineyard offers a collection of efficient data structures tailored for data-intensive tasks, +such as tensors, data frames, tables, and graphs. These data types can be easily extended +to accommodate custom requirements. By registering user-defined types in the vineyard type +registry, computing engines built on top of vineyard can instantly leverage the advantages +provided by these custom data structures.

+
+
+
+
+ +
+

Craft builders and resolvers for custom Python data types.

+
+
+
+
+
+ +
+

Implement and register custom data types in C++ for seamless integration with vineyard’s ecosystem.

+
+
+
+
+
+
+ +
+
+
+ + + + + + + + + +
+
+ + Rendered with Sphinx and Furo +

The Linux Foundation has registered trademarks and uses trademarks. For a list of trademarks of The Linux Foundation, + please see our Trademark Usage page. +

+
+ +
+ +
+
+ +
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/vineyard-sigmod-2023.pdf b/vineyard-sigmod-2023.pdf new file mode 100644 index 0000000000..d2c13b208b Binary files /dev/null and b/vineyard-sigmod-2023.pdf differ