diff --git a/.asf.yaml b/.asf.yaml deleted file mode 100644 index 99596cfd6..000000000 --- a/.asf.yaml +++ /dev/null @@ -1,6 +0,0 @@ -notifications: - commits: commits@rocketmq.apache.org - issues: commits@rocketmq.apache.org - pullrequests: commits@rocketmq.apache.org - jobs: commits@rocketmq.apache.org - discussions: dev@rocketmq.apache.org diff --git a/.bazelignore b/.bazelignore new file mode 100644 index 000000000..8c28fe2ba --- /dev/null +++ b/.bazelignore @@ -0,0 +1,2 @@ +_build +cmake-build-debug \ No newline at end of file diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 000000000..dce4c4711 --- /dev/null +++ b/.bazelrc @@ -0,0 +1,138 @@ +# Bazel doesn't need more than 200MB of memory for local build based on memory profiling: +# https://docs.bazel.build/versions/master/skylark/performance.html#memory-profiling +# The default JVM max heapsize is 1/4 of physical memory up to 32GB which could be large +# enough to consume all memory constrained by cgroup in large host. +# Limiting JVM heapsize here to let it do GC more when approaching the limit to +# leave room for compiler/linker. +# The number 2G is chosen heuristically to both support large VM and small VM with RBE. +# Startup options cannot be selected via config. +startup --host_jvm_args=-Xmx2g + +run --color=yes + +build --color=yes + +build --host_force_python=PY3 +build --host_javabase=@bazel_tools//tools/jdk:remote_jdk11 +build --javabase=@bazel_tools//tools/jdk:remote_jdk11 + +# https://docs.bazel.build/versions/main/command-line-reference.html#flag--enable_platform_specific_config +# If true, Bazel picks up host-OS-specific config lines from bazelrc files. For example, if the host OS is Linux and +# you run bazel build, Bazel picks up lines starting with build:linux. Supported OS identifiers are linux, macos, +# windows, freebsd, and openbsd. Enabling this flag is equivalent to using --config=linux on Linux, +# --config=windows on Windows, etc. +build --enable_platform_specific_config + +build:windows --cxxopt=/std:c++14 + +build:macos --cxxopt=-std=c++11 +build:macos --strip=never +build:macos --copt -g + +# Enable position independent code (this is the default on macOS and Windows) +# (Workaround for https://github.com/bazelbuild/rules_foreign_cc/issues/421) +build:linux --copt=-fPIC +build:linux --cxxopt=-std=c++11 +build:linux --strip=never + +# We already have absl in the build, define absl=1 to tell googletest to use absl for backtrace. +build --define absl=1 +build --define SPDLOG_FMT_EXTERNAL=1 + +# Pass PATH, CC, CXX and LLVM_CONFIG variables from the environment. +build --action_env=CC +build --action_env=CXX +build --action_env=LD_LIBRARY_PATH +build --action_env=LLVM_CONFIG +build --action_env=PATH + +build --copt=-maes + +# Common flags for sanitizers +build:sanitizer --define tcmalloc=disabled +build:sanitizer --linkopt -ldl +build:sanitizer --build_tag_filters=-no_san +build:sanitizer --test_tag_filters=-no_san + +# Common flags for Clang +build:clang --action_env=BAZEL_COMPILER=clang +build:clang --linkopt=-fuse-ld=lld + + +# Address sanitizer +# To use it: bazel build --config=asan +build:asan --config=sanitizer +build:asan --compiler clang +build:asan --strip=never +build:asan --copt -fsanitize=address +# ASAN needs -O1 to get reasonable performance. +build:asan --copt -O1 +build:asan --copt -fno-optimize-sibling-calls +build:asan --copt -g +build:asan --copt -fno-omit-frame-pointer +build:asan --linkopt -fsanitize=address +build:asan --copt -DADDRESS_SANITIZER=1 +build:asan --copt -D__SANITIZE_ADDRESS__ + +# Clang ASAN/UBSAN +build:clang-asan --config=asan +build:clang-asan --linkopt -fuse-ld=lld + +build:macos-asan --config=asan +# Workaround, see https://github.com/bazelbuild/bazel/issues/6932 +build:macos-asan --copt -Wno-macro-redefined +build:macos-asan --copt -D_FORTIFY_SOURCE=0 +# Workaround, see https://github.com/bazelbuild/bazel/issues/4341 +build:macos-asan --copt -DGRPC_BAZEL_BUILD +# Dynamic link cause issues like: `dyld: malformed mach-o: load commands size (59272) > 32768` +build:macos-asan --dynamic_mode=off + +# Thread sanitizer +# bazel build --config=tsan +build:tsan --config=sanitizer +build:tsan --compiler clang +build:tsan --strip=never +build:tsan --copt -fsanitize=thread +build:tsan --copt -DTHREAD_SANITIZER +build:tsan --copt -DDYNAMIC_ANNOTATIONS_ENABLED=1 +build:tsan --copt -DDYNAMIC_ANNOTATIONS_EXTERNAL_IMPL=1 +build:tsan --copt -O1 +build:tsan --copt -fno-omit-frame-pointer +build:tsan --linkopt -fsanitize=thread + +# --config msan: Memory sanitizer +build:msan --compiler clang +build:msan --strip=never +build:msan --copt -fsanitize=memory +build:msan --copt -DADDRESS_SANITIZER +build:msan --copt -O1 +build:msan --copt -fno-omit-frame-pointer +build:msan --linkopt -fsanitize=memory + +# --config ubsan: Undefined Behavior Sanitizer +build:ubsan --compiler clang +build:ubsan --strip=never +build:ubsan --copt -fsanitize=undefined +build:ubsan --copt -O1 +build:ubsan --copt -fno-omit-frame-pointer +build:ubsan --linkopt -fsanitize=undefined +build:ubsan --linkopt -lubsan + +# Use remote cache, --config=remote_cache See https://docs.bazel.build/versions/main/guide.html#--config +build:remote_cache --remote_cache=grpc://11.122.50.85:9092 +build:remote_cache --experimental_remote_downloader=grpc://11.122.50.85:9092 +test:remote_cache --remote_cache=grpc://11.122.50.85:9090 +test:remote_cache --remote_upload_local_results=true + +# Coverage options +coverage --config=coverage +# 1.5x original timeout + 300s for trace merger in all categories +build:coverage --test_timeout=390,750,1500,5700 +build:coverage --define=dynamic_link_tests=true +build:coverage --combined_report=lcov +build:coverage --strategy=TestRunner=sandboxed,local +build:coverage --strategy=CoverageReport=sandboxed,local +build:coverage --collect_code_coverage +build:coverage --instrumentation_filter="//src/main/cpp[/:],//api[/:],-//src/main/cpp/base/mocks[/:],-//src/main/cpp/client/mocks[/:],-//src/main/cpp/rocketmq/mocks[/:]" + +test --test_output=errors \ No newline at end of file diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 000000000..af8c8ec7c --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +4.2.2 diff --git a/.clang-format b/.clang-format index 7904cdf16..fb63bcfb3 100644 --- a/.clang-format +++ b/.clang-format @@ -1,3 +1,28 @@ -BasedOnStyle: Chromium +--- +BasedOnStyle: Google +IndentWidth: 2 +--- +Language: Cpp +AccessModifierOffset: -2 +BinPackParameters: false ColumnLimit: 120 -TabWidth: 2 +DerivePointerAlignment: false +PointerAlignment: Left +SortIncludes: true +NamespaceIndentation: Inner +AlwaysBreakTemplateDeclarations: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +IndentCaseBlocks: false +IndentCaseLabels: true +ReflowComments: true +... + +--- +Language: Proto +ColumnLimit: 120 +SpacesInContainerLiterals: false +AllowShortFunctionsOnASingleLine: None +ReflowComments: false +... diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 000000000..693858657 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,81 @@ +Checks: '-clang-analyzer-core.NonNullParamChecker, + -clang-analyzer-optin.cplusplus.UninitializedObject, + abseil-duration-*, + abseil-faster-strsplit-delimiter, + abseil-no-namespace, + abseil-redundant-strcat-calls, + abseil-str-cat-append, + abseil-string-find-startswith, + abseil-upgrade-duration-conversions, + bugprone-assert-side-effect, + bugprone-unused-raii, + bugprone-use-after-move, + clang-analyzer-core.DivideZero, + misc-unused-using-decls, + modernize-deprecated-headers, + modernize-loop-convert, + modernize-make-shared, + modernize-make-unique, + modernize-return-braced-init-list, + modernize-use-default-member-init, + modernize-use-equals-default, + modernize-use-nullptr, + modernize-use-override, + modernize-use-using, + performance-faster-string-find, + performance-for-range-copy, + performance-inefficient-algorithm, + performance-inefficient-vector-operation, + performance-noexcept-move-constructor, + performance-move-constructor-init, + performance-type-promotion-in-math-fn, + performance-unnecessary-copy-initialization, + readability-braces-around-statements, + readability-container-size-empty, + readability-identifier-naming, + readability-redundant-control-flow, + readability-redundant-member-init, + readability-redundant-smartptr-get, + readability-redundant-string-cstr' + +WarningsAsErrors: '*' + +CheckOptions: + - key: bugprone-assert-side-effect.AssertMacros + value: 'ASSERT' + + - key: bugprone-dangling-handle.HandleClasses + value: 'std::basic_string_view;std::experimental::basic_string_view;absl::string_view' + + - key: modernize-use-auto.MinTypeNameLength + value: '10' + + - key: readability-identifier-naming.ClassCase + value: 'CamelCase' + + - key: readability-identifier-naming.EnumCase + value: 'CamelCase' + + - key: readability-identifier-naming.EnumConstantCase + value: 'CamelCase' + + - key: readability-identifier-naming.ParameterCase + value: 'lower_case' + + - key: readability-identifier-naming.PrivateMemberCase + value: 'lower_case' + + - key: readability-identifier-naming.PrivateMemberSuffix + value: '_' + + - key: readability-identifier-naming.StructCase + value: 'CamelCase' + + - key: readability-identifier-naming.TypeAliasCase + value: 'CamelCase' + + - key: readability-identifier-naming.UnionCase + value: 'CamelCase' + + - key: readability-identifier-naming.FunctionCase + value: 'camelBack' diff --git a/.github/ISSUE_TEMPLATE/issue_template.md b/.github/ISSUE_TEMPLATE/issue_template.md deleted file mode 100644 index f3ad25a46..000000000 --- a/.github/ISSUE_TEMPLATE/issue_template.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: ISSUE_TEMPLATE -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -The issue tracker is **ONLY** used for the CPP/C client (feature request of RocketMQ need to follow [RIP process](https://github.com/apache/rocketmq/wiki/RocketMQ-Improvement-Proposal)). Keep in mind, please check whether there is an existing same report before your raise a new one. - -Alternately (especially if your communication is not a bug report), you can send mail to our [mailing lists](http://rocketmq.apache.org/about/contact/). We welcome any friendly suggestions, bug fixes, collaboration, and other improvements. - -Please ensure that your bug report is clear and that it is complete. Otherwise, we may be unable to understand it or to reproduce it, either of which would prevent us from fixing the bug. We strongly recommend the report(bug report or feature request) could include some hints as to the following: - -**BUG REPORT** - -1. Please describe the issue you observed: - -- What did you do (The steps to reproduce)? - -- What did you expect to see? - -- What did you see instead? - -2. Please tell us about your environment: - - - What is your OS? - - - What is your client version? - - - What is your RocketMQ version? - -3. Other information (e.g. detailed explanation, logs, related issues, suggestions on how to fix, etc): - -**FEATURE REQUEST** - -1. Please describe the feature you are requesting. - -2. Provide any additional detail on your proposed use case for this feature. - -2. Indicate the importance of this issue to you (blocker, must-have, should-have, nice-to-have). Are you currently using any workarounds to address this issue? - -4. If there are some sub-tasks using -[] for each subtask and create a corresponding issue to map to the sub task: - -- [sub-task1-issue-number](example_sub_issue1_link_here): sub-task1 description here, -- [sub-task2-issue-number](example_sub_issue2_link_here): sub-task2 description here, -- ... diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 000000000..26c6d3b36 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,36 @@ +# This is a basic workflow to help you get started with Actions + +name: CI + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the master branch + push: + branches: [ main ] + pull_request: + branches: [ main ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v2 + + - name: Setup Bazel + run: | + sudo apt-get -qq install npm + sudo npm install -g @bazel/bazelisk + - name: Use Bazel + if: matrix.os != 'windows' + run: bazel -h + - name: Compile All Targets + run: bazel build //... \ No newline at end of file diff --git a/.gitignore b/.gitignore index 013ac4aa0..23e0e933d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,20 @@ +bazel-bin +bazel-out +bazel-rocketmq-cpp +bazel-testlogs +cmake-build-debug +.clwb +compile_commands.json +logs +_build +cmake-build-debug-coverage .idea -cmake-build-debug/ -bin -build -libs/signature/lib -tmp_* -Testing -.vscode .cache -compile_commands.json +.DS_Store +external +bazel-apache_rocketmq_client_cpp +bazel-rocketmq-client-cpp +/external +/bazel-* +/compile_commands.json +/.cache/ diff --git a/.travis.yml b/.travis.yml index 2d7869994..d2440c443 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,60 +1,173 @@ language: cpp -sudo: required -dist: trusty -compiler: gcc - -addons: - apt: - packages: lcov - -install: - #- sudo apt-get update - #- sudo apt-get install -y git gcc-4.8 g++-4.8 autoconf cmake libtool wget unzip libbz2-dev zlib1g-dev - - echo 'MAVEN_OPTS="$MAVEN_OPTS -Xmx1024m -XX:MaxPermSize=512m -XX:+BytecodeVerificationLocal"' >> ~/.mavenrc - - cat ~/.mavenrc - - if [ "$TRAVIS_OS_NAME" == "osx" ]; then export JAVA_HOME=$(/usr/libexec/java_home); fi - - if [ "$TRAVIS_OS_NAME" == "linux" ]; then jdk_switcher use "$CUSTOM_JDK"; fi - -before_script: - - wget https://archive.apache.org/dist/rocketmq/4.3.2/rocketmq-all-4.3.2-bin-release.zip - - unzip rocketmq-all-4.3.2-bin-release.zip - - cd rocketmq-all-4.3.2-bin-release - - perl -i -pe's/-Xms8g -Xmx8g -Xmn4g/-Xms2g -Xmx2g -Xmn1g/g' bin/runbroker.sh - - nohup sh bin/mqnamesrv & - - nohup sh bin/mqbroker -n localhost:9876 & - - sleep 10 - - ./bin/mqadmin updateTopic -b '127.0.0.1:10911' –n '127.0.0.1:9876' -t test - - ./bin/mqadmin updateSubGroup -b '127.0.0.1:10911' –n '127.0.0.1:9876' -g testGroup - - cd .. - -script: - - ./build.sh test codecov noVerbose - -after_success: - # Create lcov report - # capture coverage info - - lcov --directory . --capture --output-file coverage.info - # filter out system and extra files. - # To also not include test code in coverage add them with full path to the patterns: '*/tests/*' - - lcov --remove coverage.info '/usr/*' '/home/travis/build/*/rocketmq-client-cpp/bin/*' '/home/travis/build/*/rocketmq-client-cpp/libs/*' --output-file coverage.info - # output coverage data for debugging (optional) - - lcov --list coverage.info - # Uploading to CodeCov - # '-f' specifies file(s) to use and disables manual coverage gathering and file search which has already been done above - - bash <(curl -s https://codecov.io/bash) -f coverage.info || echo "Codecov did not collect coverage reports" - -matrix: +dist: focal +jobs: include: - os: linux - env: CUSTOM_JDK="oraclejdk8" + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - sourceline: 'deb https://apt.kitware.com/ubuntu/ focal main' + key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' + packages: + - g++-4.9 + - cmake + env: + - MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9" + # works on Precise and Trusty + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - sourceline: 'deb https://apt.kitware.com/ubuntu/ focal main' + key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' + packages: + - g++-5 + - cmake + env: + - MATRIX_EVAL="CC=gcc-5 && CXX=g++-5" + + # works on Precise and Trusty + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - sourceline: 'deb https://apt.kitware.com/ubuntu/ focal main' + key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' + packages: + - g++-6 + - cmake + env: + - MATRIX_EVAL="CC=gcc-6 && CXX=g++-6" + + # works on Precise and Trusty + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - sourceline: 'deb https://apt.kitware.com/ubuntu/ focal main' + key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' + packages: + - g++-7 + - cmake + env: + - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" + # Clang on Linux + # works on Precise and Trusty + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + - sourceline: 'deb https://apt.kitware.com/ubuntu/ focal main' + key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' + packages: + - clang-3.6 + - cmake + env: + - MATRIX_EVAL="CC=clang-3.6 && CXX=clang++-3.6" + + # works on Precise and Trusty + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + - sourceline: 'deb https://apt.kitware.com/ubuntu/ focal main' + key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' + packages: + - clang-3.7 + - cmake + env: + - MATRIX_EVAL="CC=clang-3.7 && CXX=clang++-3.7" + + # works on Precise and Trusty + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + - sourceline: 'deb https://apt.kitware.com/ubuntu/ focal main' + key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' + packages: + - clang-3.8 + - cmake + env: + - MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8" + + # works on Trusty + - os: linux + addons: + apt: + sources: + - llvm-toolchain-trusty-3.9 + - sourceline: 'deb https://apt.kitware.com/ubuntu/ focal main' + key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' + packages: + - clang-3.9 + - cmake + env: + - MATRIX_EVAL="CC=clang-3.9 && CXX=clang++-3.9" - # This is the job to check code format. + # works on Trusty - os: linux - dist: trusty - env: LINT=1 PYTHON=2.7 - before_install: - #- sudo apt-get update -qq - #- sudo apt-get install -qq clang-format-3.8 - install: [] - script: - - sudo sh .travis/check-git-clang-format.sh + addons: + apt: + sources: + - llvm-toolchain-trusty-4.0 + - sourceline: 'deb https://apt.kitware.com/ubuntu/ focal main' + key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' + packages: + - clang-4.0 + - cmake + env: + - MATRIX_EVAL="CC=clang-4.0 && CXX=clang++-4.0" + + # works on Trusty + - os: linux + addons: + apt: + sources: + - llvm-toolchain-trusty-5.0 + - sourceline: 'deb https://apt.kitware.com/ubuntu/ focal main' + key_url: 'https://apt.kitware.com/keys/kitware-archive-latest.asc' + packages: + - clang-5.0 + - cmake + env: + - MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0" + # GCC on Mac +# - os: osx +# osx_image: xcode8 +# env: +# - MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9" +# +# - os: osx +# osx_image: xcode8 +# env: +# - MATRIX_EVAL="brew install gcc5 && CC=gcc-5 && CXX=g++-5" +# +# - os: osx +# osx_image: xcode8 +# env: +# - MATRIX_EVAL="brew install gcc6 && CC=gcc-6 && CXX=g++-6" +# +# - os: osx +# osx_image: xcode8 +# env: +# - MATRIX_EVAL="brew install gcc && CC=gcc-7 && CXX=g++-7" +before_install: + - eval "${MATRIX_EVAL}" + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + brew update ; + brew install cmake ; + fi + +script: + - ci/build.sh diff --git a/.travis/git-clang-format b/.travis/git-clang-format deleted file mode 100644 index c41be9509..000000000 --- a/.travis/git-clang-format +++ /dev/null @@ -1,490 +0,0 @@ -#!/usr/bin/env python -# -#===- git-clang-format - ClangFormat Git Integration ---------*- python -*--===# -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -#===------------------------------------------------------------------------===# - -r""" -clang-format git integration -============================ - -This file provides a clang-format integration for git. Put it somewhere in your -path and ensure that it is executable. Then, "git clang-format" will invoke -clang-format on the changes in current files or a specific commit. - -For further details, run: -git clang-format -h - -Requires Python 2.7 -""" - -import argparse -import collections -import contextlib -import errno -import os -import re -import subprocess -import sys - -usage = 'git clang-format [OPTIONS] [] [--] [...]' - -desc = ''' -Run clang-format on all lines that differ between the working directory -and , which defaults to HEAD. Changes are only applied to the working -directory. - -The following git-config settings set the default of the corresponding option: - clangFormat.binary - clangFormat.commit - clangFormat.extension - clangFormat.style -''' - -# Name of the temporary index file in which save the output of clang-format. -# This file is created within the .git directory. -temp_index_basename = 'clang-format-index' - - -Range = collections.namedtuple('Range', 'start, count') - - -def main(): - config = load_git_config() - - # In order to keep '--' yet allow options after positionals, we need to - # check for '--' ourselves. (Setting nargs='*' throws away the '--', while - # nargs=argparse.REMAINDER disallows options after positionals.) - argv = sys.argv[1:] - try: - idx = argv.index('--') - except ValueError: - dash_dash = [] - else: - dash_dash = argv[idx:] - argv = argv[:idx] - - default_extensions = ','.join([ - # From clang/lib/Frontend/FrontendOptions.cpp, all lower case - 'c', 'h', # C - 'm', # ObjC - 'mm', # ObjC++ - 'cc', 'cp', 'cpp', 'c++', 'cxx', 'hpp', # C++ - # Other languages that clang-format supports - 'proto', 'protodevel', # Protocol Buffers - 'js', # JavaScript - 'ts', # TypeScript - ]) - - p = argparse.ArgumentParser( - usage=usage, formatter_class=argparse.RawDescriptionHelpFormatter, - description=desc) - p.add_argument('--binary', - default=config.get('clangformat.binary', 'clang-format'), - help='path to clang-format'), - p.add_argument('--commit', - default=config.get('clangformat.commit', 'HEAD'), - help='default commit to use if none is specified'), - p.add_argument('--diff', action='store_true', - help='print a diff instead of applying the changes') - p.add_argument('--extensions', - default=config.get('clangformat.extensions', - default_extensions), - help=('comma-separated list of file extensions to format, ' - 'excluding the period and case-insensitive')), - p.add_argument('--exclude', help='Exclude files matching this regex.') - p.add_argument('-f', '--force', action='store_true', - help='allow changes to unstaged files') - p.add_argument('-p', '--patch', action='store_true', - help='select hunks interactively') - p.add_argument('-q', '--quiet', action='count', default=0, - help='print less information') - p.add_argument('--style', - default=config.get('clangformat.style', None), - help='passed to clang-format'), - p.add_argument('-v', '--verbose', action='count', default=0, - help='print extra information') - # We gather all the remaining positional arguments into 'args' since we need - # to use some heuristics to determine whether or not was present. - # However, to print pretty messages, we make use of metavar and help. - p.add_argument('args', nargs='*', metavar='', - help='revision from which to compute the diff') - p.add_argument('ignored', nargs='*', metavar='...', - help='if specified, only consider differences in these files') - opts = p.parse_args(argv) - - opts.verbose -= opts.quiet - del opts.quiet - - commit, files = interpret_args(opts.args, dash_dash, opts.commit) - changed_lines = compute_diff_and_extract_lines(commit, files) - if opts.verbose >= 1: - ignored_files = set(changed_lines) - filter_by_extension(changed_lines, opts.extensions.lower().split(',')) - if opts.exclude: - for filename in changed_lines.keys(): - if re.match(opts.exclude, filename): - del changed_lines[filename] - if opts.verbose >= 1: - ignored_files.difference_update(changed_lines) - if ignored_files: - print 'Ignoring changes in the following files:' - for filename in ignored_files: - print ' ', filename - if changed_lines: - print 'Running clang-format on the following files:' - for filename in changed_lines: - print ' ', filename - if not changed_lines: - print 'no modified files to format' - return - # The computed diff outputs absolute paths, so we must cd before accessing - # those files. - cd_to_toplevel() - old_tree = create_tree_from_workdir(changed_lines) - new_tree = run_clang_format_and_save_to_tree(changed_lines, - binary=opts.binary, - style=opts.style) - if opts.verbose >= 1: - print 'old tree:', old_tree - print 'new tree:', new_tree - if old_tree == new_tree: - if opts.verbose >= 0: - print 'clang-format did not modify any files' - elif opts.diff: - print_diff(old_tree, new_tree) - else: - changed_files = apply_changes(old_tree, new_tree, force=opts.force, - patch_mode=opts.patch) - if (opts.verbose >= 0 and not opts.patch) or opts.verbose >= 1: - print 'changed files:' - for filename in changed_files: - print ' ', filename - - -def load_git_config(non_string_options=None): - """Return the git configuration as a dictionary. - - All options are assumed to be strings unless in `non_string_options`, in which - is a dictionary mapping option name (in lower case) to either "--bool" or - "--int".""" - if non_string_options is None: - non_string_options = {} - out = {} - for entry in run('git', 'config', '--list', '--null').split('\0'): - if entry: - name, value = entry.split('\n', 1) - if name in non_string_options: - value = run('git', 'config', non_string_options[name], name) - out[name] = value - return out - - -def interpret_args(args, dash_dash, default_commit): - """Interpret `args` as "[commit] [--] [files...]" and return (commit, files). - - It is assumed that "--" and everything that follows has been removed from - args and placed in `dash_dash`. - - If "--" is present (i.e., `dash_dash` is non-empty), the argument to its - left (if present) is taken as commit. Otherwise, the first argument is - checked if it is a commit or a file. If commit is not given, - `default_commit` is used.""" - if dash_dash: - if len(args) == 0: - commit = default_commit - elif len(args) > 1: - die('at most one commit allowed; %d given' % len(args)) - else: - commit = args[0] - object_type = get_object_type(commit) - if object_type not in ('commit', 'tag'): - if object_type is None: - die("'%s' is not a commit" % commit) - else: - die("'%s' is a %s, but a commit was expected" % (commit, object_type)) - files = dash_dash[1:] - elif args: - if disambiguate_revision(args[0]): - commit = args[0] - files = args[1:] - else: - commit = default_commit - files = args - else: - commit = default_commit - files = [] - return commit, files - - -def disambiguate_revision(value): - """Returns True if `value` is a revision, False if it is a file, or dies.""" - # If `value` is ambiguous (neither a commit nor a file), the following - # command will die with an appropriate error message. - run('git', 'rev-parse', value, verbose=False) - object_type = get_object_type(value) - if object_type is None: - return False - if object_type in ('commit', 'tag'): - return True - die('`%s` is a %s, but a commit or filename was expected' % - (value, object_type)) - - -def get_object_type(value): - """Returns a string description of an object's type, or None if it is not - a valid git object.""" - cmd = ['git', 'cat-file', '-t', value] - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = p.communicate() - if p.returncode != 0: - return None - return stdout.strip() - - -def compute_diff_and_extract_lines(commit, files): - """Calls compute_diff() followed by extract_lines().""" - diff_process = compute_diff(commit, files) - changed_lines = extract_lines(diff_process.stdout) - diff_process.stdout.close() - diff_process.wait() - if diff_process.returncode != 0: - # Assume error was already printed to stderr. - sys.exit(2) - return changed_lines - - -def compute_diff(commit, files): - """Return a subprocess object producing the diff from `commit`. - - The return value's `stdin` file object will produce a patch with the - differences between the working directory and `commit`, filtered on `files` - (if non-empty). Zero context lines are used in the patch.""" - cmd = ['git', 'diff-index', '-p', '-U0', commit, '--'] - cmd.extend(files) - p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) - p.stdin.close() - return p - - -def extract_lines(patch_file): - """Extract the changed lines in `patch_file`. - - The return value is a dictionary mapping filename to a list of (start_line, - line_count) pairs. - - The input must have been produced with ``-U0``, meaning unidiff format with - zero lines of context. The return value is a dict mapping filename to a - list of line `Range`s.""" - matches = {} - for line in patch_file: - match = re.search(r'^\+\+\+\ [^/]+/(.*)', line) - if match: - filename = match.group(1).rstrip('\r\n') - match = re.search(r'^@@ -[0-9,]+ \+(\d+)(,(\d+))?', line) - if match: - start_line = int(match.group(1)) - line_count = 1 - if match.group(3): - line_count = int(match.group(3)) - if line_count > 0: - matches.setdefault(filename, []).append(Range(start_line, line_count)) - return matches - - -def filter_by_extension(dictionary, allowed_extensions): - """Delete every key in `dictionary` that doesn't have an allowed extension. - - `allowed_extensions` must be a collection of lowercase file extensions, - excluding the period.""" - allowed_extensions = frozenset(allowed_extensions) - for filename in dictionary.keys(): - base_ext = filename.rsplit('.', 1) - if len(base_ext) == 1 or base_ext[1].lower() not in allowed_extensions: - del dictionary[filename] - - -def cd_to_toplevel(): - """Change to the top level of the git repository.""" - toplevel = run('git', 'rev-parse', '--show-toplevel') - os.chdir(toplevel) - - -def create_tree_from_workdir(filenames): - """Create a new git tree with the given files from the working directory. - - Returns the object ID (SHA-1) of the created tree.""" - return create_tree(filenames, '--stdin') - - -def run_clang_format_and_save_to_tree(changed_lines, binary='clang-format', - style=None): - """Run clang-format on each file and save the result to a git tree. - - Returns the object ID (SHA-1) of the created tree.""" - def index_info_generator(): - for filename, line_ranges in changed_lines.iteritems(): - mode = oct(os.stat(filename).st_mode) - blob_id = clang_format_to_blob(filename, line_ranges, binary=binary, - style=style) - yield '%s %s\t%s' % (mode, blob_id, filename) - return create_tree(index_info_generator(), '--index-info') - - -def create_tree(input_lines, mode): - """Create a tree object from the given input. - - If mode is '--stdin', it must be a list of filenames. If mode is - '--index-info' is must be a list of values suitable for "git update-index - --index-info", such as " ". Any other mode - is invalid.""" - assert mode in ('--stdin', '--index-info') - cmd = ['git', 'update-index', '--add', '-z', mode] - with temporary_index_file(): - p = subprocess.Popen(cmd, stdin=subprocess.PIPE) - for line in input_lines: - p.stdin.write('%s\0' % line) - p.stdin.close() - if p.wait() != 0: - die('`%s` failed' % ' '.join(cmd)) - tree_id = run('git', 'write-tree') - return tree_id - - -def clang_format_to_blob(filename, line_ranges, binary='clang-format', - style=None): - """Run clang-format on the given file and save the result to a git blob. - - Returns the object ID (SHA-1) of the created blob.""" - clang_format_cmd = [binary, filename] - if style: - clang_format_cmd.extend(['-style='+style]) - clang_format_cmd.extend([ - '-lines=%s:%s' % (start_line, start_line+line_count-1) - for start_line, line_count in line_ranges]) - try: - clang_format = subprocess.Popen(clang_format_cmd, stdin=subprocess.PIPE, - stdout=subprocess.PIPE) - except OSError as e: - if e.errno == errno.ENOENT: - die('cannot find executable "%s"' % binary) - else: - raise - clang_format.stdin.close() - hash_object_cmd = ['git', 'hash-object', '-w', '--path='+filename, '--stdin'] - hash_object = subprocess.Popen(hash_object_cmd, stdin=clang_format.stdout, - stdout=subprocess.PIPE) - clang_format.stdout.close() - stdout = hash_object.communicate()[0] - if hash_object.returncode != 0: - die('`%s` failed' % ' '.join(hash_object_cmd)) - if clang_format.wait() != 0: - die('`%s` failed' % ' '.join(clang_format_cmd)) - return stdout.rstrip('\r\n') - - -@contextlib.contextmanager -def temporary_index_file(tree=None): - """Context manager for setting GIT_INDEX_FILE to a temporary file and deleting - the file afterward.""" - index_path = create_temporary_index(tree) - old_index_path = os.environ.get('GIT_INDEX_FILE') - os.environ['GIT_INDEX_FILE'] = index_path - try: - yield - finally: - if old_index_path is None: - del os.environ['GIT_INDEX_FILE'] - else: - os.environ['GIT_INDEX_FILE'] = old_index_path - os.remove(index_path) - - -def create_temporary_index(tree=None): - """Create a temporary index file and return the created file's path. - - If `tree` is not None, use that as the tree to read in. Otherwise, an - empty index is created.""" - gitdir = run('git', 'rev-parse', '--git-dir') - path = os.path.join(gitdir, temp_index_basename) - if tree is None: - tree = '--empty' - run('git', 'read-tree', '--index-output='+path, tree) - return path - - -def print_diff(old_tree, new_tree): - """Print the diff between the two trees to stdout.""" - # We use the porcelain 'diff' and not plumbing 'diff-tree' because the output - # is expected to be viewed by the user, and only the former does nice things - # like color and pagination. - subprocess.check_call(['git', 'diff', old_tree, new_tree, '--']) - - -def apply_changes(old_tree, new_tree, force=False, patch_mode=False): - """Apply the changes in `new_tree` to the working directory. - - Bails if there are local changes in those files and not `force`. If - `patch_mode`, runs `git checkout --patch` to select hunks interactively.""" - changed_files = run('git', 'diff-tree', '-r', '-z', '--name-only', old_tree, - new_tree).rstrip('\0').split('\0') - if not force: - unstaged_files = run('git', 'diff-files', '--name-status', *changed_files) - if unstaged_files: - print >>sys.stderr, ('The following files would be modified but ' - 'have unstaged changes:') - print >>sys.stderr, unstaged_files - print >>sys.stderr, 'Please commit, stage, or stash them first.' - sys.exit(2) - if patch_mode: - # In patch mode, we could just as well create an index from the new tree - # and checkout from that, but then the user will be presented with a - # message saying "Discard ... from worktree". Instead, we use the old - # tree as the index and checkout from new_tree, which gives the slightly - # better message, "Apply ... to index and worktree". This is not quite - # right, since it won't be applied to the user's index, but oh well. - with temporary_index_file(old_tree): - subprocess.check_call(['git', 'checkout', '--patch', new_tree]) - index_tree = old_tree - else: - with temporary_index_file(new_tree): - run('git', 'checkout-index', '-a', '-f') - return changed_files - - -def run(*args, **kwargs): - stdin = kwargs.pop('stdin', '') - verbose = kwargs.pop('verbose', True) - strip = kwargs.pop('strip', True) - for name in kwargs: - raise TypeError("run() got an unexpected keyword argument '%s'" % name) - p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - stdin=subprocess.PIPE) - stdout, stderr = p.communicate(input=stdin) - if p.returncode == 0: - if stderr: - if verbose: - print >>sys.stderr, '`%s` printed to stderr:' % ' '.join(args) - print >>sys.stderr, stderr.rstrip() - if strip: - stdout = stdout.rstrip('\r\n') - return stdout - if verbose: - print >>sys.stderr, '`%s` returned %s' % (' '.join(args), p.returncode) - if stderr: - print >>sys.stderr, stderr.rstrip() - sys.exit(2) - - -def die(message): - print >>sys.stderr, 'error:', message - sys.exit(2) - - -if __name__ == '__main__': - main() diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..9d42abdaf --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,17 @@ +{ + "C_Cpp.intelliSenseEngine": "Disabled", + "C_Cpp.autocomplete": "Disabled", // So you don't get autocomplete from both extensions. + "C_Cpp.errorSquiggles": "Disabled", // So you don't get error squiggles from both extensions (clangd's seem to be more reliable anyway). + "clangd.arguments": [ + "-log=verbose", + "-pretty", + "--background-index", + "--header-insertion=never", + "--compile-commands-dir=${workspaceFolder}/", + "--query-driver=/**/*", + ], + "cSpell.words": [ + "Opencensus", + "SPDLOG" + ] +} \ No newline at end of file diff --git a/dep/rocketmq_amd64/DEBIAN/postinst b/BUILD.bazel old mode 100755 new mode 100644 similarity index 97% rename from dep/rocketmq_amd64/DEBIAN/postinst rename to BUILD.bazel index 9d78f353a..28e0699af --- a/dep/rocketmq_amd64/DEBIAN/postinst +++ b/BUILD.bazel @@ -1,17 +1,16 @@ -#!/bin/sh - +# # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. -ldconfig \ No newline at end of file +# diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100755 index baa227d0d..000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,284 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. - -cmake_minimum_required(VERSION 2.8) - -if (APPLE) - set(CMAKE_MACOSX_RPATH 1) -endif (APPLE) - -# CMake complains if we don't have this. -if (COMMAND cmake_policy) - cmake_policy(SET CMP0003 NEW) -endif () - -# We're escaping quotes in the Windows version number, because -# for some reason CMake won't do it at config version 2.4.7 -# It seems that this restores the newer behaviour where define -# args are not auto-escaped. -if (COMMAND cmake_policy) - cmake_policy(SET CMP0005 NEW) -endif () - -# First, declare project (important for prerequisite checks). -project(rocketmq-client-cpp) -if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Release") -endif () -set(CMAKE_CONFIGURATION_TYPES "Release") -set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) -set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) -set(CMAKE_VERBOSE_MAKEFILE 1) -option(BUILD_ROCKETMQ_STATIC "build rocketmq-client static library" ON) -option(BUILD_ROCKETMQ_SHARED "build rocketmq-client shared library" ON) - -option(OPENSSL_USE_STATIC_LIBS "only find openssl static libs" ON) # only find static libs -if (WIN32) - find_package(OpenSSL 1.1.1 REQUIRED COMPONENTS) - if (OPENSSL_FOUND) - include_directories(${OPENSSL_INCLUDE_DIR}) - message(STATUS "** OpenSSL Include dir: ${OPENSSL_INCLUDE_DIR}") - message(STATUS "** OpenSSL Libraries: ${OPENSSL_LIBRARIES}") - endif () -else () - #find_package(OpenSSL 1.1.1 REQUIRED COMPONENTS) - set(OPENSSL_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/bin/include) - set(OPENSSL_LIBRARIES_DIR ${PROJECT_SOURCE_DIR}/bin/lib) - set(OPENSSL_LIBRARIES ${OPENSSL_LIBRARIES_DIR}/libssl.a;${OPENSSL_LIBRARIES_DIR}/libcrypto.a) - include_directories(${OPENSSL_INCLUDE_DIR}) -endif () -message(STATUS "** OpenSSL_INCLUDE_DIR: ${OPENSSL_INCLUDE_DIR}") -message(STATUS "** OpenSSL_LIBRARIES: ${OPENSSL_LIBRARIES}") - -#Find dependency -option(Boost_USE_STATIC_LIBS "only find boost static libs" ON) # only find static libs -set(Boost_USE_MULTITHREADED ON) -set(Boost_USE_STATIC_RUNTIME ON) -if (WIN32) - find_package(Boost 1.56 REQUIRED COMPONENTS atomic thread system chrono date_time - log log_setup regex serialization filesystem locale iostreams zlib) - if (Boost_FOUND) - message(STATUS "** Boost Include dir: ${Boost_INCLUDE_DIR}") - message(STATUS "** Boost Libraries dir: ${Boost_LIBRARY_DIRS}") - message(STATUS "** Boost Libraries: ${Boost_LIBRARIES}") - include_directories(${Boost_INCLUDE_DIRS}) - endif () -else () - #find_package(Boost 1.56 REQUIRED COMPONENTS atomic thread system chrono date_time log log_setup regex serialization filesystem locale iostreams) - set(Boost_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/bin/include) - set(Boost_LIBRARY_DIRS ${PROJECT_SOURCE_DIR}/bin/lib) - set(Boost_LIBRARIES ${Boost_LIBRARY_DIRS}/libboost_atomic.a;${Boost_LIBRARY_DIRS}/libboost_thread.a;${Boost_LIBRARY_DIRS}/libboost_system.a; - ${Boost_LIBRARY_DIRS}/libboost_chrono.a;${Boost_LIBRARY_DIRS}/libboost_date_time.a;${Boost_LIBRARY_DIRS}/libboost_log.a; - ${Boost_LIBRARY_DIRS}/libboost_log_setup.a;${Boost_LIBRARY_DIRS}/libboost_regex.a;${Boost_LIBRARY_DIRS}/libboost_serialization.a; - ${Boost_LIBRARY_DIRS}/libboost_filesystem.a;${Boost_LIBRARY_DIRS}/libboost_locale.a;${Boost_LIBRARY_DIRS}/libboost_iostreams.a) - include_directories(${Boost_INCLUDE_DIR}) -endif () - -message(STATUS "** Boost_INCLUDE_DIR: ${Boost_INCLUDE_DIR}") -message(STATUS "** Boost_LIBRARIES: ${Boost_LIBRARIES}") - -option(Libevent_USE_STATIC_LIBS "only find libevent static libs" ON) # only find static libs -if (WIN32) - find_package(Libevent 2.0.22 REQUIRED COMPONENTS) - if (LIBEVENT_FOUND) - include_directories(${LIBEVENT_INCLUDE_DIRS}) - message(STATUS "** libevent Include dir: ${LIBEVENT_INCLUDE_DIRS}") - message(STATUS "** libevent Libraries: ${LIBEVENT_LIBRARIES}") - endif () -else () - #find_package(Libevent 2.0.22 REQUIRED COMPONENTS) - set(LIBEVENT_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/bin/include) - set(LIBEVENT_LIBRARIES_DIR ${PROJECT_SOURCE_DIR}/bin/lib) - set(LIBEVENT_LIBRARIES ${LIBEVENT_LIBRARIES_DIR}/libevent.a;${LIBEVENT_LIBRARIES_DIR}/libevent_core.a;${LIBEVENT_LIBRARIES_DIR}/libevent_extra.a; - ${LIBEVENT_LIBRARIES_DIR}/libevent_pthreads.a;${LIBEVENT_LIBRARIES_DIR}/libevent_openssl.a) - include_directories(${LIBEVENT_INCLUDE_DIRS}) -endif () - -message(STATUS "** LIBEVENT_INCLUDE_DIR: ${LIBEVENT_INCLUDE_DIRS}") -message(STATUS "** LIBEVENT_LIBRARIES: ${LIBEVENT_LIBRARIES}") - -option(JSONCPP_USE_STATIC_LIBS "only find jsoncpp static libs" ON) # only find static libs -if (WIN32) - find_package(Jsoncpp 0.10.6) - if (JSONCPP_FOUND) - include_directories(${JSONCPP_INCLUDE_DIRS}) - endif () -else () - set(JSONCPP_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/bin/include/jsoncpp) - set(JSONCPP_LIBRARIES_DIR ${PROJECT_SOURCE_DIR}/bin/lib) - set(JSONCPP_LIBRARIES ${JSONCPP_LIBRARIES_DIR}/libjsoncpp.a) - include_directories(${JSONCPP_INCLUDE_DIRS}) -endif () - -message(STATUS "** JSONCPP_INCLUDE_DIRS: ${JSONCPP_INCLUDE_DIRS}") -message(STATUS "** JSONCPP_LIBRARIES: ${JSONCPP_LIBRARIES}") - -# put binaries in a different dir to make them easier to find. -set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) -set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) - -# for unix, put debug files in a separate bin "debug" dir. -# release bin files should stay in the root of the bin dir. -# if (CMAKE_GENERATOR STREQUAL "Unix Makefiles") -# if (CMAKE_BUILD_TYPE STREQUAL Debug) -# set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin/debug) -# set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin/debug) -# endif() -# endif() - -IF (WIN32) - add_definitions(-DWIN32 -DROCKETMQCLIENT_EXPORTS) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") -ELSE () - set(C_FLAGS - #-g - -Wall - -Wno-deprecated - -fPIC - -fno-strict-aliasing - ) - set(CXX_FLAGS - #-g - -Wall - -Wno-deprecated - -fPIC - -fno-strict-aliasing - -std=c++11 - -Wno-unused-local-typedef - -Wno-expansion-to-defined - # -finline-limit=1000 - # -Wextra - # -pedantic - # -pedantic-errors - # -D_FILE_OFFSET_BITS=64 - # -DVALGRIND - # -DCHECK_PTHREAD_RETURN_VALUE - # -Werror - # -Wconversion - # -Wno-unused-parameter - # -Wunused-but-set-variable - # -Wold-style-cast - # -Woverloaded-virtual - # -Wpointer-arith - # -Wshadow - # -Wwrite-strings - # -Wdeprecated-declarations - # -march=native - # -MMD - # -std=c++0x - # -rdynamic - ) - - if (CMAKE_BUILD_BITS EQUAL 32) - list(APPEND CXX_FLAGS "-m32") - else () #not-condition - list(APPEND CXX_FLAGS "-m64") - endif () - - string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}") - string(REPLACE ";" " " CMAKE_C_FLAGS "${C_FLAGS}") - - option(ENABLE_ASAN "Enable asan reporting" OFF) - if (ENABLE_ASAN) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -static-libasan") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer -static-libasan") - message(STATUS "** ENABLE_ASAN: ${ENABLE_ASAN} Enable asan reporting") - endif () - - option(ENABLE_LSAN "Enable lsan reporting" OFF) - if (ENABLE_LSAN) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=leak -fno-omit-frame-pointer -static-liblsan") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=leak -fno-omit-frame-pointer -static-liblsan") - message(STATUS "** ENABLE_LSAN: ${ENABLE_LSAN} Enable lsan reporting") - endif () - - set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -DDEBUG") - set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG") - set(CMAKE_C_FLAGS_DEBUG "-g -O0 -DDEBUG") - set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG") - - - # Declare deplibs, so we can use list in linker later. There's probably - # a more elegant way of doing this; with SCons, when you check for the - # lib, it is automatically passed to the linker. - set(deplibs) - - # For some reason, the check_function_exists macro doesn't detect - # the inet_aton on some pure Unix platforms (e.g. sunos5). So we - # need to do a more detailed check and also include some extra deplibs. - list(APPEND deplibs dl) - list(APPEND deplibs pthread) - if (NOT APPLE) - list(APPEND deplibs rt) - endif () - list(APPEND deplibs z) - - option(CODE_COVERAGE "Enable coverage reporting" OFF) - if (CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") - # Add required flags (GCC & LLVM/Clang) - # Code Coverage Configuration - add_library(coverage_config INTERFACE) - target_compile_options(coverage_config INTERFACE - -O0 # no optimization - -g # generate debug info - --coverage # sets all required flags - ) - if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) - target_link_options(coverage_config INTERFACE --coverage) - else () - target_link_libraries(coverage_config INTERFACE --coverage) - endif () - list(APPEND deplibs coverage_config) - endif (CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") - # add include dir for bsd (posix uses /usr/include/) - set(CMAKE_INCLUDE_PATH "${CMAKE_INCLUDE_PATH}:/usr/local/include") -ENDIF () - -# For config.h, set some static values; it may be a good idea to make -# these values dynamic for non-standard UNIX compilers. -set(ACCEPT_TYPE_ARG3 socklen_t) -set(HAVE_CXX_BOOL 1) -set(HAVE_CXX_CASTS 1) -set(HAVE_CXX_EXCEPTIONS 1) -set(HAVE_CXX_MUTABLE 1) -set(HAVE_CXX_STDLIB 1) -set(HAVE_PTHREAD_SIGNAL 1) -set(SELECT_TYPE_ARG1 int) -set(SELECT_TYPE_ARG234 "(fd_set *)") -set(SELECT_TYPE_ARG5 "(struct timeval *)") -set(STDC_HEADERS 1) -set(TIME_WITH_SYS_TIME 1) -set(HAVE_SOCKLEN_T 1) - -# For config.h, save the results based on a template (config.h.in). -# configure_file(res/config.h.in ${root_dir}/config.h) - -# add_definitions(-DSYSAPI_UNIX=1 -DHAVE_CONFIG_H) - -add_subdirectory(libs) -add_subdirectory(project) -add_subdirectory(example) - - -option(RUN_UNIT_TEST "RUN_UNIT_TEST" OFF) - -if (RUN_UNIT_TEST) - message(STATUS "** RUN_UNIT_TEST: ${RUN_UNIT_TEST} Do execution testing") - enable_testing() - add_subdirectory(test) -endif () - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 7ba226e8a..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,2 +0,0 @@ -## How to Contribute - Contributions are warmly welcome! Be it trivial cleanup, major new feature or other suggestion. Read this [how to contribute](http://rocketmq.apache.org/docs/how-to-contribute/) guide for more details. diff --git a/LICENSE b/LICENSE index 360cc7426..261eeb9e9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ - Apache License + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -15,7 +15,7 @@ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, - "control" means (properties) the power, direct or indirect, to cause the + "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. @@ -199,65 +199,3 @@ 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 product has a bundle disruptor--, which is available under BSD License. - The source code of disruptor-- can be found at https://github.com/fsaintjacques/disruptor--. - - Copyright (c) 2011, François Saint-Jacques - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the disruptor-- nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL FRANÇOIS SAINT-JACQUES BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ------- - This product has a bundle of big_endian.h and big_endian.cpp, which is available under BSD License. - The source code of them can be found at https://github.com/chromium/chromium/tree/master/base. - - Copyright 2015 The Chromium Authors. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/NOTICE b/NOTICE deleted file mode 100644 index 85b0032cd..000000000 --- a/NOTICE +++ /dev/null @@ -1,5 +0,0 @@ -Apache RocketMQ -Copyright 2016-2024 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 7f27427ed..000000000 --- a/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,19 +0,0 @@ -## What is the purpose of the change - -XXXXX - -## Brief changelog - -XX - -## Verifying this change - -XXXX - -Follow this checklist to help us incorporate your contribution quickly and easily. Notice, `it would be helpful if you could finish the following 5 checklist(the last one is not necessary)before request the community to review your PR`. - -- [x] Make sure there is a [Github issue](https://github.com/apache/rocketmq/issues) filed for the change (usually before you start working on it). Trivial changes like typos do not require a Github issue. Your pull request should address just this issue, without pulling in other changes - one PR resolves one issue. -- [x] Format the pull request title like `[ISSUE #123] Fix UnknownException when host config not exist`. Each commit in the pull request should have a meaningful subject line and body. -- [x] Write a pull request description that is detailed enough to understand what the pull request does, how, and why. -- [x] Write necessary unit-test(over 80% coverage) to verify your logic correction, more mock a little better when a cross-module dependency exists. -- [ ] If this contribution is large, please file an [Apache Individual Contributor License Agreement](http://www.apache.org/licenses/#clas). diff --git a/README.md b/README.md index 6bc2222fa..7ce243853 100644 --- a/README.md +++ b/README.md @@ -1,76 +1,92 @@ -# RocketMQ Client CPP -[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) -[![Build Status](https://app.travis-ci.com/apache/rocketmq-client-cpp.svg?branch=master)](https://app.travis-ci.com/apache/rocketmq-client-cpp) -[![CodeCov](https://codecov.io/gh/apache/rocketmq-client-cpp/branch/master/graph/badge.svg)](https://codecov.io/gh/apache/rocketmq-client-cpp) -[![GitHub release](https://img.shields.io/github/downloads/apache/rocketmq-client-cpp/total)](https://github.com/apache/rocketmq-client-cpp/releases) -![Twitter Follow](https://img.shields.io/twitter/follow/ApacheRocketMQ?style=social) - -RocketMQ-Client-CPP is the C/C++ client of Apache RocketMQ, a distributed messaging and streaming platform with low latency, high performance and reliability, trillion-level capacity and flexible scalability. - -## Features - -- produce messages, including normal and delayed messages, synchronously or asynchronously. -- consume messages, in cluster or broadcast model, concurrently or orderly -- c and c++ style API. -- cross-platform, all features are supported on Windows, Linux and Mac OS. -- automatically rebalanced, both in producing and consuming process. -- reliability, any downtime broker or name server has no impact on the client. - -## Build and Install - -### Linux and Mac OS - -**note**: make sure the following compile tools or libraries have been installed before running the build script **build.sh**. - -- compile tools: - - gcc-c++ 4.8.2: c++ compiler while need support C++11 - - cmake 2.8.0: build jsoncpp require it - - automake 1.11.1: build libevent require it - - autoconf 2.65: build libevent require it - - libtool 2.2.6: build libevent require it - -- libraries: - - bzip2-devel 1.0.6: boost depend it - - zlib-devel - -The **build.sh** script will automatically download and build the dependency libraries including libevent, json and boost. It will save libraries under rocketmq-client-cpp folder, and then build both static and shared libraries for rocketmq-client. If the dependent libraries are built failed, you could try to build it manually with sources [libevent 2.0.22](https://github.com/libevent/libevent/archive/release-2.0.22-stable.zip "lib event 2.0.22"), [jsoncpp 0.10.7](https://github.com/open-source-parsers/jsoncpp/archive/0.10.7.zip "jsoncpp 0.10.7"), [boost 1.58.0](http://sourceforge.net/projects/boost/files/boost/1.58.0/boost_1_58_0.tar.gz "boost 1.58.0") - -If your host is not available to internet to download the three library source files, you can copy the three library source files (release-2.0.22-stable.zip 0.10.7.zip and boost_1_58_0.tar.gz) to rocketmq-client-cpp root dir, then the build.sh will automatically use the three library source files to build rocketmq-client-cpp: - - sh build.sh - -Finally, both librocketmq.a and librocketmq.so are saved in rocketmq-client-cpp/bin. when using them to build application or library, besides rocketmq you should also link with following libraries -lpthread -lz -ldl -lrt. Here is an example: - - g++ -o consumer_example consumer_example.cpp -lrocketmq -lpthread -lz -ldl -lrt - -### Windows -**note**: make sure the following compile tools or libraries have been installed before running the build script **win32_build.bat**: - -- compile tools: - - vs2015: libevent,jsoncpp,zlib,boost rocket-client require it - - git: download source code - -The build script will automatically download dependent libraries including libevent json and boost to build shared library: - - win32_build.bat - - -If your host is not available to internet to download the four library source files by build script, you can copy the four library source files - -[zlib-1.2.3-src](https://codeload.github.com/jsj020122/zlib-1.2.3-src/zip/master "zlib-1.2.3-src") Extract to $(rocketmq-client-cpp root dir)/thirdparty/zlib-1.2.3-src - -[libevent-release-2.0.22](https://codeload.github.com/jsj020122/libevent-release-2.0.22/zip/master "libevent-release-2.0.22") Extract to $(rocketmq-client-cpp root dir)/thirdparty/libevent-release-2.0.22 - -[boost_1_58_0](https://codeload.github.com/jsj020122/boost_1_58_0/zip/master "boost_1_58_0") Extract to $(rocketmq-client-cpp root dir)/thirdparty/boost_1_58_0 - -[jsoncpp-0.10.6](https://codeload.github.com/jsj020122/jsoncpp-0.10.6/zip/master "jsoncpp-0.10.6") Extract to $(rocketmq-client-cpp root dir)/thirdparty/jsoncpp-0.10.6 - -And then run following command to build x86 rocketmq-client: - - win32_build.bat build - -to build x64 rocketmq-client: - - win32_build.bat build64 - - +[![CI](https://github.com/apache/rocketmq-client-cpp/actions/workflows/main.yml/badge.svg)](https://github.com/lizhanhui/rocketmq-client-cpp/actions/workflows/main.yml) +### Introduction +Apache RocketMQ supports two styles of APIs to acknowledge messages once they are successfully processed. + +1. Selective Acknowledgement + For each logical message queue(aka, topic partition), SDK manages offsets locally and periodically syncs committed offset to brokers in charge. +2. Per Message Acknowledgement + On consumption of each message, SDK acknowledge it to the broker instantly. Broker is responsible of managing consuming progress. + +Either of them is widely adopted by products. Per message acknowledgement simplifies SDK implementation while selective approach is more performant considering that fewer RPCs are required. + +### Transport Layer + +This SDK is built on top of [gRPC](https://grpc.io/). [Protocol Buffers](https://developers.google.com/protocol-buffers) is used to serialize application messages. + +### Type Hierarchy +Classes of this project are designed to be interface oriented. +![Basic class hierarchy](docs/assets/BasicMode.png) +This paradigm makes dependency injection possible. DI is especially helpful when writing unit tests. + +### Core Concepts +![Class Diagram](docs/assets/class_diagram.png) + +### Code Style +Generally, we follow [Google C++ Code Style](https://google.github.io/styleguide/cppguide.html). A few exceptions are made to maintain API compatibility. +1. C++ exception is only allowed in the outer wrapper classes, for example, DefaultMQProducer, DefaultMQConsumer. +2. C++ --std=c++11 is preferred. We intend to maintain the same compiler compatibility matrix to [those of gRPC](https://github.com/grpc/grpc/blob/master/BUILDING.md) +3. Smart pointers are preferred where it makes sense. Use raw pointers only when it is really necessary. + +### Dependency Management +Considering SDK built on top of gRPC, ensure it is really necessary before introducing a third-party library. Check [gRPC deps](https://github.com/grpc/grpc/blob/master/bazel/grpc_deps.bzl) and [gRPC extra deps](https://github.com/grpc/grpc/blob/master/bazel/grpc_extra_deps.bzl) first! + +When introducing a third-party dependency or raising version of a dependency, make sure it is back-off friendly. For example, +``` +if "com_google_googletest" not in native.existing_rules(): + http_archive( + name = "com_google_googletest", + sha256 = "b4870bf121ff7795ba20d20bcdd8627b8e088f2d1dab299a031c1034eddc93d5", + strip_prefix = "googletest-release-1.11.0", + urls = [ + "https://github.com/google/googletest/archive/refs/tags/release-1.11.0.tar.gz", + ], + ) +``` + +### How To Build +[Google Bazel](https://bazel.build/) is the primary build tool we supported, Please follow [bazel installation guide](https://docs.bazel.build/versions/main/install.html). + + +1. Build + From the repository root, + ``` + bazel build //... + ``` +2. Run Unit Tests + From the repository root, + ``` + bazel test //src/test/cpp/ut/... + ``` + +### IDE +[Visual Studio Code](https://code.visualstudio.com/) + [Clangd](https://clangd.llvm.org/) is the recommended development toolset. +1. VSCode + Clangd + + [Clangd](https://clangd.llvm.org/) is a really nice code completion tool. Clangd requires compile_commands.json to work properly. + To generate the file, we need clone another repository along with the current one. + + ``` + git clone git@github.com:grailbio/bazel-compilation-database.git + ``` + From current repository root, + + ``` + ../bazel-compilation-database/generate.sh + ``` + Once the script completes, you should have compile_commands.json file in the repository root directory. + + LLVM project has an extension for [clangd](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd). Please install it from the extension market. + + The following configuration entries should be appended to your VSC settings file. + ```text + "C_Cpp.intelliSenseEngine": "Disabled", + "C_Cpp.autocomplete": "Disabled", // So you don't get autocomplete from both extensions. + "C_Cpp.errorSquiggles": "Disabled", // So you don't get error squiggles from both extensions (clangd's seem to be more reliable anyway). + "clangd.path": "/Users/lizhanhui/usr/clangd_12.0.0/bin/clangd", + "clangd.arguments": ["-log=verbose", "-pretty", "--background-index"], + "clangd.onConfigChanged": "restart", + ``` + +2. CLion + Bazel Plugin + + Bazel also has a plugin for CLion. diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 000000000..644b5d7a9 --- /dev/null +++ b/WORKSPACE @@ -0,0 +1,20 @@ +workspace(name = "org_apache_rocketmq") +load("//bazel:rocketmq_deps.bzl", "rocketmq_deps") +rocketmq_deps() + +load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps", "grpc_test_only_deps") +grpc_deps() +grpc_test_only_deps() +load("@com_github_grpc_grpc//bazel:grpc_extra_deps.bzl", "grpc_extra_deps") +grpc_extra_deps() + +load("@rules_proto_grpc//:repositories.bzl", "rules_proto_grpc_toolchains", "rules_proto_grpc_repos") +rules_proto_grpc_toolchains() +rules_proto_grpc_repos() + +load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains") +rules_proto_dependencies() +rules_proto_toolchains() + +load("@hedron_compile_commands//:workspace_setup.bzl", "hedron_compile_commands_setup") +hedron_compile_commands_setup() \ No newline at end of file diff --git a/Win32/rocketmq-client-cpp.sln b/Win32/rocketmq-client-cpp.sln deleted file mode 100644 index a0858b171..000000000 --- a/Win32/rocketmq-client-cpp.sln +++ /dev/null @@ -1,188 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rocketmq-client-cpp", "rocketmq-client-cpp.vcxproj", "{DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AsyncProducer", "AsyncProducer.vcxproj", "{AC059D17-1D30-4D83-AE00-5FFFE3ED50A9}" - ProjectSection(ProjectDependencies) = postProject - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} = {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AsyncPushConsumer", "AsyncPushConsumer.vcxproj", "{19D42952-0418-4162-92EA-6B601B11847C}" - ProjectSection(ProjectDependencies) = postProject - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} = {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OrderlyPushConsumer", "OrderlyPushConsumer.vcxproj", "{F1657573-16CB-440E-9CAD-E6333141377D}" - ProjectSection(ProjectDependencies) = postProject - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} = {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "COrderlyAsyncProducer", "COrderlyAsyncProducer.vcxproj", "{F1657573-16CB-440E-9CAD-E6333141387D}" - ProjectSection(ProjectDependencies) = postProject - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} = {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OrderProducer", "OrderProducer.vcxproj", "{7BB3595B-CF36-4F12-8F12-897342C643CD}" - ProjectSection(ProjectDependencies) = postProject - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} = {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Producer", "Producer.vcxproj", "{52063BCB-8547-463D-AADA-A086B5339167}" - ProjectSection(ProjectDependencies) = postProject - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} = {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PullConsumer", "PullConsumer.vcxproj", "{B167E18F-71BE-4873-A806-6B340C5838EF}" - ProjectSection(ProjectDependencies) = postProject - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} = {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PushConsumeMessage", "PushConsumeMessage.vcxproj", "{00DA7C52-1EB6-46B5-9D2A-177E6A81F598}" - ProjectSection(ProjectDependencies) = postProject - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} = {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PushConsumer", "PushConsumer.vcxproj", "{07CA501C-90B7-45A5-BC89-886ACB3B30CC}" - ProjectSection(ProjectDependencies) = postProject - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} = {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SendDelayMsg", "SendDelayMsg.vcxproj", "{0B156CC7-A991-4554-A29D-8CD0ED982773}" - ProjectSection(ProjectDependencies) = postProject - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} = {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SyncProducer", "SyncProducer.vcxproj", "{C281AB41-79DE-49DD-AEEF-F300C0580D18}" - ProjectSection(ProjectDependencies) = postProject - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} = {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "example", "example", "{9B81E85B-7438-4B55-8BE0-798B4A7C8775}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{097B656C-BF7C-445B-9C2B-57292DF0BD92}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13}.Debug|x64.ActiveCfg = Debug|x64 - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13}.Debug|x64.Build.0 = Debug|x64 - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13}.Debug|x86.ActiveCfg = Debug|Win32 - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13}.Debug|x86.Build.0 = Debug|Win32 - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13}.Release|x64.ActiveCfg = Release|x64 - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13}.Release|x64.Build.0 = Release|x64 - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13}.Release|x86.ActiveCfg = Release|Win32 - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13}.Release|x86.Build.0 = Release|Win32 - {AC059D17-1D30-4D83-AE00-5FFFE3ED50A9}.Debug|x64.ActiveCfg = Debug|x64 - {AC059D17-1D30-4D83-AE00-5FFFE3ED50A9}.Debug|x64.Build.0 = Debug|x64 - {AC059D17-1D30-4D83-AE00-5FFFE3ED50A9}.Debug|x86.ActiveCfg = Debug|Win32 - {AC059D17-1D30-4D83-AE00-5FFFE3ED50A9}.Debug|x86.Build.0 = Debug|Win32 - {AC059D17-1D30-4D83-AE00-5FFFE3ED50A9}.Release|x64.ActiveCfg = Release|x64 - {AC059D17-1D30-4D83-AE00-5FFFE3ED50A9}.Release|x64.Build.0 = Release|x64 - {AC059D17-1D30-4D83-AE00-5FFFE3ED50A9}.Release|x86.ActiveCfg = Release|Win32 - {AC059D17-1D30-4D83-AE00-5FFFE3ED50A9}.Release|x86.Build.0 = Release|Win32 - {19D42952-0418-4162-92EA-6B601B11847C}.Debug|x64.ActiveCfg = Debug|x64 - {19D42952-0418-4162-92EA-6B601B11847C}.Debug|x64.Build.0 = Debug|x64 - {19D42952-0418-4162-92EA-6B601B11847C}.Debug|x86.ActiveCfg = Debug|Win32 - {19D42952-0418-4162-92EA-6B601B11847C}.Debug|x86.Build.0 = Debug|Win32 - {19D42952-0418-4162-92EA-6B601B11847C}.Release|x64.ActiveCfg = Release|x64 - {19D42952-0418-4162-92EA-6B601B11847C}.Release|x64.Build.0 = Release|x64 - {19D42952-0418-4162-92EA-6B601B11847C}.Release|x86.ActiveCfg = Release|Win32 - {19D42952-0418-4162-92EA-6B601B11847C}.Release|x86.Build.0 = Release|Win32 - {F1657573-16CB-440E-9CAD-E6333141377D}.Debug|x64.ActiveCfg = Debug|x64 - {F1657573-16CB-440E-9CAD-E6333141377D}.Debug|x64.Build.0 = Debug|x64 - {F1657573-16CB-440E-9CAD-E6333141377D}.Debug|x86.ActiveCfg = Debug|Win32 - {F1657573-16CB-440E-9CAD-E6333141377D}.Debug|x86.Build.0 = Debug|Win32 - {F1657573-16CB-440E-9CAD-E6333141377D}.Release|x64.ActiveCfg = Release|x64 - {F1657573-16CB-440E-9CAD-E6333141377D}.Release|x64.Build.0 = Release|x64 - {F1657573-16CB-440E-9CAD-E6333141377D}.Release|x86.ActiveCfg = Release|Win32 - {F1657573-16CB-440E-9CAD-E6333141377D}.Release|x86.Build.0 = Release|Win32 - {F1657573-16CB-440E-9CAD-E6333141387D}.Debug|x64.ActiveCfg = Debug|x64 - {F1657573-16CB-440E-9CAD-E6333141387D}.Debug|x64.Build.0 = Debug|x64 - {F1657573-16CB-440E-9CAD-E6333141387D}.Debug|x86.ActiveCfg = Debug|Win32 - {F1657573-16CB-440E-9CAD-E6333141387D}.Debug|x86.Build.0 = Debug|Win32 - {F1657573-16CB-440E-9CAD-E6333141387D}.Release|x64.ActiveCfg = Release|x64 - {F1657573-16CB-440E-9CAD-E6333141387D}.Release|x64.Build.0 = Release|x64 - {F1657573-16CB-440E-9CAD-E6333141387D}.Release|x86.ActiveCfg = Release|Win32 - {F1657573-16CB-440E-9CAD-E6333141387D}.Release|x86.Build.0 = Release|Win32 - {7BB3595B-CF36-4F12-8F12-897342C643CD}.Debug|x64.ActiveCfg = Debug|x64 - {7BB3595B-CF36-4F12-8F12-897342C643CD}.Debug|x64.Build.0 = Debug|x64 - {7BB3595B-CF36-4F12-8F12-897342C643CD}.Debug|x86.ActiveCfg = Debug|Win32 - {7BB3595B-CF36-4F12-8F12-897342C643CD}.Debug|x86.Build.0 = Debug|Win32 - {7BB3595B-CF36-4F12-8F12-897342C643CD}.Release|x64.ActiveCfg = Release|x64 - {7BB3595B-CF36-4F12-8F12-897342C643CD}.Release|x64.Build.0 = Release|x64 - {7BB3595B-CF36-4F12-8F12-897342C643CD}.Release|x86.ActiveCfg = Release|Win32 - {7BB3595B-CF36-4F12-8F12-897342C643CD}.Release|x86.Build.0 = Release|Win32 - {52063BCB-8547-463D-AADA-A086B5339167}.Debug|x64.ActiveCfg = Debug|x64 - {52063BCB-8547-463D-AADA-A086B5339167}.Debug|x64.Build.0 = Debug|x64 - {52063BCB-8547-463D-AADA-A086B5339167}.Debug|x86.ActiveCfg = Debug|Win32 - {52063BCB-8547-463D-AADA-A086B5339167}.Debug|x86.Build.0 = Debug|Win32 - {52063BCB-8547-463D-AADA-A086B5339167}.Release|x64.ActiveCfg = Release|x64 - {52063BCB-8547-463D-AADA-A086B5339167}.Release|x64.Build.0 = Release|x64 - {52063BCB-8547-463D-AADA-A086B5339167}.Release|x86.ActiveCfg = Release|Win32 - {52063BCB-8547-463D-AADA-A086B5339167}.Release|x86.Build.0 = Release|Win32 - {B167E18F-71BE-4873-A806-6B340C5838EF}.Debug|x64.ActiveCfg = Debug|x64 - {B167E18F-71BE-4873-A806-6B340C5838EF}.Debug|x64.Build.0 = Debug|x64 - {B167E18F-71BE-4873-A806-6B340C5838EF}.Debug|x86.ActiveCfg = Debug|Win32 - {B167E18F-71BE-4873-A806-6B340C5838EF}.Debug|x86.Build.0 = Debug|Win32 - {B167E18F-71BE-4873-A806-6B340C5838EF}.Release|x64.ActiveCfg = Release|x64 - {B167E18F-71BE-4873-A806-6B340C5838EF}.Release|x64.Build.0 = Release|x64 - {B167E18F-71BE-4873-A806-6B340C5838EF}.Release|x86.ActiveCfg = Release|Win32 - {B167E18F-71BE-4873-A806-6B340C5838EF}.Release|x86.Build.0 = Release|Win32 - {00DA7C52-1EB6-46B5-9D2A-177E6A81F598}.Debug|x64.ActiveCfg = Debug|x64 - {00DA7C52-1EB6-46B5-9D2A-177E6A81F598}.Debug|x64.Build.0 = Debug|x64 - {00DA7C52-1EB6-46B5-9D2A-177E6A81F598}.Debug|x86.ActiveCfg = Debug|Win32 - {00DA7C52-1EB6-46B5-9D2A-177E6A81F598}.Debug|x86.Build.0 = Debug|Win32 - {00DA7C52-1EB6-46B5-9D2A-177E6A81F598}.Release|x64.ActiveCfg = Release|x64 - {00DA7C52-1EB6-46B5-9D2A-177E6A81F598}.Release|x64.Build.0 = Release|x64 - {00DA7C52-1EB6-46B5-9D2A-177E6A81F598}.Release|x86.ActiveCfg = Release|Win32 - {00DA7C52-1EB6-46B5-9D2A-177E6A81F598}.Release|x86.Build.0 = Release|Win32 - {07CA501C-90B7-45A5-BC89-886ACB3B30CC}.Debug|x64.ActiveCfg = Debug|x64 - {07CA501C-90B7-45A5-BC89-886ACB3B30CC}.Debug|x64.Build.0 = Debug|x64 - {07CA501C-90B7-45A5-BC89-886ACB3B30CC}.Debug|x86.ActiveCfg = Debug|Win32 - {07CA501C-90B7-45A5-BC89-886ACB3B30CC}.Debug|x86.Build.0 = Debug|Win32 - {07CA501C-90B7-45A5-BC89-886ACB3B30CC}.Release|x64.ActiveCfg = Release|x64 - {07CA501C-90B7-45A5-BC89-886ACB3B30CC}.Release|x64.Build.0 = Release|x64 - {07CA501C-90B7-45A5-BC89-886ACB3B30CC}.Release|x86.ActiveCfg = Release|Win32 - {07CA501C-90B7-45A5-BC89-886ACB3B30CC}.Release|x86.Build.0 = Release|Win32 - {0B156CC7-A991-4554-A29D-8CD0ED982773}.Debug|x64.ActiveCfg = Debug|x64 - {0B156CC7-A991-4554-A29D-8CD0ED982773}.Debug|x64.Build.0 = Debug|x64 - {0B156CC7-A991-4554-A29D-8CD0ED982773}.Debug|x86.ActiveCfg = Debug|Win32 - {0B156CC7-A991-4554-A29D-8CD0ED982773}.Debug|x86.Build.0 = Debug|Win32 - {0B156CC7-A991-4554-A29D-8CD0ED982773}.Release|x64.ActiveCfg = Release|x64 - {0B156CC7-A991-4554-A29D-8CD0ED982773}.Release|x64.Build.0 = Release|x64 - {0B156CC7-A991-4554-A29D-8CD0ED982773}.Release|x86.ActiveCfg = Release|Win32 - {0B156CC7-A991-4554-A29D-8CD0ED982773}.Release|x86.Build.0 = Release|Win32 - {C281AB41-79DE-49DD-AEEF-F300C0580D18}.Debug|x64.ActiveCfg = Debug|x64 - {C281AB41-79DE-49DD-AEEF-F300C0580D18}.Debug|x64.Build.0 = Debug|x64 - {C281AB41-79DE-49DD-AEEF-F300C0580D18}.Debug|x86.ActiveCfg = Debug|Win32 - {C281AB41-79DE-49DD-AEEF-F300C0580D18}.Debug|x86.Build.0 = Debug|Win32 - {C281AB41-79DE-49DD-AEEF-F300C0580D18}.Release|x64.ActiveCfg = Release|x64 - {C281AB41-79DE-49DD-AEEF-F300C0580D18}.Release|x64.Build.0 = Release|x64 - {C281AB41-79DE-49DD-AEEF-F300C0580D18}.Release|x86.ActiveCfg = Release|Win32 - {C281AB41-79DE-49DD-AEEF-F300C0580D18}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} = {097B656C-BF7C-445B-9C2B-57292DF0BD92} - {AC059D17-1D30-4D83-AE00-5FFFE3ED50A9} = {9B81E85B-7438-4B55-8BE0-798B4A7C8775} - {19D42952-0418-4162-92EA-6B601B11847C} = {9B81E85B-7438-4B55-8BE0-798B4A7C8775} - {F1657573-16CB-440E-9CAD-E6333141377D} = {9B81E85B-7438-4B55-8BE0-798B4A7C8775} - {7BB3595B-CF36-4F12-8F12-897342C643CD} = {9B81E85B-7438-4B55-8BE0-798B4A7C8775} - {52063BCB-8547-463D-AADA-A086B5339167} = {9B81E85B-7438-4B55-8BE0-798B4A7C8775} - {B167E18F-71BE-4873-A806-6B340C5838EF} = {9B81E85B-7438-4B55-8BE0-798B4A7C8775} - {00DA7C52-1EB6-46B5-9D2A-177E6A81F598} = {9B81E85B-7438-4B55-8BE0-798B4A7C8775} - {07CA501C-90B7-45A5-BC89-886ACB3B30CC} = {9B81E85B-7438-4B55-8BE0-798B4A7C8775} - {0B156CC7-A991-4554-A29D-8CD0ED982773} = {9B81E85B-7438-4B55-8BE0-798B4A7C8775} - {C281AB41-79DE-49DD-AEEF-F300C0580D18} = {9B81E85B-7438-4B55-8BE0-798B4A7C8775} - EndGlobalSection -EndGlobal diff --git a/Win32/rocketmq-client-cpp.vcxproj b/Win32/rocketmq-client-cpp.vcxproj deleted file mode 100644 index 720aab464..000000000 --- a/Win32/rocketmq-client-cpp.vcxproj +++ /dev/null @@ -1,308 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {DFF2BED1-4A9E-4B0B-B1EC-F01D70457E13} - Win32Proj - 8.1 - - - - DynamicLibrary - true - v140 - - - DynamicLibrary - false - v140_xp - - - DynamicLibrary - true - v140 - - - DynamicLibrary - false - v140 - - - - - - - - - - - - - - - - - - - - - true - $(WindowsSdk_71A_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)..\thirdparty\boost_1_58_0;$(SolutionDir)..\include;$(SolutionDir)..\thirdparty\libevent-release-2.0.22\include;$(SolutionDir)..\thirdparty\libevent-release-2.0.22\WIN32-Code\;$(SolutionDir)..\src\common;$(SolutionDir)..\src\consumer;$(SolutionDir)..\src\log;$(SolutionDir)..\src\message;$(SolutionDir)..\src\producer;$(SolutionDir)..\src\protocol;$(SolutionDir)..\src\thread;$(SolutionDir)..\src\transport;$(SolutionDir)..\thirdparty\jsoncpp-0.10.6\;$(SolutionDir)..\src;$(SolutionDir)..\libs\signature\include;$(VC_IncludePath) - $(WindowsSdk_71A_LibraryPath_x86);$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;$(SolutionDir)thirdparty..\boost_1_58_0\stage\lib - - - true - $(WindowsSdk_71A_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)..\thirdparty\boost_1_58_0;$(SolutionDir)..\include;$(SolutionDir)..\thirdparty\libevent-release-2.0.22\include;$(SolutionDir)..\thirdparty\libevent-release-2.0.22\WIN32-Code\;$(SolutionDir)..\src\common;$(SolutionDir)..\src\consumer;$(SolutionDir)..\src\log;$(SolutionDir)..\src\message;$(SolutionDir)..\src\producer;$(SolutionDir)..\src\protocol;$(SolutionDir)..\src\thread;$(SolutionDir)..\src\transport;$(SolutionDir)..\thirdparty\jsoncpp-0.10.6\;$(SolutionDir)..\src;$(SolutionDir)..\libs\signature\include;$(VC_IncludePath) - $(WindowsSdk_71A_LibraryPath_x86);$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;$(SolutionDir)..\thirdparty\boost_1_58_0\stage\lib - $(Configuration)\$(ProjectName) - - - true - $(WindowsSdk_71A_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)..\thirdparty\boost_1_58_0;$(SolutionDir)..\include;$(SolutionDir)..\thirdparty\libevent-release-2.0.22\include;$(SolutionDir)..\thirdparty\libevent-release-2.0.22\WIN32-Code\;$(SolutionDir)..\src\common;$(SolutionDir)..\src\consumer;$(SolutionDir)..\src\log;$(SolutionDir)..\src\message;$(SolutionDir)..\src\producer;$(SolutionDir)..\src\protocol;$(SolutionDir)..\src\thread;$(SolutionDir)..\src\transport;$(SolutionDir)..\thirdparty\jsoncpp-0.10.6\;$(SolutionDir)..\src;$(SolutionDir)..\libs\signature\include;$(VC_IncludePath) - $(WindowsSdk_71A_LibraryPath_x64);$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;$(SolutionDir)..\thirdparty\boost_1_58_0\stage\lib - $(Configuration)\$(ProjectName) - - - true - $(WindowsSdk_71A_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)..\thirdparty\boost_1_58_0;$(SolutionDir)..\include;$(SolutionDir)..\thirdparty\libevent-release-2.0.22\include;$(SolutionDir)..\thirdparty\libevent-release-2.0.22\WIN32-Code\;$(SolutionDir)..\src\common;$(SolutionDir)..\src\consumer;$(SolutionDir)..\src\log;$(SolutionDir)..\src\message;$(SolutionDir)..\src\producer;$(SolutionDir)..\src\protocol;$(SolutionDir)..\src\thread;$(SolutionDir)..\src\transport;$(SolutionDir)..\thirdparty\jsoncpp-0.10.6\;$(SolutionDir)..\src;$(SolutionDir)..\libs\signature\include;$(VC_IncludePath) - $(WindowsSdk_71A_LibraryPath_x64);$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;$(SolutionDir)..\thirdparty\boost_1_58_0\stage\lib - $(Configuration)\$(ProjectName) - - - - WIN32;_DEBUG;ROCKETMQCLIENT_EXPORTS;_WIN32_WINNT=0x501;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - Level3 - ProgramDatabase - Disabled - /MDd %(AdditionalOptions) - - - MachineX86 - true - Console - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;$(SolutionDir)..\thirdparty\libevent-release-2.0.22\$(Configuration)\libevent.lib;$(SolutionDir)..\thirdparty\jsoncpp-0.10.6\$(Configuration)\jsoncpp_lib_static.lib;%(AdditionalDependencies) - /NODEFAULTLIB:library %(AdditionalOptions) - - - - - WIN32;NDEBUG;ROCKETMQCLIENT_EXPORTS;_WIN32_WINNT=0x501;%(PreprocessorDefinitions) - MultiThreadedDLL - Level3 - ProgramDatabase - - - MachineX86 - true - Console - true - true - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;$(SolutionDir)..\thirdparty\libevent-release-2.0.22\$(Configuration)\libevent.lib;$(SolutionDir)..\thirdparty\jsoncpp-0.10.6\$(Configuration)\jsoncpp_lib_static.lib;%(AdditionalDependencies) - - - - - WIN32;NDEBUG;ROCKETMQCLIENT_EXPORTS;_WIN32_WINNT=0x501;%(PreprocessorDefinitions) - MultiThreadedDLL - Level3 - ProgramDatabase - /FS %(AdditionalOptions) - - - MachineX64 - true - Console - true - true - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;$(SolutionDir)..\thirdparty\libevent-release-2.0.22\$(Platform)\$(Configuration)\libevent.lib;$(SolutionDir)..\thirdparty\jsoncpp-0.10.6\$(Platform)\$(Configuration)\jsoncpp_lib_static.lib;%(AdditionalDependencies) - - - - - - - WIN32;_DEBUG;ROCKETMQCLIENT_EXPORTS;_WIN32_WINNT=0x501;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - Level3 - ProgramDatabase - Disabled - /FS /MDd %(AdditionalOptions) - - - MachineX64 - true - Console - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;$(SolutionDir)..\thirdparty\libevent-release-2.0.22\$(Configuration)\libevent.lib;$(SolutionDir)..\thirdparty\jsoncpp-0.10.6\$(Configuration)\jsoncpp_lib_static.lib;%(AdditionalDependencies) - /NODEFAULTLIB:library %(AdditionalOptions) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Win32/rocketmq-client-cpp.vcxproj.filters b/Win32/rocketmq-client-cpp.vcxproj.filters deleted file mode 100644 index b92019c3f..000000000 --- a/Win32/rocketmq-client-cpp.vcxproj.filters +++ /dev/null @@ -1,450 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - {41638677-648d-470b-a0dd-27ffbb643445} - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/.travis/check-git-clang-format.sh b/api/BUILD.bazel similarity index 60% rename from .travis/check-git-clang-format.sh rename to api/BUILD.bazel index b8d3d1ffa..f5d75d558 100644 --- a/.travis/check-git-clang-format.sh +++ b/api/BUILD.bazel @@ -1,32 +1,28 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_library") -#!/bin/bash - - if [ "$TRAVIS_PULL_REQUEST" = "true" ]; then - base_commit="$TRAVIS_BRANCH" -else - base_commit="HEAD^" -fi - - output="$(sudo python .travis/git-clang-format --binary clang-format-3.8 --commit $base_commit --diff)" - - if [ "$output" = "no modified files to format" ] || [ "$output" = "clang-format did not modify any files" ]; then - echo "clang-format passed." - exit 0 -else - echo "clang-format failed." - echo "$output" - exit 1 -fi +cc_library( + name = "rocketmq_interface", + hdrs = glob(["rocketmq/*.h"]), + strip_include_prefix = "//api", + visibility = ["//visibility:public"], + deps = [ + "@com_google_absl//absl/strings", + "@io_opencensus_cpp//opencensus/trace", + ], +) \ No newline at end of file diff --git a/api/rocketmq/AdminServer.h b/api/rocketmq/AdminServer.h new file mode 100644 index 000000000..3876a2ca0 --- /dev/null +++ b/api/rocketmq/AdminServer.h @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "State.h" + +namespace rocketmq { +namespace admin { + + class AdminServer { + public: + virtual ~AdminServer() = default; + + virtual bool start() = 0; + + virtual bool stop() = 0; + + virtual int port() const = 0; + }; + + class AdminFacade { + public: + static AdminServer& getServer(); + }; + +} // namespace admin +} // namespace rocketmq \ No newline at end of file diff --git a/api/rocketmq/BackoffPolicy.h b/api/rocketmq/BackoffPolicy.h new file mode 100644 index 000000000..89aa7d17d --- /dev/null +++ b/api/rocketmq/BackoffPolicy.h @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "RocketMQ.h" +#include +#include +#include + +ROCKETMQ_NAMESPACE_BEGIN + +class BackoffPolicy { +public: + virtual ~BackoffPolicy() = default; + + virtual std::size_t maxAttempts() const = 0; + + virtual std::chrono::milliseconds backoff(std::size_t attempt) const = 0; +}; + +class ExponentialBackoffPolicy : public BackoffPolicy { +public: + ExponentialBackoffPolicy(std::size_t max_attempts, std::chrono::milliseconds initial_backoff, + std::chrono::milliseconds max_backoff, std::size_t multiplier) + : max_attempts_(max_attempts), initial_backoff_(initial_backoff), max_backoff_(max_backoff), + multiplier_(multiplier) { + } + + std::size_t maxAttempts() const override { + return max_attempts_; + } + + std::chrono::milliseconds backoff(std::size_t attempt) const override { + if (attempt <= 1) { + return initial_backoff_; + } + + if (attempt >= max_attempts_) { + return max_backoff_; + } + + auto duration = initial_backoff_ * static_cast(std::pow(multiplier_, attempt)); + if (duration > max_backoff_) { + return max_backoff_; + } + return duration; + } + +private: + std::size_t max_attempts_; + std::chrono::milliseconds initial_backoff_; + std::chrono::milliseconds max_backoff_; + std::size_t multiplier_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/Configuration.h b/api/rocketmq/Configuration.h new file mode 100644 index 000000000..90cdf7d27 --- /dev/null +++ b/api/rocketmq/Configuration.h @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include + +#include "ConfigurationDefaults.h" +#include "CredentialsProvider.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ConfigurationBuilder; + +class Configuration { +public: + static ConfigurationBuilder newBuilder(); + + const std::string& endpoints() const { + return endpoints_; + } + + CredentialsProviderPtr credentialsProvider() const { + return credentials_provider_; + } + + std::chrono::milliseconds requestTimeout() const { + return request_timeout_; + } + +protected: + friend class ConfigurationBuilder; + + Configuration() = default; + +private: + std::string endpoints_; + CredentialsProviderPtr credentials_provider_; + std::chrono::milliseconds request_timeout_{ConfigurationDefaults::RequestTimeout}; +}; + +class ConfigurationBuilder { +public: + ConfigurationBuilder& withEndpoints(std::string endpoints); + + ConfigurationBuilder& withCredentialsProvider(std::shared_ptr provider); + + ConfigurationBuilder& withRequestTimeout(std::chrono::milliseconds request_timeout); + + Configuration build(); + +private: + Configuration configuration_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/include/CErrorMessage.h b/api/rocketmq/ConfigurationDefaults.h similarity index 75% rename from include/CErrorMessage.h rename to api/rocketmq/ConfigurationDefaults.h index 7d11b5638..08a256765 100644 --- a/include/CErrorMessage.h +++ b/api/rocketmq/ConfigurationDefaults.h @@ -14,19 +14,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once -#ifndef __CERROR_MESSAGE_H__ -#define __CERROR_MESSAGE_H__ +#include -#include "CCommon.h" +#include "RocketMQ.h" -#ifdef __cplusplus -extern "C" { -#endif +ROCKETMQ_NAMESPACE_BEGIN -ROCKETMQCLIENT_API const char* GetLatestErrorMessage(); // Return the last error message +class ConfigurationDefaults { +public: + /** + * @brief Default request-timeout: 3.0 seconds. + * + */ + static const std::chrono::milliseconds RequestTimeout; +}; -#ifdef __cplusplus -} -#endif -#endif //__CERROR_MESSAGE_H__ +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/include/MQAdmin.h b/api/rocketmq/ConsumeResult.h similarity index 77% rename from src/include/MQAdmin.h rename to api/rocketmq/ConsumeResult.h index 545dacb3d..5dcdf77ca 100644 --- a/src/include/MQAdmin.h +++ b/api/rocketmq/ConsumeResult.h @@ -14,15 +14,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once -#ifndef DEFAULTMQADMIN_H__ -#define DEFAULTMQADMIN_H__ -#include "DefaultMQClient.h" +#include -namespace rocketmq { -class MQAdmin : public DefaultMQClient { - public: - virtual ~MQAdmin() {} +#include "RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +enum class ConsumeResult : uint8_t { + SUCCESS = 0, + FAILURE = 1 }; -} // namespace rocketmq -#endif // DEFAULTMQADMIN_H__ \ No newline at end of file + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/Credentials.h b/api/rocketmq/Credentials.h new file mode 100644 index 000000000..1bd5dbcfc --- /dev/null +++ b/api/rocketmq/Credentials.h @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class Credentials { +public: + Credentials() : expiration_instant_(std::chrono::system_clock::time_point::max()) { + } + + Credentials(std::string access_key, std::string access_secret) + : access_key_(std::move(access_key)), access_secret_(std::move(access_secret)), + expiration_instant_(std::chrono::system_clock::time_point::max()) { + } + + Credentials(std::string access_key, std::string access_secret, std::string session_token, + std::chrono::system_clock::time_point expiration) + : access_key_(std::move(access_key)), access_secret_(std::move(access_secret)), + session_token_(std::move(session_token)), expiration_instant_(expiration) { + } + + bool operator==(const Credentials& rhs) const { + return access_key_ == rhs.access_key_ && access_secret_ == rhs.access_secret_ && + session_token_ == rhs.session_token_ && expiration_instant_ == rhs.expiration_instant_; + } + + bool operator!=(const Credentials& rhs) const { + return !(*this == rhs); + } + + bool empty() const { + return access_key_.empty() || access_secret_.empty(); + } + + bool expired() const { + return std::chrono::system_clock::now() > expiration_instant_; + } + + const std::string& accessKey() const { + return access_key_; + } + + const std::string& accessSecret() const { + return access_secret_; + } + + const std::string& sessionToken() const { + return session_token_; + } + + std::chrono::system_clock::time_point expirationInstant() const { + return expiration_instant_; + } + +private: + std::string access_key_; + std::string access_secret_; + std::string session_token_; + std::chrono::system_clock::time_point expiration_instant_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/CredentialsProvider.h b/api/rocketmq/CredentialsProvider.h new file mode 100644 index 000000000..595746f1c --- /dev/null +++ b/api/rocketmq/CredentialsProvider.h @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include + +#include "Credentials.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class CredentialsProvider { +public: + virtual ~CredentialsProvider() = default; + + virtual Credentials getCredentials() = 0; +}; + +using CredentialsProviderPtr = std::shared_ptr; + +class StaticCredentialsProvider : public CredentialsProvider { +public: + StaticCredentialsProvider(std::string access_key, std::string access_secret); + + ~StaticCredentialsProvider() override = default; + + Credentials getCredentials() override; + +private: + std::string access_key_; + std::string access_secret_; +}; + +/** + * Read credentials from environment variables ROCKETMQ_ACCESS_KEY, ROCKETMQ_ACCESS_SECRET + */ +class EnvironmentVariablesCredentialsProvider : public CredentialsProvider { +public: + EnvironmentVariablesCredentialsProvider(); + + ~EnvironmentVariablesCredentialsProvider() override = default; + + Credentials getCredentials() override; + + static const char* ENVIRONMENT_ACCESS_KEY; + static const char* ENVIRONMENT_ACCESS_SECRET; + +private: + std::string access_key_; + std::string access_secret_; +}; + +/** + * Read credentials from configuration file: ~/rocketmq/credentials. By default, the client library would refresh every + * 10 seconds. + */ +class ConfigFileCredentialsProvider : public CredentialsProvider { +public: + ConfigFileCredentialsProvider(); + + ConfigFileCredentialsProvider(std::string config_file, std::chrono::milliseconds refresh_interval); + + Credentials getCredentials() override; + + /** + * For test purpose only. + * @return + */ + static const char* credentialFile() { + return CREDENTIAL_FILE_; + } + +private: + std::chrono::system_clock::duration refresh_interval_{std::chrono::seconds(10)}; + std::string access_key_; + std::string access_secret_; + static const char* CREDENTIAL_FILE_; + static const char* ACCESS_KEY_FIELD_NAME; + static const char* ACCESS_SECRET_FIELD_NAME; +}; + +class StsCredentialsProviderImpl; + +class StsCredentialsProvider : public CredentialsProvider { +public: + explicit StsCredentialsProvider(std::string ram_role_name); + + Credentials getCredentials() override; + +private: + std::unique_ptr impl_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/status/ConsumeStats.h b/api/rocketmq/ErrorCategory.h similarity index 66% rename from src/status/ConsumeStats.h rename to api/rocketmq/ErrorCategory.h index e6f76a500..075266b86 100644 --- a/src/status/ConsumeStats.h +++ b/api/rocketmq/ErrorCategory.h @@ -14,29 +14,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once -#ifndef __CONSUMER_STATUS_H__ -#define __CONSUMER_STATUS_H__ +#include "ErrorCode.h" -#include "UtilAll.h" -#include "json/json.h" +ROCKETMQ_NAMESPACE_BEGIN -namespace rocketmq { -class ConsumeStats { - public: - ConsumeStats(); - virtual ~ConsumeStats() {} - Json::Value toJson() const; +class ErrorCategory : public std::error_category { +public: + static const ErrorCategory& instance() { + static ErrorCategory instance; + return instance; + } - public: - double pullRT; - double pullTPS; - double consumeRT; - double consumeOKTPS; - double consumeFailedTPS; - uint64 consumeFailedMsgs; -}; + const char* name() const noexcept override { + return "RocketMQ"; + } + + std::string message(int code) const override; -} // namespace rocketmq +private: + ErrorCategory() = default; +}; -#endif +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/ErrorCode.h b/api/rocketmq/ErrorCode.h new file mode 100644 index 000000000..5068c83c2 --- /dev/null +++ b/api/rocketmq/ErrorCode.h @@ -0,0 +1,183 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "RocketMQ.h" + +#include +#include +#include + +ROCKETMQ_NAMESPACE_BEGIN + +enum class ErrorCode : int { + Success = 0, + + /** + * @brief Client state not as expected. Call Producer#start() first. + * + */ + IllegalState = 1, + + /** + * @brief Broker has processed the request but is not going to return any content. + */ + NoContent = 204, + + /** + * @brief Bad configuration. For example, negative max-attempt-times. + * + */ + BadConfiguration = 300, + + /** + * @brief The server cannot process the request due to apprent client-side + * error. For example, topic contains invalid character or is excessively + * long. + * + */ + BadRequest = 400, + + /** + * @brief To publish FIFO messages, only synchronous API is supported. + */ + BadRequestAsyncPubFifoMessage = 40001, + + /** + * @brief Authentication failed. Possibly caused by invalid credentials. + * + */ + Unauthorized = 401, + + /** + * @brief Credentials are understood by server but authenticated user does not + * have privilege to perform the requested action. + * + */ + Forbidden = 403, + + /** + * @brief Topic not found, which should be created through console or + * administration API before hand. + * + */ + NotFound = 404, + + TopicNotFound = 404001, + + GroupNotFound = 404002, + + /** + * @brief Timeout when connecting, reading from or writing to brokers. + * + */ + RequestTimeout = 408, + + /** + * @brief Message body is too large. + * + */ + PayloadTooLarge = 413, + + /** + * @brief When trying to perform an action whose dependent procedure state is + * not right, this code will be used. + * 1. Acknowledge a message that is not previously received; + * 2. Commit/Rollback a transactional message that does not exist; + * 3. Commit an offset which is greater than maximum of partition; + */ + PreconditionRequired = 428, + + /** + * @brief Quota exchausted. The user has sent too many requests in a given + * amount of time. + * + */ + TooManyRequest = 429, + + /** + * @brief The server is unwilling to process the request because either an + * individual header field, or all the header fields collectively, are too + * large + * + */ + HeaderFieldsTooLarge = 431, + + /** + * @brief A server operator has received a legal demand to deny access to a + * resource or to a set of resources that includes the requested resource. + * + */ + UnavailableForLegalReasons = 451, + + /** + * @brief Server side interval error + * + */ + InternalServerError = 500, + + /** + * @brief The server either does not recognize the request method, or it lacks + * the ability to fulfil the request. + * + */ + NotImplemented = 501, + + /** + * @brief The server was acting as a gateway or proxy and received an invalid + * response from the upstream server. + * + */ + BadGateway = 502, + + /** + * @brief The server cannot handle the request (because it is overloaded or + * down for maintenance). Generally, this is a temporary state. + * + */ + ServiceUnavailable = 503, + + /** + * @brief The server was acting as a gateway or proxy and did not receive a + * timely response from the upstream server. + * + */ + GatewayTimeout = 504, + + /** + * @brief The server does not support the protocol version used in the + * request. + * + */ + ProtocolVersionNotSupported = 505, + + /** + * @brief The server is unable to store the representation needed to complete + * the request. + * + */ + InsufficientStorage = 507, +}; + +std::error_code make_error_code(ErrorCode code); + +ROCKETMQ_NAMESPACE_END + +namespace std { +template <> +struct is_error_code_enum : true_type {}; +} // namespace std \ No newline at end of file diff --git a/api/rocketmq/Executor.h b/api/rocketmq/Executor.h new file mode 100644 index 000000000..bbac1d0eb --- /dev/null +++ b/api/rocketmq/Executor.h @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +using Executor = std::function&)>; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/extern/CSendResult.cpp b/api/rocketmq/ExpressionType.h similarity index 83% rename from src/extern/CSendResult.cpp rename to api/rocketmq/ExpressionType.h index c43464a95..6c2848fe5 100644 --- a/src/extern/CSendResult.cpp +++ b/api/rocketmq/ExpressionType.h @@ -14,13 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once -#include "CSendResult.h" +#include -#ifdef __cplusplus -extern "C" { -#endif +#include "RocketMQ.h" -#ifdef __cplusplus -} -#endif +ROCKETMQ_NAMESPACE_BEGIN + +enum ExpressionType : int8_t +{ + TAG = 0, + SQL92 = 1 +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/FilterExpression.h b/api/rocketmq/FilterExpression.h new file mode 100644 index 000000000..19e910a48 --- /dev/null +++ b/api/rocketmq/FilterExpression.h @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "ExpressionType.h" +#include "Message.h" + +ROCKETMQ_NAMESPACE_BEGIN + +/** + * Server supported message filtering expression. At present, two types are supported: tag and SQL92. + */ +struct FilterExpression { + FilterExpression(std::string expression, ExpressionType expression_type = ExpressionType::TAG) + : content_(std::move(expression)), type_(expression_type), version_(std::chrono::steady_clock::now()) { + if (ExpressionType::TAG == type_ && content_.empty()) { + content_ = WILD_CARD_TAG; + } + } + + bool accept(const Message& message) const; + + std::string content_; + ExpressionType type_; + std::chrono::steady_clock::time_point version_; + + static const char* WILD_CARD_TAG; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/producer/StringIdMaker.h b/api/rocketmq/Logger.h similarity index 50% rename from src/producer/StringIdMaker.h rename to api/rocketmq/Logger.h index 0433b41d5..7518d19f7 100644 --- a/src/producer/StringIdMaker.h +++ b/api/rocketmq/Logger.h @@ -14,52 +14,59 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef __STRINGID_MAKER_H__ -#define __STRINGID_MAKER_H__ +#pragma once -#include +#include #include +#include +#include #include -#include +#include -namespace rocketmq { +#include "RocketMQ.h" -class StringIdMaker { - private: - StringIdMaker(); - ~StringIdMaker(); +#ifndef SPDLOG_ACTIVE_LEVEL +#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE +#endif - public: - static StringIdMaker& getInstance() { - // After c++11, the initialization occurs exactly once - static StringIdMaker singleton_; - return singleton_; - } +ROCKETMQ_NAMESPACE_BEGIN + +enum class Level : uint8_t +{ + Trace = 0, + Debug = 1, + Info = 2, + Warn = 3, + Error = 4 +}; - /* ID format: - * ip: 4 bytes - * pid: 2 bytes - * random: 4 bytes - * time: 4 bytes - * auto num: 2 bytes +class Logger { +public: + virtual ~Logger() = default; + + /** + * @brief Set log level for file sink. Its default log level is: Info. + * + * @param level */ - std::string createUniqID(); + virtual void setLevel(Level level) = 0; - private: - void setStartTime(uint64_t millis); + /** + * @brief Set log level for stdout, aka, console. Its default log level is: Warn. + * + * @param level + */ + virtual void setConsoleLevel(Level level) = 0; - static uint32_t getIP(); - static void hexdump(unsigned char* buffer, char* out_buff, std::size_t index); + virtual void setFileSize(std::size_t file_size) = 0; - private: - uint64_t mStartTime; - uint64_t mNextStartTime; - std::atomic mCounter; + virtual void setFileCount(std::size_t file_count) = 0; - char kFixString[21]; + virtual void setPattern(std::string pattern) = 0; - static const char sHexAlphabet[16]; + virtual void init() = 0; }; -} // namespace rocketmq -#endif +Logger& getLogger(); + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/MQClientException.h b/api/rocketmq/MQClientException.h new file mode 100644 index 000000000..f74c45f3c --- /dev/null +++ b/api/rocketmq/MQClientException.h @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include + +#include "RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class MQException : public std::exception { +public: + MQException(const std::string& msg, int error, const char* file, int line) noexcept + : m_error(error), m_line(line), m_file(file) { + try { + std::stringstream ss; + ss << "msg: " << msg << ",error:" << error << ",in file <" << file << "> line:" << line; + m_msg = ss.str(); + } catch (...) { + } + } + + MQException(const std::string& msg, int error, const char* file, const char* type, int line) noexcept + : m_error(error), m_line(line), m_file(file), m_type(type) { + try { + std::stringstream ss; + ss << "msg: " << msg << ",error:" << error << ",in file <" << file << "> line:" << line; + m_msg = ss.str(); + } catch (...) { + } + } + + ~MQException() noexcept override = default; + + const char* what() const noexcept override { + return m_msg.c_str(); + } + + int GetError() const noexcept { + return m_error; + } + + virtual const char* GetType() const noexcept { + return m_type.c_str(); + } + +protected: + int m_error; + int m_line; + std::string m_msg; + std::string m_file; + std::string m_type; +}; + +inline std::ostream& operator<<(std::ostream& os, const MQException& e) { + os << "Type: " << e.GetType() << " , " << e.what(); + return os; +} + +#define DEFINE_MQ_CLIENT_EXCEPTION(name) \ + class name : public MQException { \ + public: \ + name(const std::string& msg, int error, const char* file, int line) throw() \ + : MQException(msg, error, file, #name, line) { \ + } \ + virtual const char* GetType() const throw() { \ + return m_type.c_str(); \ + } \ + }; + +DEFINE_MQ_CLIENT_EXCEPTION(MQClientException) +DEFINE_MQ_CLIENT_EXCEPTION(MQBrokerException) +DEFINE_MQ_CLIENT_EXCEPTION(InterruptedException) +DEFINE_MQ_CLIENT_EXCEPTION(RemotingException) +DEFINE_MQ_CLIENT_EXCEPTION(UnknownHostException) + +#define THROW_MQ_EXCEPTION(e, msg, err) throw e(msg, err, __FILE__, __LINE__) +#define NEW_MQ_EXCEPTION(e, msg, err) e(msg, err, __FILE__, __LINE__) + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/Message.h b/api/rocketmq/Message.h new file mode 100644 index 000000000..0c2ef02a1 --- /dev/null +++ b/api/rocketmq/Message.h @@ -0,0 +1,180 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "RocketMQ.h" +#include "absl/types/optional.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class MessageBuilder; + +/** + * @brief Extension is intended for internal use only, which is subject to change without notice. + */ +struct Extension { + std::chrono::system_clock::time_point store_time{std::chrono::system_clock::now()}; + std::string store_host; + std::chrono::system_clock::time_point delivery_timepoint{std::chrono::system_clock::now()}; + std::uint16_t delivery_attempt{0}; + std::chrono::system_clock::time_point decode_time{std::chrono::system_clock::now()}; + std::chrono::system_clock::duration invisible_period{0}; + std::string receipt_handle; + std::string target_endpoint; + std::int32_t queue_id{0}; + std::int64_t offset{0}; + std::string nonce; + std::string transaction_id; +}; + +class Message { +public: + const std::string& id() const { + return id_; + } + + const std::string& topic() const { + return topic_; + } + + absl::optional tag() const { + if (tag_.empty()) { + return {}; + } + return absl::make_optional(tag_); + } + + const std::vector& keys() const { + return keys_; + } + + absl::optional traceContext() const { + if (trace_context_.empty()) { + return {}; + } + return absl::make_optional(trace_context_); + } + + void traceContext(std::string &&trace_context) { + trace_context_ = std::move(trace_context); + } + + const std::string& bornHost() const { + return born_host_; + } + + const std::chrono::system_clock::time_point& bornTime() const { + return born_time_; + } + + absl::optional deliveryTimestamp() const { + return delivery_timestamp_; + } + + const std::string& body() const { + return body_; + } + + const std::unordered_map& properties() const { + return properties_; + } + + absl::optional group() const { + if (group_.empty()) { + return {}; + } + return absl::make_optional(group_); + } + + const Extension& extension() const { + return extension_; + } + + Extension& mutableExtension() { + return extension_; + } + + static MessageBuilder newBuilder(); + +protected: + friend std::unique_ptr absl::make_unique(); + friend class MessageBuilder; + + Message(); + +private: + std::string id_; + std::string topic_; + std::string tag_; + std::vector keys_; + std::string trace_context_; + std::string born_host_; + std::chrono::system_clock::time_point born_time_{std::chrono::system_clock::now()}; + absl::optional delivery_timestamp_; + std::string body_; + std::unordered_map properties_; + std::string group_; + Extension extension_; +}; + +using MessagePtr = std::unique_ptr; +using MessageConstPtr = std::unique_ptr; +using MessageConstSharedPtr = std::shared_ptr; +using MessageSharedPtr = std::shared_ptr; + +class MessageBuilder { +public: + MessageBuilder(); + + MessageBuilder& withTopic(std::string topic); + + MessageBuilder& withTag(std::string tag); + + MessageBuilder& withKeys(std::vector keys); + + MessageBuilder& withTraceContext(std::string trace_context); + + MessageBuilder& withBody(std::string body); + + MessageBuilder& withGroup(std::string group); + + MessageBuilder& withProperties(std::unordered_map properties); + + MessageConstPtr build(); + +private: + friend class ClientManagerImpl; + + MessageBuilder& withId(std::string id); + + MessageBuilder& withBornTime(std::chrono::system_clock::time_point born_time); + + MessageBuilder& withBornHost(std::string born_host); + + MessagePtr message_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/MessageListener.h b/api/rocketmq/MessageListener.h new file mode 100644 index 000000000..cd5ef056e --- /dev/null +++ b/api/rocketmq/MessageListener.h @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "ConsumeResult.h" +#include "Message.h" + +ROCKETMQ_NAMESPACE_BEGIN + +using MessageListener = std::function; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/Producer.h b/api/rocketmq/Producer.h new file mode 100644 index 000000000..cb70065b5 --- /dev/null +++ b/api/rocketmq/Producer.h @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include +#include + +#include "Configuration.h" +#include "ErrorCode.h" +#include "Logger.h" +#include "Message.h" +#include "SendCallback.h" +#include "SendReceipt.h" +#include "TransactionChecker.h" + +ROCKETMQ_NAMESPACE_BEGIN + +/** + * This class employs pointer-to-implementation paradigm to achieve the goal of stable ABI. + * Refer https://en.cppreference.com/w/cpp/language/pimpl for an explanation. + */ +class ProducerImpl; + +class ProducerBuilder; + +/** + * @brief + * + */ +class Producer { +public: + static ProducerBuilder newBuilder(); + + /** + * @brief Send message synchronously. + * + * @param message Message to publish. Note the pointer, std::unique_ptr, is 'moved' into. + * @param ec Error code and message + * @return SendReceipt Receipt of the pub action if successful, which holds an identifier for the message. + */ + SendReceipt send(MessageConstPtr message, std::error_code& ec) noexcept; + + /** + * @brief Send message in asynchronous manner. + * + * @param message Message to send. Note the pointer, std::unique_ptr, is 'moved' into. + * @param callback Callback to execute on completion. + */ + void send(MessageConstPtr message, const SendCallback& callback) noexcept; + +private: + explicit Producer(std::shared_ptr impl) : impl_(std::move(impl)) { + } + + void start(); + + std::shared_ptr impl_; + + friend class ProducerBuilder; +}; + +class ProducerBuilder { +public: + ProducerBuilder(); + + ProducerBuilder& withConfiguration(Configuration configuration); + + ProducerBuilder& withTopics(const std::vector& topics); + + ProducerBuilder& withTransactionChecker(const TransactionChecker& checker); + + Producer build(); + +private: + std::shared_ptr impl_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/PushConsumer.h b/api/rocketmq/PushConsumer.h new file mode 100644 index 000000000..500c34b0f --- /dev/null +++ b/api/rocketmq/PushConsumer.h @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include + +#include "Configuration.h" +#include "CredentialsProvider.h" +#include "Executor.h" +#include "ExpressionType.h" +#include "FilterExpression.h" +#include "Logger.h" +#include "MessageListener.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class PushConsumerImpl; +class PushConsumerBuilder; + +class PushConsumer { +public: + static PushConsumerBuilder newBuilder(); + + void subscribe(std::string topic, FilterExpression filter_expression); + + void unsubscribe(const std::string& topic); + +private: + friend class PushConsumerBuilder; + + PushConsumer(std::shared_ptr impl) + : impl_(std::move(impl)) { + } + + std::shared_ptr impl_; +}; + +class PushConsumerBuilder { +public: + PushConsumerBuilder() : configuration_(Configuration::newBuilder().build()) {} + + PushConsumerBuilder &withConfiguration(Configuration configuration) { + configuration_ = std::move(configuration); + return *this; + } + + PushConsumerBuilder &withGroup(std::string group) { + group_ = std::move(group); + return *this; + } + + PushConsumerBuilder &withConsumeThreads(std::size_t consume_thread) { + consume_thread_ = consume_thread; + return *this; + } + + PushConsumerBuilder &withListener(MessageListener listener) { + listener_ = std::move(listener); + return *this; + } + + PushConsumerBuilder &subscribe(std::string topic, + FilterExpression filter_expression) { + subscriptions_.insert({topic, filter_expression}); + return *this; + } + + PushConsumer build(); + +private: + std::string group_; + Configuration configuration_; + std::size_t consume_thread_; + MessageListener listener_; + + std::unordered_map subscriptions_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/extern/CErrorMessage.cpp b/api/rocketmq/RocketMQ.h similarity index 75% rename from src/extern/CErrorMessage.cpp rename to api/rocketmq/RocketMQ.h index 420fbe261..bc8e10ba8 100644 --- a/src/extern/CErrorMessage.cpp +++ b/api/rocketmq/RocketMQ.h @@ -14,20 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once -#include "CErrorMessage.h" -#include "CCommon.h" -#include "MQClientErrorContainer.h" - -#ifdef __cplusplus -extern "C" { +#ifndef ROCKETMQ_NAMESPACE +#define ROCKETMQ_NAMESPACE rocketmq #endif -using namespace rocketmq; - -const char* GetLatestErrorMessage() { - return MQClientErrorContainer::getErr().c_str(); -} -#ifdef __cplusplus -}; -#endif \ No newline at end of file +#define ROCKETMQ_NAMESPACE_BEGIN namespace ROCKETMQ_NAMESPACE { +#define ROCKETMQ_NAMESPACE_END } \ No newline at end of file diff --git a/api/rocketmq/SendCallback.h b/api/rocketmq/SendCallback.h new file mode 100644 index 000000000..8468f6354 --- /dev/null +++ b/api/rocketmq/SendCallback.h @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include + +#include "RocketMQ.h" +#include "SendReceipt.h" + +ROCKETMQ_NAMESPACE_BEGIN + +using SendCallback = std::function; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/SendReceipt.h b/api/rocketmq/SendReceipt.h new file mode 100644 index 000000000..06a01ccbf --- /dev/null +++ b/api/rocketmq/SendReceipt.h @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include + +#include "RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +struct SendReceipt { + std::string message_id; + + std::string transaction_id; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/SimpleConsumer.h b/api/rocketmq/SimpleConsumer.h new file mode 100644 index 000000000..0f7030fd6 --- /dev/null +++ b/api/rocketmq/SimpleConsumer.h @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "Configuration.h" +#include "FilterExpression.h" +#include "Message.h" +#include "RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +using ReceiveCallback = std::function&)>; + +using AckCallback = std::function; + +using ChangeInvisibleDurationCallback = std::function; + +class SimpleConsumerImpl; + +class SimpleConsumerBuilder; + +class SimpleConsumer { +public: + ~SimpleConsumer(); + + static SimpleConsumerBuilder newBuilder(); + + void subscribe(std::string topic, FilterExpression filter_expression); + + void unsubscribe(const std::string& topic); + + void receive(std::size_t limit, + std::chrono::milliseconds invisible_duration, + std::error_code& ec, + std::vector& messages); + + void asyncReceive(std::size_t limit, std::chrono::milliseconds invisible_duration, ReceiveCallback callback); + + void ack(const Message& message, std::error_code& ec); + + void asyncAck(const Message& message, AckCallback callback); + + void changeInvisibleDuration(const Message& message, std::chrono::milliseconds duration, std::error_code& ec); + + void asyncChangeInvisibleDuration(const Message& message, + std::chrono::milliseconds duration, + ChangeInvisibleDurationCallback callback); + +private: + std::shared_ptr impl_; + + SimpleConsumer(std::string group); + + void start(); + + friend class SimpleConsumerBuilder; +}; + +class SimpleConsumerBuilder { +public: + SimpleConsumerBuilder(); + + SimpleConsumerBuilder& withGroup(std::string group) { + group_ = std::move(group); + return *this; + } + + SimpleConsumerBuilder& subscribe(std::string topic, FilterExpression expression) { + subscriptions_.insert({std::move(topic), std::move(expression)}); + return *this; + } + + SimpleConsumerBuilder& withConfiguration(Configuration configuration) { + configuration_ = std::move(configuration); + return *this; + } + + SimpleConsumer build(); + +private: + // Group name the consumer belongs to + std::string group_; + + Configuration configuration_; + + std::unordered_map subscriptions_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/State.h b/api/rocketmq/State.h new file mode 100644 index 000000000..8c8ca529b --- /dev/null +++ b/api/rocketmq/State.h @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +enum State : uint8_t +{ + CREATED = 0, + STARTING = 1, + STARTED = 2, + STOPPING = 3, + STOPPED = 4 +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/Tracing.h b/api/rocketmq/Tracing.h new file mode 100644 index 000000000..bc1236210 --- /dev/null +++ b/api/rocketmq/Tracing.h @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "opencensus/trace/sampler.h" + +#include "RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +opencensus::trace::Sampler* traceSampler() __attribute__((weak)); + +ROCKETMQ_NAMESPACE_END diff --git a/api/rocketmq/Transaction.h b/api/rocketmq/Transaction.h new file mode 100644 index 000000000..2728d12ce --- /dev/null +++ b/api/rocketmq/Transaction.h @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include + +#include "RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class Transaction { +public: + Transaction() = default; + + virtual ~Transaction() = default; + + virtual bool commit() = 0; + + virtual bool rollback() = 0; + + virtual const std::string& topic() const = 0; + + virtual const std::string& messageId() const = 0; + + virtual const std::string& transactionId() const = 0; + + virtual const std::string& traceContext() const = 0; + + virtual const std::string& endpoint() const = 0; +}; + +using TransactionPtr = std::unique_ptr; +using TransactionConstPtr = std::unique_ptr; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/TransactionChecker.h b/api/rocketmq/TransactionChecker.h new file mode 100644 index 000000000..604e7bd5f --- /dev/null +++ b/api/rocketmq/TransactionChecker.h @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "Message.h" +#include "TransactionState.h" + +ROCKETMQ_NAMESPACE_BEGIN + +using TransactionChecker = std::function; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/api/rocketmq/TransactionState.h b/api/rocketmq/TransactionState.h new file mode 100644 index 000000000..decdf2178 --- /dev/null +++ b/api/rocketmq/TransactionState.h @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +enum class TransactionState : int8_t { + COMMIT = 0, + ROLLBACK = 1, +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/libs/CMakeLists.txt b/bazel/BUILD.bazel old mode 100755 new mode 100644 similarity index 96% rename from libs/CMakeLists.txt rename to bazel/BUILD.bazel index 015951dcc..28e0699af --- a/libs/CMakeLists.txt +++ b/bazel/BUILD.bazel @@ -1,16 +1,16 @@ +# # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. - -add_subdirectory(signature) +# diff --git a/bazel/curl.bzl b/bazel/curl.bzl new file mode 100644 index 000000000..b83d054b8 --- /dev/null +++ b/bazel/curl.bzl @@ -0,0 +1,201 @@ +# Copyright 2018, OpenCensus Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Compiler options for building libcurl. + +BASE_CURL_COPTS = [ + # Disable everything else except HTTP protocol. + "-DHTTP_ONLY=1", + "-DENABLE_IPV6=1", + "-DGETHOSTNAME_TYPE_ARG2=size_t", + "-DGETSERVBYPORT_R_ARGS=6", + "-DGETSERVBYPORT_R_BUFSIZE=4096", + "-DHAVE_ALARM=1", + "-DHAVE_ALLOCA_H=1", + "-DHAVE_ARPA_INET_H=1", + "-DHAVE_ARPA_TFTP_H=1", + "-DHAVE_ASSERT_H=1", + "-DHAVE_BASENAME=1", + "-DHAVE_BOOL_T=1", + "-DHAVE_CLOCK_GETTIME_MONOTONIC=1", + "-DHAVE_CONNECT=1", + "-DHAVE_DLFCN_H=1", + "-DHAVE_ENGINE_LOAD_BUILTIN_ENGINES=1", + "-DHAVE_ERRNO_H=1", + "-DHAVE_FCNTL=1", + "-DHAVE_FCNTL_H=1", + "-DHAVE_FCNTL_O_NONBLOCK=1", + "-DHAVE_FDOPEN=1", + "-DHAVE_FREEADDRINFO=1", + "-DHAVE_FREEIFADDRS=1", + "-DHAVE_FSETXATTR=1", + "-DHAVE_FSETXATTR_5=1", + "-DHAVE_FTRUNCATE=1", + "-DHAVE_GAI_STRERROR=1", + "-DHAVE_GETADDRINFO=1", + "-DHAVE_GETADDRINFO_THREADSAFE=1", + "-DHAVE_GETEUID=1", + "-DHAVE_GETHOSTBYADDR=1", + "-DHAVE_GETHOSTBYADDR_R=1", + "-DHAVE_GETHOSTBYADDR_R_8=1", + "-DHAVE_GETHOSTBYNAME=1", + "-DHAVE_GETHOSTBYNAME_R=1", + "-DHAVE_GETHOSTBYNAME_R_6=1", + "-DHAVE_GETHOSTNAME=1", + "-DHAVE_GETIFADDRS=1", + "-DHAVE_GETNAMEINFO=1", + "-DHAVE_GETPPID=1", + "-DHAVE_GETPWUID=1", + "-DHAVE_GETPWUID_R=1", + "-DHAVE_GETRLIMIT=1", + "-DHAVE_GETSERVBYPORT_R=1", + "-DHAVE_GETTIMEOFDAY=1", + "-DHAVE_GMTIME_R=1", + "-DHAVE_IFADDRS_H=1", + "-DHAVE_IF_NAMETOINDEX=1", + "-DHAVE_INET_NTOP=1", + "-DHAVE_INET_PTON=1", + "-DHAVE_INTTYPES_H=1", + "-DHAVE_IOCTL=1", + "-DHAVE_IOCTL_FIONBIO=1", + "-DHAVE_IOCTL_SIOCGIFADDR=1", + "-DHAVE_LIBGEN_H=1", + "-DHAVE_LL=1", + "-DHAVE_LOCALE_H=1", + "-DHAVE_LOCALTIME_R=1", + "-DHAVE_LONGLONG=1", + "-DHAVE_MALLOC_H=1", + "-DHAVE_MEMORY_H=1", + "-DHAVE_NETDB_H=1", + "-DHAVE_NETINET_IN_H=1", + "-DHAVE_NETINET_TCP_H=1", + "-DHAVE_NET_IF_H=1", + "-DHAVE_PIPE=1", + "-DHAVE_POLL=1", + "-DHAVE_POLL_FINE=1", + "-DHAVE_POLL_H=1", + "-DHAVE_POSIX_STRERROR_R=1", + "-DHAVE_PTHREAD_H=1", + "-DHAVE_PWD_H=1", + "-DHAVE_RECV=1", + "-DHAVE_SELECT=1", + "-DHAVE_SEND=1", + "-DHAVE_SETJMP_H=1", + "-DHAVE_SETLOCALE=1", + "-DHAVE_SETRLIMIT=1", + "-DHAVE_SETSOCKOPT=1", + "-DHAVE_SGTTY_H=1", + "-DHAVE_SIGACTION=1", + "-DHAVE_SIGINTERRUPT=1", + "-DHAVE_SIGNAL=1", + "-DHAVE_SIGNAL_H=1", + "-DHAVE_SIGSETJMP=1", + "-DHAVE_SIG_ATOMIC_T=1", + "-DHAVE_SOCKADDR_IN6_SIN6_SCOPE_ID=1", + "-DHAVE_SOCKET=1", + "-DHAVE_SOCKETPAIR=1", + "-DHAVE_STDBOOL_H=1", + "-DHAVE_STDINT_H=1", + "-DHAVE_STDIO_H=1", + "-DHAVE_STDLIB_H=1", + "-DHAVE_STRCASECMP=1", + "-DHAVE_STRDUP=1", + "-DHAVE_STRERROR_R=1", + "-DHAVE_STRINGS_H=1", + "-DHAVE_STRING_H=1", + "-DHAVE_STRNCASECMP=1", + "-DHAVE_STRSTR=1", + "-DHAVE_STRTOK_R=1", + "-DHAVE_STRTOLL=1", + "-DHAVE_STRUCT_SOCKADDR_STORAGE=1", + "-DHAVE_STRUCT_TIMEVAL=1", + "-DHAVE_SYS_IOCTL_H=1", + "-DHAVE_SYS_PARAM_H=1", + "-DHAVE_SYS_POLL_H=1", + "-DHAVE_SYS_RESOURCE_H=1", + "-DHAVE_SYS_SELECT_H=1", + "-DHAVE_SYS_SOCKET_H=1", + "-DHAVE_SYS_STAT_H=1", + "-DHAVE_SYS_TIME_H=1", + "-DHAVE_SYS_TYPES_H=1", + "-DHAVE_SYS_UIO_H=1", + "-DHAVE_SYS_UN_H=1", + "-DHAVE_SYS_WAIT_H=1", + "-DHAVE_SYS_XATTR_H=1", + "-DHAVE_TERMIOS_H=1", + "-DHAVE_TERMIO_H=1", + "-DHAVE_TIME_H=1", + "-DHAVE_UNISTD_H=1", + "-DHAVE_UTIME=1", + "-DHAVE_UTIMES=1", + "-DHAVE_UTIME_H=1", + "-DHAVE_VARIADIC_MACROS_C99=1", + "-DHAVE_VARIADIC_MACROS_GCC=1", + "-DHAVE_WRITABLE_ARGV=1", + "-DHAVE_WRITEV=1", + "-DRECV_TYPE_ARG1=int", + "-DRECV_TYPE_ARG2=void*", + "-DRECV_TYPE_ARG3=size_t", + "-DRECV_TYPE_ARG4=int", + "-DRECV_TYPE_RETV=ssize_t", + "-DRETSIGTYPE=void", + "-DSELECT_QUAL_ARG5=", + "-DSELECT_TYPE_ARG1=int", + "-DSELECT_TYPE_ARG234=fd_set*", + "-DSELECT_TYPE_RETV=int", + "-DSEND_QUAL_ARG2=const", + "-DSEND_TYPE_ARG1=int", + "-DSEND_TYPE_ARG2=void*", + "-DSEND_TYPE_ARG3=size_t", + "-DSEND_TYPE_ARG4=int", + "-DSEND_TYPE_RETV=ssize_t", + "-DSIZEOF_CURL_OFF_T=8", + "-DSIZEOF_INT=4", + "-DSIZEOF_LONG=8", + "-DSIZEOF_OFF_T=8", + "-DSIZEOF_SHORT=2", + "-DSIZEOF_SIZE_T=8", + "-DSIZEOF_TIME_T=8", + "-DSTDC_HEADERS=1", + "-DSTRERROR_R_TYPE_ARG3=size_t", + "-DTIME_WITH_SYS_TIME=1", + "-DUSE_THREADS_POSIX=1", + "-DUSE_UNIX_SOCKETS=1", + + # Extra defines needed by curl + "-DBUILDING_LIBCURL", + "-DCURL_HIDDEN_SYMBOLS", +] + +LINUX_CURL_COPTS = [ + "-DHAVE_LINUX_TCP_H=1", + "-DHAVE_MSG_NOSIGNAL=1", +] + +CURL_COPTS = select({ + "//:windows": [ + # Disable everything else except HTTP protocol. + "/DHTTP_ONLY=1", + "/DCURL_STATICLIB", + "/DWIN32", + "/DBUILDING_LIBCURL", + "/DUSE_WIN32_IDN", + "/DWANT_IDN_PROTOTYPES", + "/DUSE_IPV6", + "/DUSE_WINDOWS_SSPI", + "/DUSE_SCHANNEL", + ], + "//:osx": BASE_CURL_COPTS, + "//conditions:default": BASE_CURL_COPTS + LINUX_CURL_COPTS, +}) diff --git a/bazel/rocketmq_deps.bzl b/bazel/rocketmq_deps.bzl new file mode 100644 index 000000000..39f364292 --- /dev/null +++ b/bazel/rocketmq_deps.bzl @@ -0,0 +1,170 @@ +"""Load dependencies needed to compile and test the RocketMQ library as a 3rd-party consumer.""" +load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +def rocketmq_deps(): + """Loads dependencies need to compile and test the RocketMQ library.""" + native.bind( + name = "opentelementry_api", + actual = "@com_github_opentelemetry//api:api", + ) + + if "rules_python" not in native.existing_rules(): + http_archive( + name = "rules_python", + sha256 = "cdf6b84084aad8f10bf20b46b77cb48d83c319ebe6458a18e9d2cebf57807cdd", + strip_prefix = "rules_python-0.8.1", + urls = [ + "https://shutian.oss-cn-hangzhou.aliyuncs.com/cdn/rules-python/rules_python-0.8.1.tar.gz", + "https://github.com/bazelbuild/rules_python/archive/refs/tags/0.8.1.tar.gz", + ], + ) + + if "com_google_googletest" not in native.existing_rules(): + http_archive( + name = "com_google_googletest", + sha256 = "b4870bf121ff7795ba20d20bcdd8627b8e088f2d1dab299a031c1034eddc93d5", + strip_prefix = "googletest-release-1.11.0", + urls = [ + "https://github.com/google/googletest/archive/refs/tags/release-1.11.0.tar.gz", + ], + ) + + if "com_github_gulrak_filesystem" not in native.existing_rules(): + http_archive( + name = "com_github_gulrak_filesystem", + strip_prefix = "filesystem-1.5.0", + sha256 = "eb6f3b0739908ad839cde68885d70e7324db191b9fad63d9915beaa40444d9cb", + urls = [ + "https://github.com/gulrak/filesystem/archive/v1.5.0.tar.gz", + ], + build_file = "@org_apache_rocketmq//third_party:filesystem.BUILD", + ) + + if "com_github_gabime_spdlog" not in native.existing_rules(): + http_archive( + name = "com_github_gabime_spdlog", + strip_prefix = "spdlog-1.9.2", + sha256 = "6fff9215f5cb81760be4cc16d033526d1080427d236e86d70bb02994f85e3d38", + urls = [ + "https://github.com/gabime/spdlog/archive/refs/tags/v1.9.2.tar.gz", + ], + build_file = "@org_apache_rocketmq//third_party:spdlog.BUILD", + ) + + if "com_github_fmtlib_fmt" not in native.existing_rules(): + http_archive( + name = "com_github_fmtlib_fmt", + strip_prefix = "fmt-8.0.1", + sha256 = "b06ca3130158c625848f3fb7418f235155a4d389b2abc3a6245fb01cb0eb1e01", + urls = [ + "https://github.com/fmtlib/fmt/archive/refs/tags/8.0.1.tar.gz", + ], + build_file = "@org_apache_rocketmq//third_party:fmtlib.BUILD", + ) + + if "com_google_protobuf" not in native.existing_rules(): + http_archive( + name = "com_google_protobuf", + sha256 = "8b28fdd45bab62d15db232ec404248901842e5340299a57765e48abe8a80d930", + strip_prefix = "protobuf-3.20.1", + urls = [ + "https://shutian.oss-cn-hangzhou.aliyuncs.com/cdn/protobuf/protobuf-3.20.1.tar.gz", + "https://github.com/protocolbuffers/protobuf/archive/refs/tags/v3.20.1.tar.gz", + ], + ) + + if "rules_proto_grpc" not in native.existing_rules(): + http_archive( + name = "rules_proto_grpc", + sha256 = "507e38c8d95c7efa4f3b1c0595a8e8f139c885cb41a76cab7e20e4e67ae87731", + strip_prefix = "rules_proto_grpc-4.1.1", + urls = [ + "https://shutian.oss-cn-hangzhou.aliyuncs.com/cdn/rules_proto_grpc/rules_proto_grpc-4.1.1.tar.gz", + "https://github.com/rules-proto-grpc/rules_proto_grpc/archive/refs/tags/4.1.1.tar.gz" + ], + ) + + maybe( + http_archive, + name = "io_opencensus_cpp", + sha256 = "317f2bfdaba469561c7e64b1a55282b87e677c109c9d8877097940e6d5cbca08", + urls = [ + "https://shutian.oss-cn-hangzhou.aliyuncs.com/cdn/opencensus-cpp/opencensus-cpp-0.4.1.tar.gz", + "https://github.com/lizhanhui/opencensus-cpp/archive/refs/tags/v0.4.1.tar.gz", + ], + strip_prefix = "opencensus-cpp-0.4.1", + ) + + if "com_google_absl" not in native.existing_rules(): + http_archive( + name = "com_google_absl", + sha256 = "dcf71b9cba8dc0ca9940c4b316a0c796be8fab42b070bb6b7cab62b48f0e66c4", + strip_prefix = "abseil-cpp-20211102.0", + urls = [ + "https://shutian.oss-cn-hangzhou.aliyuncs.com/cdn/abseil/abseil-cpp-20211102.0.tar.gz", + "https://github.com/abseil/abseil-cpp/archive/refs/tags/20211102.0.tar.gz", + ], + ) + + if "com_github_grpc_grpc" not in native.existing_rules(): + http_archive( + name = "com_github_grpc_grpc", + strip_prefix = "grpc-1.46.0", + sha256 = "67423a4cd706ce16a88d1549297023f0f9f0d695a96dd684adc21e67b021f9bc", + urls = [ + "https://shutian.oss-cn-hangzhou.aliyuncs.com/cdn/grpc/grpc-1.46.0.tar.gz", + "https://github.com/grpc/grpc/archive/refs/tags/v1.46.0.tar.gz", + ], + ) + + maybe( + http_archive, + name = "asio", + sha256 = "c864363205f78768c795ba14a9989200075e732f877ddef01a19237c2eccf44b", + build_file = "@org_apache_rocketmq//third_party:asio.BUILD", + strip_prefix = "asio-1.18.2", + urls = [ + "https://github.com/lizhanhui/asio/archive/refs/tags/v1.18.2.tar.gz", + ], + ) + + maybe( + http_archive, + name = "com_github_yhirose_cpp_httplib", + sha256 = "0ff62e28eb0f6e563178d44b77c94dddb8702141d83dd34b83cb046399c2b1d5", + build_file = "@org_apache_rocketmq//third_party:cpp_httplib.BUILD", + strip_prefix = "cpp-httplib-0.9.4", + urls = ["https://github.com/yhirose/cpp-httplib/archive/refs/tags/v0.9.4.tar.gz"], + ) + + maybe( + http_archive, + name = "com_google_googleapis", + sha256 = "e89f15d54b0ddab0cd41d18cb2299e5447db704e2b05ff141cb1769170671466", + urls = [ + "https://github.com/googleapis/googleapis/archive/af7fb72df59a814221b123a4d1acb3f6c3e6cc95.zip" + ], + strip_prefix = "googleapis-af7fb72df59a814221b123a4d1acb3f6c3e6cc95", + ) + + maybe( + http_archive, + name = "hedron_compile_commands", + sha256 = "4f69ccafa253825d93191977dcbcecee74e576aadbd21f1cfb25a19111ecdf21", + urls = [ + "https://shutian.oss-cn-hangzhou.aliyuncs.com/cdn/bazel-compile-commands-extractor/bazel-compile-commands-extractor-1.0.tar.gz", + "https://github.com/lizhanhui/bazel-compile-commands-extractor/archive/refs/tags/v1.0.tar.gz", + ], + strip_prefix = "bazel-compile-commands-extractor-1.0", + ) + + maybe( + http_archive, + name = "rules_swift", + urls = [ + "https://shutian.oss-cn-hangzhou.aliyuncs.com/cdn/rules_swift/rules_swift-0.27.0.tar.gz", + "https://github.com/bazelbuild/rules_swift/archive/refs/tags/0.27.0.tar.gz", + ], + strip_prefix = "rules_swift-0.27.0", + ) \ No newline at end of file diff --git a/build.sh b/build.sh deleted file mode 100755 index be500a6cd..000000000 --- a/build.sh +++ /dev/null @@ -1,532 +0,0 @@ -#!/usr/bin/env bash - -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. - -basepath=$( - cd $(dirname $0) - pwd -) -declare down_dir="${basepath}/tmp_down_dir" -declare build_dir="${basepath}/tmp_build_dir" -declare packet_dir="${basepath}/tmp_packet_dir" -declare install_lib_dir="${basepath}/bin" -declare static_package_dir="${basepath}/tmp_static_package_dir" -declare fname_openssl="openssl*.tar.gz" - -declare fname_libevent="libevent*.zip" -declare fname_jsoncpp="jsoncpp*.zip" -declare fname_boost="boost*.tar.gz" -declare fname_openssl_down="openssl-1.1.1d.tar.gz" -declare fname_libevent_down="release-2.1.11-stable.zip" -declare fname_jsoncpp_down="0.10.7.zip" -declare fname_boost_down="1.78.0/boost_1_78_0.tar.gz" - -PrintParams() { - echo "=========================================one key build help============================================" - echo "sh build.sh [no build libevent:noEvent] [no build json:noJson] [no build boost:noBoost] [ execution test:test]" - echo "usage: sh build.sh noJson noEvent noBoost test" - echo "=========================================one key build help============================================" - echo "" -} - -if test "$(uname)" = "Linux"; then - declare cpu_num=$(cat /proc/cpuinfo | grep "processor" | wc -l) -elif test "$(uname)" = "Darwin" ; then - declare cpu_num=$(sysctl -n machdep.cpu.thread_count) -fi - -declare need_build_openssl=1 -declare need_build_libevent=1 -declare need_build_jsoncpp=1 -declare need_build_boost=1 -declare enable_asan=0 -declare enable_lsan=0 -declare verbose=1 -declare codecov=0 -declare debug=0 -declare test=0 - -pasres_arguments() { - for var in "$@"; do - case "$var" in - noOpenSSL) - need_build_openssl=0 - ;; - noEvent) - need_build_libevent=0 - ;; - noJson) - need_build_jsoncpp=0 - ;; - noBoost) - need_build_boost=0 - ;; - asan) - enable_asan=1 - ;; - lsan) - enable_lsan=1 - ;; - noVerbose) - verbose=0 - ;; - codecov) - codecov=1 - ;; - debug) - debug=1 - ;; - test) - test=1 - ;; - esac - done - -} -pasres_arguments $@ - -PrintParams() { - echo "###########################################################################" - if [ $need_build_openssl -eq 0 ]; then - echo "no need build openssl lib" - else - echo "need build openssl lib" - fi - if [ $need_build_jsoncpp -eq 0 ]; then - echo "no need build jsoncpp lib" - else - echo "need build jsoncpp lib" - fi - if [ $need_build_libevent -eq 0 ]; then - echo "no need build libevent lib" - else - echo "need build libevent lib" - fi - if [ $need_build_boost -eq 0 ]; then - echo "no need build boost lib" - else - echo "need build boost lib" - fi - if [ $enable_asan -eq 1 ]; then - echo "enable asan reporting" - else - echo "disable asan reporting" - fi - if [ $enable_lsan -eq 1 ]; then - echo "enable lsan reporting" - else - echo "disable lsan reporting" - fi - if [ $verbose -eq 0 ]; then - echo "no need print detail logs" - else - echo "need print detail logs" - fi - if [ $codecov -eq 1 ]; then - echo "run unit tests with code coverage" - else - echo "run unit tests without code coverage" - fi - if [ $debug -eq 1 ]; then - echo "enable debug" - else - echo "disable debug" - fi - if [ $test -eq 1 ]; then - echo "build unit tests" - else - echo "without build unit tests" - fi - - echo "###########################################################################" - echo "" -} - -Prepare() { - if [ -e ${down_dir} ]; then - echo "${down_dir} exists" - #cd ${down_dir} - #ls |grep -v ${fname_libevent} |grep -v ${fname_jsoncpp} | grep -v ${fname_boost} |xargs rm -rf - else - mkdir -p ${down_dir} - fi - - cd ${basepath} - if [ -e ${fname_openssl} ]; then - mv -f ${basepath}/${fname_openssl} ${down_dir} - fi - - if [ -e ${fname_libevent} ]; then - mv -f ${basepath}/${fname_libevent} ${down_dir} - fi - - if [ -e ${fname_jsoncpp} ]; then - mv -f ${basepath}/${fname_jsoncpp} ${down_dir} - fi - - if [ -e ${fname_boost} ]; then - mv -f ${basepath}/${fname_boost} ${down_dir} - fi - - if [ -e ${build_dir} ]; then - echo "${build_dir} exists" - #rm -rf ${build_dir}/* - else - mkdir -p ${build_dir} - fi - - if [ -e ${packet_dir} ]; then - echo "${packet_dir} exists" - #rm -rf ${packet_dir}/* - else - mkdir -p ${packet_dir} - fi - - if [ -e ${install_lib_dir} ]; then - echo "${install_lib_dir} exists" - else - mkdir -p ${install_lib_dir} - fi -} - -BuildOpenSSL() { - if [ $need_build_openssl -eq 0 ]; then - echo "no need build openssl lib" - return 0 - fi - - cd ${down_dir} - if [ -e ${fname_openssl} ]; then - echo "${fname_openssl} exists" - else - wget https://www.openssl.org/source/old/1.1.1/${fname_openssl_down} -O ${fname_openssl_down} --no-check-certificate - fi - tar -zxvf ${fname_openssl} &> unzipopenssl.txt - if [ $? -ne 0 ]; then - exit 1 - fi - - openssl_dir=$(ls | grep ^openssl | grep .*[^gz]$) - cd ${openssl_dir} - if [ $? -ne 0 ]; then - exit 1 - fi - echo "build openssl static #####################" - if [ $verbose -eq 0 ]; then - ./config shared CFLAGS=-fPIC CPPFLAGS=-fPIC --prefix=${install_lib_dir} --openssldir=${install_lib_dir} &> opensslconfig.txt - else - ./config shared CFLAGS=-fPIC CPPFLAGS=-fPIC --prefix=${install_lib_dir} --openssldir=${install_lib_dir} - fi - if [ $? -ne 0 ]; then - exit 1 - fi - if [ $verbose -eq 0 ]; then - echo "build openssl without detail log." - make depend &> opensslbuild.txt - make -j $cpu_num &> opensslbuild.txt - else - make depend - make -j $cpu_num - fi - if [ $? -ne 0 ]; then - exit 1 - fi - make install - echo "build openssl success." -} - -BuildLibevent() { - if [ $need_build_libevent -eq 0 ]; then - echo "no need build libevent lib" - return 0 - fi - - cd ${down_dir} - if [ -e ${fname_libevent} ]; then - echo "${fname_libevent} exists" - else - wget https://github.com/libevent/libevent/archive/${fname_libevent_down} -O libevent-${fname_libevent_down} - fi - unzip -o ${fname_libevent} &> unziplibevent.txt - if [ $? -ne 0 ]; then - exit 1 - fi - - libevent_dir=$(ls | grep ^libevent | grep .*[^zip^txt]$) - cd ${libevent_dir} - if [ $? -ne 0 ]; then - exit 1 - fi - ./autogen.sh - if [ $? -ne 0 ]; then - exit 1 - fi - echo "build libevent static #####################" - if [ $verbose -eq 0 ]; then - ./configure --enable-static=yes --enable-shared=no CFLAGS="-fPIC -I${install_lib_dir}/include" CPPFLAGS="-fPIC -I${install_lib_dir}/include" LDFLAGS="-L${install_lib_dir}/lib" --prefix=${install_lib_dir} &> libeventconfig.txt - else - ./configure --enable-static=yes --enable-shared=no CFLAGS="-fPIC -I${install_lib_dir}/include" CPPFLAGS="-fPIC -I${install_lib_dir}/include" LDFLAGS="-L${install_lib_dir}/lib" --prefix=${install_lib_dir} - fi - if [ $? -ne 0 ]; then - exit 1 - fi - if [ $verbose -eq 0 ]; then - echo "build libevent without detail log." - make -j $cpu_num &> libeventbuild.txt - else - make -j $cpu_num - fi - if [ $? -ne 0 ]; then - exit 1 - fi - make install - echo "build linevent success." -} - -BuildJsonCPP() { - if [ $need_build_jsoncpp -eq 0 ]; then - echo "no need build jsoncpp lib" - return 0 - fi - - cd ${down_dir} - - if [ -e ${fname_jsoncpp} ]; then - echo "${fname_jsoncpp} exists" - else - wget https://github.com/open-source-parsers/jsoncpp/archive/${fname_jsoncpp_down} -O jsoncpp-${fname_jsoncpp_down} - fi - unzip -o ${fname_jsoncpp} &> unzipjsoncpp.txt - if [ $? -ne 0 ]; then - exit 1 - fi - jsoncpp_dir=$(ls | grep ^jsoncpp | grep .*[^zip]$) - cd ${jsoncpp_dir} - if [ $? -ne 0 ]; then - exit 1 - fi - mkdir build - cd build - echo "build jsoncpp static ######################" - if [ $verbose -eq 0 ]; then - echo "build jsoncpp without detail log." - cmake .. -DCMAKE_CXX_FLAGS=-fPIC -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=${install_lib_dir} &> jsoncppbuild.txt - else - cmake .. -DCMAKE_CXX_FLAGS=-fPIC -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=${install_lib_dir} - fi - if [ $? -ne 0 ]; then - exit 1 - fi - if [ $verbose -eq 0 ]; then - make -j $cpu_num &> jsoncppbuild.txt - else - make -j $cpu_num - fi - if [ $? -ne 0 ]; then - exit 1 - fi - make install - echo "build jsoncpp success." - if [ ! -f ${install_lib_dir}/lib/libjsoncpp.a ]; then - echo " ./bin/lib directory is not libjsoncpp.a" - cp ${install_lib_dir}/lib/x86_64-linux-gnu/libjsoncpp.a ${install_lib_dir}/lib/ - fi -} - -BuildBoost() { - if [ $need_build_boost -eq 0 ]; then - echo "no need build boost lib" - return 0 - fi - - cd ${down_dir} - if [ -e ${fname_boost} ]; then - echo "${fname_boost} exists" - else - wget http://sourceforge.net/projects/boost/files/boost/${fname_boost_down} --no-check-certificate - fi - tar -zxvf ${fname_boost} &> unzipboost.txt - boost_dir=$(ls | grep ^boost | grep .*[^gz]$) - cd ${boost_dir} - if [ $? -ne 0 ]; then - exit 1 - fi - ./bootstrap.sh - if [ $? -ne 0 ]; then - exit 1 - fi - echo "build boost static #####################" - pwd - if [ $verbose -eq 0 ]; then - echo "build boost without detail log." - ./b2 -j$cpu_num cflags=-fPIC cxxflags=-fPIC --with-atomic --with-thread --with-system --with-chrono --with-date_time --with-log --with-regex --with-serialization --with-filesystem --with-locale --with-iostreams threading=multi link=static release install --prefix=${install_lib_dir} &> boostbuild.txt - else - ./b2 -j$cpu_num cflags=-fPIC cxxflags=-fPIC --with-atomic --with-thread --with-system --with-chrono --with-date_time --with-log --with-regex --with-serialization --with-filesystem --with-locale --with-iostreams threading=multi link=static release install --prefix=${install_lib_dir} - fi - if [ $? -ne 0 ]; then - exit 1 - fi -} - -BuildRocketMQClient() { - cd ${build_dir} - echo "============start to build rocketmq client cpp.=========" - local ROCKETMQ_CMAKE_FLAG="" - if [ $test -eq 1 ]; then - if [ $codecov -eq 1 ]; then - ROCKETMQ_CMAKE_FLAG=$ROCKETMQ_CMAKE_FLAG" -DRUN_UNIT_TEST=ON -DCODE_COVERAGE=ON" - else - ROCKETMQ_CMAKE_FLAG=$ROCKETMQ_CMAKE_FLAG" -DRUN_UNIT_TEST=ON -DCODE_COVERAGE=OFF" - fi - else - ROCKETMQ_CMAKE_FLAG=$ROCKETMQ_CMAKE_FLAG" -DRUN_UNIT_TEST=OFF -DCODE_COVERAGE=OFF" - fi - if [ $enable_asan -eq 1 ]; then - ROCKETMQ_CMAKE_FLAG=$ROCKETMQ_CMAKE_FLAG" -DENABLE_ASAN=ON" - else - ROCKETMQ_CMAKE_FLAG=$ROCKETMQ_CMAKE_FLAG" -DENABLE_ASAN=OFF" - fi - if [ $enable_lsan -eq 1 ]; then - ROCKETMQ_CMAKE_FLAG=$ROCKETMQ_CMAKE_FLAG" -DENABLE_LSAN=ON" - else - ROCKETMQ_CMAKE_FLAG=$ROCKETMQ_CMAKE_FLAG" -DENABLE_LSAN=OFF" - fi - if [ $debug -eq 1 ]; then - ROCKETMQ_CMAKE_FLAG=$ROCKETMQ_CMAKE_FLAG" -DCMAKE_BUILD_TYPE=Debug" - else - ROCKETMQ_CMAKE_FLAG=$ROCKETMQ_CMAKE_FLAG" -DCMAKE_BUILD_TYPE=Release" - fi - cmake .. $ROCKETMQ_CMAKE_FLAG - if [ $verbose -eq 0 ]; then - echo "build rocketmq without detail log." - make -j $cpu_num &> buildclient.txt - else - make -j $cpu_num - fi - if [ $? -ne 0 ]; then - echo "build error....." - exit 1 - fi - #sudo make install - PackageRocketMQStatic -} - -BuildGoogleTest() { - if [ $test -eq 0 ]; then - echo "no need build google test lib" - return 0 - fi - if [ -f ./bin/lib/libgtest.a ]; then - echo "GTest already exists, no need build" - return 0 - fi - cd ${down_dir} - if [ -e release-1.8.1.tar.gz ]; then - echo "${fname_boost} exists" - else - wget https://github.com/abseil/googletest/archive/release-1.8.1.tar.gz - fi - if [ ! -d "googletest-release-1.8.1" ]; then - tar -zxvf release-1.8.1.tar.gz &> googletest.txt - fi - cd googletest-release-1.8.1 - mkdir -p build - cd build - echo "build googletest static #####################" - if [ $verbose -eq 0 ]; then - echo "build googletest without detail log." - cmake .. -DCMAKE_CXX_FLAGS=-fPIC -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=${install_lib_dir} &> googletestbuild.txt - else - cmake .. -DCMAKE_CXX_FLAGS=-fPIC -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=${install_lib_dir} - fi - if [ $? -ne 0 ]; then - exit 1 - fi - if [ $verbose -eq 0 ]; then - make -j $cpu_num &> gtestbuild.txt - else - make -j $cpu_num - fi - if [ $? -ne 0 ]; then - exit 1 - fi - make install - - if [ ! -f ${install_lib_dir}/lib/libgtest.a ]; then - echo " ./bin/lib directory is not libgtest.a" - cp ${install_lib_dir}/lib64/lib* ${install_lib_dir}/lib - fi -} - -ExecutionTesting() { - if [ $test -eq 0 ]; then - echo "Build success without executing unit tests." - return 0 - fi - echo "############# unit test start ###########" - cd ${build_dir} - if [ $verbose -eq 0 ]; then - ctest - else - ctest -V - fi - if [ $? -ne 0 ]; then - echo "############# unit test failed ###########" - exit 1 - fi - echo "############# unit test finish ###########" -} - -PackageRocketMQStatic() { - echo "############# Start package static rocketmq library. #############" - if test "$(uname)" = "Linux"; then - #packet libevent,jsoncpp,boost,rocketmq,Signature to one librocketmq.a - cp -f ${basepath}/libs/signature/lib/libSignature.a ${install_lib_dir}/lib - ar -M <${basepath}/package_rocketmq.mri - cp -f librocketmq.a ${install_lib_dir} - elif test "$(uname)" = "Darwin" ; then - mkdir -p ${static_package_dir} - cd ${static_package_dir} - cp -f ${basepath}/libs/signature/lib/libSignature.a . - cp -f ${install_lib_dir}/lib/lib*.a . - cp -f ${install_lib_dir}/librocketmq.a . - echo "Md5 Hash RocketMQ Before:" - md5sum librocketmq.a - local dir=`ls *.a | grep -E 'gtest|gmock'` - for i in $dir - do - rm -rf $i - done - libtool -no_warning_for_no_symbols -static -o librocketmq.a *.a - echo "Md5 Hash RocketMQ After:" - md5sum librocketmq.a - echo "Try to copy $(pwd)/librocketmq.a to ${install_lib_dir}/" - cp -f librocketmq.a ${install_lib_dir}/ - cd ${basepath} - rm -rf ${static_package_dir} - fi - echo "############# Package static rocketmq library success.#############" -} - -PrintParams -Prepare -BuildOpenSSL -BuildLibevent -BuildJsonCPP -BuildBoost -BuildGoogleTest -BuildRocketMQClient -ExecutionTesting diff --git a/ci/build.sh b/ci/build.sh new file mode 100755 index 000000000..3b48b7d66 --- /dev/null +++ b/ci/build.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +CI_DIR=$(dirname "$0") +BASE_DIR=$(pwd $CI_DIR/..) + +cd $BASE_DIR +mkdir _build +cd _build +cmake .. +make -j $(nproc) +ctest \ No newline at end of file diff --git a/cmake/FindJsoncpp.cmake b/cmake/FindJsoncpp.cmake deleted file mode 100755 index 963211811..000000000 --- a/cmake/FindJsoncpp.cmake +++ /dev/null @@ -1,95 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. - -# Find jsoncpp -# -# Find the jsoncpp includes and library -# -# if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH -# -# -*- cmake -*- -# - Find JSONCpp -# Find the JSONCpp includes and library -# This module defines -# JSONCPP_INCLUDE_DIRS, where to find json.h, etc. -# JSONCPP_LIBRARIES, the libraries needed to use jsoncpp. -# JSONCPP_FOUND, If false, do not try to use jsoncpp. -# also defined, but not for general use are -# JSONCPP_LIBRARIES, where to find the jsoncpp library. - -# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES -if( JSONCPP_USE_STATIC_LIBS ) - set(_jsoncpp_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES :${CMAKE_FIND_LIBRARY_SUFFIXES}) - if(WIN32) - list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .lib .a) - else() - set(CMAKE_FIND_LIBRARY_SUFFIXES .a) - endif() -else() - set(_jsoncpp_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES :${CMAKE_FIND_LIBRARY_SUFFIXES}) - if(WIN32) - list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .dll .so) - else() - set(CMAKE_FIND_LIBRARY_SUFFIXES .so) - endif() -endif() - -FIND_PATH(JSONCPP_INCLUDE_DIRS -NAMES - json.h - json/json.h -PATHS - ${CMAKE_SOURCE_DIR}/bin/include - C:/jsoncpp/include - ${CMAKE_SOURCE_DIR}/win32-deps/include - C:/jsoncpp-0.10.6/include -PATH_SUFFIXES jsoncpp -) - -find_library(JSONCPP_LIBRARIES - NAMES jsoncpp - PATHS ${CMAKE_SOURCE_DIR}/bin/lib C:/jsoncpp/lib ${CMAKE_SOURCE_DIR}/win32-deps/lib C:/jsoncpp-0.10.6/ -) -IF (JSONCPP_LIBRARIES AND JSONCPP_INCLUDE_DIRS) - SET(JSONCPP_LIBRARIES ${JSONCPP_LIBRARIES}) - SET(JSONCPP_FOUND "YES") -ELSE (JSONCPP_LIBRARIES AND JSONCPP_INCLUDE_DIRS) - SET(JSONCPP_FOUND "NO") -ENDIF (JSONCPP_LIBRARIES AND JSONCPP_INCLUDE_DIRS) - - -IF (JSONCPP_FOUND) - IF (NOT JSONCPP_FIND_QUIETLY) - MESSAGE(STATUS "Found JSONCpp: ${JSONCPP_LIBRARIES}") - ENDIF (NOT JSONCPP_FIND_QUIETLY) -ELSE (JSONCPP_FOUND) - IF (JSONCPP_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find JSONCPP library include: ${JSONCPP_INCLUDE_DIRS}, lib: ${JSONCPP_LIBRARIES}") - ENDIF (JSONCPP_FIND_REQUIRED) -ENDIF (JSONCPP_FOUND) - -# Deprecated declarations. -SET (NATIVE_JSONCPP_INCLUDE_PATH ${JSONCPP_INCLUDE_DIRS} ) -GET_FILENAME_COMPONENT (NATIVE_JSONCPP_LIB_PATH ${JSONCPP_LIBRARIES} PATH) - -MARK_AS_ADVANCED( - JSONCPP_LIBRARIES - JSONCPP_INCLUDE_DIRS - ) - -# Restore the original find library ordering -if( JSONCPP_USE_STATIC_LIBS ) - set(CMAKE_FIND_LIBRARY_SUFFIXES ${_jsoncpp_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) -endif() diff --git a/cmake/FindLibevent.cmake b/cmake/FindLibevent.cmake deleted file mode 100755 index c013d4981..000000000 --- a/cmake/FindLibevent.cmake +++ /dev/null @@ -1,152 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. - -# - Try to find libevent -#.rst -# FindLibevent -# ------------ -# -# Find Libevent include directories and libraries. Invoke as:: -# -# find_package(Libevent -# [version] [EXACT] # Minimum or exact version -# [REQUIRED] # Fail if Libevent is not found -# [COMPONENT ...]) # Libraries to look for -# -# Valid components are one or more of:: libevent core extra pthreads openssl. -# Note that 'libevent' contains both core and extra. You must specify one of -# them for the other components. -# -# This module will define the following variables:: -# -# LIBEVENT_FOUND - True if headers and requested libraries were found -# LIBEVENT_INCLUDE_DIRS - Libevent include directories -# LIBEVENT_LIBRARIES - Libevent libraries to be linked -# LIBEVENT__FOUND - Component was found ( is uppercase) -# LIBEVENT__LIBRARY - Library to be linked for Libevent component . - -find_package(PkgConfig QUIET) -pkg_check_modules(PC_LIBEVENT QUIET libevent) - -# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES -if( Libevent_USE_STATIC_LIBS ) - set(_libevent_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES :${CMAKE_FIND_LIBRARY_SUFFIXES}) - if(WIN32) - list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .lib .a) - else() - set(CMAKE_FIND_LIBRARY_SUFFIXES .a) - endif() -else() - set(_libevent_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES :${CMAKE_FIND_LIBRARY_SUFFIXES}) - if(WIN32) - list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .dll .so) - else() - set(CMAKE_FIND_LIBRARY_SUFFIXES .so) - endif() -endif() -# Look for the Libevent 2.0 or 1.4 headers -find_path(LIBEVENT_INCLUDE_DIR - NAMES - WIN32-Code/event2/event-config.h - event2/event-config.h - event-config.h - PATHS ${CMAKE_SOURCE_DIR}/bin/include C:/libevent/include ${CMAKE_SOURCE_DIR}/win32-deps/include - HINTS - ${PC_LIBEVENT_INCLUDE_DIRS} -) - -# ------------------------------------------------------------------------ -# Prefix initialization -# ------------------------------------------------------------------------ -set(Libevent_LIB_PREFIX "") -set(LIBEVENT_EVENT_CONFIG_DIR ${LIBEVENT_INCLUDE_DIR}) -if(WIN32) - set(Libevent_LIB_PREFIX "lib") - set(LIBEVENT_EVENT_CONFIG_DIR "${LIBEVENT_INCLUDE_DIR}/../WIN32-Code/") -endif() - -if(LIBEVENT_INCLUDE_DIR) - set(_version_regex "^#define[ \t]+_EVENT_VERSION[ \t]+\"([^\"]+)\".*") - if(EXISTS "${LIBEVENT_EVENT_CONFIG_DIR}/event2/event-config.h") - # Libevent 2.0 - file(STRINGS "${LIBEVENT_EVENT_CONFIG_DIR}/event2/event-config.h" - LIBEVENT_VERSION REGEX "${_version_regex}") - else() - # Libevent 1.4 - if(EXISTS "${LIBEVENT_EVENT_CONFIG_DIR}/event-config.h") - file(STRINGS "${LIBEVENT_EVENT_CONFIG_DIR}/event-config.h" - LIBEVENT_VERSION REGEX "${_version_regex}") - endif() - endif() - string(REGEX REPLACE "${_version_regex}" "\\1" - LIBEVENT_VERSION "${LIBEVENT_VERSION}") - unset(_version_regex) -endif() - -set(_LIBEVENT_REQUIRED_VARS) -if(WIN32) - set(Libevent_FIND_COMPONENTS ${Libevent_LIB_PREFIX}event core extras) -else() - set(Libevent_FIND_COMPONENTS ${Libevent_LIB_PREFIX}event core extra pthreads) -endif() -message(status "** libevent components: ${Libevent_FIND_COMPONENTS}") -foreach(COMPONENT ${Libevent_FIND_COMPONENTS}) - set(_LIBEVENT_LIBNAME "${Libevent_LIB_PREFIX}event") - # Note: compare two variables to avoid a CMP0054 policy warning - if(COMPONENT STREQUAL _LIBEVENT_LIBNAME) - set(_LIBEVENT_LIBNAME "${Libevent_LIB_PREFIX}event") - else() - set(_LIBEVENT_LIBNAME "${Libevent_LIB_PREFIX}event_${COMPONENT}") - endif() - string(TOUPPER "${COMPONENT}" COMPONENT_UPPER) - message(status "** ${_LIBEVENT_LIBNAME}") - find_library(LIBEVENT_${COMPONENT_UPPER}_LIBRARY - NAMES ${_LIBEVENT_LIBNAME} - PATHS ${CMAKE_SOURCE_DIR}/bin/lib C:/libevent-2.0.22-stable C:/libevent-2.0.22-stable/lib C:/libevent/lib ${CMAKE_SOURCE_DIR}/win32-deps/lib - HINTS ${PC_LIBEVENT_LIBRARY_DIRS} - ) - if(LIBEVENT_${COMPONENT_UPPER}_LIBRARY) - set(Libevent_${COMPONENT}_FOUND 1) - endif() - list(APPEND _LIBEVENT_REQUIRED_VARS LIBEVENT_${COMPONENT_UPPER}_LIBRARY) -endforeach() -unset(_LIBEVENT_LIBNAME) - -include(FindPackageHandleStandardArgs) -# handle the QUIETLY and REQUIRED arguments and set LIBEVENT_FOUND to TRUE -# if all listed variables are TRUE and the requested version matches. -find_package_handle_standard_args(Libevent REQUIRED_VARS - ${_LIBEVENT_REQUIRED_VARS} - LIBEVENT_INCLUDE_DIR - VERSION_VAR LIBEVENT_VERSION - HANDLE_COMPONENTS) - -if(LIBEVENT_FOUND) - set(LIBEVENT_INCLUDE_DIRS ${LIBEVENT_INCLUDE_DIR}) - set(LIBEVENT_LIBRARIES) - foreach(COMPONENT ${Libevent_FIND_COMPONENTS}) - string(TOUPPER "${COMPONENT}" COMPONENT_UPPER) - list(APPEND LIBEVENT_LIBRARIES ${LIBEVENT_${COMPONENT_UPPER}_LIBRARY}) - set(LIBEVENT_${COMPONENT_UPPER}_FOUND ${Libevent_${COMPONENT}_FOUND}) - endforeach() -endif() - -mark_as_advanced(LIBEVENT_INCLUDE_DIR ${_LIBEVENT_REQUIRED_VARS}) - -# Restore the original find library ordering -if( Libevent_USE_STATIC_LIBS ) - set(CMAKE_FIND_LIBRARY_SUFFIXES ${_libevent_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) -endif() -unset(_LIBEVENT_REQUIRED_VARS) diff --git a/dep/build.sh b/dep/build.sh deleted file mode 100644 index d33e7c4c3..000000000 --- a/dep/build.sh +++ /dev/null @@ -1,29 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. -BASEDIR=$(dirname "$0") -if [[ ! -d ${BASEDIR}/rocketmq_amd64/usr/local/include/rocketmq ]]; then - mkdir -p ${BASEDIR}/rocketmq_amd64/usr/local/include/rocketmq -fi - -if [[ ! -d ${BASEDIR}/rocketmq_amd64/usr/local/lib ]]; then - mkdir -p ${BASEDIR}/rocketmq_amd64/usr/local/lib -fi - -cp -R ${BASEDIR}/../include/* ${BASEDIR}/rocketmq_amd64/usr/local/include/rocketmq -cp ${BASEDIR}/../bin/librocketmq.so ${BASEDIR}/rocketmq_amd64/usr/local/lib/ -cp ${BASEDIR}/../bin/librocketmq.a ${BASEDIR}/rocketmq_amd64/usr/local/lib/ - -VERSION=`cat ${BASEDIR}/rocketmq_amd64/DEBIAN/control | grep Version | awk -F ':' '{print $2}'| sed 's/^ *//'` -dpkg-deb --build ${BASEDIR}/rocketmq_amd64 rocketmq-client-cpp-${VERSION}.amd64.deb diff --git a/dep/rocketmq_amd64/DEBIAN/control b/dep/rocketmq_amd64/DEBIAN/control deleted file mode 100644 index 53fa7fc84..000000000 --- a/dep/rocketmq_amd64/DEBIAN/control +++ /dev/null @@ -1,8 +0,0 @@ -Package: RocketMQ -Version: 2.2.0 -Architecture: amd64 -Essential: no -Priority: optional -Depends: -Maintainer: "Apache RocketMQ" -Description: This package is C++ client of Apache RocketMQ for debian and its derivertives like Ubuntu. diff --git a/distribution/deploy.sh b/distribution/deploy.sh deleted file mode 100755 index ae6c9c6a6..000000000 --- a/distribution/deploy.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh - -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. - - -VERSION="2.2.0" -PKG_NAME="rocketmq-client-cpp" -CWD_DIR=$(cd "$(dirname "$0")"; pwd) -DEPLOY_BUILD_HOME=${CWD_DIR}/${PKG_NAME} - -# ##==================================================================== -#make -# ##==================================================================== -# # deploy -rm -rf ${DEPLOY_BUILD_HOME} -mkdir -p ${DEPLOY_BUILD_HOME}/lib -cp -rf ${CWD_DIR}/../bin/*.a ${DEPLOY_BUILD_HOME}/lib/ -if test "$(uname)" = "Linux"; then -cp -rf ${CWD_DIR}/../bin/*.so ${DEPLOY_BUILD_HOME}/lib/ -fi -if test "$(uname)" = "Darwin"; then -cp -rf ${CWD_DIR}/../bin/*.dylib ${DEPLOY_BUILD_HOME}/lib/ -fi -cp -rf ${CWD_DIR}/../include ${DEPLOY_BUILD_HOME}/ -cp -rf ${CWD_DIR}/../example ${DEPLOY_BUILD_HOME}/ -cp -rf ${CWD_DIR}/../README.md ${DEPLOY_BUILD_HOME}/ -cp -rf ${CWD_DIR}/../LICENSE ${DEPLOY_BUILD_HOME}/LICENSE -cp -rf ${CWD_DIR}/../NOTICE ${DEPLOY_BUILD_HOME}/NOTICE - -cd ${CWD_DIR} && tar -cvzf ./${PKG_NAME}-${VERSION}-bin-release.tar.gz ./${PKG_NAME} &> /dev/null -rm -rf ${DEPLOY_BUILD_HOME} -# # ##==================================================================== -#make clean diff --git a/docs/assets/BasicMode.png b/docs/assets/BasicMode.png new file mode 100644 index 000000000..f04258515 Binary files /dev/null and b/docs/assets/BasicMode.png differ diff --git a/docs/assets/class_diagram.png b/docs/assets/class_diagram.png new file mode 100644 index 000000000..b22e3e467 Binary files /dev/null and b/docs/assets/class_diagram.png differ diff --git a/docs/gtest.md b/docs/gtest.md new file mode 100644 index 000000000..0c40d9d7f --- /dev/null +++ b/docs/gtest.md @@ -0,0 +1,8 @@ +## Run a single test case +1. Get all test cases by running tests with --gtest_list_tests +1. Parse this data into your GUI +1. Select test cases you want ro run +1. Run test executable with option --gtest_filter= + +## Run tests multiple times +bazel test --runs_per_test=10 //... \ No newline at end of file diff --git a/docs/test_coverage.md b/docs/test_coverage.md new file mode 100644 index 000000000..2c836a9ce --- /dev/null +++ b/docs/test_coverage.md @@ -0,0 +1,15 @@ +### Generate Coverage Data +```text + bazel coverage -s \ + --instrument_test_targets \ + --experimental_cc_coverage \ + --combined_report=lcov \ + --coverage_report_generator=@bazel_tools//tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator:Main \ + //src/test/... +``` + +### Generate HTML pages +```text +genhtml bazel-out/_coverage/_coverage_report.dat \ + --output-directory coverage_html +``` diff --git a/example/AsyncProducer.cpp b/example/AsyncProducer.cpp deleted file mode 100644 index 5be900c6e..000000000 --- a/example/AsyncProducer.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "common.h" - -using namespace rocketmq; - -std::atomic g_quit; -std::mutex g_mtx; -std::condition_variable g_finished; -SendCallback* g_callback = NULL; -TpsReportService g_tps; - -class MySendCallback : public SendCallback { - virtual void onSuccess(SendResult& sendResult) { - g_msgCount--; - g_tps.Increment(); - if (g_msgCount.load() <= 0) { - std::unique_lock lck(g_mtx); - g_finished.notify_one(); - } - } - virtual void onException(MQException& e) { cout << "send Exception\n"; } -}; - -class MyAutoDeleteSendCallback : public AutoDeleteSendCallBack { - public: - virtual ~MyAutoDeleteSendCallback() {} - virtual void onSuccess(SendResult& sendResult) { - g_msgCount--; - if (g_msgCount.load() <= 0) { - std::unique_lock lck(g_mtx); - g_finished.notify_one(); - } - } - virtual void onException(MQException& e) { std::cout << "send Exception" << e << "\n"; } -}; - -void AsyncProducerWorker(RocketmqSendAndConsumerArgs* info, DefaultMQProducer* producer) { - while (!g_quit.load()) { - if (g_msgCount.load() <= 0) { - std::unique_lock lck(g_mtx); - g_finished.notify_one(); - } - MQMessage msg(info->topic, // topic - "*", // tag - info->body); // body - - if (info->IsAutoDeleteSendCallback) { - g_callback = new MyAutoDeleteSendCallback(); // auto delete - } - - try { - producer->send(msg, g_callback); - } catch (MQException& e) { - std::cout << e << endl; // if catch excepiton , need re-send this msg by - // service - } - } -} - -int main(int argc, char* argv[]) { - RocketmqSendAndConsumerArgs info; - if (!ParseArgs(argc, argv, &info)) { - exit(-1); - } - - DefaultMQProducer producer("please_rename_unique_group_name"); - if (!info.IsAutoDeleteSendCallback) { - g_callback = new MySendCallback(); - } - - PrintRocketmqSendAndConsumerArgs(info); - - if (!info.namesrv.empty()) - producer.setNamesrvAddr(info.namesrv); - - producer.setGroupName(info.groupname); - producer.setInstanceName(info.groupname); - producer.setNamesrvDomain(info.namesrv_domain); - producer.start(); - g_tps.start(); - std::vector> work_pool; - auto start = std::chrono::system_clock::now(); - int msgcount = g_msgCount.load(); - for (int j = 0; j < info.thread_count; j++) { - std::shared_ptr th = std::make_shared(AsyncProducerWorker, &info, &producer); - work_pool.push_back(th); - } - - { - std::unique_lock lck(g_mtx); - g_finished.wait(lck); - g_quit.store(true); - } - - auto end = std::chrono::system_clock::now(); - auto duration = std::chrono::duration_cast(end - start); - - std::cout << "per msg time: " << duration.count() / (double)msgcount << "ms \n" - << "========================finished==============================\n"; - - producer.shutdown(); - for (size_t th = 0; th != work_pool.size(); ++th) { - work_pool[th]->join(); - } - if (!info.IsAutoDeleteSendCallback) { - delete g_callback; - } - return 0; -} diff --git a/example/AsyncPushConsumer.cpp b/example/AsyncPushConsumer.cpp deleted file mode 100644 index 671c2e474..000000000 --- a/example/AsyncPushConsumer.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include - -#include -#include -#include -#include - -#include "common.h" - -std::mutex g_mtx; -std::condition_variable g_finished; -TpsReportService g_tps; -using namespace rocketmq; - -class MyMsgListener : public MessageListenerConcurrently { - public: - MyMsgListener() {} - virtual ~MyMsgListener() {} - - virtual ConsumeStatus consumeMessage(const std::vector& msgs) { - g_msgCount.store(g_msgCount.load() - msgs.size()); - for (size_t i = 0; i < msgs.size(); ++i) { - g_tps.Increment(); - } - - if (g_msgCount.load() <= 0) { - std::unique_lock lck(g_mtx); - g_finished.notify_one(); - } - return CONSUME_SUCCESS; - } -}; - -int main(int argc, char* argv[]) { - RocketmqSendAndConsumerArgs info; - if (!ParseArgs(argc, argv, &info)) { - exit(-1); - } - PrintRocketmqSendAndConsumerArgs(info); - DefaultMQPushConsumer consumer("please_rename_unique_group_name"); - DefaultMQProducer producer("please_rename_unique_group_name"); - - producer.setNamesrvAddr(info.namesrv); - producer.setGroupName("msg-persist-group_producer_sandbox"); - producer.setNamesrvDomain(info.namesrv_domain); - producer.start(); - - consumer.setNamesrvAddr(info.namesrv); - consumer.setGroupName(info.groupname); - consumer.setNamesrvDomain(info.namesrv_domain); - consumer.setConsumeFromWhere(CONSUME_FROM_LAST_OFFSET); - - consumer.setInstanceName(info.groupname); - - consumer.subscribe(info.topic, "*"); - consumer.setConsumeThreadCount(15); - consumer.setTcpTransportTryLockTimeout(1000); - consumer.setTcpTransportConnectTimeout(400); - - MyMsgListener msglistener; - consumer.registerMessageListener(&msglistener); - - try { - consumer.start(); - } catch (MQClientException& e) { - cout << e << endl; - } - g_tps.start(); - - int msgcount = g_msgCount.load(); - for (int i = 0; i < msgcount; ++i) { - MQMessage msg(info.topic, // topic - "*", // tag - info.body); // body - - try { - producer.send(msg); - } catch (MQException& e) { - std::cout << e << endl; // if catch excepiton , need re-send this msg by - // service - } - } - - { - std::unique_lock lck(g_mtx); - g_finished.wait(lck); - } - producer.shutdown(); - consumer.shutdown(); - return 0; -} \ No newline at end of file diff --git a/example/BatchProducer.cpp b/example/BatchProducer.cpp deleted file mode 100644 index 18f33cbf8..000000000 --- a/example/BatchProducer.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "common.h" - -using namespace rocketmq; -using namespace std; -std::atomic g_quit; -std::mutex g_mtx; -std::condition_variable g_finished; -TpsReportService g_tps; - -void SyncProducerWorker(RocketmqSendAndConsumerArgs* info, DefaultMQProducer* producer) { - while (!g_quit.load()) { - if (g_msgCount.load() <= 0) { - std::unique_lock lck(g_mtx); - g_finished.notify_one(); - break; - } - - vector msgs; - MQMessage msg1(info->topic, "*", info->body); - msg1.setProperty("property1", "value1"); - MQMessage msg2(info->topic, "*", info->body); - msg2.setProperty("property1", "value1"); - msg2.setProperty("property2", "value2"); - MQMessage msg3(info->topic, "*", info->body); - msg3.setProperty("property1", "value1"); - msg3.setProperty("property2", "value2"); - msg3.setProperty("property3", "value3"); - msgs.push_back(msg1); - msgs.push_back(msg2); - msgs.push_back(msg3); - try { - auto start = std::chrono::system_clock::now(); - SendResult sendResult = producer->send(msgs); - g_tps.Increment(); - --g_msgCount; - auto end = std::chrono::system_clock::now(); - auto duration = std::chrono::duration_cast(end - start); - if (duration.count() >= 500) { - std::cout << "send RT more than: " << duration.count() << " ms with msgid: " << sendResult.getMsgId() << endl; - } - } catch (const MQException& e) { - std::cout << "send failed: " << e.what() << std::endl; - std::unique_lock lck(g_mtx); - g_finished.notify_one(); - return; - } - } -} - -int main(int argc, char* argv[]) { - RocketmqSendAndConsumerArgs info; - if (!ParseArgs(argc, argv, &info)) { - exit(-1); - } - PrintRocketmqSendAndConsumerArgs(info); - DefaultMQProducer producer("please_rename_unique_group_name"); - producer.setNamesrvAddr(info.namesrv); - producer.setNamesrvDomain(info.namesrv_domain); - producer.setGroupName(info.groupname); - producer.setInstanceName(info.groupname); - producer.setSessionCredentials("mq acesskey", "mq secretkey", "ALIYUN"); - producer.setSendMsgTimeout(500); - producer.setTcpTransportTryLockTimeout(1000); - producer.setTcpTransportConnectTimeout(400); - - producer.start(); - std::vector> work_pool; - auto start = std::chrono::system_clock::now(); - int msgcount = g_msgCount.load(); - g_tps.start(); - - int threadCount = info.thread_count; - for (int j = 0; j < threadCount; j++) { - std::shared_ptr th = std::make_shared(SyncProducerWorker, &info, &producer); - work_pool.push_back(th); - } - - { - std::unique_lock lck(g_mtx); - g_finished.wait(lck); - g_quit.store(true); - } - - auto end = std::chrono::system_clock::now(); - auto duration = std::chrono::duration_cast(end - start); - - std::cout << "per msg time: " << duration.count() / (double)msgcount << "ms \n" - << "========================finished==============================\n"; - - for (size_t th = 0; th != work_pool.size(); ++th) { - work_pool[th]->join(); - } - - producer.shutdown(); - - return 0; -} diff --git a/example/CAsyncProducer.c b/example/CAsyncProducer.c deleted file mode 100644 index 9837c1ff5..000000000 --- a/example/CAsyncProducer.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "CCommon.h" -#include "CMessage.h" -#include "CProducer.h" -#include "CSendResult.h" -#ifdef _WIN32 -#include -#else -#include -#include -#endif - -void thread_sleep(unsigned milliseconds) { -#ifdef _WIN32 - Sleep(milliseconds); -#else - usleep(milliseconds * 1000); // takes microseconds -#endif -} - -void SendSuccessCallback(CSendResult result) { - printf("async send success, msgid:%s\n", result.msgId); -} - -void SendExceptionCallback(CMQException e) { - char msg[1024]; - snprintf(msg, sizeof(msg), "error:%d, msg:%s, file:%s:%d", e.error, e.msg, e.file, e.line); - printf("async send exception %s\n", msg); -} - -void StartSendMessage(CProducer* producer) { - int i = 0; - int ret_code = 0; - char body[128]; - CMessage* msg = CreateMessage("T_TestTopic"); - SetMessageTags(msg, "Test_Tag"); - SetMessageKeys(msg, "Test_Keys"); - for (i = 0; i < 10; i++) { - memset(body, 0, sizeof(body)); - snprintf(body, sizeof(body), "new message body, index %d", i); - SetMessageBody(msg, body); - ret_code = SendMessageAsync(producer, msg, SendSuccessCallback, SendExceptionCallback); - printf("async send message[%d] return code: %d\n", i, ret_code); - thread_sleep(1000); - } - DestroyMessage(msg); -} - -void CreateProducerAndStartSendMessage(int i) { - printf("Producer Initializing.....\n"); - CProducer* producer = CreateProducer("Group_producer"); - SetProducerNameServerAddress(producer, "127.0.0.1:9876"); - if (i == 1) { - SetProducerSendMsgTimeout(producer, 3); - } - StartProducer(producer); - printf("Producer start.....\n"); - StartSendMessage(producer); - ShutdownProducer(producer); - DestroyProducer(producer); - printf("Producer Shutdown!\n"); -} - -int main(int argc, char* argv[]) { - printf("Send Async successCallback.....\n"); - CreateProducerAndStartSendMessage(0); - - printf("Send Async exceptionCallback.....\n"); - CreateProducerAndStartSendMessage(1); - return 0; -} diff --git a/example/CBatchProducer.c b/example/CBatchProducer.c deleted file mode 100644 index 148d9f068..000000000 --- a/example/CBatchProducer.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include "CBatchMessage.h" -#include "CCommon.h" -#include "CMessage.h" -#include "CProducer.h" -#include "CSendResult.h" - -void StartSendMessage(CProducer* producer) { - int i = 0; - int ret_code = 0; - char body[128]; - CBatchMessage* batchMessage = CreateBatchMessage("T_TestTopic"); - - for (i = 0; i < 10; i++) { - CMessage* msg = CreateMessage("T_TestTopic"); - SetMessageTags(msg, "Test_Tag"); - SetMessageKeys(msg, "Test_Keys"); - memset(body, 0, sizeof(body)); - snprintf(body, sizeof(body), "new message body, index %d", i); - SetMessageBody(msg, body); - AddMessage(batchMessage, msg); - } - CSendResult result; - ret_code = SendBatchMessage(producer, batchMessage, &result); - printf("SendBatchMessage %s .....\n", ret_code == 0 ? "Success" : ret_code == 11 ? "FAILED" : " It is null value"); - DestroyBatchMessage(batchMessage); -} - -void CreateProducerAndStartSendMessage() { - printf("Producer Initializing.....\n"); - CProducer* producer = CreateProducer("Group_producer"); - SetProducerNameServerAddress(producer, "127.0.0.1:9876"); - StartProducer(producer); - printf("Producer start.....\n"); - StartSendMessage(producer); - ShutdownProducer(producer); - DestroyProducer(producer); - printf("Producer Shutdown!\n"); -} - -int main(int argc, char* argv[]) { - printf("Send Batch.....\n"); - CreateProducerAndStartSendMessage(); - return 0; -} diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt deleted file mode 100755 index daf9c3bc2..000000000 --- a/example/CMakeLists.txt +++ /dev/null @@ -1,60 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. - -project(example) - -set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin) - -include_directories(${CMAKE_SOURCE_DIR}/include) -include_directories(${Boost_INCLUDE_DIRS}) - -link_directories(${Boost_LIBRARY_DIRS}) -link_directories(${LIBEVENT_LIBRARY}) -link_directories(${JSONCPP_LIBRARY}) -link_directories(${OPENSSL_LIBRARIES_DIR}) - -#if (BUILD_ROCKETMQ_SHARED) -# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBOOST_ALL_DYN_LINK -shared ") -#endif() - -file(GLOB files "*.c*") -foreach(file ${files}) - get_filename_component(basename ${file} NAME_WE) - add_executable(${basename} ${file}) - if(MSVC) - if(CMAKE_CONFIGURATION_TYPES STREQUAL "Release") - set_target_properties( ${basename} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:LIBCMT" ) - else() - set_target_properties( ${basename} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:LIBCMTD" ) - endif() - endif() - - if (MSVC) - if (BUILD_ROCKETMQ_SHARED) - target_link_libraries (${basename} rocketmq_shared ${deplibs} - ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${LIBEVENT_LIBRARIES} ${JSONCPP_LIBRARIES}) - else() - target_link_libraries (${basename} rocketmq_static ${deplibs} - ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${LIBEVENT_LIBRARIES} ${JSONCPP_LIBRARIES}) - endif() - else() - if (BUILD_ROCKETMQ_SHARED) - target_link_libraries (${basename} rocketmq_shared) - else() - target_link_libraries (${basename} rocketmq_static) - endif() - endif() - -endforeach() diff --git a/example/COrderlyAsyncProducer.c b/example/COrderlyAsyncProducer.c deleted file mode 100644 index b48fb5485..000000000 --- a/example/COrderlyAsyncProducer.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "CCommon.h" -#include "CMessage.h" -#include "CProducer.h" -#include "CSendResult.h" -#ifdef _WIN32 -#include -#else -#include -#include -#endif - -void thread_sleep(unsigned milliseconds) { -#ifdef _WIN32 - Sleep(milliseconds); -#else - usleep(milliseconds * 1000); // takes microseconds -#endif -} - -void SendSuccessCallback(CSendResult result) { - printf("async send success, msgid:%s\n", result.msgId); -} - -void SendExceptionCallback(CMQException e) { - char msg[1024]; - snprintf(msg, sizeof(msg), "error:%d, msg:%s, file:%s:%d", e.error, e.msg, e.file, e.line); - printf("async send exception %s\n", msg); -} - -int aQueueSelectorCallback(int size, CMessage* msg, void* arg) { - return 0; -}; - -void StartSendMessage(CProducer* producer) { - int i = 0; - int ret_code = 0; - char body[128]; - CMessage* msg = CreateMessage("topic_COrderlyAsyncProducer"); - SetMessageTags(msg, "Test_Tag"); - SetMessageKeys(msg, "Test_Keys"); - for (i = 0; i < 10; i++) { - memset(body, 0, sizeof(body)); - snprintf(body, sizeof(body), "new message body, index %d", i); - SetMessageBody(msg, body); - ret_code = SendMessageOrderlyAsync(producer, msg, aQueueSelectorCallback, (void*)&i, SendSuccessCallback, - SendExceptionCallback); - printf("async send message[%d] return code: %d\n", i, ret_code); - thread_sleep(1000); - } - DestroyMessage(msg); -} - -void CreateProducerAndStartSendMessage(int i) { - printf("Producer Initializing.....\n"); - CProducer* producer = CreateProducer("FooBarGroup1"); - SetProducerNameServerAddress(producer, "192.168.0.149:9876"); - if (i == 1) { - SetProducerSendMsgTimeout(producer, 3); - } - StartProducer(producer); - printf("Producer start.....\n"); - StartSendMessage(producer); - ShutdownProducer(producer); - DestroyProducer(producer); - printf("Producer Shutdown!\n"); -} - -int main(int argc, char* argv[]) { - printf("COrderlyAsyncProducer successCallback.....\n"); - CreateProducerAndStartSendMessage(0); - - printf("COrderlyAsyncProducer exceptionCallback.....\n"); - CreateProducerAndStartSendMessage(1); - return 0; -} diff --git a/example/OrderProducer.cpp b/example/OrderProducer.cpp deleted file mode 100644 index 402e916d9..000000000 --- a/example/OrderProducer.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include -#include -#include -#include - -#include "common.h" - -using namespace rocketmq; - -std::condition_variable g_finished; -std::mutex g_mtx; -std::atomic g_quit(false); - -class SelectMessageQueueByHash : public MessageQueueSelector { - public: - MQMessageQueue select(const std::vector& mqs, const MQMessage& msg, void* arg) { - int orderId = *static_cast(arg); - int index = orderId % mqs.size(); - return mqs[index]; - } -}; - -SelectMessageQueueByHash g_mySelector; - -void ProducerWorker(RocketmqSendAndConsumerArgs* info, DefaultMQProducer* producer) { - while (!g_quit.load()) { - if (g_msgCount.load() <= 0) { - std::unique_lock lck(g_mtx); - g_finished.notify_one(); - } - MQMessage msg(info->topic, // topic - "*", // tag - info->body); // body - - int orderId = 1; - SendResult sendResult = - producer->send(msg, &g_mySelector, static_cast(&orderId), info->retrytimes, info->SelectUnactiveBroker); - --g_msgCount; - } -} - -int main(int argc, char* argv[]) { - RocketmqSendAndConsumerArgs info; - if (!ParseArgs(argc, argv, &info)) { - exit(-1); - } - - DefaultMQProducer producer("please_rename_unique_group_name"); - PrintRocketmqSendAndConsumerArgs(info); - - producer.setNamesrvAddr(info.namesrv); - producer.setNamesrvDomain(info.namesrv_domain); - producer.setGroupName(info.groupname); - producer.setInstanceName(info.groupname); - - producer.start(); - - int msgcount = g_msgCount.load(); - std::vector> work_pool; - - int threadCount = info.thread_count; - for (int j = 0; j < threadCount; j++) { - std::shared_ptr th = std::make_shared(ProducerWorker, &info, &producer); - work_pool.push_back(th); - } - - auto start = std::chrono::system_clock::now(); - { - std::unique_lock lck(g_mtx); - g_finished.wait(lck); - g_quit.store(true); - } - - auto end = std::chrono::system_clock::now(); - auto duration = std::chrono::duration_cast(end - start); - - std::cout << "per msg time: " << duration.count() / (double)msgcount << "ms \n" - << "========================finished==============================\n"; - - for (size_t th = 0; th != work_pool.size(); ++th) { - work_pool[th]->join(); - } - - producer.shutdown(); - - return 0; -} diff --git a/example/OrderlyPushConsumer.cpp b/example/OrderlyPushConsumer.cpp deleted file mode 100644 index 174e2b3a9..000000000 --- a/example/OrderlyPushConsumer.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "common.h" - -using namespace rocketmq; - -std::condition_variable g_finished; -std::mutex g_mtx; -std::atomic g_consumedCount(0); -std::atomic g_quit(false); -TpsReportService g_tps; - -class MyMsgListener : public MessageListenerOrderly { - public: - MyMsgListener() {} - virtual ~MyMsgListener() {} - - virtual ConsumeStatus consumeMessage(const vector& msgs) { - if (g_consumedCount.load() >= g_msgCount) { - std::unique_lock lK(g_mtx); - g_quit.store(true); - g_finished.notify_one(); - } - for (size_t i = 0; i < msgs.size(); i++) { - ++g_consumedCount; - g_tps.Increment(); - } - return CONSUME_SUCCESS; - } -}; - -int main(int argc, char* argv[]) { - RocketmqSendAndConsumerArgs info; - if (!ParseArgs(argc, argv, &info)) { - exit(-1); - } - PrintRocketmqSendAndConsumerArgs(info); - DefaultMQPushConsumer consumer("please_rename_unique_group_name"); - DefaultMQProducer producer("please_rename_unique_group_name"); - - producer.setNamesrvAddr(info.namesrv); - producer.setGroupName("msg-persist-group_producer_sandbox"); - producer.start(); - - consumer.setNamesrvAddr(info.namesrv); - consumer.setNamesrvDomain(info.namesrv_domain); - consumer.setGroupName(info.groupname); - consumer.setConsumeFromWhere(CONSUME_FROM_LAST_OFFSET); - consumer.subscribe(info.topic, "*"); - consumer.setConsumeThreadCount(info.thread_count); - consumer.setConsumeMessageBatchMaxSize(31); - if (info.syncpush) - consumer.setAsyncPull(false); - - MyMsgListener msglistener; - consumer.registerMessageListener(&msglistener); - g_tps.start(); - - try { - consumer.start(); - } catch (MQClientException& e) { - std::cout << e << std::endl; - } - - int msgcount = g_msgCount.load(); - for (int i = 0; i < msgcount; ++i) { - MQMessage msg(info.topic, // topic - "*", // tag - info.body); // body - - try { - producer.send(msg); - } catch (MQException& e) { - std::cout << e << endl; // if catch excepiton , need re-send this msg by - // service - } - } - - while (!g_quit.load()) { - std::unique_lock lk(g_mtx); - g_finished.wait(lk); - } - - producer.shutdown(); - consumer.shutdown(); - return 0; -} diff --git a/example/Producer.c b/example/Producer.c deleted file mode 100644 index 9ae23a94d..000000000 --- a/example/Producer.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "CCommon.h" -#include "CMessage.h" -#include "CProducer.h" -#include "CSendResult.h" -#ifdef _WIN32 -#include -#else -#include -#include -#endif - -void thread_sleep(unsigned int milliseconds) { -#ifdef _WIN32 - Sleep(milliseconds); -#else - usleep(milliseconds * 1000); // suspend execution for microsecond intervals -#endif -} - -void StartSendMessage(CProducer* producer) { - int i = 0; - char body[256]; - CMessage* msg = CreateMessage("T_TestTopic"); - SetMessageTags(msg, "Test_Tag"); - SetMessageKeys(msg, "Test_Keys"); - CSendResult result; - for (i = 0; i < 3; i++) { - memset(body, 0, sizeof(body)); - snprintf(body, sizeof(body), "new message body, index %d", i); - SetMessageBody(msg, body); - int status = SendMessageSync(producer, msg, &result); - if (status == OK) { - printf("send message[%d] result status:%d, msgId:%s\n", i, (int)result.sendStatus, result.msgId); - } else { - printf("send message[%d] failed !\n", i); - } - thread_sleep(1000); - } - DestroyMessage(msg); -} - -int main(int argc, char* argv[]) { - CProducer* producer = CreateProducer("Group_producer"); - SetProducerNameServerAddress(producer, "127.0.0.1:9876"); - StartProducer(producer); - printf("Producer initialized. \n"); - - StartSendMessage(producer); - - ShutdownProducer(producer); - DestroyProducer(producer); - printf("Producer stopped !\n"); - - return 0; -} diff --git a/example/PullConsumeMessage.c b/example/PullConsumeMessage.c deleted file mode 100644 index f9b9bc217..000000000 --- a/example/PullConsumeMessage.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "CCommon.h" -#include "CMessageExt.h" -#include "CMessageQueue.h" -#include "CPullConsumer.h" -#include "CPullResult.h" -#ifdef _WIN32 -#include -#else -#include -#include -#endif - -void thread_sleep(unsigned milliseconds) { -#ifdef _WIN32 - Sleep(milliseconds); -#else - usleep(milliseconds * 1000); // takes microseconds -#endif -} - -int main(int argc, char* argv[]) { - int i = 0, j = 0; - int ret = 0; - int size = 0; - CMessageQueue* mqs = NULL; - printf("PullConsumer Initializing....\n"); - CPullConsumer* consumer = CreatePullConsumer("Group_Consumer_Test"); - SetPullConsumerNameServerAddress(consumer, "172.17.0.2:9876"); - StartPullConsumer(consumer); - printf("Pull Consumer Start...\n"); - for (i = 1; i <= 5; i++) { - printf("FetchSubscriptionMessageQueues : %d times\n", i); - ret = FetchSubscriptionMessageQueues(consumer, "T_TestTopic", &mqs, &size); - if (ret != OK) { - printf("Get MQ Queue Failed,ErrorCode:%d\n", ret); - } - printf("Get MQ Size:%d\n", size); - for (j = 0; j < size; j++) { - int noNewMsg = 0; - long long tmpoffset = 0; - printf("Pull Message For Topic:%s,Queue:%s,QueueId:%d\n", mqs[j].topic, mqs[j].brokerName, mqs[j].queueId); - do { - int k = 0; - CPullResult pullResult = Pull(consumer, &mqs[j], "*", tmpoffset, 32); - if (pullResult.pullStatus != E_BROKER_TIMEOUT) { - tmpoffset = pullResult.nextBeginOffset; - } - printf("PullStatus:%d,MaxOffset:%lld,MinOffset:%lld,NextBegainOffset:%lld", pullResult.pullStatus, - pullResult.maxOffset, pullResult.minOffset, pullResult.nextBeginOffset); - switch (pullResult.pullStatus) { - case E_FOUND: - printf("Get Message Size:%d\n", pullResult.size); - for (k = 0; k < pullResult.size; ++k) { - printf("Got Message ID:%s,Body:%s\n", GetMessageId(pullResult.msgFoundList[k]), - GetMessageBody(pullResult.msgFoundList[k])); - } - break; - case E_NO_MATCHED_MSG: - noNewMsg = 1; - break; - default: - noNewMsg = 0; - } - ReleasePullResult(pullResult); - thread_sleep(100); - } while (noNewMsg == 0); - thread_sleep(1000); - } - thread_sleep(2000); - ReleaseSubscriptionMessageQueue(mqs); - } - thread_sleep(5000); - ShutdownPullConsumer(consumer); - DestroyPullConsumer(consumer); - printf("PullConsumer Shutdown!\n"); - return 0; -} diff --git a/example/PullConsumer.cpp b/example/PullConsumer.cpp deleted file mode 100644 index e85a82188..000000000 --- a/example/PullConsumer.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include -#include -#include -#include -#include - -#include "common.h" - -using namespace rocketmq; - -std::map g_offseTable; - -void putMessageQueueOffset(MQMessageQueue mq, uint64_t offset) { - g_offseTable[mq] = offset; -} - -uint64_t getMessageQueueOffset(MQMessageQueue mq) { - map::iterator it = g_offseTable.find(mq); - if (it != g_offseTable.end()) { - return it->second; - } - return 0; -} - -int main(int argc, char* argv[]) { - RocketmqSendAndConsumerArgs info; - if (!ParseArgs(argc, argv, &info)) { - exit(-1); - } - PrintRocketmqSendAndConsumerArgs(info); - DefaultMQPullConsumer consumer("please_rename_unique_group_name"); - consumer.setNamesrvAddr(info.namesrv); - consumer.setNamesrvDomain(info.namesrv_domain); - consumer.setGroupName(info.groupname); - consumer.setInstanceName(info.groupname); - consumer.registerMessageQueueListener(info.topic, NULL); - consumer.start(); - std::vector mqs; - - try { - consumer.fetchSubscribeMessageQueues(info.topic, mqs); - auto iter = mqs.begin(); - for (; iter != mqs.end(); ++iter) { - std::cout << "mq:" << (*iter).toString() << endl; - } - } catch (MQException& e) { - std::cout << e << endl; - } - - auto start = std::chrono::system_clock::now(); - auto iter = mqs.begin(); - for (; iter != mqs.end(); ++iter) { - MQMessageQueue mq = (*iter); - // if cluster model - // putMessageQueueOffset(mq, g_consumer.fetchConsumeOffset(mq,true)); - // if broadcast model - // putMessageQueueOffset(mq, your last consume offset); - - bool noNewMsg = false; - do { - try { - PullResult result = consumer.pull(mq, "*", getMessageQueueOffset(mq), 32); - g_msgCount += result.msgFoundList.size(); - std::cout << result.msgFoundList.size() << std::endl; - // if pull request timeout or received NULL response, pullStatus will be - // setted to BROKER_TIMEOUT, - // And nextBeginOffset/minOffset/MaxOffset will be setted to 0 - if (result.pullStatus != BROKER_TIMEOUT) { - putMessageQueueOffset(mq, result.nextBeginOffset); - PrintPullResult(&result); - } else { - cout << "broker timeout occur" << endl; - } - switch (result.pullStatus) { - case FOUND: - case NO_MATCHED_MSG: - case OFFSET_ILLEGAL: - case BROKER_TIMEOUT: - break; - case NO_NEW_MSG: - noNewMsg = true; - break; - default: - break; - } - } catch (MQClientException& e) { - std::cout << e << std::endl; - } - } while (!noNewMsg); - } - - auto end = std::chrono::system_clock::now(); - auto duration = std::chrono::duration_cast(end - start); - - std::cout << "msg count: " << g_msgCount.load() << "\n"; - std::cout << "per msg time: " << duration.count() / (double)g_msgCount.load() << "ms \n" - << "========================finished==============================\n"; - - consumer.shutdown(); - return 0; -} diff --git a/example/PushConsumeMessage.c b/example/PushConsumeMessage.c deleted file mode 100644 index 85ea28c0a..000000000 --- a/example/PushConsumeMessage.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "CCommon.h" -#include "CMessageExt.h" -#include "CPushConsumer.h" -#ifdef _WIN32 -#include -#else -#include -#include -#endif - -void thread_sleep(unsigned milliseconds) { -#ifdef _WIN32 - Sleep(milliseconds); -#else - usleep(milliseconds * 1000); // takes microseconds -#endif -} - -int doConsumeMessage(struct CPushConsumer* consumer, CMessageExt* msgExt) { - printf("Hello,doConsumeMessage by Application!\n"); - printf("Msg Topic:%s\n", GetMessageTopic(msgExt)); - printf("Msg Tags:%s\n", GetMessageTags(msgExt)); - printf("Msg Keys:%s\n", GetMessageKeys(msgExt)); - printf("Msg Body:%s\n", GetMessageBody(msgExt)); - return E_CONSUME_SUCCESS; -} - -int main(int argc, char* argv[]) { - int i = 0; - printf("PushConsumer Initializing....\n"); - CPushConsumer* consumer = CreatePushConsumer("Group_Consumer_Test"); - SetPushConsumerNameServerAddress(consumer, "172.17.0.2:9876"); - Subscribe(consumer, "T_TestTopic", "*"); - RegisterMessageCallback(consumer, doConsumeMessage); - StartPushConsumer(consumer); - printf("Push Consumer Start...\n"); - for (i = 0; i < 10; i++) { - printf("Now Running : %d S\n", i * 10); - thread_sleep(10000); - } - ShutdownPushConsumer(consumer); - DestroyPushConsumer(consumer); - printf("PushConsumer Shutdown!\n"); - return 0; -} diff --git a/example/PushConsumer.cpp b/example/PushConsumer.cpp deleted file mode 100644 index 0b69ca5b9..000000000 --- a/example/PushConsumer.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common.h" - -std::mutex g_mtx; -std::condition_variable g_finished; -TpsReportService g_tps; - -using namespace rocketmq; - -class MyMsgListener : public MessageListenerConcurrently { - public: - MyMsgListener() {} - virtual ~MyMsgListener() {} - - virtual ConsumeStatus consumeMessage(const std::vector& msgs) { - g_msgCount.store(g_msgCount.load() - msgs.size()); - for (size_t i = 0; i < msgs.size(); ++i) { - g_tps.Increment(); - // cout << "msg body: "<< msgs[i].getBody() << endl; - } - - if (g_msgCount.load() <= 0) { - std::unique_lock lck(g_mtx); - g_finished.notify_one(); - } - return CONSUME_SUCCESS; - } -}; - -int main(int argc, char* argv[]) { - RocketmqSendAndConsumerArgs info; - if (!ParseArgs(argc, argv, &info)) { - exit(-1); - } - PrintRocketmqSendAndConsumerArgs(info); - DefaultMQPushConsumer consumer("please_rename_unique_group_name"); - DefaultMQProducer producer("please_rename_unique_group_name"); - producer.setSessionCredentials("AccessKey", "SecretKey", "ALIYUN"); - producer.setTcpTransportTryLockTimeout(1000); - producer.setTcpTransportConnectTimeout(400); - producer.setNamesrvDomain(info.namesrv_domain); - producer.setNamesrvAddr(info.namesrv); - producer.setGroupName("msg-persist-group_producer_sandbox"); - producer.start(); - - consumer.setNamesrvAddr(info.namesrv); - consumer.setGroupName(info.groupname); - consumer.setSessionCredentials("AccessKey", "SecretKey", "ALIYUN"); - consumer.setConsumeThreadCount(info.thread_count); - consumer.setNamesrvDomain(info.namesrv_domain); - consumer.setConsumeFromWhere(CONSUME_FROM_LAST_OFFSET); - - if (info.syncpush) - consumer.setAsyncPull(false); // set sync pull - if (info.broadcasting) { - consumer.setMessageModel(rocketmq::BROADCASTING); - } - - consumer.setInstanceName(info.groupname); - - consumer.subscribe(info.topic, "*"); - consumer.setConsumeThreadCount(15); - consumer.setTcpTransportTryLockTimeout(1000); - consumer.setTcpTransportConnectTimeout(400); - - MyMsgListener msglistener; - consumer.registerMessageListener(&msglistener); - - try { - consumer.start(); - } catch (MQClientException& e) { - cout << e << endl; - } - g_tps.start(); - - int msgcount = g_msgCount.load(); - for (int i = 0; i < msgcount; ++i) { - MQMessage msg(info.topic, // topic - "*", // tag - info.body); // body - - // std::this_thread::sleep_for(std::chrono::seconds(100000)); - try { - producer.send(msg); - } catch (MQException& e) { - std::cout << e << endl; // if catch excepiton , need re-send this msg by - // service - } - } - - { - std::unique_lock lck(g_mtx); - g_finished.wait(lck); - } - producer.shutdown(); - consumer.shutdown(); - return 0; -} diff --git a/example/PushConsumerOrderly.c b/example/PushConsumerOrderly.c deleted file mode 100644 index 9601799a7..000000000 --- a/example/PushConsumerOrderly.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef WIN32 -#include -#endif -#include -#include "CCommon.h" -#include "CMessageExt.h" -#include "CPushConsumer.h" - -int doConsumeMessage(struct CPushConsumer* consumer, CMessageExt* msgExt) { - printf("Hello,doConsumeMessage by Application!\n"); - printf("Msg Topic:%s\n", GetMessageTopic(msgExt)); - printf("Msg Tags:%s\n", GetMessageTags(msgExt)); - printf("Msg Keys:%s\n", GetMessageKeys(msgExt)); - printf("Msg Body:%s\n", GetMessageBody(msgExt)); - return E_CONSUME_SUCCESS; -} - -int main(int argc, char* argv[]) { - int i = 0; - printf("PushConsumer Initializing....\n"); - CPushConsumer* consumer = CreatePushConsumer("Group_Consumer_Test"); - SetPushConsumerNameServerAddress(consumer, "127.0.0.1:9876"); - Subscribe(consumer, "test", "*"); - RegisterMessageCallbackOrderly(consumer, doConsumeMessage); - StartPushConsumer(consumer); - printf("Push Consumer Start...\n"); - for (i = 0; i < 10; i++) { - printf("Now Running : %d S\n", i * 10); - sleep(10); - } - ShutdownPushConsumer(consumer); - DestroyPushConsumer(consumer); - printf("PushConsumer Shutdown!\n"); - return 0; -} diff --git a/example/README.md b/example/README.md deleted file mode 100644 index 378a4ead3..000000000 --- a/example/README.md +++ /dev/null @@ -1 +0,0 @@ -1. AsyncProducer 2. OrderlyProducer 3. SyncProducer diff --git a/example/SendDelayMsg.cpp b/example/SendDelayMsg.cpp deleted file mode 100644 index 860f5b33d..000000000 --- a/example/SendDelayMsg.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "common.h" - -using namespace rocketmq; - -int main(int argc, char* argv[]) { - RocketmqSendAndConsumerArgs info; - if (!ParseArgs(argc, argv, &info)) { - exit(-1); - } - PrintRocketmqSendAndConsumerArgs(info); - DefaultMQProducer producer("please_rename_unique_group_name"); - producer.setNamesrvAddr(info.namesrv); - producer.setNamesrvDomain(info.namesrv_domain); - producer.setGroupName(info.groupname); - producer.setInstanceName(info.groupname); - - producer.setSendMsgTimeout(500); - producer.setTcpTransportTryLockTimeout(1000); - producer.setTcpTransportConnectTimeout(400); - - producer.start(); - - MQMessage msg(info.topic, // topic - "*", // tag - info.body); // body - - // messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h - // 2h - msg.setDelayTimeLevel(5); // 1m - try { - SendResult sendResult = producer.send(msg, info.SelectUnactiveBroker); - } catch (const MQException& e) { - std::cout << "send failed: " << std::endl; - } - - producer.shutdown(); - return 0; -} diff --git a/example/SyncProducer.cpp b/example/SyncProducer.cpp deleted file mode 100644 index 5d66da259..000000000 --- a/example/SyncProducer.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "common.h" - -using namespace rocketmq; - -std::atomic g_quit; -std::mutex g_mtx; -std::condition_variable g_finished; -TpsReportService g_tps; - -void SyncProducerWorker(RocketmqSendAndConsumerArgs* info, DefaultMQProducer* producer) { - while (!g_quit.load()) { - if (g_msgCount.load() <= 0) { - std::unique_lock lck(g_mtx); - g_finished.notify_one(); - } - MQMessage msg(info->topic, // topic - "*", // tag - info->body); // body - try { - auto start = std::chrono::system_clock::now(); - SendResult sendResult = producer->send(msg, info->SelectUnactiveBroker); - g_tps.Increment(); - --g_msgCount; - auto end = std::chrono::system_clock::now(); - auto duration = std::chrono::duration_cast(end - start); - if (duration.count() >= 500) { - std::cout << "send RT more than: " << duration.count() << " ms with msgid: " << sendResult.getMsgId() << endl; - } - } catch (const MQException& e) { - std::cout << "send failed: " << std::endl; - } - } -} - -int main(int argc, char* argv[]) { - RocketmqSendAndConsumerArgs info; - if (!ParseArgs(argc, argv, &info)) { - exit(-1); - } - PrintRocketmqSendAndConsumerArgs(info); - DefaultMQProducer producer("please_rename_unique_group_name"); - producer.setNamesrvAddr(info.namesrv); - producer.setNamesrvDomain(info.namesrv_domain); - producer.setGroupName(info.groupname); - producer.setInstanceName(info.groupname); - producer.setSessionCredentials("mq acesskey", "mq secretkey", "ALIYUN"); - producer.setSendMsgTimeout(500); - producer.setTcpTransportTryLockTimeout(1000); - producer.setTcpTransportConnectTimeout(400); - - producer.start(); - std::vector> work_pool; - auto start = std::chrono::system_clock::now(); - int msgcount = g_msgCount.load(); - g_tps.start(); - - int threadCount = info.thread_count; - for (int j = 0; j < threadCount; j++) { - std::shared_ptr th = std::make_shared(SyncProducerWorker, &info, &producer); - work_pool.push_back(th); - } - - { - std::unique_lock lck(g_mtx); - g_finished.wait(lck); - g_quit.store(true); - } - - auto end = std::chrono::system_clock::now(); - auto duration = std::chrono::duration_cast(end - start); - - std::cout << "per msg time: " << duration.count() / (double)msgcount << "ms \n" - << "========================finished==============================\n"; - - for (size_t th = 0; th != work_pool.size(); ++th) { - work_pool[th]->join(); - } - - producer.shutdown(); - - return 0; -} diff --git a/example/TransactionProducer.cpp b/example/TransactionProducer.cpp deleted file mode 100644 index 1aabb0887..000000000 --- a/example/TransactionProducer.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include "TransactionListener.h" -#include "TransactionMQProducer.h" -#include "TransactionSendResult.h" -#include "common.h" - -using namespace rocketmq; - -std::atomic g_quit; -std::mutex g_mtx; -std::condition_variable g_finished; -TpsReportService g_tps; - -class MyTransactionListener : public TransactionListener { - virtual LocalTransactionState executeLocalTransaction(const MQMessage& msg, void* arg) { - if (!arg) { - std::cout << "executeLocalTransaction transactionId:" << msg.getTransactionId() - << ", return state: COMMIT_MESAGE " << endl; - return LocalTransactionState::COMMIT_MESSAGE; - } - - LocalTransactionState state = (LocalTransactionState)(*(int*)arg % 3); - std::cout << "executeLocalTransaction transactionId:" << msg.getTransactionId() << ", return state: " << state - << endl; - return state; - } - - virtual LocalTransactionState checkLocalTransaction(const MQMessageExt& msg) { - std::cout << "checkLocalTransaction enter msg:" << msg.toString() << endl; - return LocalTransactionState::COMMIT_MESSAGE; - } -}; - -void SyncProducerWorker(RocketmqSendAndConsumerArgs* info, TransactionMQProducer* producer) { - while (!g_quit.load()) { - if (g_msgCount.load() <= 0) { - std::this_thread::sleep_for(std::chrono::seconds(60)); - std::unique_lock lck(g_mtx); - g_finished.notify_one(); - break; - } - - MQMessage msg(info->topic, // topic - "*", // tag - info->body); // body - try { - auto start = std::chrono::system_clock::now(); - std::cout << "before sendMessageInTransaction" << endl; - LocalTransactionState state = LocalTransactionState::UNKNOWN; - TransactionSendResult sendResult = producer->sendMessageInTransaction(msg, &state); - std::cout << "after sendMessageInTransaction msgId: " << sendResult.getMsgId() << endl; - g_tps.Increment(); - --g_msgCount; - auto end = std::chrono::system_clock::now(); - auto duration = std::chrono::duration_cast(end - start); - if (duration.count() >= 500) { - std::cout << "send RT more than: " << duration.count() << " ms with msgid: " << sendResult.getMsgId() << endl; - } - } catch (const MQException& e) { - std::cout << "send failed: " << e.what() << std::endl; - } - } -} - -int main(int argc, char* argv[]) { - RocketmqSendAndConsumerArgs info; - if (!ParseArgs(argc, argv, &info)) { - exit(-1); - } - PrintRocketmqSendAndConsumerArgs(info); - TransactionMQProducer producer("please_rename_unique_group_name"); - producer.setNamesrvAddr(info.namesrv); - producer.setNamesrvDomain(info.namesrv_domain); - producer.setGroupName(info.groupname); - producer.setInstanceName(info.groupname); - producer.setSessionCredentials("mq acesskey", "mq secretkey", "ALIYUN"); - producer.setSendMsgTimeout(500); - producer.setTcpTransportTryLockTimeout(1000); - producer.setTcpTransportConnectTimeout(400); - producer.setLogLevel(eLOG_LEVEL_DEBUG); - producer.setTransactionListener(new MyTransactionListener()); - producer.start(); - std::vector> work_pool; - auto start = std::chrono::system_clock::now(); - int msgcount = g_msgCount.load(); - g_tps.start(); - - int threadCount = info.thread_count; - for (int j = 0; j < threadCount; j++) { - std::shared_ptr th = std::make_shared(SyncProducerWorker, &info, &producer); - work_pool.push_back(th); - } - - { - std::unique_lock lck(g_mtx); - g_finished.wait(lck); - g_quit.store(true); - } - - auto end = std::chrono::system_clock::now(); - auto duration = std::chrono::duration_cast(end - start); - - std::cout << "per msg time: " << duration.count() / (double)msgcount << "ms \n" - << "========================finished==============================\n"; - - for (size_t th = 0; th != work_pool.size(); ++th) { - work_pool[th]->join(); - } - - producer.shutdown(); - - return 0; -} diff --git a/example/common.h b/example/common.h deleted file mode 100644 index 065b759e8..000000000 --- a/example/common.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef ROCKETMQ_CLIENT4CPP_EXAMPLE_COMMON_H_ -#define ROCKETMQ_CLIENT4CPP_EXAMPLE_COMMON_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef WIN32 -#include "unistd.h" -#endif -#include "Arg_helper.h" -#include "DefaultMQProducer.h" -#include "DefaultMQPullConsumer.h" -#include "DefaultMQPushConsumer.h" -using namespace std; - -std::atomic g_msgCount(1); - -class RocketmqSendAndConsumerArgs { - public: - RocketmqSendAndConsumerArgs() - : body("msgbody for test"), - thread_count(std::thread::hardware_concurrency()), - broadcasting(false), - syncpush(false), - SelectUnactiveBroker(false), - IsAutoDeleteSendCallback(false), - retrytimes(5), - PrintMoreInfo(false) {} - - public: - std::string namesrv; - std::string namesrv_domain; - std::string groupname; - std::string topic; - std::string body; - int thread_count; - bool broadcasting; - bool syncpush; - bool SelectUnactiveBroker; // default select active broker - bool IsAutoDeleteSendCallback; - int retrytimes; // default retry 5 times; - bool PrintMoreInfo; -}; - -class TpsReportService { - public: - TpsReportService() : tps_interval_(1), quit_flag_(false), tps_count_(0) {} - - ~TpsReportService() { - quit_flag_.store(true); - if (tps_thread_ == nullptr) { - std::cout << "tps_thread_ is null" << std::endl; - return; - } - if (tps_thread_->joinable()) { - tps_thread_->join(); - } - } - - void start() { - if (tps_thread_ != nullptr) { - std::cout << "tps_thread_ is not null" << std::endl; - return; - } - tps_thread_.reset(new std::thread(std::bind(&TpsReportService::TpsReport, this))); - } - - void Increment() { ++tps_count_; } - - void TpsReport() { - while (!quit_flag_.load()) { - std::this_thread::sleep_for(tps_interval_); - std::cout << "tps: " << tps_count_.load() << std::endl; - tps_count_.store(0); - } - } - - private: - std::chrono::seconds tps_interval_; - std::shared_ptr tps_thread_; - std::atomic quit_flag_; - std::atomic tps_count_; -}; - -void PrintPullResult(rocketmq::PullResult* result) { - std::cout << result->toString() << std::endl; - if (result->pullStatus == rocketmq::FOUND) { - std::cout << result->toString() << endl; - std::vector::iterator it = result->msgFoundList.begin(); - for (; it != result->msgFoundList.end(); ++it) { - cout << "=======================================================" << endl << (*it).toString() << endl; - } - } -} - -static void PrintRocketmqSendAndConsumerArgs(const RocketmqSendAndConsumerArgs& info) { - std::cout << "nameserver: " << info.namesrv << endl - << "topic: " << info.topic << endl - << "groupname: " << info.groupname << endl - << "produce content: " << info.body << endl - << "msg count: " << g_msgCount.load() << endl - << "thread count: " << info.thread_count << endl; -} - -static void help() { - std::cout << "need option,like follow: \n" - << "-n nameserver addr, if not set -n and -i ,no nameSrv will be got \n" - "-i nameserver domain name, if not set -n and -i ,no nameSrv will be " - "got \n" - "-g groupname \n" - "-t msg topic \n" - "-m messagecout(default value: 1) \n" - "-c content(default value: only test ) \n" - "-b (BROADCASTING model, default value: CLUSTER) \n" - "-s sync push(default is async push)\n" - "-r setup retry times(default value: 5 times)\n" - "-u select active broker to send msg(default value: false)\n" - "-d use AutoDeleteSendcallback by cpp client(defalut value: false) \n" - "-T thread count of send msg or consume msg(defalut value: system cpu " - "core number) \n" - "-v print more details information \n"; -} - -static bool ParseArgs(int argc, char* argv[], RocketmqSendAndConsumerArgs* info) { -#ifndef WIN32 - int ch; - while ((ch = getopt(argc, argv, "n:i:g:t:m:c:b:s:h:r:T:bu")) != -1) { - switch (ch) { - case 'n': - info->namesrv.insert(0, optarg); - break; - case 'i': - info->namesrv_domain.insert(0, optarg); - break; - case 'g': - info->groupname.insert(0, optarg); - break; - case 't': - info->topic.insert(0, optarg); - break; - case 'm': - g_msgCount.store(atoi(optarg)); - break; - case 'c': - info->body.insert(0, optarg); - break; - case 'b': - info->broadcasting = true; - break; - case 's': - info->syncpush = true; - break; - case 'r': - info->retrytimes = atoi(optarg); - break; - case 'u': - info->SelectUnactiveBroker = true; - break; - case 'T': - info->thread_count = atoi(optarg); - break; - case 'v': - info->PrintMoreInfo = true; - break; - case 'h': - help(); - return false; - default: - help(); - return false; - } - } -#else - rocketmq::Arg_helper arg_help(argc, argv); - info->namesrv = arg_help.get_option_value("-n"); - info->namesrv_domain = arg_help.get_option_value("-i"); - info->groupname = arg_help.get_option_value("-g"); - info->topic = arg_help.get_option_value("-t"); - info->broadcasting = atoi(arg_help.get_option_value("-b").c_str()); - string msgContent(arg_help.get_option_value("-c")); - if (!msgContent.empty()) - info->body = msgContent; - info->syncpush = atoi(arg_help.get_option_value("-s").c_str()); - int retrytimes = atoi(arg_help.get_option_value("-r").c_str()); - if (retrytimes > 0) - info->retrytimes = retrytimes; - info->SelectUnactiveBroker = atoi(arg_help.get_option_value("-u").c_str()); - int thread_count = atoi(arg_help.get_option_value("-T").c_str()); - if (thread_count > 0) - info->thread_count = thread_count; - info->PrintMoreInfo = atoi(arg_help.get_option_value("-v").c_str()); - g_msgCount = atoi(arg_help.get_option_value("-m").c_str()); -#endif - if (info->groupname.empty() || info->topic.empty() || (info->namesrv_domain.empty() && info->namesrv.empty())) { - std::cout << "please use -g to setup groupname and -t setup topic \n"; - help(); - return false; - } - return true; -} -#endif // ROCKETMQ_CLIENT4CPP_EXAMPLE_COMMON_H_ diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel new file mode 100644 index 000000000..dfa114a2d --- /dev/null +++ b/examples/BUILD.bazel @@ -0,0 +1,137 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_binary") + +cc_binary( + name = "example_producer", + srcs = [ + "ExampleProducer.cpp", + ], + deps = [ + "//src/main/cpp/rocketmq:rocketmq_library", + ], +) + +cc_binary( + name = "example_fifo_producer", + srcs = [ + "ExampleFifoProducer.cpp", + ], + deps = [ + "//src/main/cpp/rocketmq:rocketmq_library", + ], +) + +cc_binary( + name = "example_async_producer", + srcs = [ + "ExampleAsyncProducer.cpp", + ], + deps = [ + "//src/main/cpp/rocketmq:rocketmq_library", + ], +) + +cc_binary( + name = "example_simple_consumer", + srcs = [ + "ExampleSimpleConsumer.cpp", + ], + deps = [ + "//src/main/cpp/rocketmq:rocketmq_library", + ], +) + +# cc_binary( +# name = "sql_producer", +# srcs = [ +# "SqlProducer.cpp", +# ], +# deps = [ +# "//src/main/cpp/rocketmq:rocketmq_library", +# ], +# ) + +cc_binary( + name = "example_push_consumer", + srcs = [ + "ExamplePushConsumer.cpp", + ], + deps = [ + "//src/main/cpp/rocketmq:rocketmq_library", + ], +) + +# cc_binary( +# name = "example_fifo_push_consumer", +# srcs = [ +# "ExampleFifoPushConsumer.cpp", +# ], +# deps = [ +# "//src/main/cpp/rocketmq:rocketmq_library", +# ], +# ) + +# cc_binary( +# name = "push_consumer_with_custom_executor", +# srcs = [ +# "PushConsumerWithCustomExecutor.cpp", +# ], +# deps = [ +# "//src/main/cpp/rocketmq:rocketmq_library", +# ], +# ) + +# cc_binary( +# name = "push_consumer_with_throttle", +# srcs = [ +# "PushConsumerWithThrottle.cpp", +# ], +# deps = [ +# "//src/main/cpp/rocketmq:rocketmq_library", +# ], +# ) + +# cc_binary( +# name = "sql_consumer", +# srcs = [ +# "SqlConsumer.cpp", +# ], +# deps = [ +# "//src/main/cpp/rocketmq:rocketmq_library", +# ], +# ) + +# cc_binary( +# name = "benchmark_push_consumer", +# srcs = [ +# "BenchmarkPushConsumer.cpp", +# ], +# deps = [ +# "//src/main/cpp/rocketmq:rocketmq_library", +# ], +# ) + +# cc_binary( +# name = "example_transaction_producer", +# srcs = [ +# "ExampleTransactionProducer.cpp", +# ], +# deps = [ +# "//src/main/cpp/rocketmq:rocketmq_library", +# ], +# ) \ No newline at end of file diff --git a/examples/BenchmarkPushConsumer.cpp b/examples/BenchmarkPushConsumer.cpp new file mode 100644 index 000000000..400fa8071 --- /dev/null +++ b/examples/BenchmarkPushConsumer.cpp @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "rocketmq/DefaultMQPushConsumer.h" + +#include +#include +#include +#include +#include + +using namespace rocketmq; + +class CounterMessageListener : public StandardMessageListener { +public: + explicit CounterMessageListener(std::atomic_long& counter) : counter_(counter) { + } + + ConsumeMessageResult consumeMessage(const std::vector& msgs) override { + counter_.fetch_add(msgs.size()); + return ConsumeMessageResult::SUCCESS; + } + +private: + std::atomic_long& counter_; +}; + +int main(int argc, char* argv[]) { + + Logger& logger = getLogger(); + logger.setLevel(Level::Debug); + logger.init(); + + std::atomic_long counter(0); + + DefaultMQPushConsumer push_consumer("CID_sample"); + MessageListener* listener = new CounterMessageListener(counter); + + push_consumer.setGroupName("CID_sample"); + push_consumer.setInstanceName("CID_sample_member_0"); + push_consumer.subscribe("TopicTest", "*"); + push_consumer.setNamesrvAddr("11.167.164.105:9876"); + push_consumer.registerMessageListener(listener); + push_consumer.start(); + + std::atomic_bool stopped(false); + std::thread report_thread([&counter, &stopped]() { + while (!stopped) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + long qps; + while (true) { + qps = counter.load(std::memory_order_relaxed); + if (counter.compare_exchange_weak(qps, 0, std::memory_order_relaxed)) { + break; + } + } + std::cout << "QPS: " << qps << std::endl; + } + }); + + std::this_thread::sleep_for(std::chrono::minutes(30)); + stopped.store(true); + + if (report_thread.joinable()) { + report_thread.join(); + } + + push_consumer.shutdown(); + return EXIT_SUCCESS; +} diff --git a/examples/ExampleAsyncProducer.cpp b/examples/ExampleAsyncProducer.cpp new file mode 100644 index 000000000..2d28d74dd --- /dev/null +++ b/examples/ExampleAsyncProducer.cpp @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "rocketmq/Message.h" +#include "rocketmq/Producer.h" + +using namespace ROCKETMQ_NAMESPACE; + +const std::string& alphaNumeric() { + static std::string alpha_numeric("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + return alpha_numeric; +} + +std::string randomString(std::string::size_type len) { + std::string result; + result.reserve(len); + std::random_device rd; + std::mt19937 generator(rd()); + std::string source(alphaNumeric()); + std::string::size_type generated = 0; + while (generated < len) { + std::shuffle(source.begin(), source.end(), generator); + std::string::size_type delta = std::min({len - generated, source.length()}); + result.append(source.substr(0, delta)); + generated += delta; + } + return result; +} + +int main(int argc, char* argv[]) { + const char* topic = "cpp_sdk_standard"; + const char* name_server = "11.166.42.94:8081"; + + auto producer = + Producer::newBuilder().withConfiguration(Configuration::newBuilder().withEndpoints(name_server).build()).build(); + + std::atomic_bool stopped; + std::atomic_long count(0); + + auto stats_lambda = [&] { + while (!stopped.load(std::memory_order_relaxed)) { + long cnt = count.load(std::memory_order_relaxed); + while (count.compare_exchange_weak(cnt, 0)) { + break; + } + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::cout << "QPS: " << cnt << std::endl; + } + }; + + std::thread stats_thread(stats_lambda); + + std::string body = randomString(1024 * 4); + std::cout << "Message body size: " << body.length() << std::endl; + + std::size_t total = 256; + std::size_t completed = 0; + std::mutex mtx; + std::condition_variable cv; + + try { + auto send_callback = [&](const std::error_code& ec, const SendReceipt& receipt) { + std::unique_lock lk(mtx); + completed++; + count++; + std::cout << "Message[id=" << receipt.message_id << "] sent" << std::endl; + if (completed >= total) { + cv.notify_all(); + } + }; + + for (std::size_t i = 0; i < total; ++i) { + auto message = Message::newBuilder().withTopic(topic).withTag("TagA").withKeys({"Key-0"}).withBody(body).build(); + producer.send(std::move(message), send_callback); + } + + { + std::unique_lock lk(mtx); + cv.wait(lk, [&]() { return completed >= total; }); + } + } catch (...) { + std::cerr << "Ah...No!!!" << std::endl; + } + stopped.store(true, std::memory_order_relaxed); + if (stats_thread.joinable()) { + stats_thread.join(); + } + + std::this_thread::sleep_for(std::chrono::seconds(1)); + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/examples/ExampleFifoProducer.cpp b/examples/ExampleFifoProducer.cpp new file mode 100644 index 000000000..947ae5dc6 --- /dev/null +++ b/examples/ExampleFifoProducer.cpp @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +#include "rocketmq/Message.h" +#include "rocketmq/Producer.h" + +using namespace ROCKETMQ_NAMESPACE; + +const std::string& alphaNumeric() { + static std::string alpha_numeric("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + return alpha_numeric; +} + +std::string randomString(std::string::size_type len) { + std::string result; + result.reserve(len); + std::random_device rd; + std::mt19937 generator(rd()); + std::string source(alphaNumeric()); + std::string::size_type generated = 0; + while (generated < len) { + std::shuffle(source.begin(), source.end(), generator); + std::string::size_type delta = std::min({len - generated, source.length()}); + result.append(source.substr(0, delta)); + generated += delta; + } + return result; +} + +int main(int argc, char* argv[]) { + const char* topic = "cpp_sdk_standard"; + const char* name_server = "11.166.42.94:8081"; + + auto producer = + Producer::newBuilder().withConfiguration(Configuration::newBuilder().withEndpoints(name_server).build()).build(); + + std::atomic_bool stopped; + std::atomic_long count(0); + + auto stats_lambda = [&] { + while (!stopped.load(std::memory_order_relaxed)) { + long cnt = count.load(std::memory_order_relaxed); + while (count.compare_exchange_weak(cnt, 0)) { + break; + } + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::cout << "QPS: " << cnt << std::endl; + } + }; + + std::thread stats_thread(stats_lambda); + + std::string body = randomString(1024 * 4); + std::cout << "Message body size: " << body.length() << std::endl; + + try { + for (int i = 0; i < 256; ++i) { + auto message = Message::newBuilder() + .withTopic(topic) + .withTag("TagA") + .withKeys({"Key-0"}) + .withBody(body) + .withGroup("message-group-0") + .build(); + std::error_code ec; + SendReceipt send_receipt = producer.send(std::move(message), ec); + std::cout << "Message-ID: " << send_receipt.message_id << std::endl; + count++; + } + } catch (...) { + std::cerr << "Ah...No!!!" << std::endl; + } + + stopped.store(true, std::memory_order_relaxed); + if (stats_thread.joinable()) { + stats_thread.join(); + } + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/examples/ExampleFifoPushConsumer.cpp b/examples/ExampleFifoPushConsumer.cpp new file mode 100644 index 000000000..df039d7f8 --- /dev/null +++ b/examples/ExampleFifoPushConsumer.cpp @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include + +#include "rocketmq/Logger.h" + +#include "rocketmq/MessageListener.h" +#include "spdlog/spdlog.h" + +#include "rocketmq/DefaultMQPushConsumer.h" + +using namespace rocketmq; + +class SampleMQMessageListener : public FifoMessageListener { +public: + ConsumeMessageResult consumeMessage(const MQMessageExt& message) override { + SPDLOG_INFO("Consume message[Topic={}, MessageId={}] OK", message.getTopic(), message.getMsgId()); + std::cout << "Consume Message[MsgId=" << message.getMsgId() << "] OK. Body Size: " << message.getBody().size() + << std::endl; + // std::this_thread::sleep_for(std::chrono::seconds(1)); + return ConsumeMessageResult::SUCCESS; + } +}; + +int main(int argc, char* argv[]) { + + Logger& logger = getLogger(); + logger.setLevel(Level::Debug); + logger.init(); + + const char* group_id = "GID_lingchu_test_order"; + const char* topic = "lingchu_test_order_topic"; + const char* resource_namespace = "MQ_INST_1080056302921134_BXyTLppt"; + + DefaultMQPushConsumer push_consumer(group_id); + push_consumer.setResourceNamespace(resource_namespace); + push_consumer.setCredentialsProvider(std::make_shared()); + push_consumer.setNamesrvAddr("120.25.100.131:8081"); + FifoMessageListener* listener = new SampleMQMessageListener(); + push_consumer.setInstanceName("instance_0"); + push_consumer.subscribe(topic, "*"); + push_consumer.registerMessageListener(listener); + push_consumer.setConsumeThreadCount(4); + push_consumer.start(); + + std::this_thread::sleep_for(std::chrono::minutes(30)); + + push_consumer.shutdown(); + return EXIT_SUCCESS; +} diff --git a/examples/ExampleProducer.cpp b/examples/ExampleProducer.cpp new file mode 100644 index 000000000..fa86af73a --- /dev/null +++ b/examples/ExampleProducer.cpp @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include + +#include "rocketmq/Message.h" +#include "rocketmq/Producer.h" + +using namespace ROCKETMQ_NAMESPACE; + +const std::string& alphaNumeric() { + static std::string alpha_numeric("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + return alpha_numeric; +} + +std::string randomString(std::string::size_type len) { + std::string result; + result.reserve(len); + std::random_device rd; + std::mt19937 generator(rd()); + std::string source(alphaNumeric()); + std::string::size_type generated = 0; + while (generated < len) { + std::shuffle(source.begin(), source.end(), generator); + std::string::size_type delta = std::min({len - generated, source.length()}); + result.append(source.substr(0, delta)); + generated += delta; + } + return result; +} + +int main(int argc, char* argv[]) { + const char* topic = "cpp_sdk_standard"; + const char* name_server = "11.166.42.94:8081"; + + auto producer = + Producer::newBuilder().withConfiguration(Configuration::newBuilder().withEndpoints(name_server).build()).build(); + + std::atomic_bool stopped; + std::atomic_long count(0); + + auto stats_lambda = [&] { + while (!stopped.load(std::memory_order_relaxed)) { + long cnt = count.load(std::memory_order_relaxed); + while (count.compare_exchange_weak(cnt, 0)) { + break; + } + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::cout << "QPS: " << cnt << std::endl; + } + }; + + std::thread stats_thread(stats_lambda); + + std::string body = randomString(1024 * 4); + std::cout << "Message body size: " << body.length() << std::endl; + + try { + for (int i = 0; i < 256; ++i) { + auto message = Message::newBuilder().withTopic(topic).withTag("TagA").withKeys({"Key-0"}).withBody(body).build(); + std::error_code ec; + SendReceipt send_receipt = producer.send(std::move(message), ec); + std::cout << "Message-ID: " << send_receipt.message_id << std::endl; + count++; + } + } catch (...) { + std::cerr << "Ah...No!!!" << std::endl; + } + stopped.store(true, std::memory_order_relaxed); + if (stats_thread.joinable()) { + stats_thread.join(); + } + + // std::this_thread::sleep_for(std::chrono::seconds(1)); + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/examples/ExamplePushConsumer.cpp b/examples/ExamplePushConsumer.cpp new file mode 100644 index 000000000..00954ffea --- /dev/null +++ b/examples/ExamplePushConsumer.cpp @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include + +#include "rocketmq/Logger.h" +#include "rocketmq/PushConsumer.h" +#include "spdlog/spdlog.h" + +using namespace ROCKETMQ_NAMESPACE; + +int main(int argc, char* argv[]) { + const char* topic = "cpp_sdk_standard"; + const char* name_server = "11.166.42.94:8081"; + const char* group = "GID_cpp_sdk_standard"; + std::string tag = "*"; + + auto listener = [](const Message& message) { return ConsumeResult::SUCCESS; }; + + auto push_consumer = PushConsumer::newBuilder() + .withGroup(group) + .withConfiguration(Configuration::newBuilder() + .withEndpoints(name_server) + .withRequestTimeout(std::chrono::seconds(3)) + .build()) + .withConsumeThreads(4) + .withListener(listener) + .subscribe(topic, tag) + .build(); + + std::this_thread::sleep_for(std::chrono::minutes(30)); + + return EXIT_SUCCESS; +} diff --git a/examples/ExampleSimpleConsumer.cpp b/examples/ExampleSimpleConsumer.cpp new file mode 100644 index 000000000..dc7671874 --- /dev/null +++ b/examples/ExampleSimpleConsumer.cpp @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include + +#include "rocketmq/SimpleConsumer.h" + +using namespace ROCKETMQ_NAMESPACE; + +int main(int argc, char* argv[]) { + const char* group = "ExampleSimpleGroup"; + const char* topic = "cpp_sdk_standard"; + const char* name_server = "11.166.42.94:8081"; + std::string tag = "*"; + + auto simple_consumer = SimpleConsumer::newBuilder() + .withGroup(group) + .withConfiguration(Configuration::newBuilder().withEndpoints(name_server).build()) + .subscribe(topic, tag) + .build(); + std::vector messages; + std::error_code ec; + simple_consumer.receive(4, std::chrono::seconds(3), ec, messages); + + if (ec) { + std::cerr << "Failed to receive messages. Cause: " << ec.message() << std::endl; + return EXIT_FAILURE; + } + + std::cout << "Received " << messages.size() << " messages" << std::endl; + std::size_t i = 0; + for (const auto& message : messages) { + std::cout << "Received a message[topic=" << message->topic() << ", message-id=" << message->id() + << ", receipt-handle='" << message->extension().receipt_handle << "']" << std::endl; + + std::error_code ec; + if (++i % 2 == 0) { + simple_consumer.ack(*message, ec); + if (ec) { + std::cerr << "Failed to ack message. Cause: " << ec.message() << std::endl; + } + } else { + simple_consumer.changeInvisibleDuration(*message, std::chrono::milliseconds(100), ec); + if (ec) { + std::cerr << "Failed to change invisible duration of message. Cause: " << ec.message() << std::endl; + } + } + } + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/examples/ExampleTransactionProducer.cpp b/examples/ExampleTransactionProducer.cpp new file mode 100644 index 000000000..1041b9267 --- /dev/null +++ b/examples/ExampleTransactionProducer.cpp @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "rocketmq/DefaultMQProducer.h" +#include + +using namespace ROCKETMQ_NAMESPACE; + +int main(int argc, char* argv[]) { + DefaultMQProducer producer("TestGroup"); + + const char* topic = "cpp_sdk_standard"; + const char* name_server = "47.98.116.189:80"; + + producer.setNamesrvAddr(name_server); + producer.compressBodyThreshold(256); + const char* resource_namespace = "MQ_INST_1080056302921134_BXuIbML7"; + producer.setRegion("cn-hangzhou-pre"); + producer.setResourceNamespace(resource_namespace); + producer.setCredentialsProvider(std::make_shared()); + + MQMessage message; + message.setTopic(topic); + message.setTags("TagA"); + message.setKey("Yuck! Why-plural?"); + message.setBody("ABC"); + + producer.start(); + + auto transaction = producer.prepare(message); + + transaction->commit(); + + std::this_thread::sleep_for(std::chrono::minutes(30)); + + producer.shutdown(); + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/examples/PushConsumerWithCustomExecutor.cpp b/examples/PushConsumerWithCustomExecutor.cpp new file mode 100644 index 000000000..82dd57de4 --- /dev/null +++ b/examples/PushConsumerWithCustomExecutor.cpp @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "rocketmq/DefaultMQPushConsumer.h" +#include "rocketmq/State.h" +#include +#include +#include +#include +#include +#include + +ROCKETMQ_NAMESPACE_BEGIN + +class ExecutorImpl { +public: + ExecutorImpl() : state_(State::CREATED) { + } + + virtual ~ExecutorImpl() { + switch (state_.load(std::memory_order_relaxed)) { + case CREATED: + case STOPPING: + case STOPPED: + break; + + case STARTING: + case STARTED: + state_.store(State::STOPPED); + if (worker_.joinable()) { + worker_.join(); + } + break; + } + } + + void submit(const std::function& task) { + if (State::STOPPED == state_.load(std::memory_order_relaxed)) { + return; + } + + { + std::unique_lock lock(task_mtx_); + tasks_.push_back(task); + } + cv_.notify_one(); + } + + void start() { + State expected = State::CREATED; + if (state_.compare_exchange_strong(expected, State::STARTING)) { + worker_ = std::thread(std::bind(&ExecutorImpl::loop, this)); + state_.store(State::STARTED); + } + } + + void stop() { + state_.store(State::STOPPED); + if (worker_.joinable()) { + worker_.join(); + } + } + +private: + void loop() { + while (state_.load(std::memory_order_relaxed) != State::STOPPED) { + std::function func; + { + std::unique_lock lk(task_mtx_); + if (!tasks_.empty()) { + func = tasks_.back(); + } + } + + if (func) { + func(); + } else { + std::unique_lock lk(task_mtx_); + cv_.wait_for(lk, std::chrono::seconds(3), + [&]() { return state_.load(std::memory_order_relaxed) == State::STOPPED || !tasks_.empty(); }); + } + } + } + + std::atomic state_; + std::vector> tasks_; + std::mutex task_mtx_; + std::condition_variable cv_; + std::thread worker_; +}; + +class SampleMQMessageListener : public StandardMessageListener { +public: + ConsumeMessageResult consumeMessage(const std::vector& msgs) override { + std::lock_guard lk(console_mtx_); + for (const MQMessageExt& msg : msgs) { + std::cout << "Topic=" << msg.getTopic() << ", MsgId=" << msg.getMsgId() << ", Body=" << msg.getBody() + << std::endl; + } + return ConsumeMessageResult::SUCCESS; + } + +private: + std::mutex console_mtx_; +}; + +ROCKETMQ_NAMESPACE_END + +int main(int argc, char* argv[]) { + using namespace ROCKETMQ_NAMESPACE; + Logger& logger = getLogger(); + logger.setLevel(Level::Debug); + logger.init(); + + DefaultMQPushConsumer push_consumer("TestGroup"); + MessageListener* listener = new SampleMQMessageListener; + + auto pool = new ExecutorImpl; + pool->start(); + push_consumer.setCustomExecutor(std::bind(&ExecutorImpl::submit, pool, std::placeholders::_1)); + push_consumer.setGroupName("TestGroup"); + push_consumer.setInstanceName("CID_sample_member_0"); + push_consumer.subscribe("TestTopic", "*"); + push_consumer.setNamesrvAddr("11.167.164.105:9876"); + push_consumer.registerMessageListener(listener); + push_consumer.start(); + + std::this_thread::sleep_for(std::chrono::minutes(30)); + pool->stop(); + delete pool; + + push_consumer.shutdown(); + return EXIT_SUCCESS; +} diff --git a/examples/PushConsumerWithThrottle.cpp b/examples/PushConsumerWithThrottle.cpp new file mode 100644 index 000000000..c03b6c54e --- /dev/null +++ b/examples/PushConsumerWithThrottle.cpp @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "rocketmq/DefaultMQPushConsumer.h" + +#include +#include +#include +#include +#include + +ROCKETMQ_NAMESPACE_BEGIN + +class CounterMessageListener : public StandardMessageListener { +public: + explicit CounterMessageListener(std::atomic_long& counter) : counter_(counter) { + } + + ConsumeMessageResult consumeMessage(const std::vector& msgs) override { + counter_.fetch_add(msgs.size()); + return ConsumeMessageResult::SUCCESS; + } + +private: + std::atomic_long& counter_; +}; + +ROCKETMQ_NAMESPACE_END + +int main(int argc, char* argv[]) { + + using namespace ROCKETMQ_NAMESPACE; + + Logger& logger = getLogger(); + logger.setLevel(Level::Debug); + logger.init(); + + std::atomic_long counter(0); + + DefaultMQPushConsumer push_consumer("TestGroup"); + MessageListener* listener = new CounterMessageListener(counter); + + push_consumer.setGroupName("TestGroup"); + push_consumer.setInstanceName("CID_sample_member_0"); + push_consumer.subscribe("TestTopic", "*"); + push_consumer.setNamesrvAddr("11.167.164.105:9876"); + push_consumer.registerMessageListener(listener); + push_consumer.setThrottle("TestTopic", 20); + push_consumer.start(); + + std::atomic_bool stopped(false); + std::thread report_thread([&counter, &stopped]() { + while (!stopped) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + long qps; + while (true) { + qps = counter.load(std::memory_order_relaxed); + if (counter.compare_exchange_weak(qps, 0, std::memory_order_relaxed)) { + break; + } + } + std::cout << "QPS: " << qps << std::endl; + } + }); + + std::this_thread::sleep_for(std::chrono::seconds(10)); + stopped.store(true); + + if (report_thread.joinable()) { + report_thread.join(); + } + + push_consumer.shutdown(); + return EXIT_SUCCESS; +} diff --git a/examples/SqlConsumer.cpp b/examples/SqlConsumer.cpp new file mode 100644 index 000000000..c07e4a034 --- /dev/null +++ b/examples/SqlConsumer.cpp @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "rocketmq/DefaultMQPushConsumer.h" + +#include +#include +#include +#include + +using namespace rocketmq; + +class SampleMQMessageListener : public StandardMessageListener { +public: + ConsumeMessageResult consumeMessage(const std::vector& msgs) override { + std::lock_guard lk(console_mtx_); + for (const MQMessageExt& msg : msgs) { + std::cout << "Topic=" << msg.getTopic() << ", MsgId=" << msg.getMsgId() << ", Tag=" << msg.getTags() + << ", a=" << msg.getProperty("a") << ", Body=" << msg.getBody() << std::endl; + } + return ConsumeMessageResult::SUCCESS; + } + +private: + std::mutex console_mtx_; +}; + +int main(int argc, char* argv[]) { + Logger& logger = getLogger(); + logger.setLevel(Level::Debug); + logger.init(); + + DefaultMQPushConsumer push_consumer("TestGroup"); + MessageListener* listener = new SampleMQMessageListener; + + push_consumer.setGroupName("TestGroup"); + push_consumer.setInstanceName("CID_sample_member_0"); + std::string sql_filter("(TAGS is not null and TAGS in ('TagA', 'TagB')) and (a is not null and a between 0 and 3)"); + push_consumer.subscribe("TestTopic", sql_filter, ExpressionType::SQL92); + // push_consumer.setNamesrvAddr("11.167.164.105:9876"); + push_consumer.registerMessageListener(listener); + push_consumer.start(); + + std::this_thread::sleep_for(std::chrono::seconds(30)); + + push_consumer.shutdown(); + return EXIT_SUCCESS; +} diff --git a/examples/SqlProducer.cpp b/examples/SqlProducer.cpp new file mode 100644 index 000000000..bc0fb4744 --- /dev/null +++ b/examples/SqlProducer.cpp @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "rocketmq/DefaultMQProducer.h" +#include + +using namespace rocketmq; + +int main(int argc, char* argv[]) { + + Logger& logger = getLogger(); + logger.setLevel(Level::Debug); + logger.init(); + + DefaultMQProducer producer("PID_sample"); + producer.setNamesrvAddr("11.167.164.105:9876"); + + MQMessage message; + message.setTopic("TestTopic"); + try { + producer.start(); + for (int i = 0; i < 8; ++i) { + std::string body = std::to_string(i); + message.setBody(body); + message.setProperty("a", std::to_string(i % 5)); + switch (i % 3) { + case 0: + message.setTags("TagA"); + break; + case 1: + message.setTags("TagB"); + break; + case 2: + message.setTags("TagC"); + break; + } + SendResult sendResult = producer.send(message); + std::cout << "Message sent with msgId=" << sendResult.getMsgId() + << ", Queue=" << sendResult.getMessageQueue().simpleName() << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + } catch (...) { + std::cerr << "Ah...No!!!" << std::endl; + } + producer.shutdown(); + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/format.sh b/format.sh deleted file mode 100755 index 7aa812efe..000000000 --- a/format.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/bash - -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. - - -TMPFILE=".clang_format_file.tmp" -FORMAT="{BasedOnStyle: Chromium, ColumnLimit: 120, TabWidth: 2}" - -function Usage -{ - echo "Usage: $0 want-format-file|want-format-dir ..." - #echo "Currently only format a file or dir at a time" -} - -#Setp1 check clang-format support -if ! which clang-format &> /dev/null; then - echo -e "\033[32m !!!!!!please install clang-format \033[0m" - exit 1 -fi - - -#Setp2 check weather incoming format file -if [ ! $# -ge 1 ];then - Usage - exit 1 -fi - -for dest in "$@" -do - if [ ! -e $dest ]; then - echo -e "\033[32m $dest not exists,please check this file weather exists \033[0m" - fi -done - - -#Setp3 get filelist -for dest in $* -do - if [ -f $dest ];then - files="$files $dest" - elif [ -d $dest ];then - files="$files `ls $dest/*.cpp $dest/*.h $dest/*.cc 2>/dev/null`" - else - echo -e "\033[32m $dest sorry current $0 only support regular file or dir \033[0m" - fi -done - -#Setp4 use clang-format format dest file -for file in $files -do - echo $file - clang-format $file > $TMPFILE - - if [ -e $TMPFILE ];then - filesize=`wc -c $TMPFILE |cut -d " " -f1` - if [ $filesize -eq 0 ];then - echo -e "\033[32m formt file error,May be because of the size of the source file is 0, or format program error \033[0m" - exit 1 - fi - fi - - #Setp4 replace source file - mv -f $TMPFILE $file -done diff --git a/include/AsyncCallback.h b/include/AsyncCallback.h deleted file mode 100644 index 8ebac1d2a..000000000 --- a/include/AsyncCallback.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __SENDCALLBACK_H__ -#define __SENDCALLBACK_H__ - -#include "MQClientException.h" -#include "PullResult.h" -#include "RocketMQClient.h" -#include "SendResult.h" - -namespace rocketmq { -struct AsyncCallback {}; -typedef enum sendCallbackType { noAutoDeleteSendCallback = 0, autoDeleteSendCallback = 1 } sendCallbackType; - -class ROCKETMQCLIENT_API SendCallback : public AsyncCallback { - public: - virtual ~SendCallback() {} - virtual void onSuccess(SendResult& sendResult) = 0; - virtual void onException(MQException& e) = 0; - virtual sendCallbackType getSendCallbackType() { return noAutoDeleteSendCallback; } -}; - -// async SendCallback will be deleted automatically by rocketmq cpp after invoke callback interface -class ROCKETMQCLIENT_API AutoDeleteSendCallBack : public SendCallback { - public: - virtual ~AutoDeleteSendCallBack() {} - virtual void onSuccess(SendResult& sendResult) = 0; - virtual void onException(MQException& e) = 0; - virtual sendCallbackType getSendCallbackType() { return autoDeleteSendCallback; } -}; - -class ROCKETMQCLIENT_API PullCallback : public AsyncCallback { - public: - virtual ~PullCallback() {} - virtual void onSuccess(MQMessageQueue& mq, PullResult& result, bool bProducePullRequest) = 0; - virtual void onException(MQException& e) = 0; -}; -} // namespace rocketmq -#endif diff --git a/include/CCommon.h b/include/CCommon.h deleted file mode 100644 index ae8a9e1b3..000000000 --- a/include/CCommon.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __C_COMMON_H__ -#define __C_COMMON_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#define MAX_MESSAGE_ID_LENGTH 256 -#define MAX_TOPIC_LENGTH 512 -#define MAX_BROKER_NAME_ID_LENGTH 256 -#define MAX_SDK_VERSION_LENGTH 256 -#define DEFAULT_SDK_VERSION "DefaultVersion" -typedef enum _CStatus_ { - // Success - OK = 0, - // Failed, null pointer value - NULL_POINTER = 1, - MALLOC_FAILED = 2, - PRODUCER_ERROR_CODE_START = 10, - PRODUCER_START_FAILED = 10, - PRODUCER_SEND_SYNC_FAILED = 11, - PRODUCER_SEND_ONEWAY_FAILED = 12, - PRODUCER_SEND_ORDERLY_FAILED = 13, - PRODUCER_SEND_ASYNC_FAILED = 14, - PRODUCER_SEND_ORDERLYASYNC_FAILED = 15, - PRODUCER_SEND_TRANSACTION_FAILED = 16, - - PUSHCONSUMER_ERROR_CODE_START = 20, - PUSHCONSUMER_START_FAILED = 20, - - PULLCONSUMER_ERROR_CODE_START = 30, - PULLCONSUMER_START_FAILED = 30, - PULLCONSUMER_FETCH_MQ_FAILED = 31, - PULLCONSUMER_FETCH_MESSAGE_FAILED = 32, - - Not_Support = 500, - NOT_SUPPORT_NOW = -1 -} CStatus; - -typedef enum _CLogLevel_ { - E_LOG_LEVEL_FATAL = 1, - E_LOG_LEVEL_ERROR = 2, - E_LOG_LEVEL_WARN = 3, - E_LOG_LEVEL_INFO = 4, - E_LOG_LEVEL_DEBUG = 5, - E_LOG_LEVEL_TRACE = 6, - E_LOG_LEVEL_LEVEL_NUM = 7 -} CLogLevel; - -#ifdef WIN32 -#ifdef ROCKETMQCLIENT_EXPORTS -#ifdef _WINDLL -#define ROCKETMQCLIENT_API __declspec(dllexport) -#else -#define ROCKETMQCLIENT_API -#endif -#else -#ifdef ROCKETMQCLIENT_IMPORT -#define ROCKETMQCLIENT_API __declspec(dllimport) -#else -#define ROCKETMQCLIENT_API -#endif -#endif -#else -#define ROCKETMQCLIENT_API -#endif - -typedef enum _CMessageModel_ { BROADCASTING, CLUSTERING } CMessageModel; -typedef enum _CTraceModel_ { OPEN, CLOSE } CTraceModel; - -#ifdef __cplusplus -} -#endif -#endif //__C_COMMON_H__ diff --git a/include/CMQException.h b/include/CMQException.h deleted file mode 100644 index 4bdf3d149..000000000 --- a/include/CMQException.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __C_MQEXCPTION_H__ -#define __C_MQEXCPTION_H__ -#include "CCommon.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define MAX_EXEPTION_MSG_LENGTH 512 -#define MAX_EXEPTION_FILE_LENGTH 256 -#define MAX_EXEPTION_TYPE_LENGTH 128 -typedef struct _CMQException_ { - int error; - int line; - char file[MAX_EXEPTION_FILE_LENGTH]; - char msg[MAX_EXEPTION_MSG_LENGTH]; - char type[MAX_EXEPTION_TYPE_LENGTH]; - -} CMQException; - -#ifdef __cplusplus -} -#endif -#endif diff --git a/include/CMessage.h b/include/CMessage.h deleted file mode 100644 index a02305dd6..000000000 --- a/include/CMessage.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __C_MESSAGE_H__ -#define __C_MESSAGE_H__ -#include "CCommon.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// typedef struct _CMessage_ CMessage; -typedef struct CMessage CMessage; - -ROCKETMQCLIENT_API CMessage* CreateMessage(const char* topic); -ROCKETMQCLIENT_API int DestroyMessage(CMessage* msg); -ROCKETMQCLIENT_API int SetMessageTopic(CMessage* msg, const char* topic); -ROCKETMQCLIENT_API int SetMessageTags(CMessage* msg, const char* tags); -ROCKETMQCLIENT_API int SetMessageKeys(CMessage* msg, const char* keys); -ROCKETMQCLIENT_API int SetMessageBody(CMessage* msg, const char* body); -ROCKETMQCLIENT_API int SetByteMessageBody(CMessage* msg, const char* body, int len); -ROCKETMQCLIENT_API int SetMessageProperty(CMessage* msg, const char* key, const char* value); -ROCKETMQCLIENT_API int SetDelayTimeLevel(CMessage* msg, int level); -ROCKETMQCLIENT_API const char* GetOriginMessageTopic(CMessage* msg); -ROCKETMQCLIENT_API const char* GetOriginMessageTags(CMessage* msg); -ROCKETMQCLIENT_API const char* GetOriginMessageKeys(CMessage* msg); -ROCKETMQCLIENT_API const char* GetOriginMessageBody(CMessage* msg); -ROCKETMQCLIENT_API int GetOriginMessageBodyLength(CMessage* msg); -ROCKETMQCLIENT_API const char* GetOriginMessageProperty(CMessage* msg, const char* key); -ROCKETMQCLIENT_API int GetOriginDelayTimeLevel(CMessage* msg); - -#ifdef __cplusplus -} -#endif -#endif //__C_MESSAGE_H__ diff --git a/include/CMessageExt.h b/include/CMessageExt.h deleted file mode 100644 index 818ee726f..000000000 --- a/include/CMessageExt.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __C_MESSAGE_EXT_H__ -#define __C_MESSAGE_EXT_H__ - -#include "CCommon.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// typedef struct _CMessageExt_ _CMessageExt; -typedef struct CMessageExt CMessageExt; - -ROCKETMQCLIENT_API const char* GetMessageTopic(CMessageExt* msgExt); -ROCKETMQCLIENT_API const char* GetMessageTags(CMessageExt* msgExt); -ROCKETMQCLIENT_API const char* GetMessageKeys(CMessageExt* msgExt); -ROCKETMQCLIENT_API const char* GetMessageBody(CMessageExt* msgExt); -ROCKETMQCLIENT_API int GetMessageBodyLength(CMessageExt* msgExt); -ROCKETMQCLIENT_API const char* GetMessageProperty(CMessageExt* msgExt, const char* key); -ROCKETMQCLIENT_API const char* GetMessageId(CMessageExt* msgExt); -ROCKETMQCLIENT_API int GetMessageDelayTimeLevel(CMessageExt* msgExt); -ROCKETMQCLIENT_API int GetMessageQueueId(CMessageExt* msgExt); -ROCKETMQCLIENT_API int GetMessageReconsumeTimes(CMessageExt* msgExt); -ROCKETMQCLIENT_API int GetMessageStoreSize(CMessageExt* msgExt); -ROCKETMQCLIENT_API long long GetMessageBornTimestamp(CMessageExt* msgExt); -ROCKETMQCLIENT_API long long GetMessageStoreTimestamp(CMessageExt* msgExt); -ROCKETMQCLIENT_API long long GetMessageQueueOffset(CMessageExt* msgExt); -ROCKETMQCLIENT_API long long GetMessageCommitLogOffset(CMessageExt* msgExt); -ROCKETMQCLIENT_API long long GetMessagePreparedTransactionOffset(CMessageExt* msgExt); -ROCKETMQCLIENT_API const char* GetMessageStoreHost(CMessageExt* msg); -ROCKETMQCLIENT_API const char* GetMessageBornHost(CMessageExt* msg); - -#ifdef __cplusplus -} -#endif -#endif //__C_MESSAGE_EXT_H__ diff --git a/include/CProducer.h b/include/CProducer.h deleted file mode 100644 index e383793d8..000000000 --- a/include/CProducer.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __C_PRODUCER_H__ -#define __C_PRODUCER_H__ - -#include "CBatchMessage.h" -#include "CMQException.h" -#include "CMessage.h" -#include "CMessageExt.h" -#include "CSendResult.h" -#include "CTransactionStatus.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// typedef struct _CProducer_ _CProducer; -typedef struct CProducer CProducer; -typedef int (*QueueSelectorCallback)(int size, CMessage* msg, void* arg); -typedef void (*CSendSuccessCallback)(CSendResult result); -typedef void (*CSendExceptionCallback)(CMQException e); -typedef void (*COnSendSuccessCallback)(CSendResult result, CMessage* msg, void* userData); -typedef void (*COnSendExceptionCallback)(CMQException e, CMessage* msg, void* userData); -typedef CTransactionStatus (*CLocalTransactionCheckerCallback)(CProducer* producer, CMessageExt* msg, void* data); -typedef CTransactionStatus (*CLocalTransactionExecutorCallback)(CProducer* producer, CMessage* msg, void* data); - -ROCKETMQCLIENT_API CProducer* CreateProducer(const char* groupId); -ROCKETMQCLIENT_API CProducer* CreateOrderlyProducer(const char* groupId); -ROCKETMQCLIENT_API CProducer* CreateTransactionProducer(const char* groupId, - CLocalTransactionCheckerCallback callback, - void* userData); -ROCKETMQCLIENT_API int DestroyProducer(CProducer* producer); -ROCKETMQCLIENT_API int StartProducer(CProducer* producer); -ROCKETMQCLIENT_API int ShutdownProducer(CProducer* producer); -ROCKETMQCLIENT_API const char* ShowProducerVersion(CProducer* producer); - -ROCKETMQCLIENT_API int SetProducerNameServerAddress(CProducer* producer, const char* namesrv); -ROCKETMQCLIENT_API int SetProducerNameServerDomain(CProducer* producer, const char* domain); -ROCKETMQCLIENT_API int SetProducerGroupName(CProducer* producer, const char* groupName); -ROCKETMQCLIENT_API int SetProducerInstanceName(CProducer* producer, const char* instanceName); -ROCKETMQCLIENT_API int SetProducerSessionCredentials(CProducer* producer, - const char* accessKey, - const char* secretKey, - const char* onsChannel); -ROCKETMQCLIENT_API int SetProducerLogPath(CProducer* producer, const char* logPath); -ROCKETMQCLIENT_API int SetProducerLogFileNumAndSize(CProducer* producer, int fileNum, long fileSize); -ROCKETMQCLIENT_API int SetProducerLogLevel(CProducer* producer, CLogLevel level); -ROCKETMQCLIENT_API int SetProducerSendMsgTimeout(CProducer* producer, int timeout); -ROCKETMQCLIENT_API int SetProducerCompressLevel(CProducer* producer, int level); -ROCKETMQCLIENT_API int SetProducerMaxMessageSize(CProducer* producer, int size); -ROCKETMQCLIENT_API int SetProducerMessageTrace(CProducer* producer, CTraceModel openTrace); -ROCKETMQCLIENT_API int SetProducerSsl(CProducer* producer, int enableSsl); -ROCKETMQCLIENT_API int SetProducerSslPropertyFile(CProducer* producer, const char* sslPropertyFile); - -ROCKETMQCLIENT_API int SendMessageSync(CProducer* producer, CMessage* msg, CSendResult* result); -ROCKETMQCLIENT_API int SendBatchMessage(CProducer* producer, CBatchMessage* msg, CSendResult* result); -ROCKETMQCLIENT_API int SendMessageAsync(CProducer* producer, - CMessage* msg, - CSendSuccessCallback cSendSuccessCallback, - CSendExceptionCallback cSendExceptionCallback); -ROCKETMQCLIENT_API int SendAsync(CProducer* producer, - CMessage* msg, - COnSendSuccessCallback cSendSuccessCallback, - COnSendExceptionCallback cSendExceptionCallback, - void* userData); -ROCKETMQCLIENT_API int SendMessageOneway(CProducer* producer, CMessage* msg); -ROCKETMQCLIENT_API int SendMessageOnewayOrderly(CProducer* producer, - CMessage* msg, - QueueSelectorCallback selector, - void* arg); -ROCKETMQCLIENT_API int SendMessageOrderly(CProducer* producer, - CMessage* msg, - QueueSelectorCallback callback, - void* arg, - int autoRetryTimes, - CSendResult* result); - -ROCKETMQCLIENT_API int SendMessageOrderlyAsync(CProducer* producer, - CMessage* msg, - QueueSelectorCallback callback, - void* arg, - CSendSuccessCallback cSendSuccessCallback, - CSendExceptionCallback cSendExceptionCallback); -ROCKETMQCLIENT_API int SendMessageOrderlyByShardingKey(CProducer* producer, - CMessage* msg, - const char* shardingKey, - CSendResult* result); -ROCKETMQCLIENT_API int SendMessageTransaction(CProducer* producer, - CMessage* msg, - CLocalTransactionExecutorCallback callback, - void* userData, - CSendResult* result); -#ifdef __cplusplus -} -#endif -#endif //__C_PRODUCER_H__ \ No newline at end of file diff --git a/include/CPullConsumer.h b/include/CPullConsumer.h deleted file mode 100644 index 4f5ba8546..000000000 --- a/include/CPullConsumer.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __C_PULL_CONSUMER_H__ -#define __C_PULL_CONSUMER_H__ - -#include "CCommon.h" -#include "CMessageExt.h" -#include "CMessageQueue.h" -#include "CPullResult.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct CPullConsumer CPullConsumer; - -ROCKETMQCLIENT_API CPullConsumer* CreatePullConsumer(const char* groupId); -ROCKETMQCLIENT_API int DestroyPullConsumer(CPullConsumer* consumer); -ROCKETMQCLIENT_API int StartPullConsumer(CPullConsumer* consumer); -ROCKETMQCLIENT_API int ShutdownPullConsumer(CPullConsumer* consumer); -ROCKETMQCLIENT_API const char* ShowPullConsumerVersion(CPullConsumer* consumer); - -ROCKETMQCLIENT_API int SetPullConsumerGroupID(CPullConsumer* consumer, const char* groupId); -ROCKETMQCLIENT_API const char* GetPullConsumerGroupID(CPullConsumer* consumer); -ROCKETMQCLIENT_API int SetPullConsumerNameServerAddress(CPullConsumer* consumer, const char* namesrv); -ROCKETMQCLIENT_API int SetPullConsumerNameServerDomain(CPullConsumer* consumer, const char* domain); -ROCKETMQCLIENT_API int SetPullConsumerSessionCredentials(CPullConsumer* consumer, - const char* accessKey, - const char* secretKey, - const char* channel); -ROCKETMQCLIENT_API int SetPullConsumerLogPath(CPullConsumer* consumer, const char* logPath); -ROCKETMQCLIENT_API int SetPullConsumerLogFileNumAndSize(CPullConsumer* consumer, int fileNum, long fileSize); -ROCKETMQCLIENT_API int SetPullConsumerLogLevel(CPullConsumer* consumer, CLogLevel level); -ROCKETMQCLIENT_API int SetPullConsumerSsl(CPullConsumer* consumer, int enableSsl); -ROCKETMQCLIENT_API int SetPullConsumerSslPropertyFile(CPullConsumer* consumer, const char* sslPropertyFile); - -ROCKETMQCLIENT_API int FetchSubscriptionMessageQueues(CPullConsumer* consumer, - const char* topic, - CMessageQueue** mqs, - int* size); -ROCKETMQCLIENT_API int ReleaseSubscriptionMessageQueue(CMessageQueue* mqs); - -ROCKETMQCLIENT_API CPullResult -Pull(CPullConsumer* consumer, const CMessageQueue* mq, const char* subExpression, long long offset, int maxNums); -ROCKETMQCLIENT_API int ReleasePullResult(CPullResult pullResult); - -#ifdef __cplusplus -} -#endif -#endif //__C_PUSH_CONSUMER_H__ diff --git a/include/CPullResult.h b/include/CPullResult.h deleted file mode 100644 index 3c5aaaceb..000000000 --- a/include/CPullResult.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __C_PULL_RESULT_H__ -#define __C_PULL_RESULT_H__ - -#include "CCommon.h" -#include "CMessageExt.h" - -#ifdef __cplusplus -extern "C" { -#endif -typedef enum E_CPullStatus { - E_FOUND, - E_NO_NEW_MSG, - E_NO_MATCHED_MSG, - E_OFFSET_ILLEGAL, - E_BROKER_TIMEOUT // indicate pull request timeout or received NULL response -} CPullStatus; - -typedef struct _CPullResult_ { - CPullStatus pullStatus; - long long nextBeginOffset; - long long minOffset; - long long maxOffset; - CMessageExt** msgFoundList; - int size; - void* pData; -} CPullResult; - -#ifdef __cplusplus -} -#endif -#endif //__C_PULL_RESULT_H__ diff --git a/include/CPushConsumer.h b/include/CPushConsumer.h deleted file mode 100644 index fd803c10c..000000000 --- a/include/CPushConsumer.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __C_PUSH_CONSUMER_H__ -#define __C_PUSH_CONSUMER_H__ - -#include "CCommon.h" -#include "CMessageExt.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// typedef struct _CConsumer_ _CConsumer; -typedef struct CPushConsumer CPushConsumer; - -typedef enum E_CConsumeStatus { E_CONSUME_SUCCESS = 0, E_RECONSUME_LATER = 1 } CConsumeStatus; - -typedef int (*MessageCallBack)(CPushConsumer*, CMessageExt*); - -ROCKETMQCLIENT_API CPushConsumer* CreatePushConsumer(const char* groupId); -ROCKETMQCLIENT_API int DestroyPushConsumer(CPushConsumer* consumer); -ROCKETMQCLIENT_API int StartPushConsumer(CPushConsumer* consumer); -ROCKETMQCLIENT_API int ShutdownPushConsumer(CPushConsumer* consumer); -ROCKETMQCLIENT_API const char* ShowPushConsumerVersion(CPushConsumer* consumer); -ROCKETMQCLIENT_API int SetPushConsumerGroupID(CPushConsumer* consumer, const char* groupId); -ROCKETMQCLIENT_API const char* GetPushConsumerGroupID(CPushConsumer* consumer); -ROCKETMQCLIENT_API int SetPushConsumerNameServerAddress(CPushConsumer* consumer, const char* namesrv); -ROCKETMQCLIENT_API int SetPushConsumerNameServerDomain(CPushConsumer* consumer, const char* domain); -ROCKETMQCLIENT_API int Subscribe(CPushConsumer* consumer, const char* topic, const char* expression); -ROCKETMQCLIENT_API int RegisterMessageCallbackOrderly(CPushConsumer* consumer, MessageCallBack pCallback); -ROCKETMQCLIENT_API int RegisterMessageCallback(CPushConsumer* consumer, MessageCallBack pCallback); -ROCKETMQCLIENT_API int UnregisterMessageCallbackOrderly(CPushConsumer* consumer); -ROCKETMQCLIENT_API int UnregisterMessageCallback(CPushConsumer* consumer); -ROCKETMQCLIENT_API int SetPushConsumerThreadCount(CPushConsumer* consumer, int threadCount); -ROCKETMQCLIENT_API int SetPushConsumerMessageBatchMaxSize(CPushConsumer* consumer, int batchSize); -ROCKETMQCLIENT_API int SetPushConsumerInstanceName(CPushConsumer* consumer, const char* instanceName); -ROCKETMQCLIENT_API int SetPushConsumerSessionCredentials(CPushConsumer* consumer, - const char* accessKey, - const char* secretKey, - const char* channel); -ROCKETMQCLIENT_API int SetPushConsumerLogPath(CPushConsumer* consumer, const char* logPath); -ROCKETMQCLIENT_API int SetPushConsumerLogFileNumAndSize(CPushConsumer* consumer, int fileNum, long fileSize); -ROCKETMQCLIENT_API int SetPushConsumerLogLevel(CPushConsumer* consumer, CLogLevel level); -ROCKETMQCLIENT_API int SetPushConsumerMessageModel(CPushConsumer* consumer, CMessageModel messageModel); -ROCKETMQCLIENT_API int SetPushConsumerMaxCacheMessageSize(CPushConsumer* consumer, int maxCacheSize); -ROCKETMQCLIENT_API int SetPushConsumerMaxCacheMessageSizeInMb(CPushConsumer* consumer, int maxCacheSizeInMb); -ROCKETMQCLIENT_API int SetPushConsumerMessageTrace(CPushConsumer* consumer, CTraceModel openTrace); -ROCKETMQCLIENT_API int SetPushConsumerSsl(CPushConsumer* consumer, int enableSsl); -ROCKETMQCLIENT_API int SetPushConsumerSslPropertyFile(CPushConsumer* consumer, const char* sslPropertyFile); - -#ifdef __cplusplus -} -#endif -#endif //__C_PUSH_CONSUMER_H__ diff --git a/include/CSendResult.h b/include/CSendResult.h deleted file mode 100644 index 78f21c83a..000000000 --- a/include/CSendResult.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __C_SEND_RESULT_H__ -#define __C_SEND_RESULT_H__ - -#include "CCommon.h" -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum E_CSendStatus_ { - E_SEND_OK = 0, - E_SEND_FLUSH_DISK_TIMEOUT = 1, - E_SEND_FLUSH_SLAVE_TIMEOUT = 2, - E_SEND_SLAVE_NOT_AVAILABLE = 3 -} CSendStatus; - -typedef struct _SendResult_ { - CSendStatus sendStatus; - char msgId[MAX_MESSAGE_ID_LENGTH]; - long long offset; -} CSendResult; - -#ifdef __cplusplus -} -#endif -#endif //__C_PRODUCER_H__ diff --git a/include/ConsumeType.h b/include/ConsumeType.h deleted file mode 100644 index 4cbe5cd70..000000000 --- a/include/ConsumeType.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __CONSUMETYPE_H__ -#define __CONSUMETYPE_H__ - -namespace rocketmq { -//& msgs); - virtual SendResult send(std::vector& msgs, const MQMessageQueue& mq); - virtual void send(MQMessage& msg, SendCallback* pSendCallback, bool bSelectActiveBroker = false); - virtual void send(MQMessage& msg, const MQMessageQueue& mq, SendCallback* pSendCallback); - virtual void send(MQMessage& msg, MessageQueueSelector* selector, void* arg, SendCallback* pSendCallback); - virtual void sendOneway(MQMessage& msg, bool bSelectActiveBroker = false); - virtual void sendOneway(MQMessage& msg, const MQMessageQueue& mq); - virtual void sendOneway(MQMessage& msg, MessageQueueSelector* selector, void* arg); - - const std::string& getNamesrvAddr() const; - void setNamesrvAddr(const std::string& namesrvAddr); - - void setSessionCredentials(const std::string& accessKey, - const std::string& secretKey, - const std::string& accessChannel); - const SessionCredentials& getSessionCredentials() const; - - const std::string& getNamesrvDomain() const; - void setNamesrvDomain(const std::string& namesrvDomain); - - const std::string& getNameSpace() const; - void setNameSpace(const std::string& nameSpace); - - const std::string& getGroupName() const; - void setGroupName(const std::string& groupname); - - const std::string& getInstanceName() const; - void setInstanceName(const std::string& instanceName); - - /** - * Log configuration interface, default LOG_LEVEL is LOG_LEVEL_INFO, default - * log file num is 3, each log size is 100M - **/ - void setLogLevel(elogLevel inputLevel); - elogLevel getLogLevel(); - void setLogPath(const std::string& logPath); - void setLogFileSizeAndNum(int fileNum, long perFileSize); // perFileSize is MB unit - - int getSendMsgTimeout() const; - void setSendMsgTimeout(int sendMsgTimeout); - - /* - * If msgBody size is large than compressMsgBodyOverHowmuch - * rocketmq cpp will compress msgBody according to compressLevel - */ - int getCompressMsgBodyOverHowmuch() const; - void setCompressMsgBodyOverHowmuch(int compressMsgBodyOverHowmuch); - int getCompressLevel() const; - void setCompressLevel(int compressLevel); - - int getMaxMessageSize() const; - void setMaxMessageSize(int maxMessageSize); - - int getRetryTimes() const; - void setRetryTimes(int times); - - int getRetryTimes4Async() const; - void setRetryTimes4Async(int times); - - /** Set TcpTransport pull thread num, which dermine the num of threads to - * distribute network data, - * 1. its default value is CPU num, it must be setted before producer/consumer - * start, minimum value is CPU num; - * 2. this pullThread num must be tested on your environment to find the best - * value for RT of sendMsg or delay time of consume msg before you change it; - * 3. producer and consumer need different pullThread num, if set this num, - * producer and consumer must set different instanceName. - **/ - void setTcpTransportPullThreadNum(int num); - int getTcpTransportPullThreadNum() const; - - /** Timeout of tcp connect, it is same meaning for both producer and consumer; - * 1. default value is 3000ms - * 2. input parameter could only be milliSecond, suggestion value is - * 1000-3000ms; - **/ - void setTcpTransportConnectTimeout(uint64_t timeout); // ms - uint64_t getTcpTransportConnectTimeout() const; - - /** Timeout of tryLock tcpTransport before sendMsg/pullMsg, if timeout, - * returns NULL - * 1. paremeter unit is ms, default value is 3000ms, the minimun value is 1000ms - * suggestion value is 3000ms; - * 2. if configured with value smaller than 1000ms, the tryLockTimeout value - * will be setted to 1000ms - **/ - void setTcpTransportTryLockTimeout(uint64_t timeout); // ms - uint64_t getTcpTransportTryLockTimeout() const; - - void setUnitName(std::string unitName); - const std::string& getUnitName() const; - void setMessageTrace(bool messageTrace); - bool getMessageTrace() const; - - void setEnableSsl(bool enableSsl); - bool getEnableSsl() const; - - void setSslPropertyFile(const std::string& sslPropertyFile); - const std::string& getSslPropertyFile() const; - - private: - DefaultMQProducerImpl* impl; -}; -} // namespace rocketmq -#endif diff --git a/include/DefaultMQPullConsumer.h b/include/DefaultMQPullConsumer.h deleted file mode 100644 index 0883bca0b..000000000 --- a/include/DefaultMQPullConsumer.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __DEFAULTMQPULLCONSUMER_H__ -#define __DEFAULTMQPULLCONSUMER_H__ - -#include -#include -#include "AsyncCallback.h" -#include "ConsumeType.h" -#include "MQClient.h" -#include "MQMessage.h" -#include "MQMessageExt.h" -#include "MQMessageQueue.h" -#include "MQueueListener.h" -#include "PullResult.h" -#include "RocketMQClient.h" -#include "SessionCredentials.h" - -namespace rocketmq { -class SubscriptionData; -class DefaultMQPullConsumerImpl; -class ROCKETMQCLIENT_API DefaultMQPullConsumer { - public: - DefaultMQPullConsumer(const std::string& groupname); - virtual ~DefaultMQPullConsumer(); - - virtual void start(); - virtual void shutdown(); - virtual std::string version(); - - const std::string& getNamesrvAddr() const; - void setNamesrvAddr(const std::string& namesrvAddr); - - void setSessionCredentials(const std::string& accessKey, - const std::string& secretKey, - const std::string& accessChannel); - const SessionCredentials& getSessionCredentials() const; - - const std::string& getNamesrvDomain() const; - void setNamesrvDomain(const std::string& namesrvDomain); - - const std::string& getInstanceName() const; - void setInstanceName(const std::string& instanceName); - - const std::string& getNameSpace() const; - void setNameSpace(const std::string& nameSpace); - - const std::string& getGroupName() const; - void setGroupName(const std::string& groupname); - - void setEnableSsl(bool enableSsl); - bool getEnableSsl() const; - - void setSslPropertyFile(const std::string& sslPropertyFile); - const std::string& getSslPropertyFile() const; - - /** - * Log configuration interface, default LOG_LEVEL is LOG_LEVEL_INFO, default - * log file num is 3, each log size is 100M - **/ - void setLogLevel(elogLevel inputLevel); - elogLevel getLogLevel(); - void setLogPath(const std::string& logPath); - void setLogFileSizeAndNum(int fileNum, long perFileSize); // perFileSize is MB unit - - virtual void fetchSubscribeMessageQueues(const std::string& topic, std::vector& mqs); - - /** - * Pull message from specified queue, if no msg in queue, return directly - * - * @param mq - * specify the pulled queue - * @param subExpression - * set filter expression for pulled msg, broker will filter msg actively - * Now only OR operation is supported, eg: "tag1 || tag2 || tag3" - * if subExpression is setted to "null" or "*", all msg will be subscribed - * @param offset - * specify the started pull offset - * @param maxNums - * specify max msg num by per pull - * @return - * PullResult - */ - virtual PullResult pull(const MQMessageQueue& mq, const std::string& subExpression, int64 offset, int maxNums); - virtual void pull(const MQMessageQueue& mq, - const std::string& subExpression, - int64 offset, - int maxNums, - PullCallback* pPullCallback); - - /** - * Pull msg from specified queue, if no msg, broker will suspend the pull request 20s - * - * @param mq - * specify the pulled queue - * @param subExpression - * set filter expression for pulled msg, broker will filter msg actively - * Now only OR operation is supported, eg: "tag1 || tag2 || tag3" - * if subExpression is setted to "null" or "*", all msg will be subscribed - * @param offset - * specify the started pull offset - * @param maxNums - * specify max msg num by per pull - * @return - * accroding to PullResult - */ - virtual PullResult pullBlockIfNotFound(const MQMessageQueue& mq, - const std::string& subExpression, - int64 offset, - int maxNums); - virtual void pullBlockIfNotFound(const MQMessageQueue& mq, - const std::string& subExpression, - int64 offset, - int maxNums, - PullCallback* pPullCallback); - - void persistConsumerOffset(); - void persistConsumerOffsetByResetOffset(); - void updateTopicSubscribeInfo(const std::string& topic, std::vector& info); - ConsumeFromWhere getConsumeFromWhere(); - void getSubscriptions(std::vector&); - void updateConsumeOffset(const MQMessageQueue& mq, int64 offset); - void removeConsumeOffset(const MQMessageQueue& mq); - - void registerMessageQueueListener(const std::string& topic, MQueueListener* pListener); - - int64 fetchConsumeOffset(const MQMessageQueue& mq, bool fromStore); - - void fetchMessageQueuesInBalance(const std::string& topic, std::vector mqs); - - void persistConsumerOffset4PullConsumer(const MQMessageQueue& mq); - - private: - DefaultMQPullConsumerImpl* impl; -}; -} // namespace rocketmq -#endif diff --git a/include/DefaultMQPushConsumer.h b/include/DefaultMQPushConsumer.h deleted file mode 100644 index 5d3bc3523..000000000 --- a/include/DefaultMQPushConsumer.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __DEFAULTMQPUSHCONSUMER_H__ -#define __DEFAULTMQPUSHCONSUMER_H__ - -#include -#include "AsyncCallback.h" -#include "ConsumeType.h" -#include "MQClient.h" -#include "MQMessageListener.h" -#include "MQMessageQueue.h" -#include "SessionCredentials.h" - -namespace rocketmq { -class DefaultMQPushConsumerImpl; -class ROCKETMQCLIENT_API DefaultMQPushConsumer { - public: - DefaultMQPushConsumer(const std::string& groupname); - - virtual ~DefaultMQPushConsumer(); - - virtual void start(); - virtual void shutdown(); - virtual std::string version(); - - const std::string& getNamesrvAddr() const; - void setNamesrvAddr(const std::string& namesrvAddr); - - void setSessionCredentials(const std::string& accessKey, - const std::string& secretKey, - const std::string& accessChannel); - const SessionCredentials& getSessionCredentials() const; - - void subscribe(const std::string& topic, const std::string& subExpression); - - void registerMessageListener(MQMessageListener* pMessageListener); - MessageListenerType getMessageListenerType(); - - MessageModel getMessageModel() const; - void setMessageModel(MessageModel messageModel); - - void setConsumeFromWhere(ConsumeFromWhere consumeFromWhere); - ConsumeFromWhere getConsumeFromWhere(); - - const std::string& getNamesrvDomain() const; - void setNamesrvDomain(const std::string& namesrvDomain); - - const std::string& getInstanceName() const; - void setInstanceName(const std::string& instanceName); - - const std::string& getNameSpace() const; - void setNameSpace(const std::string& nameSpace); - - const std::string& getGroupName() const; - void setGroupName(const std::string& groupname); - - void setEnableSsl(bool enableSsl); - bool getEnableSsl() const; - - void setSslPropertyFile(const std::string& sslPropertyFile); - const std::string& getSslPropertyFile() const; - - /** - * Log configuration interface, default LOG_LEVEL is LOG_LEVEL_INFO, default - * log file num is 3, each log size is 100M - **/ - void setLogLevel(elogLevel inputLevel); - elogLevel getLogLevel(); - void setLogPath(const std::string& logPath); - void setLogFileSizeAndNum(int fileNum, long perFileSize); // perFileSize is MB unit - - void setConsumeThreadCount(int threadCount); - int getConsumeThreadCount() const; - - void setMaxReconsumeTimes(int maxReconsumeTimes); - int getMaxReconsumeTimes() const; - - void setPullMsgThreadPoolCount(int threadCount); - int getPullMsgThreadPoolCount() const; - - void setConsumeMessageBatchMaxSize(int consumeMessageBatchMaxSize); - int getConsumeMessageBatchMaxSize() const; - - /** - * Set max cache msg size perQueue in memory if consumer could not consume msgs - * immediately - * default maxCacheMsgSize perQueue is 1000, set range is:1~65535 - **/ - void setMaxCacheMsgSizePerQueue(int maxCacheSize); - int getMaxCacheMsgSizePerQueue() const; - - /** Set TcpTransport pull thread num, which dermine the num of threads to - * distribute network data, - * 1. its default value is CPU num, it must be setted before producer/consumer - * start, minimum value is CPU num; - * 2. this pullThread num must be tested on your environment to find the best - * value for RT of sendMsg or delay time of consume msg before you change it; - * 3. producer and consumer need different pullThread num, if set this num, - * producer and consumer must set different instanceName. - **/ - void setTcpTransportPullThreadNum(int num); - int getTcpTransportPullThreadNum() const; - - /** Timeout of tcp connect, it is same meaning for both producer and consumer; - * 1. default value is 3000ms - * 2. input parameter could only be milliSecond, suggestion value is - * 1000-3000ms; - **/ - void setTcpTransportConnectTimeout(uint64_t timeout); // ms - uint64_t getTcpTransportConnectTimeout() const; - - /** Timeout of tryLock tcpTransport before sendMsg/pullMsg, if timeout, - * returns NULL - * 1. paremeter unit is ms, default value is 3000ms, the minimun value is 1000ms - * suggestion value is 3000ms; - * 2. if configured with value smaller than 1000ms, the tryLockTimeout value - * will be setted to 1000ms - **/ - void setTcpTransportTryLockTimeout(uint64_t timeout); // ms - uint64_t getTcpTransportTryLockTimeout() const; - - void setUnitName(std::string unitName); - const std::string& getUnitName() const; - - void setAsyncPull(bool asyncFlag); - void setMessageTrace(bool messageTrace); - bool getMessageTrace() const; - - private: - DefaultMQPushConsumerImpl* impl; -}; -} // namespace rocketmq -#endif diff --git a/include/MQClientException.h b/include/MQClientException.h deleted file mode 100644 index 883cd64ae..000000000 --- a/include/MQClientException.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __MQCLIENTEXCEPTION_H__ -#define __MQCLIENTEXCEPTION_H__ - -#include -#include -#include -#include -#include -#include "RocketMQClient.h" - -namespace rocketmq { -class ROCKETMQCLIENT_API MQException : public std::exception { - public: - MQException(const std::string& msg, int error, const char* file, int line) throw() - : m_error(error), m_line(line), m_file(file) { - try { - std::stringstream ss; - ss << "msg: " << msg << ",error:" << error << ",in file <" << file << "> line:" << line; - m_msg = ss.str(); - } catch (...) { - } - } - - MQException(const std::string& msg, int error, const char* file, const char* type, int line) throw() - : m_error(error), m_line(line), m_file(file), m_type(type) { - try { - std::stringstream ss; - ss << "msg: " << msg << ",error:" << error << ",in file <" << file << "> line:" << line; - m_msg = ss.str(); - } catch (...) { - } - } - - virtual ~MQException() throw() {} - const char* what() const throw() { return m_msg.c_str(); } - int GetError() const throw() { return m_error; } - virtual const char* GetType() const throw() { return m_type.c_str(); } - int GetLine() { return m_line; } - const char* GetFile() { return m_file.c_str(); } - - protected: - int m_error; - int m_line; - std::string m_msg; - std::string m_file; - std::string m_type; -}; - -inline std::ostream& operator<<(std::ostream& os, const MQException& e) { - os << "Type: " << e.GetType() << " , " << e.what(); - return os; -} - -#define DEFINE_MQCLIENTEXCEPTION(name) \ - class ROCKETMQCLIENT_API name : public MQException { \ - public: \ - name(const std::string& msg, int error, const char* file, int line) throw() \ - : MQException(msg, error, file, #name, line) {} \ - virtual const char* GetType() const throw() { return m_type.c_str(); } \ - }; - -DEFINE_MQCLIENTEXCEPTION(MQClientException) -DEFINE_MQCLIENTEXCEPTION(MQBrokerException) -DEFINE_MQCLIENTEXCEPTION(InterruptedException) -DEFINE_MQCLIENTEXCEPTION(RemotingException) -DEFINE_MQCLIENTEXCEPTION(UnknownHostException) - -#define THROW_MQEXCEPTION(e, msg, err) throw e(msg, err, __FILE__, __LINE__) -#define NEW_MQEXCEPTION(e, msg, err) e(msg, err, __FILE__, __LINE__) - -} // namespace rocketmq -#endif diff --git a/include/MQMessage.h b/include/MQMessage.h deleted file mode 100644 index dd2f7c010..000000000 --- a/include/MQMessage.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __MESSAGE_H__ -#define __MESSAGE_H__ - -#include -#include -#include -#include -#include "RocketMQClient.h" - -namespace rocketmq { -class ROCKETMQCLIENT_API MQMessage { - public: - MQMessage(); - MQMessage(const std::string& topic, const std::string& body); - MQMessage(const std::string& topic, const std::string& tags, const std::string& body); - MQMessage(const std::string& topic, const std::string& tags, const std::string& keys, const std::string& body); - MQMessage(const std::string& topic, - const std::string& tags, - const std::string& keys, - const int flag, - const std::string& body, - bool waitStoreMsgOK); - - virtual ~MQMessage(); - MQMessage(const MQMessage& other); - MQMessage& operator=(const MQMessage& other); - - void setProperty(const std::string& name, const std::string& value); - const std::string& getProperty(const std::string& name) const; - - const std::string& getTopic() const; - void setTopic(const std::string& topic); - void setTopic(const char* body, int len); - - const std::string& getTags() const; - void setTags(const std::string& tags); - - const std::string& getKeys() const; - void setKeys(const std::string& keys); - void setKeys(const std::vector& keys); - - int getDelayTimeLevel() const; - void setDelayTimeLevel(int level); - - bool isWaitStoreMsgOK() const; - void setWaitStoreMsgOK(bool waitStoreMsgOK); - - int getFlag() const; - void setFlag(int flag); - - int getSysFlag() const; - void setSysFlag(int sysFlag); - - const std::string& getBody() const; - - void setBody(const char* body, int len); - void setBody(const std::string& body); - - void setTransactionId(const std::string& id) { m_transactionId = id; } - std::string getTransactionId() const { return m_transactionId; } - - std::map getProperties() const; - void setProperties(std::map& properties); - - const std::string toString() const { - std::stringstream ss; - std::string tags = getTags(); - ss << "Message [topic=" << m_topic << ", flag=" << m_flag << ", tag=" << tags << "]"; - return ss.str(); - } - - protected: - friend class MQDecoder; - void setPropertyInternal(const std::string& name, const std::string& value); - void setPropertiesInternal(std::map& properties); - - void Init(const std::string& topic, - const std::string& tags, - const std::string& keys, - const int flag, - const std::string& body, - bool waitStoreMsgOK); - - public: - static const std::string PROPERTY_KEYS; - static const std::string PROPERTY_TAGS; - static const std::string PROPERTY_WAIT_STORE_MSG_OK; - static const std::string PROPERTY_DELAY_TIME_LEVEL; - static const std::string PROPERTY_RETRY_TOPIC; - static const std::string PROPERTY_REAL_TOPIC; - static const std::string PROPERTY_REAL_QUEUE_ID; - static const std::string PROPERTY_TRANSACTION_PREPARED; - static const std::string PROPERTY_PRODUCER_GROUP; - static const std::string PROPERTY_MIN_OFFSET; - static const std::string PROPERTY_MAX_OFFSET; - - static const std::string PROPERTY_BUYER_ID; - static const std::string PROPERTY_ORIGIN_MESSAGE_ID; - static const std::string PROPERTY_TRANSFER_FLAG; - static const std::string PROPERTY_CORRECTION_FLAG; - static const std::string PROPERTY_MQ2_FLAG; - static const std::string PROPERTY_RECONSUME_TIME; - static const std::string PROPERTY_MSG_REGION; - static const std::string PROPERTY_TRACE_SWITCH; - static const std::string PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX; - static const std::string PROPERTY_MAX_RECONSUME_TIMES; - static const std::string PROPERTY_CONSUME_START_TIMESTAMP; - static const std::string PROPERTY_TRANSACTION_PREPARED_QUEUE_OFFSET; - static const std::string PROPERTY_TRANSACTION_CHECK_TIMES; - static const std::string PROPERTY_CHECK_IMMUNITY_TIME_IN_SECONDS; - - static const std::string KEY_SEPARATOR; - - protected: - int m_sysFlag; - - private: - std::string m_topic; - int m_flag; - std::string m_body; - std::string m_transactionId; - std::map m_properties; -}; -} // namespace rocketmq -#endif diff --git a/include/MQMessageExt.h b/include/MQMessageExt.h deleted file mode 100644 index 969f04bce..000000000 --- a/include/MQMessageExt.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __MESSAGEEXT_H__ -#define __MESSAGEEXT_H__ - -#ifdef WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#include -#else -#include -#endif - -#include "MQMessage.h" -#include "RocketMQClient.h" - -namespace rocketmq { -// -#include "MQMessageExt.h" -#include "MQMessageQueue.h" - -namespace rocketmq { -//& msgs) = 0; - virtual MessageListenerType getMessageListenerType() { return messageListenerDefaultly; } -}; - -class ROCKETMQCLIENT_API MessageListenerOrderly : public MQMessageListener { - public: - virtual ~MessageListenerOrderly() {} - virtual ConsumeStatus consumeMessage(const std::vector& msgs) = 0; - virtual MessageListenerType getMessageListenerType() { return messageListenerOrderly; } -}; - -class ROCKETMQCLIENT_API MessageListenerConcurrently : public MQMessageListener { - public: - virtual ~MessageListenerConcurrently() {} - virtual ConsumeStatus consumeMessage(const std::vector& msgs) = 0; - virtual MessageListenerType getMessageListenerType() { return messageListenerConcurrently; } -}; - -} // namespace rocketmq -#endif diff --git a/include/MQMessageQueue.h b/include/MQMessageQueue.h deleted file mode 100644 index 0879a94de..000000000 --- a/include/MQMessageQueue.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __MQMESSAGEQUEUE_H__ -#define __MQMESSAGEQUEUE_H__ - -#include -#include -#include -#include "RocketMQClient.h" - -namespace rocketmq { -class ROCKETMQCLIENT_API MQMessageQueue { - public: - MQMessageQueue(); - MQMessageQueue(const std::string& topic, const std::string& brokerName, int queueId); - MQMessageQueue(const MQMessageQueue& other); - MQMessageQueue& operator=(const MQMessageQueue& other); - - std::string getTopic() const; - void setTopic(const std::string& topic); - - std::string getBrokerName() const; - void setBrokerName(const std::string& brokerName); - - int getQueueId() const; - void setQueueId(int queueId); - - bool operator==(const MQMessageQueue& mq) const; - bool operator<(const MQMessageQueue& mq) const; - int compareTo(const MQMessageQueue& mq) const; - - const std::string toString() const { - std::stringstream ss; - ss << "MessageQueue [topic=" << m_topic << ", brokerName=" << m_brokerName << ", queueId=" << m_queueId << "]"; - - return ss.str(); - } - - private: - std::string m_topic; - std::string m_brokerName; - int m_queueId; -}; -} // namespace rocketmq -#endif diff --git a/include/MQSelector.h b/include/MQSelector.h deleted file mode 100644 index 46e548c3e..000000000 --- a/include/MQSelector.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef _MQSELECTOR_H_ -#define _MQSELECTOR_H_ -#include "MQMessage.h" -#include "MQMessageQueue.h" -#include "RocketMQClient.h" - -namespace rocketmq { -class ROCKETMQCLIENT_API MessageQueueSelector { - public: - virtual ~MessageQueueSelector() {} - virtual MQMessageQueue select(const std::vector& mqs, const MQMessage& msg, void* arg) = 0; -}; -} // namespace rocketmq -#endif diff --git a/include/MQueueListener.h b/include/MQueueListener.h deleted file mode 100644 index f5eac41de..000000000 --- a/include/MQueueListener.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __MESSAGEQUEUELISTENER_H__ -#define __MESSAGEQUEUELISTENER_H__ - -#include -#include "RocketMQClient.h" - -namespace rocketmq { -class ROCKETMQCLIENT_API MQueueListener { - public: - virtual ~MQueueListener() {} - virtual void messageQueueChanged(const std::string& topic, - std::vector& mqAll, - std::vector& mqDivided) = 0; -}; -} // namespace rocketmq -#endif diff --git a/include/PullResult.h b/include/PullResult.h deleted file mode 100644 index 565058b07..000000000 --- a/include/PullResult.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __PULLRESULT_H__ -#define __PULLRESULT_H__ - -#include -#include "MQMessageExt.h" -#include "RocketMQClient.h" - -namespace rocketmq { -enum PullStatus { - FOUND, - NO_NEW_MSG, - NO_MATCHED_MSG, - OFFSET_ILLEGAL, - BROKER_TIMEOUT // indicate pull request timeout or received NULL response -}; - -static const char* EnumStrings[] = {"FOUND", "NO_NEW_MSG", "NO_MATCHED_MSG", "OFFSET_ILLEGAL", "BROKER_TIMEOUT"}; - -class ROCKETMQCLIENT_API PullResult { - public: - PullResult(); - PullResult(PullStatus status); - PullResult(PullStatus pullStatus, int64 nextBeginOffset, int64 minOffset, int64 maxOffset); - - PullResult(PullStatus pullStatus, - int64 nextBeginOffset, - int64 minOffset, - int64 maxOffset, - const std::vector& src); - - virtual ~PullResult(); - - std::string toString() { - std::stringstream ss; - ss << "PullResult [ pullStatus=" << EnumStrings[pullStatus] << ", nextBeginOffset=" << nextBeginOffset - << ", minOffset=" << minOffset << ", maxOffset=" << maxOffset << ", msgFoundList=" << msgFoundList.size() - << " ]"; - return ss.str(); - } - - public: - PullStatus pullStatus; - int64 nextBeginOffset; - int64 minOffset; - int64 maxOffset; - std::vector msgFoundList; -}; -} // namespace rocketmq -#endif diff --git a/include/RocketMQClient.h b/include/RocketMQClient.h deleted file mode 100644 index 26ae37921..000000000 --- a/include/RocketMQClient.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __ROCKETMQCLIENT_H__ -#define __ROCKETMQCLIENT_H__ - -#ifdef WIN32 -#ifdef ROCKETMQCLIENT_EXPORTS -#ifdef _WINDLL -#define ROCKETMQCLIENT_API __declspec(dllexport) -#else -#define ROCKETMQCLIENT_API -#endif -#else -#ifdef ROCKETMQCLIENT_IMPORT -#define ROCKETMQCLIENT_API __declspec(dllimport) -#else -#define ROCKETMQCLIENT_API -#endif -#endif -#else -#define ROCKETMQCLIENT_API -#endif - -/** A platform-independent 8-bit signed integer type. */ -typedef signed char int8; -/** A platform-independent 8-bit unsigned integer type. */ -typedef unsigned char uint8; -/** A platform-independent 16-bit signed integer type. */ -typedef signed short int16; -/** A platform-independent 16-bit unsigned integer type. */ -typedef unsigned short uint16; -/** A platform-independent 32-bit signed integer type. */ -typedef signed int int32; -/** A platform-independent 32-bit unsigned integer type. */ -typedef unsigned int uint32; -/** A platform-independent 64-bit integer type. */ -typedef long long int64; -/** A platform-independent 64-bit unsigned integer type. */ -typedef unsigned long long uint64; - -#endif diff --git a/include/SendResult.h b/include/SendResult.h deleted file mode 100644 index 94ba543e8..000000000 --- a/include/SendResult.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __SENDRESULT_H__ -#define __SENDRESULT_H__ - -#include "MQMessageQueue.h" -#include "RocketMQClient.h" - -namespace rocketmq { - -enum SendStatus { SEND_OK, SEND_FLUSH_DISK_TIMEOUT, SEND_FLUSH_SLAVE_TIMEOUT, SEND_SLAVE_NOT_AVAILABLE }; - -class ROCKETMQCLIENT_API SendResult { - public: - SendResult(); - SendResult(const SendStatus& sendStatus, - const std::string& msgId, - const std::string& offsetMsgId, - const MQMessageQueue& messageQueue, - int64 queueOffset); - SendResult(const SendStatus& sendStatus, - const std::string& msgId, - const std::string& offsetMsgId, - const MQMessageQueue& messageQueue, - int64 queueOffset, - const std::string& regionId, - const bool traceOn); - - virtual ~SendResult(); - SendResult(const SendResult& other); - SendResult& operator=(const SendResult& other); - - void setTransactionId(const std::string& id) { m_transactionId = id; } - - std::string getTransactionId() { return m_transactionId; } - - const std::string& getMsgId() const; - const std::string& getOffsetMsgId() const; - - const std::string& getRegionId() const; - void setRegionId(const std::string& regionId); - SendStatus getSendStatus() const; - MQMessageQueue getMessageQueue() const; - int64 getQueueOffset() const; - bool getTraceOn() const; - - std::string toString() const; - - private: - SendStatus m_sendStatus; - std::string m_msgId; - std::string m_offsetMsgId; - MQMessageQueue m_messageQueue; - int64 m_queueOffset; - std::string m_transactionId; - std::string m_regionId; - bool m_traceOn; -}; - -} // namespace rocketmq -#endif diff --git a/include/SessionCredentials.h b/include/SessionCredentials.h deleted file mode 100644 index e035160ea..000000000 --- a/include/SessionCredentials.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __SESSIONCREDENTIALS_H__ -#define __SESSIONCREDENTIALS_H__ - -#include "RocketMQClient.h" - -namespace rocketmq { - -class SessionCredentials { - public: - static const std::string AccessKey; - static const std::string SecretKey; - static const std::string Signature; - static const std::string SignatureMethod; - static const std::string ONSChannelKey; - - SessionCredentials(std::string input_accessKey, std::string input_secretKey, const std::string& input_authChannel) - : accessKey(input_accessKey), secretKey(input_secretKey), authChannel(input_authChannel) {} - SessionCredentials() : authChannel("ALIYUN") {} - ~SessionCredentials() {} - - std::string getAccessKey() const { return accessKey; } - - void setAccessKey(std::string input_accessKey) { accessKey = input_accessKey; } - - std::string getSecretKey() const { return secretKey; } - - void setSecretKey(std::string input_secretKey) { secretKey = input_secretKey; } - - std::string getSignature() const { return signature; } - - void setSignature(std::string input_signature) { signature = input_signature; } - - std::string getSignatureMethod() const { return signatureMethod; } - - void setSignatureMethod(std::string input_signatureMethod) { signatureMethod = input_signatureMethod; } - - std::string getAuthChannel() const { return authChannel; } - - void setAuthChannel(std::string input_channel) { authChannel = input_channel; } - - bool isValid() const { - if (accessKey.empty() || secretKey.empty() || authChannel.empty()) - return false; - - return true; - } - - private: - std::string accessKey; - std::string secretKey; - std::string signature; - std::string signatureMethod; - std::string authChannel; -}; -} // namespace rocketmq -#endif diff --git a/include/TransactionListener.h b/include/TransactionListener.h deleted file mode 100644 index 6756e96a7..000000000 --- a/include/TransactionListener.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __TRANSACTIONLISTENER_H__ -#define __TRANSACTIONLISTENER_H__ - -#include "MQMessage.h" -#include "MQMessageExt.h" -#include "TransactionSendResult.h" - -namespace rocketmq { -class ROCKETMQCLIENT_API TransactionListener { - public: - virtual ~TransactionListener() {} - /** - * When send transactional prepare(half) message succeed, this method will be invoked to execute local transaction. - * - * @param msg Half(prepare) message - * @param arg Custom business parameter - * @return Transaction state - */ - virtual LocalTransactionState executeLocalTransaction(const MQMessage& msg, void* arg) = 0; - - /** - * When no response to prepare(half) message. broker will send check message to check the transaction status, and this - * method will be invoked to get local transaction status. - * - * @param msg Check message - * @return Transaction state - */ - virtual LocalTransactionState checkLocalTransaction(const MQMessageExt& msg) = 0; -}; -} // namespace rocketmq -#endif diff --git a/include/TransactionMQProducer.h b/include/TransactionMQProducer.h deleted file mode 100644 index 7b9da77cb..000000000 --- a/include/TransactionMQProducer.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __TRANSACTIONMQPRODUCER_H__ -#define __TRANSACTIONMQPRODUCER_H__ - -#include -#include -#include "MQClient.h" -#include "MQMessage.h" -#include "MQMessageExt.h" -#include "SessionCredentials.h" -#include "TransactionListener.h" -#include "TransactionSendResult.h" - -namespace rocketmq { -class TransactionMQProducerImpl; -class ROCKETMQCLIENT_API TransactionMQProducer { - public: - TransactionMQProducer(const std::string& producerGroup); - virtual ~TransactionMQProducer(); - - void start(); - void shutdown(); - std::string version(); - - const std::string& getNamesrvAddr() const; - void setNamesrvAddr(const std::string& namesrvAddr); - const std::string& getNamesrvDomain() const; - void setNamesrvDomain(const std::string& namesrvDomain); - const std::string& getInstanceName() const; - void setInstanceName(const std::string& instanceName); - - const std::string& getNameSpace() const; - void setNameSpace(const std::string& nameSpace); - const std::string& getGroupName() const; - void setGroupName(const std::string& groupname); - void setSessionCredentials(const std::string& accessKey, - const std::string& secretKey, - const std::string& accessChannel); - const SessionCredentials& getSessionCredentials() const; - - void setUnitName(std::string unitName); - const std::string& getUnitName() const; - - int getSendMsgTimeout() const; - void setSendMsgTimeout(int sendMsgTimeout); - void setTcpTransportPullThreadNum(int num); - int getTcpTransportPullThreadNum() const; - - void setTcpTransportConnectTimeout(uint64_t timeout); // ms - uint64_t getTcpTransportConnectTimeout() const; - - void setTcpTransportTryLockTimeout(uint64_t timeout); // ms - uint64_t getTcpTransportTryLockTimeout() const; - - int getCompressMsgBodyOverHowmuch() const; - void setCompressMsgBodyOverHowmuch(int compressMsgBodyOverHowmuch); - int getCompressLevel() const; - void setCompressLevel(int compressLevel); - - int getMaxMessageSize() const; - void setMaxMessageSize(int maxMessageSize); - - void setLogLevel(elogLevel inputLevel); - elogLevel getLogLevel(); - void setLogFileSizeAndNum(int fileNum, long perFileSize); // perFileSize is MB unit - void setMessageTrace(bool messageTrace); - bool getMessageTrace() const; - void setEnableSsl(bool enableSsl); - bool getEnableSsl() const; - void setSslPropertyFile(const std::string& sslPropertyFile); - const std::string& getSslPropertyFile() const; - std::shared_ptr getTransactionListener(); - void setTransactionListener(TransactionListener* listener); - TransactionSendResult sendMessageInTransaction(MQMessage& msg, void* arg); - void checkTransactionState(const std::string& addr, - const MQMessageExt& message, - long tranStateTableOffset, - long commitLogOffset, - const std::string& msgId, - const std::string& transactionId, - const std::string& offsetMsgId); - - private: - TransactionMQProducerImpl* impl; -}; -} // namespace rocketmq - -#endif diff --git a/include/TransactionSendResult.h b/include/TransactionSendResult.h deleted file mode 100644 index 0bb1e480e..000000000 --- a/include/TransactionSendResult.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __TRANSACTIONSENDRESULT_H__ -#define __TRANSACTIONSENDRESULT_H__ - -#include "SendResult.h" - -namespace rocketmq { - -enum LocalTransactionState { COMMIT_MESSAGE, ROLLBACK_MESSAGE, UNKNOWN }; - -class ROCKETMQCLIENT_API TransactionSendResult : public SendResult { - public: - TransactionSendResult() {} - - TransactionSendResult(const SendStatus& sendStatus, - const std::string& msgId, - const std::string& offsetMsgId, - const MQMessageQueue& messageQueue, - int64 queueOffset) - : SendResult(sendStatus, msgId, offsetMsgId, messageQueue, queueOffset) {} - - LocalTransactionState getLocalTransactionState() { return m_localTransactionState; } - - void setLocalTransactionState(LocalTransactionState localTransactionState) { - m_localTransactionState = localTransactionState; - } - - private: - LocalTransactionState m_localTransactionState; -}; -} // namespace rocketmq -#endif \ No newline at end of file diff --git a/libs/signature/include/hmac.h b/libs/signature/include/hmac.h deleted file mode 100644 index 889ad7dbf..000000000 --- a/libs/signature/include/hmac.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _HMAC_HMAC_H -#define _HMAC_HMAC_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#ifndef SHA1_DIGEST_LEN -#define SHA1_DIGEST_LEN 20 -#endif - -#ifndef SHA256_DIGEST_LEN -#define SHA256_DIGEST_LEN 32 -#endif - -#ifndef SHA512_DIGEST_LEN -#define SHA512_DIGEST_LEN 64 -#endif - -/* - * hmac_sha1: - * hmac_sha256: - * hmac_sha512: - * Calculate Hashed Message Authentication Code with sha1/256/512 algorithm - * Caution: ret_buf should provide enough space for HMAC result. - * - * @key [in]: the secure-key string - * @key_len [in]: the length of secure-key - * @data [in]: data string could be calculated. - * @data_len [in]: the length of data. length is needed because strlen could not take effect. - * @ret_buf [out]: HMAC result stored in ret_buf. - */ - -#ifdef __cplusplus -namespace rocketmqSignature { - -#endif - -extern int hmac_sha1(const void* key, size_t key_len, const void* data, size_t data_len, void* ret_buf); -extern int hmac_sha256(const void* key, size_t key_len, const void* data, size_t data_len, void* ret_buf); -extern int hmac_sha512(const void* key, size_t key_len, const void* data, size_t data_len, void* ret_buf); - -#ifdef __cplusplus -} -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/signature/include/sha1.h b/libs/signature/include/sha1.h deleted file mode 100644 index 789d4118c..000000000 --- a/libs/signature/include/sha1.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SHA1_H -#define SHA1_H 1 - -#include -#include - -#ifdef __cplusplus -namespace rocketmqSignature { -#endif - -#define SHA1_DIGEST_SIZE 20 - -/* Structure to save state of computation between the single steps. */ -struct sha1_ctx { - uint32_t A; - uint32_t B; - uint32_t C; - uint32_t D; - uint32_t E; - - uint32_t total[2]; - uint32_t buflen; - uint32_t buffer[32]; -}; - -/* Initialize structure containing state of computation. */ -extern void sha1_init_ctx(struct sha1_ctx* ctx); - -/* Starting with the result of former calls of this function (or the - initialization function update the context for the next LEN bytes - starting at BUFFER. - It is necessary that LEN is a multiple of 64!!! */ -extern void sha1_process_block(const void* buffer, size_t len, struct sha1_ctx* ctx); - -/* Starting with the result of former calls of this function (or the - initialization function update the context for the next LEN bytes - starting at BUFFER. - It is NOT required that LEN is a multiple of 64. */ -extern void sha1_process_bytes(const void* buffer, size_t len, struct sha1_ctx* ctx); - -/* Process the remaining bytes in the buffer and put result from CTX - in first 20 bytes following RESBUF. The result is always in little - endian byte order, so that a byte-wise output yields to the wanted - ASCII representation of the message digest. */ -extern void* sha1_finish_ctx(struct sha1_ctx* ctx, void* resbuf); - -/* Put result from CTX in first 20 bytes following RESBUF. The result is - always in little endian byte order, so that a byte-wise output yields - to the wanted ASCII representation of the message digest. */ -extern void* sha1_read_ctx(const struct sha1_ctx* ctx, void* resbuf); - -/* Compute SHA1 message digest for bytes read from STREAM. The - resulting message digest number will be written into the 20 bytes - beginning at RESBLOCK. */ -extern int sha1_stream(FILE* stream, void* resblock); - -/* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The - result is always in little endian byte order, so that a byte-wise - output yields to the wanted ASCII representation of the message - digest. */ -extern void* sha1_buffer(const char* buffer, size_t len, void* resblock); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/signature/include/sha256.h b/libs/signature/include/sha256.h deleted file mode 100644 index 1726b60f7..000000000 --- a/libs/signature/include/sha256.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SHA256_H -#define SHA256_H 1 - -#include -#include - -#ifdef __cplusplus -namespace rocketmqSignature { -#endif - -/* Structure to save state of computation between the single steps. */ -struct sha256_ctx { - uint32_t state[8]; - - uint32_t total[2]; - size_t buflen; - uint32_t buffer[32]; -}; - -enum { SHA224_DIGEST_SIZE = 28 }; -enum { SHA256_DIGEST_SIZE = 32 }; - -/* Initialize structure containing state of computation. */ -extern void sha256_init_ctx(struct sha256_ctx* ctx); -extern void sha224_init_ctx(struct sha256_ctx* ctx); - -/* Starting with the result of former calls of this function (or the - initialization function update the context for the next LEN bytes - starting at BUFFER. - It is necessary that LEN is a multiple of 64!!! */ -extern void sha256_process_block(const void* buffer, size_t len, struct sha256_ctx* ctx); - -/* Starting with the result of former calls of this function (or the - initialization function update the context for the next LEN bytes - starting at BUFFER. - It is NOT required that LEN is a multiple of 64. */ -extern void sha256_process_bytes(const void* buffer, size_t len, struct sha256_ctx* ctx); - -/* Process the remaining bytes in the buffer and put result from CTX - in first 32 (28) bytes following RESBUF. The result is always in little - endian byte order, so that a byte-wise output yields to the wanted - ASCII representation of the message digest. */ -extern void* sha256_finish_ctx(struct sha256_ctx* ctx, void* resbuf); -extern void* sha224_finish_ctx(struct sha256_ctx* ctx, void* resbuf); - -/* Put result from CTX in first 32 (28) bytes following RESBUF. The result is - always in little endian byte order, so that a byte-wise output yields - to the wanted ASCII representation of the message digest. */ -extern void* sha256_read_ctx(const struct sha256_ctx* ctx, void* resbuf); -extern void* sha224_read_ctx(const struct sha256_ctx* ctx, void* resbuf); - -/* Compute SHA256 (SHA224) message digest for bytes read from STREAM. The - resulting message digest number will be written into the 32 (28) bytes - beginning at RESBLOCK. */ -extern int sha256_stream(FILE* stream, void* resblock); -extern int sha224_stream(FILE* stream, void* resblock); - -/* Compute SHA256 (SHA224) message digest for LEN bytes beginning at BUFFER. The - result is always in little endian byte order, so that a byte-wise - output yields to the wanted ASCII representation of the message - digest. */ -extern void* sha256_buffer(const char* buffer, size_t len, void* resblock); -extern void* sha224_buffer(const char* buffer, size_t len, void* resblock); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/signature/include/sha512.h b/libs/signature/include/sha512.h deleted file mode 100644 index 38328a16c..000000000 --- a/libs/signature/include/sha512.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SHA512_H -#define SHA512_H 1 - -#include - -#include "u64.h" - -#ifdef __cplusplus -namespace rocketmqSignature { -#endif - -/* Structure to save state of computation between the single steps. */ -struct sha512_ctx { - u64 state[8]; - - u64 total[2]; - size_t buflen; - u64 buffer[32]; -}; - -enum { SHA384_DIGEST_SIZE = 48 }; -enum { SHA512_DIGEST_SIZE = 64 }; - -/* Initialize structure containing state of computation. */ -extern void sha512_init_ctx(struct sha512_ctx* ctx); -extern void sha384_init_ctx(struct sha512_ctx* ctx); - -/* Starting with the result of former calls of this function (or the - initialization function update the context for the next LEN bytes - starting at BUFFER. - It is necessary that LEN is a multiple of 128!!! */ -extern void sha512_process_block(const void* buffer, size_t len, struct sha512_ctx* ctx); - -/* Starting with the result of former calls of this function (or the - initialization function update the context for the next LEN bytes - starting at BUFFER. - It is NOT required that LEN is a multiple of 128. */ -extern void sha512_process_bytes(const void* buffer, size_t len, struct sha512_ctx* ctx); - -/* Process the remaining bytes in the buffer and put result from CTX - in first 64 (48) bytes following RESBUF. The result is always in little - endian byte order, so that a byte-wise output yields to the wanted - ASCII representation of the message digest. */ -extern void* sha512_finish_ctx(struct sha512_ctx* ctx, void* resbuf); -extern void* sha384_finish_ctx(struct sha512_ctx* ctx, void* resbuf); - -/* Put result from CTX in first 64 (48) bytes following RESBUF. The result is - always in little endian byte order, so that a byte-wise output yields - to the wanted ASCII representation of the message digest. - - IMPORTANT: On some systems it is required that RESBUF is correctly - aligned for a 32 bits value. */ -extern void* sha512_read_ctx(const struct sha512_ctx* ctx, void* resbuf); -extern void* sha384_read_ctx(const struct sha512_ctx* ctx, void* resbuf); - -/* Compute SHA512 (SHA384) message digest for bytes read from STREAM. The - resulting message digest number will be written into the 64 (48) bytes - beginning at RESBLOCK. */ -extern int sha512_stream(FILE* stream, void* resblock); -extern int sha384_stream(FILE* stream, void* resblock); - -/* Compute SHA512 (SHA384) message digest for LEN bytes beginning at BUFFER. The - result is always in little endian byte order, so that a byte-wise - output yields to the wanted ASCII representation of the message - digest. */ -extern void* sha512_buffer(const char* buffer, size_t len, void* resblock); -extern void* sha384_buffer(const char* buffer, size_t len, void* resblock); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/signature/include/spas_client.h b/libs/signature/include/spas_client.h deleted file mode 100644 index 7bf6aae04..000000000 --- a/libs/signature/include/spas_client.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SPAS_CLIENT_H -#define SPAS_CLIENT_H - -#include "param_list.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -namespace rocketmqSignature { -#endif - -#define SPAS_MAX_KEY_LEN 128 /* max access_key/secret_key length */ -#define SPAS_MAX_PATH 256 /* max credential file path length */ -#define SPAS_ACCESS_KEY_TAG \ - "accessKey" /* access_key tag in credential file \ - */ -#define SPAS_SECRET_KEY_TAG \ - "secretKey" /* secret_key tag in credential file \ - */ -#define SPAS_CREDENTIAL_ENV "SPAS_CREDENTIAL" /* credential file environment variable */ - -typedef enum { - SIGN_HMACSHA1 = 0, /* HmacSHA1 */ - SIGN_HMACSHA256 = 1, /* HmacSHA256 */ -} SPAS_SIGN_ALGORITHM; - -typedef enum { - NO_UPDATE = 0, /* do not update credential */ - UPDATE_BY_ALARM = 1, /* update credential by SIGALRM */ -#ifdef SPAS_MT - UPDATE_BY_THREAD = 2, /* update credential by standalone thread */ -#endif -} CREDENTIAL_UPDATE_MODE; - -typedef enum { - SPAS_NO_ERROR = 0, /* success */ - ERROR_INVALID_PARAM = -1, /* invalid parameter */ - ERROR_NO_CREDENTIAL = -2, /* credential file not specified */ - ERROR_FILE_OPEN = -3, /* file open failed */ - ERROR_MEM_ALLOC = -4, /* memory allocation failed */ - ERROR_MISSING_KEY = -5, /* missing access_key/secret_key */ - ERROR_KEY_LENGTH = -6, /* key length exceed limit */ - ERROR_UPDATE_CREDENTIAL = -7 /* update credential file failed */ - -} SPAS_ERROR_CODE; - -typedef struct _spas_credential { - char access_key[SPAS_MAX_KEY_LEN]; - char secret_key[SPAS_MAX_KEY_LEN]; -} SPAS_CREDENTIAL; - -extern int spas_load_credential(char* path, CREDENTIAL_UPDATE_MODE mode); -extern int spas_set_access_key(char* key); -extern int spas_set_secret_key(char* key); -extern char* spas_get_access_key(void); -extern char* spas_get_secret_key(void); -extern SPAS_CREDENTIAL* spas_get_credential(void); - -#ifdef SPAS_MT - -extern int spas_load_thread_credential(char* path); -extern int spas_set_thread_access_key(char* key); -extern int spas_set_thread_secret_key(char* key); -extern char* spas_get_thread_access_key(void); -extern char* spas_get_thread_secret_key(void); - -#endif - -extern char* spas_get_signature(const SPAS_PARAM_LIST* list, const char* key); -extern char* spas_get_signature2(const SPAS_PARAM_LIST* list, const char* key, SPAS_SIGN_ALGORITHM algorithm); -extern char* spas_sign(const char* data, size_t size, const char* key); -extern char* spas_sign2(const char* data, size_t size, const char* key, SPAS_SIGN_ALGORITHM algorithm); -extern void spas_mem_free(char* pSignature); -extern char* spas_get_version(void); - -#ifdef __cplusplus -} -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/signature/include/u64.h b/libs/signature/include/u64.h deleted file mode 100644 index e7580e560..000000000 --- a/libs/signature/include/u64.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -/* Return X rotated left by N bits, where 0 < N < 64. */ -#define u64rol(x, n) u64or(u64shl(x, n), u64shr(x, 64 - n)) - -#ifdef UINT64_MAX - -/* Native implementations are trivial. See below for comments on what - these operations do. */ -typedef uint64_t u64; -#define u64hilo(hi, lo) ((u64)(((u64)(hi) << 32) + (lo))) -#define u64init(hi, lo) u64hilo(hi, lo) -#define u64lo(x) ((u64)(x)) -#define u64lt(x, y) ((x) < (y)) -#define u64and(x, y) ((x) & (y)) -#define u64or(x, y) ((x) | (y)) -#define u64xor(x, y) ((x) ^ (y)) -#define u64plus(x, y) ((x) + (y)) -#define u64shl(x, n) ((x) << (n)) -#define u64shr(x, n) ((x) >> (n)) - -#else - -/* u64 is a 64-bit unsigned integer value. - u64init (HI, LO), is like u64hilo (HI, LO), but for use in - initializer contexts. */ -#ifdef WORDS_BIGENDIAN -typedef struct { uint32_t hi, lo; } u64; -#define u64init(hi, lo) \ - { hi, lo } -#else -typedef struct { uint32_t lo, hi; } u64; -#define u64init(hi, lo) \ - { lo, hi } -#endif - -/* Given the high and low-order 32-bit quantities HI and LO, return a u64 - value representing (HI << 32) + LO. */ -static inline u64 u64hilo(uint32_t hi, uint32_t lo) { - u64 r; - r.hi = hi; - r.lo = lo; - return r; -} - -/* Return a u64 value representing LO. */ -static inline u64 u64lo(uint32_t lo) { - u64 r; - r.hi = 0; - r.lo = lo; - return r; -} - -/* Return X < Y. */ -static inline int u64lt(u64 x, u64 y) { - return x.hi < y.hi || (x.hi == y.hi && x.lo < y.lo); -} - -/* Return X & Y. */ -static inline u64 u64and(u64 x, u64 y) { - u64 r; - r.hi = x.hi & y.hi; - r.lo = x.lo & y.lo; - return r; -} - -/* Return X | Y. */ -static inline u64 u64or(u64 x, u64 y) { - u64 r; - r.hi = x.hi | y.hi; - r.lo = x.lo | y.lo; - return r; -} - -/* Return X ^ Y. */ -static inline u64 u64xor(u64 x, u64 y) { - u64 r; - r.hi = x.hi ^ y.hi; - r.lo = x.lo ^ y.lo; - return r; -} - -/* Return X + Y. */ -static inline u64 u64plus(u64 x, u64 y) { - u64 r; - r.lo = x.lo + y.lo; - r.hi = x.hi + y.hi + (r.lo < x.lo); - return r; -} - -/* Return X << N. */ -static inline u64 u64shl(u64 x, int n) { - u64 r; - if (n < 32) { - r.hi = (x.hi << n) | (x.lo >> (32 - n)); - r.lo = x.lo << n; - } else { - r.hi = x.lo << (n - 32); - r.lo = 0; - } - return r; -} - -/* Return X >> N. */ -static inline u64 u64shr(u64 x, int n) { - u64 r; - if (n < 32) { - r.hi = x.hi >> n; - r.lo = (x.hi << (32 - n)) | (x.lo >> n); - } else { - r.hi = 0; - r.lo = x.hi >> (n - 32); - } - return r; -} - -#endif diff --git a/libs/signature/src/base64.c b/libs/signature/src/base64.c deleted file mode 100755 index 682a72595..000000000 --- a/libs/signature/src/base64.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -/* Get prototype. */ -#include "base64.h" - -/* Get malloc. */ -#include - -/* Get UCHAR_MAX. */ -#include - -#ifdef __cplusplus -namespace rocketmqSignature{ -#endif - -/* C89 compliant way to cast 'char' to 'unsigned char'. */ -#ifdef WIN32 -static _inline unsigned char -#else -static inline unsigned char -#endif -to_uchar (char ch) -{ - return ch; -} - -/* Base64 encode IN array of size INLEN into OUT array of size OUTLEN. - If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as - possible. If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero - terminate the output buffer. */ -void -base64_encode (const char *in, size_t inlen, - char *out, size_t outlen) -{ - static const char b64str[65] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - while (inlen && outlen) - { - *out++ = b64str[(to_uchar (in[0]) >> 2) & 0x3f]; - if (!--outlen) - break; - *out++ = b64str[((to_uchar (in[0]) << 4) - + (--inlen ? to_uchar (in[1]) >> 4 : 0)) - & 0x3f]; - if (!--outlen) - break; - *out++ = - (inlen - ? b64str[((to_uchar (in[1]) << 2) - + (--inlen ? to_uchar (in[2]) >> 6 : 0)) - & 0x3f] - : '='); - if (!--outlen) - break; - *out++ = inlen ? b64str[to_uchar (in[2]) & 0x3f] : '='; - if (!--outlen) - break; - if (inlen) - inlen--; - if (inlen) - in += 3; - } - - if (outlen) - *out = '\0'; -} - -/* Allocate a buffer and store zero terminated base64 encoded data - from array IN of size INLEN, returning BASE64_LENGTH(INLEN), i.e., - the length of the encoded data, excluding the terminating zero. On - return, the OUT variable will hold a pointer to newly allocated - memory that must be deallocated by the caller. If output string - length would overflow, 0 is returned and OUT is set to NULL. If - memory allocation failed, OUT is set to NULL, and the return value - indicates length of the requested memory block, i.e., - BASE64_LENGTH(inlen) + 1. */ -size_t -base64_encode_alloc (const char *in, size_t inlen, char **out) -{ - size_t outlen = 1 + BASE64_LENGTH (inlen); - - /* Check for overflow in outlen computation. - * - * If there is no overflow, outlen >= inlen. - * - * If the operation (inlen + 2) overflows then it yields at most +1, so - * outlen is 0. - * - * If the multiplication overflows, we lose at least half of the - * correct value, so the result is < ((inlen + 2) / 3) * 2, which is - * less than (inlen + 2) * 0.66667, which is less than inlen as soon as - * (inlen > 4). - */ - if (inlen > outlen) - { - *out = NULL; - return 0; - } - - *out = (char *)malloc (outlen); - if (!*out) - return outlen; - - base64_encode (in, inlen, *out, outlen); - - return outlen - 1; -} - -/* With this approach this file works independent of the charset used - (think EBCDIC). However, it does assume that the characters in the - Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255. POSIX - 1003.1-2001 require that char and unsigned char are 8-bit - quantities, though, taking care of that problem. But this may be a - potential problem on non-POSIX C99 platforms. - - IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_" - as the formal parameter rather than "x". */ -#define B64(_) \ - ((_) == 'A' ? 0 \ - : (_) == 'B' ? 1 \ - : (_) == 'C' ? 2 \ - : (_) == 'D' ? 3 \ - : (_) == 'E' ? 4 \ - : (_) == 'F' ? 5 \ - : (_) == 'G' ? 6 \ - : (_) == 'H' ? 7 \ - : (_) == 'I' ? 8 \ - : (_) == 'J' ? 9 \ - : (_) == 'K' ? 10 \ - : (_) == 'L' ? 11 \ - : (_) == 'M' ? 12 \ - : (_) == 'N' ? 13 \ - : (_) == 'O' ? 14 \ - : (_) == 'P' ? 15 \ - : (_) == 'Q' ? 16 \ - : (_) == 'R' ? 17 \ - : (_) == 'S' ? 18 \ - : (_) == 'T' ? 19 \ - : (_) == 'U' ? 20 \ - : (_) == 'V' ? 21 \ - : (_) == 'W' ? 22 \ - : (_) == 'X' ? 23 \ - : (_) == 'Y' ? 24 \ - : (_) == 'Z' ? 25 \ - : (_) == 'a' ? 26 \ - : (_) == 'b' ? 27 \ - : (_) == 'c' ? 28 \ - : (_) == 'd' ? 29 \ - : (_) == 'e' ? 30 \ - : (_) == 'f' ? 31 \ - : (_) == 'g' ? 32 \ - : (_) == 'h' ? 33 \ - : (_) == 'i' ? 34 \ - : (_) == 'j' ? 35 \ - : (_) == 'k' ? 36 \ - : (_) == 'l' ? 37 \ - : (_) == 'm' ? 38 \ - : (_) == 'n' ? 39 \ - : (_) == 'o' ? 40 \ - : (_) == 'p' ? 41 \ - : (_) == 'q' ? 42 \ - : (_) == 'r' ? 43 \ - : (_) == 's' ? 44 \ - : (_) == 't' ? 45 \ - : (_) == 'u' ? 46 \ - : (_) == 'v' ? 47 \ - : (_) == 'w' ? 48 \ - : (_) == 'x' ? 49 \ - : (_) == 'y' ? 50 \ - : (_) == 'z' ? 51 \ - : (_) == '0' ? 52 \ - : (_) == '1' ? 53 \ - : (_) == '2' ? 54 \ - : (_) == '3' ? 55 \ - : (_) == '4' ? 56 \ - : (_) == '5' ? 57 \ - : (_) == '6' ? 58 \ - : (_) == '7' ? 59 \ - : (_) == '8' ? 60 \ - : (_) == '9' ? 61 \ - : (_) == '+' ? 62 \ - : (_) == '/' ? 63 \ - : -1) - -static const signed char b64[0x100] = { - B64 (0), B64 (1), B64 (2), B64 (3), - B64 (4), B64 (5), B64 (6), B64 (7), - B64 (8), B64 (9), B64 (10), B64 (11), - B64 (12), B64 (13), B64 (14), B64 (15), - B64 (16), B64 (17), B64 (18), B64 (19), - B64 (20), B64 (21), B64 (22), B64 (23), - B64 (24), B64 (25), B64 (26), B64 (27), - B64 (28), B64 (29), B64 (30), B64 (31), - B64 (32), B64 (33), B64 (34), B64 (35), - B64 (36), B64 (37), B64 (38), B64 (39), - B64 (40), B64 (41), B64 (42), B64 (43), - B64 (44), B64 (45), B64 (46), B64 (47), - B64 (48), B64 (49), B64 (50), B64 (51), - B64 (52), B64 (53), B64 (54), B64 (55), - B64 (56), B64 (57), B64 (58), B64 (59), - B64 (60), B64 (61), B64 (62), B64 (63), - B64 (64), B64 (65), B64 (66), B64 (67), - B64 (68), B64 (69), B64 (70), B64 (71), - B64 (72), B64 (73), B64 (74), B64 (75), - B64 (76), B64 (77), B64 (78), B64 (79), - B64 (80), B64 (81), B64 (82), B64 (83), - B64 (84), B64 (85), B64 (86), B64 (87), - B64 (88), B64 (89), B64 (90), B64 (91), - B64 (92), B64 (93), B64 (94), B64 (95), - B64 (96), B64 (97), B64 (98), B64 (99), - B64 (100), B64 (101), B64 (102), B64 (103), - B64 (104), B64 (105), B64 (106), B64 (107), - B64 (108), B64 (109), B64 (110), B64 (111), - B64 (112), B64 (113), B64 (114), B64 (115), - B64 (116), B64 (117), B64 (118), B64 (119), - B64 (120), B64 (121), B64 (122), B64 (123), - B64 (124), B64 (125), B64 (126), B64 (127), - B64 (128), B64 (129), B64 (130), B64 (131), - B64 (132), B64 (133), B64 (134), B64 (135), - B64 (136), B64 (137), B64 (138), B64 (139), - B64 (140), B64 (141), B64 (142), B64 (143), - B64 (144), B64 (145), B64 (146), B64 (147), - B64 (148), B64 (149), B64 (150), B64 (151), - B64 (152), B64 (153), B64 (154), B64 (155), - B64 (156), B64 (157), B64 (158), B64 (159), - B64 (160), B64 (161), B64 (162), B64 (163), - B64 (164), B64 (165), B64 (166), B64 (167), - B64 (168), B64 (169), B64 (170), B64 (171), - B64 (172), B64 (173), B64 (174), B64 (175), - B64 (176), B64 (177), B64 (178), B64 (179), - B64 (180), B64 (181), B64 (182), B64 (183), - B64 (184), B64 (185), B64 (186), B64 (187), - B64 (188), B64 (189), B64 (190), B64 (191), - B64 (192), B64 (193), B64 (194), B64 (195), - B64 (196), B64 (197), B64 (198), B64 (199), - B64 (200), B64 (201), B64 (202), B64 (203), - B64 (204), B64 (205), B64 (206), B64 (207), - B64 (208), B64 (209), B64 (210), B64 (211), - B64 (212), B64 (213), B64 (214), B64 (215), - B64 (216), B64 (217), B64 (218), B64 (219), - B64 (220), B64 (221), B64 (222), B64 (223), - B64 (224), B64 (225), B64 (226), B64 (227), - B64 (228), B64 (229), B64 (230), B64 (231), - B64 (232), B64 (233), B64 (234), B64 (235), - B64 (236), B64 (237), B64 (238), B64 (239), - B64 (240), B64 (241), B64 (242), B64 (243), - B64 (244), B64 (245), B64 (246), B64 (247), - B64 (248), B64 (249), B64 (250), B64 (251), - B64 (252), B64 (253), B64 (254), B64 (255) -}; - -#if UCHAR_MAX == 255 -# define uchar_in_range(c) true -#else -# define uchar_in_range(c) ((c) <= 255) -#endif - -/* Return true if CH is a character from the Base64 alphabet, and - false otherwise. Note that '=' is padding and not considered to be - part of the alphabet. */ -bool -isbase64 (char ch) -{ - return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)]; -} - -/* Decode base64 encoded input array IN of length INLEN to output - array OUT that can hold *OUTLEN bytes. Return true if decoding was - successful, i.e. if the input was valid base64 data, false - otherwise. If *OUTLEN is too small, as many bytes as possible will - be written to OUT. On return, *OUTLEN holds the length of decoded - bytes in OUT. Note that as soon as any non-alphabet characters are - encountered, decoding is stopped and false is returned. This means - that, when applicable, you must remove any line terminators that is - part of the data stream before calling this function. */ -bool -base64_decode (const char *in, size_t inlen, - char *out, size_t *outlen) -{ - size_t outleft = *outlen; - - while (inlen >= 2) - { - if (!isbase64 (in[0]) || !isbase64 (in[1])) - break; - - if (outleft) - { - *out++ = ((b64[to_uchar (in[0])] << 2) - | (b64[to_uchar (in[1])] >> 4)); - outleft--; - } - - if (inlen == 2) - break; - - if (in[2] == '=') - { - if (inlen != 4) - break; - - if (in[3] != '=') - break; - - } - else - { - if (!isbase64 (in[2])) - break; - - if (outleft) - { - *out++ = (((b64[to_uchar (in[1])] << 4) & 0xf0) - | (b64[to_uchar (in[2])] >> 2)); - outleft--; - } - - if (inlen == 3) - break; - - if (in[3] == '=') - { - if (inlen != 4) - break; - } - else - { - if (!isbase64 (in[3])) - break; - - if (outleft) - { - *out++ = (((b64[to_uchar (in[2])] << 6) & 0xc0) - | b64[to_uchar (in[3])]); - outleft--; - } - } - } - - in += 4; - inlen -= 4; - } - - *outlen -= outleft; - - if (inlen != 0) - return false; - - return true; -} - -/* Allocate an output buffer in *OUT, and decode the base64 encoded - data stored in IN of size INLEN to the *OUT buffer. On return, the - size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL, - if the caller is not interested in the decoded length. *OUT may be - NULL to indicate an out of memory error, in which case *OUTLEN - contains the size of the memory block needed. The function returns - true on successful decoding and memory allocation errors. (Use the - *OUT and *OUTLEN parameters to differentiate between successful - decoding and memory error.) The function returns false if the - input was invalid, in which case *OUT is NULL and *OUTLEN is - undefined. */ -bool -base64_decode_alloc (const char *in, size_t inlen, char **out, - size_t *outlen) -{ - /* This may allocate a few bytes too much, depending on input, - but it's not worth the extra CPU time to compute the exact amount. - The exact amount is 3 * inlen / 4, minus 1 if the input ends - with "=" and minus another 1 if the input ends with "==". - Dividing before multiplying avoids the possibility of overflow. */ - size_t needlen = 3 * (inlen / 4) + 2; - - *out = (char *)malloc (needlen); - if (!*out) - return true; - - if (!base64_decode (in, inlen, *out, &needlen)) - { - free (*out); - *out = NULL; - return false; - } - - if (outlen) - *outlen = needlen; - - return true; -#ifdef __cplusplus -} -#endif - -} diff --git a/libs/signature/src/hmac.c b/libs/signature/src/hmac.c deleted file mode 100755 index b704ccc77..000000000 --- a/libs/signature/src/hmac.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "hmac.h" -#include "sha1.h" -#include "sha256.h" -#include "sha512.h" - -#ifdef __cplusplus -namespace rocketmqSignature{ -#endif - -#define IPAD 0x36 -#define OPAD 0x5c - -int hmac_sha1(const void *key, size_t key_len, const void *data, size_t data_len, void *ret_buf) -{ - uint32_t i; - struct sha1_ctx inner; - struct sha1_ctx outer; - struct sha1_ctx key_hash; - char ipad[64] = {0}; - char opad[64] = {0}; - char key_buf[SHA1_DIGEST_SIZE] = {0}; - char inner_buf[SHA1_DIGEST_SIZE] = {0}; - - if (key == NULL || data == NULL || ret_buf == NULL) return -1; - - if (key_len > 64) { - sha1_init_ctx(&key_hash); - sha1_process_bytes(key, key_len, &key_hash); - sha1_finish_ctx(&key_hash, key_buf); - - key = key_buf; - key_len = SHA1_DIGEST_SIZE; - } - - sha1_init_ctx (&inner); - - for (i = 0; i < 64; i++) { - if (i < key_len) { - ipad[i] = ((const char *)key)[i] ^ IPAD; - opad[i] = ((const char *)key)[i] ^ OPAD; - } else { - ipad[i] = IPAD; - opad[i] = OPAD; - } - } - - sha1_process_block (ipad, 64, &inner); - sha1_process_bytes (data, data_len, &inner); - - sha1_finish_ctx (&inner, inner_buf); - - sha1_init_ctx (&outer); - - sha1_process_block (opad, 64, &outer); - sha1_process_bytes (inner_buf, SHA1_DIGEST_SIZE, &outer); - - sha1_finish_ctx (&outer, ret_buf); - - return 0; -} - -int hmac_sha256(const void *key, size_t key_len, const void *data, size_t data_len, void *ret_buf) -{ - uint32_t i; - struct sha256_ctx inner; - struct sha256_ctx outer; - struct sha256_ctx key_hash; - char ipad[64] = {0}; - char opad[64] = {0}; - char key_buf[SHA256_DIGEST_SIZE] = {0}; - char inner_buf[SHA256_DIGEST_SIZE] = {0}; - - if (key == NULL || data == NULL || ret_buf == NULL) return -1; - - if (key_len > 64) { - sha256_init_ctx(&key_hash); - sha256_process_bytes(key, key_len, &key_hash); - sha256_finish_ctx(&key_hash, key_buf); - - key = key_buf; - key_len = SHA256_DIGEST_SIZE; - } - - sha256_init_ctx (&inner); - - for (i = 0; i < 64; i++) { - if (i < key_len) { - ipad[i] = ((const char *)key)[i] ^ IPAD; - opad[i] = ((const char *)key)[i] ^ OPAD; - } else { - ipad[i] = IPAD; - opad[i] = OPAD; - } - } - - sha256_process_block (ipad, 64, &inner); - sha256_process_bytes (data, data_len, &inner); - - sha256_finish_ctx (&inner, inner_buf); - - sha256_init_ctx (&outer); - - sha256_process_block (opad, 64, &outer); - sha256_process_bytes (inner_buf, SHA256_DIGEST_SIZE, &outer); - - sha256_finish_ctx (&outer, ret_buf); - - return 0; -} - -int hmac_sha512(const void *key, size_t key_len, const void *data, size_t data_len, void *ret_buf) -{ - uint32_t i; - struct sha512_ctx inner; - struct sha512_ctx outer; - struct sha512_ctx key_hash; - char ipad[128] = {0}; - char opad[128] = {0}; - char key_buf[SHA512_DIGEST_SIZE] = {0}; - char inner_buf[SHA512_DIGEST_SIZE] = {0}; - - if (key == NULL || data == NULL || ret_buf == NULL) return -1; - - if (key_len > 128) { - sha512_init_ctx(&key_hash); - sha512_process_bytes(key, key_len, &key_hash); - sha512_finish_ctx(&key_hash, key_buf); - - key = key_buf; - key_len = SHA512_DIGEST_SIZE; - } - - sha512_init_ctx (&inner); - - for (i = 0; i < 128; i++) { - if (i < key_len) { - ipad[i] = ((const char *)key)[i] ^ IPAD; - opad[i] = ((const char *)key)[i] ^ OPAD; - } else { - ipad[i] = IPAD; - opad[i] = OPAD; - } - } - - sha512_process_block (ipad, 128, &inner); - sha512_process_bytes (data, data_len, &inner); - - sha512_finish_ctx (&inner, inner_buf); - - sha512_init_ctx (&outer); - - sha512_process_block (opad, 128, &outer); - sha512_process_bytes (inner_buf, SHA512_DIGEST_SIZE, &outer); - - sha512_finish_ctx (&outer, ret_buf); - - return 0; -} -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/libs/signature/src/param_list.c b/libs/signature/src/param_list.c deleted file mode 100755 index 9f94748d1..000000000 --- a/libs/signature/src/param_list.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include "spas_client.h" - -#ifdef __cplusplus -namespace rocketmqSignature { -#endif - -extern void *_mem_alloc(unsigned int size); -extern void _mem_free(void *ptr); - -static int _nodecmp(SPAS_PARAM_NODE *n1, SPAS_PARAM_NODE *n2) { - int ret = strcmp(n1->name, n2->name); - if (ret == 0) { - ret = strcmp(n1->value, n2->value); - } - return ret; -} - -SPAS_PARAM_LIST *create_param_list() { - return (SPAS_PARAM_LIST *)_mem_alloc(sizeof(SPAS_PARAM_LIST)); -} - -void free_param_list(SPAS_PARAM_LIST *list) { - SPAS_PARAM_NODE *pnode = NULL; - SPAS_PARAM_NODE *pnext = NULL; - if (list == NULL) { - return; - } - pnode = list->phead; - while (pnode != NULL) { - pnext = pnode->pnext; - _mem_free(pnode->name); - _mem_free(pnode->value); - _mem_free(pnode); - pnode = pnext; - } - _mem_free(list); -} - -int add_param_to_list(SPAS_PARAM_LIST *list, const char *name, - const char *value) { - SPAS_PARAM_NODE *pnode = NULL; - SPAS_PARAM_NODE *plast = NULL; - int nlen = 0; - int vlen = 0; - if (list == NULL || name == NULL || value == NULL) { - return ERROR_INVALID_PARAM; - } - nlen = strlen(name); - vlen = strlen(value); - pnode = (SPAS_PARAM_NODE *)_mem_alloc(sizeof(SPAS_PARAM_NODE)); - if (pnode == NULL) { - return ERROR_MEM_ALLOC; - } - pnode->name = (char *)_mem_alloc(nlen + 1); - if (pnode->name == NULL) { - _mem_free(pnode); - return ERROR_MEM_ALLOC; - } - pnode->value = (char *)_mem_alloc(vlen + 1); - if (pnode->value == NULL) { - _mem_free(pnode->name); - _mem_free(pnode); - return ERROR_MEM_ALLOC; - } - memcpy(pnode->name, name, nlen); - memcpy(pnode->value, value, vlen); - if (list->phead == NULL) { - list->phead = pnode; - } else if (_nodecmp(pnode, list->phead) <= 0) { - pnode->pnext = list->phead; - list->phead = pnode; - } else { - plast = list->phead; - while (plast->pnext != NULL) { - if (_nodecmp(pnode, plast->pnext) <= 0) { - pnode->pnext = plast->pnext; - plast->pnext = pnode; - break; - } else { - plast = plast->pnext; - } - } - if (plast->pnext == NULL) { - plast->pnext = pnode; - } - } - list->length++; - list->size += nlen + vlen + 1; /* 1 overhead for '=' */ - return SPAS_NO_ERROR; -} - -char *param_list_to_str(const SPAS_PARAM_LIST *list) { - int size = 0; - int pos = 0; - char *buf = NULL; - SPAS_PARAM_NODE *pnode = NULL; - if (list == NULL) { - return NULL; - } - if (list->length == 0) { - return (char *)_mem_alloc(1); - } - size = list->size + list->length - 1; /* overhead for '&' */ - buf = (char *)_mem_alloc(size); - if (buf == NULL) { - return NULL; - } - pnode = list->phead; - if (pnode != NULL) { - sprintf(buf, "%s=%s", pnode->name, pnode->value); - pos += strlen(pnode->name) + strlen(pnode->value) + 1; - pnode = pnode->pnext; - } - while (pnode != NULL) { - sprintf(buf + pos, "&%s=%s", pnode->name, pnode->value); - pos += strlen(pnode->name) + strlen(pnode->value) + 2; - pnode = pnode->pnext; - } - return buf; -} -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/libs/signature/src/sha1.c b/libs/signature/src/sha1.c deleted file mode 100755 index 7e7c804fd..000000000 --- a/libs/signature/src/sha1.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sha1.h" - -#include -#include - -#if USE_UNLOCKED_IO -# include "unlocked-io.h" -#endif - -#ifdef __cplusplus -namespace rocketmqSignature { -#endif - -#ifdef WORDS_BIGENDIAN -# define SWAP(n) (n) -#else -# define SWAP(n) \ - (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) -#endif - -#define BLOCKSIZE 4096 -#if BLOCKSIZE % 64 != 0 -# error "invalid BLOCKSIZE" -#endif - -/* This array contains the bytes used to pad the buffer to the next - 64-byte boundary. (RFC 1321, 3.1: Step 1) */ -static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; - -/*! - * @fn void sha1_init_ctx (struct sha1_ctx *ctx) - * - * @brief initialize a context with start constants - * - * @details Take a pointer to a 160 bit block of data (five 32 bit ints) and - * initialize it to the start constants of the SHA1 algorithm. This - * must be called before using hash in the call to sha1_hash. - * - * @param[out] ctx pointer to a context to be initialized - */ -void -sha1_init_ctx (struct sha1_ctx *ctx) -{ - ctx->A = 0x67452301; - ctx->B = 0xefcdab89; - ctx->C = 0x98badcfe; - ctx->D = 0x10325476; - ctx->E = 0xc3d2e1f0; - - ctx->total[0] = ctx->total[1] = 0; - ctx->buflen = 0; -} - -/*! - * @fn static __inline__ void set_uint32 (char *cp, uint32_t v) - * - * @brief Copy the 4 byte value from v into the memory location pointed to - by *cp - * - * @details Copy the 4 byte value from v into the memory location pointed to by - * *cp, If your architecture allows unaligned access this is equivalent - * to * (uint32_t *) cp = v - * - * @param[out] cp memory location to copy v into - * @param[in] v 4 byte value to be copied - */ -#ifdef WIN32 -static _inline void -#else -static __inline__ void -#endif -set_uint32 (char *cp, uint32_t v) -{ - memcpy (cp, &v, sizeof v); -} - -/*! - * @fn void *sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf) - * - * @brief Put result from CTX in first 20 bytes following RESBUF - * - * @details Put result from CTX in first 20 bytes following RESBUF. The result - * must be in little endian byte order. - * - * @param[in] ctx context whose results will be copied - * @param[out] resbuf result of copies saved in little endian byte order - * @return resbuf - */ -void * -sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf) -{ - char *r = (char*)resbuf; - set_uint32 (r + 0 * sizeof ctx->A, SWAP (ctx->A)); - set_uint32 (r + 1 * sizeof ctx->B, SWAP (ctx->B)); - set_uint32 (r + 2 * sizeof ctx->C, SWAP (ctx->C)); - set_uint32 (r + 3 * sizeof ctx->D, SWAP (ctx->D)); - set_uint32 (r + 4 * sizeof ctx->E, SWAP (ctx->E)); - - return resbuf; -} - -/*! - * @fn void *sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf) - * - * @brief Process the remaining bytes in the internal buffer and write - the result to RESBUF. - * - * @details Process the remaining bytes in the internal buffer and the usual - * prolog according to the standard and write the result to RESBUF. - * - * @param[in] ctx context to be used - * @param[out] resbuf resultant SHA1 hash - * @return resultant SHA1 hash - */ -void * -sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf) -{ - /* Take yet unprocessed bytes into account. */ - uint32_t bytes = ctx->buflen; - size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; - - /* Now count remaining bytes. */ - ctx->total[0] += bytes; - if (ctx->total[0] < bytes) - ++ctx->total[1]; - - /* Put the 64-bit file length in *bits* at the end of the buffer. */ - ctx->buffer[size - 2] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); - ctx->buffer[size - 1] = SWAP (ctx->total[0] << 3); - - memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); - - /* Process last bytes. */ - sha1_process_block (ctx->buffer, size * 4, ctx); - - return sha1_read_ctx (ctx, resbuf); -} - - -/* - * @fn void *sha1_stream (FILE *stream, void *resblock) - * - * @brief Compute SHA1 message digest for A Stream. - * - * @details Compute SHA1 message digest for Stream. The - * result is always in little endian byte order, so that a byte-wise - * output yields to the wanted ASCII representation of the message - * digest. - * - * @param[in] stream message stream to be hashed - * @param[out] resblock resultant hash in little endian byte order - * @return resultant hash in little endian byte order - */ -int -sha1_stream (FILE *stream, void *resblock) -{ - struct sha1_ctx ctx; - char buffer[BLOCKSIZE + 72]; - size_t sum; - - /* Initialize the computation context. */ - sha1_init_ctx (&ctx); - - /* Iterate over full file contents. */ - while (1) - { - /* We read the file in blocks of BLOCKSIZE bytes. One call of the - computation function processes the whole buffer so that with the - next round of the loop another block can be read. */ - size_t n; - sum = 0; - - /* Read block. Take care for partial reads. */ - while (1) - { - n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); - - sum += n; - - if (sum == BLOCKSIZE) - break; - - if (n == 0) - { - /* Check for the error flag IFF N == 0, so that we don't - exit the loop after a partial read due to e.g., EAGAIN - or EWOULDBLOCK. */ - if (ferror (stream)) - return 1; - goto process_partial_block; - } - - /* We've read at least one byte, so ignore errors. But always - check for EOF, since feof may be true even though N > 0. - Otherwise, we could end up calling fread after EOF. */ - if (feof (stream)) - goto process_partial_block; - } - - /* Process buffer with BLOCKSIZE bytes. Note that - BLOCKSIZE % 64 == 0 - */ - sha1_process_block (buffer, BLOCKSIZE, &ctx); - } - - process_partial_block:; - - /* Process any remaining bytes. */ - if (sum > 0) - sha1_process_bytes (buffer, sum, &ctx); - - /* Construct result in desired memory. */ - sha1_finish_ctx (&ctx, resblock); - return 0; -} - - -/* - * @fn void *sha1_buffer (const char *buffer, size_t len, void *resblock) - * - * @brief Compute SHA1 message digest for LEN bytes beginning at BUFFER. - * - * @details Compute SHA1 message digest for LEN bytes beginning at BUFFER. The - * result is always in little endian byte order, so that a byte-wise - * output yields to the wanted ASCII representation of the message - * digest. - * - * @param[in] buffer message to be hashed - * @param[in] len length of buffer - * @param[out] resblock resultant hash in little endian byte order - * @return resultant hash in little endian byte order - */ -void * -sha1_buffer (const char *buffer, size_t len, void *resblock) -{ - struct sha1_ctx ctx; - - /* Initialize the computation context. */ - sha1_init_ctx (&ctx); - - /* Process whole buffer but last len % 64 bytes. */ - sha1_process_bytes (buffer, len, &ctx); - - /* Put result in desired memory area. */ - return sha1_finish_ctx (&ctx, resblock); -} - -/*! - * @fn void sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx) - * - * @brief update the context for the next LEN bytes starting at BUFFER. - * - * @details Starting with the result of former calls of this function (or the - * initialization function) update the context for the next LEN bytes - * starting at BUFFER. - * It is NOT required that LEN is a multiple of 64. - * - * @param[in] buffer buffer used to update context values - * @param[in] len length of buffer - * @param[out] ctx context to be updated - */ -void -sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx) -{ - /* When we already have some bits in our internal buffer concatenate - both inputs first. */ - if (ctx->buflen != 0) - { - size_t left_over = ctx->buflen; - size_t add = 128 - left_over > len ? len : 128 - left_over; - - memcpy (&((char *) ctx->buffer)[left_over], buffer, add); - ctx->buflen += add; - - if (ctx->buflen > 64) - { - sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx); - - ctx->buflen &= 63; - /* The regions in the following copy operation cannot overlap. */ - memcpy (ctx->buffer, - &((char *) ctx->buffer)[(left_over + add) & ~63], - ctx->buflen); - } - - buffer = (const char *) buffer + add; - len -= add; - } - - /* Process available complete blocks. */ - if (len >= 64) - { -#if !_STRING_ARCH_unaligned -# define alignof(type) offsetof (struct { char c; type x; }, x) -# define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0) - if (UNALIGNED_P (buffer)) - while (len > 64) - { - sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); - buffer = (const char *) buffer + 64; - len -= 64; - } - else -#endif - { - sha1_process_block (buffer, len & ~63, ctx); - buffer = (const char *) buffer + (len & ~63); - len &= 63; - } - } - - /* Move remaining bytes in internal buffer. */ - if (len > 0) - { - size_t left_over = ctx->buflen; - - memcpy (&((char *) ctx->buffer)[left_over], buffer, len); - left_over += len; - if (left_over >= 64) - { - sha1_process_block (ctx->buffer, 64, ctx); - left_over -= 64; - memcpy (ctx->buffer, &ctx->buffer[16], left_over); - } - ctx->buflen = left_over; - } -} - -/* --- Code below is the primary difference between md5.c and sha1.c --- */ - -/* SHA1 round constants */ -#define K1 0x5a827999 -#define K2 0x6ed9eba1 -#define K3 0x8f1bbcdc -#define K4 0xca62c1d6 - -/* Round functions. Note that F2 is the same as F4. */ -#define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) ) -#define F2(B,C,D) (B ^ C ^ D) -#define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) ) -#define F4(B,C,D) (B ^ C ^ D) - -/*! - * @fn void sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx) - * - * @brief Process LEN bytes of BUFFER, accumulating context into CTX. - * - * @details Process LEN bytes of BUFFER, accumulating context into CTX. - * It is assumed that LEN % 64 == 0. - * Most of this code comes from GnuPG's cipher/sha1.c. - * - * @param[in] buffer buffer to be processed - * @param[in] len length of buffer - * @param[out] ctx context used to accumulate results - */ - -void -sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx) -{ - const uint32_t *words = (const uint32_t*)buffer; - size_t nwords = len / sizeof (uint32_t); - const uint32_t *endp = words + nwords; - uint32_t x[16]; - uint32_t a = ctx->A; - uint32_t b = ctx->B; - uint32_t c = ctx->C; - uint32_t d = ctx->D; - uint32_t e = ctx->E; - - /* First increment the byte count. RFC 1321 specifies the possible - length of the file up to 2^64 bits. Here we only compute the - number of bytes. Do a double word increment. */ - ctx->total[0] += len; - if (ctx->total[0] < len) - ++ctx->total[1]; - -#define rol(x, n) (((x) << (n)) | ((uint32_t) (x) >> (32 - (n)))) - -#define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \ - ^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \ - , (x[I&0x0f] = rol(tm, 1)) ) - -#define R(A,B,C,D,E,F,K,M) do { E += rol( A, 5 ) \ - + F( B, C, D ) \ - + K \ - + M; \ - B = rol( B, 30 ); \ - } while(0) - - while (words < endp) - { - uint32_t tm; - int t; - for (t = 0; t < 16; t++) - { - x[t] = SWAP (*words); - words++; - } - - R( a, b, c, d, e, F1, K1, x[ 0] ); - R( e, a, b, c, d, F1, K1, x[ 1] ); - R( d, e, a, b, c, F1, K1, x[ 2] ); - R( c, d, e, a, b, F1, K1, x[ 3] ); - R( b, c, d, e, a, F1, K1, x[ 4] ); - R( a, b, c, d, e, F1, K1, x[ 5] ); - R( e, a, b, c, d, F1, K1, x[ 6] ); - R( d, e, a, b, c, F1, K1, x[ 7] ); - R( c, d, e, a, b, F1, K1, x[ 8] ); - R( b, c, d, e, a, F1, K1, x[ 9] ); - R( a, b, c, d, e, F1, K1, x[10] ); - R( e, a, b, c, d, F1, K1, x[11] ); - R( d, e, a, b, c, F1, K1, x[12] ); - R( c, d, e, a, b, F1, K1, x[13] ); - R( b, c, d, e, a, F1, K1, x[14] ); - R( a, b, c, d, e, F1, K1, x[15] ); - R( e, a, b, c, d, F1, K1, M(16) ); - R( d, e, a, b, c, F1, K1, M(17) ); - R( c, d, e, a, b, F1, K1, M(18) ); - R( b, c, d, e, a, F1, K1, M(19) ); - R( a, b, c, d, e, F2, K2, M(20) ); - R( e, a, b, c, d, F2, K2, M(21) ); - R( d, e, a, b, c, F2, K2, M(22) ); - R( c, d, e, a, b, F2, K2, M(23) ); - R( b, c, d, e, a, F2, K2, M(24) ); - R( a, b, c, d, e, F2, K2, M(25) ); - R( e, a, b, c, d, F2, K2, M(26) ); - R( d, e, a, b, c, F2, K2, M(27) ); - R( c, d, e, a, b, F2, K2, M(28) ); - R( b, c, d, e, a, F2, K2, M(29) ); - R( a, b, c, d, e, F2, K2, M(30) ); - R( e, a, b, c, d, F2, K2, M(31) ); - R( d, e, a, b, c, F2, K2, M(32) ); - R( c, d, e, a, b, F2, K2, M(33) ); - R( b, c, d, e, a, F2, K2, M(34) ); - R( a, b, c, d, e, F2, K2, M(35) ); - R( e, a, b, c, d, F2, K2, M(36) ); - R( d, e, a, b, c, F2, K2, M(37) ); - R( c, d, e, a, b, F2, K2, M(38) ); - R( b, c, d, e, a, F2, K2, M(39) ); - R( a, b, c, d, e, F3, K3, M(40) ); - R( e, a, b, c, d, F3, K3, M(41) ); - R( d, e, a, b, c, F3, K3, M(42) ); - R( c, d, e, a, b, F3, K3, M(43) ); - R( b, c, d, e, a, F3, K3, M(44) ); - R( a, b, c, d, e, F3, K3, M(45) ); - R( e, a, b, c, d, F3, K3, M(46) ); - R( d, e, a, b, c, F3, K3, M(47) ); - R( c, d, e, a, b, F3, K3, M(48) ); - R( b, c, d, e, a, F3, K3, M(49) ); - R( a, b, c, d, e, F3, K3, M(50) ); - R( e, a, b, c, d, F3, K3, M(51) ); - R( d, e, a, b, c, F3, K3, M(52) ); - R( c, d, e, a, b, F3, K3, M(53) ); - R( b, c, d, e, a, F3, K3, M(54) ); - R( a, b, c, d, e, F3, K3, M(55) ); - R( e, a, b, c, d, F3, K3, M(56) ); - R( d, e, a, b, c, F3, K3, M(57) ); - R( c, d, e, a, b, F3, K3, M(58) ); - R( b, c, d, e, a, F3, K3, M(59) ); - R( a, b, c, d, e, F4, K4, M(60) ); - R( e, a, b, c, d, F4, K4, M(61) ); - R( d, e, a, b, c, F4, K4, M(62) ); - R( c, d, e, a, b, F4, K4, M(63) ); - R( b, c, d, e, a, F4, K4, M(64) ); - R( a, b, c, d, e, F4, K4, M(65) ); - R( e, a, b, c, d, F4, K4, M(66) ); - R( d, e, a, b, c, F4, K4, M(67) ); - R( c, d, e, a, b, F4, K4, M(68) ); - R( b, c, d, e, a, F4, K4, M(69) ); - R( a, b, c, d, e, F4, K4, M(70) ); - R( e, a, b, c, d, F4, K4, M(71) ); - R( d, e, a, b, c, F4, K4, M(72) ); - R( c, d, e, a, b, F4, K4, M(73) ); - R( b, c, d, e, a, F4, K4, M(74) ); - R( a, b, c, d, e, F4, K4, M(75) ); - R( e, a, b, c, d, F4, K4, M(76) ); - R( d, e, a, b, c, F4, K4, M(77) ); - R( c, d, e, a, b, F4, K4, M(78) ); - R( b, c, d, e, a, F4, K4, M(79) ); - - a = ctx->A += a; - b = ctx->B += b; - c = ctx->C += c; - d = ctx->D += d; - e = ctx->E += e; - } -} -#ifdef __cplusplus -} -#endif diff --git a/libs/signature/src/sha256.c b/libs/signature/src/sha256.c deleted file mode 100755 index a2ca68242..000000000 --- a/libs/signature/src/sha256.c +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sha256.h" - -#include -#include - -#if USE_UNLOCKED_IO -# include "unlocked-io.h" -#endif - -#ifdef __cplusplus -namespace rocketmqSignature { -#endif - -#ifdef WORDS_BIGENDIAN -# define SWAP(n) (n) -#else -# define SWAP(n) \ - (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) -#endif - -#define BLOCKSIZE 4096 -#if BLOCKSIZE % 64 != 0 -# error "invalid BLOCKSIZE" -#endif - -/* This array contains the bytes used to pad the buffer to the next - 64-byte boundary. */ -static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; - - -/* - Takes a pointer to a 256 bit block of data (eight 32 bit ints) and - intializes it to the start constants of the SHA256 algorithm. This - must be called before using hash in the call to sha256_hash -*/ -void -sha256_init_ctx (struct sha256_ctx *ctx) -{ - ctx->state[0] = 0x6a09e667UL; - ctx->state[1] = 0xbb67ae85UL; - ctx->state[2] = 0x3c6ef372UL; - ctx->state[3] = 0xa54ff53aUL; - ctx->state[4] = 0x510e527fUL; - ctx->state[5] = 0x9b05688cUL; - ctx->state[6] = 0x1f83d9abUL; - ctx->state[7] = 0x5be0cd19UL; - - ctx->total[0] = ctx->total[1] = 0; - ctx->buflen = 0; -} - -void -sha224_init_ctx (struct sha256_ctx *ctx) -{ - ctx->state[0] = 0xc1059ed8UL; - ctx->state[1] = 0x367cd507UL; - ctx->state[2] = 0x3070dd17UL; - ctx->state[3] = 0xf70e5939UL; - ctx->state[4] = 0xffc00b31UL; - ctx->state[5] = 0x68581511UL; - ctx->state[6] = 0x64f98fa7UL; - ctx->state[7] = 0xbefa4fa4UL; - - ctx->total[0] = ctx->total[1] = 0; - ctx->buflen = 0; -} - -/* Copy the value from v into the memory location pointed to by *cp, - If your architecture allows unaligned access this is equivalent to - * (uint32_t *) cp = v */ -#ifdef WIN32 -static _inline void -#else -static __inline__ void -#endif -set_uint32 (char *cp, uint32_t v) -{ - memcpy (cp, &v, sizeof v); -} - -/* Put result from CTX in first 32 bytes following RESBUF. The result - must be in little endian byte order. */ -void * -sha256_read_ctx (const struct sha256_ctx *ctx, void *resbuf) -{ - int i; - char *r = (char*)resbuf; - - for (i = 0; i < 8; i++) - set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); - - return resbuf; -} - -void * -sha224_read_ctx (const struct sha256_ctx *ctx, void *resbuf) -{ - int i; - char *r = (char*)resbuf; - - for (i = 0; i < 7; i++) - set_uint32 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); - - return resbuf; -} - -/* Process the remaining bytes in the internal buffer and the usual - prolog according to the standard and write the result to RESBUF. */ -static void -sha256_conclude_ctx (struct sha256_ctx *ctx) -{ - /* Take yet unprocessed bytes into account. */ - size_t bytes = ctx->buflen; - size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; - - /* Now count remaining bytes. */ - ctx->total[0] += bytes; - if (ctx->total[0] < bytes) - ++ctx->total[1]; - - /* Put the 64-bit file length in *bits* at the end of the buffer. - Use set_uint32 rather than a simple assignment, to avoid risk of - unaligned access. */ - set_uint32 ((char *) &ctx->buffer[size - 2], - SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29))); - set_uint32 ((char *) &ctx->buffer[size - 1], - SWAP (ctx->total[0] << 3)); - - memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); - - /* Process last bytes. */ - sha256_process_block (ctx->buffer, size * 4, ctx); -} - -void * -sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf) -{ - sha256_conclude_ctx (ctx); - return sha256_read_ctx (ctx, resbuf); -} - -void * -sha224_finish_ctx (struct sha256_ctx *ctx, void *resbuf) -{ - sha256_conclude_ctx (ctx); - return sha224_read_ctx (ctx, resbuf); -} - -/* Compute SHA256 message digest for bytes read from STREAM. The - resulting message digest number will be written into the 32 bytes - beginning at RESBLOCK. */ -int -sha256_stream (FILE *stream, void *resblock) -{ - struct sha256_ctx ctx; - char buffer[BLOCKSIZE + 72]; - size_t sum; - - /* Initialize the computation context. */ - sha256_init_ctx (&ctx); - - /* Iterate over full file contents. */ - while (1) - { - /* We read the file in blocks of BLOCKSIZE bytes. One call of the - computation function processes the whole buffer so that with the - next round of the loop another block can be read. */ - size_t n; - sum = 0; - - /* Read block. Take care for partial reads. */ - while (1) - { - n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); - - sum += n; - - if (sum == BLOCKSIZE) - break; - - if (n == 0) - { - /* Check for the error flag IFF N == 0, so that we don't - exit the loop after a partial read due to e.g., EAGAIN - or EWOULDBLOCK. */ - if (ferror (stream)) - return 1; - goto process_partial_block; - } - - /* We've read at least one byte, so ignore errors. But always - check for EOF, since feof may be true even though N > 0. - Otherwise, we could end up calling fread after EOF. */ - if (feof (stream)) - goto process_partial_block; - } - - /* Process buffer with BLOCKSIZE bytes. Note that - BLOCKSIZE % 64 == 0 - */ - sha256_process_block (buffer, BLOCKSIZE, &ctx); - } - - process_partial_block:; - - /* Process any remaining bytes. */ - if (sum > 0) - sha256_process_bytes (buffer, sum, &ctx); - - /* Construct result in desired memory. */ - sha256_finish_ctx (&ctx, resblock); - return 0; -} - -/* FIXME: Avoid code duplication */ -int -sha224_stream (FILE *stream, void *resblock) -{ - struct sha256_ctx ctx; - char buffer[BLOCKSIZE + 72]; - size_t sum; - - /* Initialize the computation context. */ - sha224_init_ctx (&ctx); - - /* Iterate over full file contents. */ - while (1) - { - /* We read the file in blocks of BLOCKSIZE bytes. One call of the - computation function processes the whole buffer so that with the - next round of the loop another block can be read. */ - size_t n; - sum = 0; - - /* Read block. Take care for partial reads. */ - while (1) - { - n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); - - sum += n; - - if (sum == BLOCKSIZE) - break; - - if (n == 0) - { - /* Check for the error flag IFF N == 0, so that we don't - exit the loop after a partial read due to e.g., EAGAIN - or EWOULDBLOCK. */ - if (ferror (stream)) - return 1; - goto process_partial_block; - } - - /* We've read at least one byte, so ignore errors. But always - check for EOF, since feof may be true even though N > 0. - Otherwise, we could end up calling fread after EOF. */ - if (feof (stream)) - goto process_partial_block; - } - - /* Process buffer with BLOCKSIZE bytes. Note that - BLOCKSIZE % 64 == 0 - */ - sha256_process_block (buffer, BLOCKSIZE, &ctx); - } - - process_partial_block:; - - /* Process any remaining bytes. */ - if (sum > 0) - sha256_process_bytes (buffer, sum, &ctx); - - /* Construct result in desired memory. */ - sha224_finish_ctx (&ctx, resblock); - return 0; -} - -/* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The - result is always in little endian byte order, so that a byte-wise - output yields to the wanted ASCII representation of the message - digest. */ -void * -sha256_buffer (const char *buffer, size_t len, void *resblock) -{ - struct sha256_ctx ctx; - - /* Initialize the computation context. */ - sha256_init_ctx (&ctx); - - /* Process whole buffer but last len % 64 bytes. */ - sha256_process_bytes (buffer, len, &ctx); - - /* Put result in desired memory area. */ - return sha256_finish_ctx (&ctx, resblock); -} - -void * -sha224_buffer (const char *buffer, size_t len, void *resblock) -{ - struct sha256_ctx ctx; - - /* Initialize the computation context. */ - sha224_init_ctx (&ctx); - - /* Process whole buffer but last len % 64 bytes. */ - sha256_process_bytes (buffer, len, &ctx); - - /* Put result in desired memory area. */ - return sha224_finish_ctx (&ctx, resblock); -} - -void -sha256_process_bytes (const void *buffer, size_t len, struct sha256_ctx *ctx) -{ - /* When we already have some bits in our internal buffer concatenate - both inputs first. */ - if (ctx->buflen != 0) - { - size_t left_over = ctx->buflen; - size_t add = 128 - left_over > len ? len : 128 - left_over; - - memcpy (&((char *) ctx->buffer)[left_over], buffer, add); - ctx->buflen += add; - - if (ctx->buflen > 64) - { - sha256_process_block (ctx->buffer, ctx->buflen & ~63, ctx); - - ctx->buflen &= 63; - /* The regions in the following copy operation cannot overlap. */ - memcpy (ctx->buffer, - &((char *) ctx->buffer)[(left_over + add) & ~63], - ctx->buflen); - } - - buffer = (const char *) buffer + add; - len -= add; - } - - /* Process available complete blocks. */ - if (len >= 64) - { -#if !_STRING_ARCH_unaligned -# define alignof(type) offsetof (struct { char c; type x; }, x) -# define UNALIGNED_P(p) (((size_t) p) % alignof (uint32_t) != 0) - if (UNALIGNED_P (buffer)) - while (len > 64) - { - sha256_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); - buffer = (const char *) buffer + 64; - len -= 64; - } - else -#endif - { - sha256_process_block (buffer, len & ~63, ctx); - buffer = (const char *) buffer + (len & ~63); - len &= 63; - } - } - - /* Move remaining bytes in internal buffer. */ - if (len > 0) - { - size_t left_over = ctx->buflen; - - memcpy (&((char *) ctx->buffer)[left_over], buffer, len); - left_over += len; - if (left_over >= 64) - { - sha256_process_block (ctx->buffer, 64, ctx); - left_over -= 64; - memcpy (ctx->buffer, &ctx->buffer[16], left_over); - } - ctx->buflen = left_over; - } -} - -/* --- Code below is the primary difference between sha1.c and sha256.c --- */ - -/* SHA256 round constants */ -#define K(I) sha256_round_constants[I] -static const uint32_t sha256_round_constants[64] = { - 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, - 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, - 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, - 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, - 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, - 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, - 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, - 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, - 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, - 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, - 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, - 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, - 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, - 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, - 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, - 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL, -}; - -/* Round functions. */ -#define F2(A,B,C) ( ( A & B ) | ( C & ( A | B ) ) ) -#define F1(E,F,G) ( G ^ ( E & ( F ^ G ) ) ) - -/* Process LEN bytes of BUFFER, accumulating context into CTX. - It is assumed that LEN % 64 == 0. - Most of this code comes from GnuPG's cipher/sha1.c. */ - -void -sha256_process_block (const void *buffer, size_t len, struct sha256_ctx *ctx) -{ - const uint32_t *words = (const uint32_t *)buffer; - size_t nwords = len / sizeof (uint32_t); - const uint32_t *endp = words + nwords; - uint32_t x[16]; - uint32_t a = ctx->state[0]; - uint32_t b = ctx->state[1]; - uint32_t c = ctx->state[2]; - uint32_t d = ctx->state[3]; - uint32_t e = ctx->state[4]; - uint32_t f = ctx->state[5]; - uint32_t g = ctx->state[6]; - uint32_t h = ctx->state[7]; - - /* First increment the byte count. FIPS PUB 180-2 specifies the possible - length of the file up to 2^64 bits. Here we only compute the - number of bytes. Do a double word increment. */ - ctx->total[0] += len; - if (ctx->total[0] < len) - ++ctx->total[1]; - -#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) -#define S0(x) (rol(x,25)^rol(x,14)^(x>>3)) -#define S1(x) (rol(x,15)^rol(x,13)^(x>>10)) -#define SS0(x) (rol(x,30)^rol(x,19)^rol(x,10)) -#define SS1(x) (rol(x,26)^rol(x,21)^rol(x,7)) - -#define M(I) ( tm = S1(x[(I-2)&0x0f]) + x[(I-7)&0x0f] \ - + S0(x[(I-15)&0x0f]) + x[I&0x0f] \ - , x[I&0x0f] = tm ) - -#define R(A,B,C,D,E,F,G,H,K,M) do { t0 = SS0(A) + F2(A,B,C); \ - t1 = H + SS1(E) \ - + F1(E,F,G) \ - + K \ - + M; \ - D += t1; H = t0 + t1; \ - } while(0) - - while (words < endp) - { - uint32_t tm; - uint32_t t0, t1; - int t; - /* FIXME: see sha1.c for a better implementation. */ - for (t = 0; t < 16; t++) - { - x[t] = SWAP (*words); - words++; - } - - R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); - R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); - R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); - R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); - R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); - R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); - R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); - R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); - R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); - R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); - R( g, h, a, b, c, d, e, f, K(10), x[10] ); - R( f, g, h, a, b, c, d, e, K(11), x[11] ); - R( e, f, g, h, a, b, c, d, K(12), x[12] ); - R( d, e, f, g, h, a, b, c, K(13), x[13] ); - R( c, d, e, f, g, h, a, b, K(14), x[14] ); - R( b, c, d, e, f, g, h, a, K(15), x[15] ); - R( a, b, c, d, e, f, g, h, K(16), M(16) ); - R( h, a, b, c, d, e, f, g, K(17), M(17) ); - R( g, h, a, b, c, d, e, f, K(18), M(18) ); - R( f, g, h, a, b, c, d, e, K(19), M(19) ); - R( e, f, g, h, a, b, c, d, K(20), M(20) ); - R( d, e, f, g, h, a, b, c, K(21), M(21) ); - R( c, d, e, f, g, h, a, b, K(22), M(22) ); - R( b, c, d, e, f, g, h, a, K(23), M(23) ); - R( a, b, c, d, e, f, g, h, K(24), M(24) ); - R( h, a, b, c, d, e, f, g, K(25), M(25) ); - R( g, h, a, b, c, d, e, f, K(26), M(26) ); - R( f, g, h, a, b, c, d, e, K(27), M(27) ); - R( e, f, g, h, a, b, c, d, K(28), M(28) ); - R( d, e, f, g, h, a, b, c, K(29), M(29) ); - R( c, d, e, f, g, h, a, b, K(30), M(30) ); - R( b, c, d, e, f, g, h, a, K(31), M(31) ); - R( a, b, c, d, e, f, g, h, K(32), M(32) ); - R( h, a, b, c, d, e, f, g, K(33), M(33) ); - R( g, h, a, b, c, d, e, f, K(34), M(34) ); - R( f, g, h, a, b, c, d, e, K(35), M(35) ); - R( e, f, g, h, a, b, c, d, K(36), M(36) ); - R( d, e, f, g, h, a, b, c, K(37), M(37) ); - R( c, d, e, f, g, h, a, b, K(38), M(38) ); - R( b, c, d, e, f, g, h, a, K(39), M(39) ); - R( a, b, c, d, e, f, g, h, K(40), M(40) ); - R( h, a, b, c, d, e, f, g, K(41), M(41) ); - R( g, h, a, b, c, d, e, f, K(42), M(42) ); - R( f, g, h, a, b, c, d, e, K(43), M(43) ); - R( e, f, g, h, a, b, c, d, K(44), M(44) ); - R( d, e, f, g, h, a, b, c, K(45), M(45) ); - R( c, d, e, f, g, h, a, b, K(46), M(46) ); - R( b, c, d, e, f, g, h, a, K(47), M(47) ); - R( a, b, c, d, e, f, g, h, K(48), M(48) ); - R( h, a, b, c, d, e, f, g, K(49), M(49) ); - R( g, h, a, b, c, d, e, f, K(50), M(50) ); - R( f, g, h, a, b, c, d, e, K(51), M(51) ); - R( e, f, g, h, a, b, c, d, K(52), M(52) ); - R( d, e, f, g, h, a, b, c, K(53), M(53) ); - R( c, d, e, f, g, h, a, b, K(54), M(54) ); - R( b, c, d, e, f, g, h, a, K(55), M(55) ); - R( a, b, c, d, e, f, g, h, K(56), M(56) ); - R( h, a, b, c, d, e, f, g, K(57), M(57) ); - R( g, h, a, b, c, d, e, f, K(58), M(58) ); - R( f, g, h, a, b, c, d, e, K(59), M(59) ); - R( e, f, g, h, a, b, c, d, K(60), M(60) ); - R( d, e, f, g, h, a, b, c, K(61), M(61) ); - R( c, d, e, f, g, h, a, b, K(62), M(62) ); - R( b, c, d, e, f, g, h, a, K(63), M(63) ); - - a = ctx->state[0] += a; - b = ctx->state[1] += b; - c = ctx->state[2] += c; - d = ctx->state[3] += d; - e = ctx->state[4] += e; - f = ctx->state[5] += f; - g = ctx->state[6] += g; - h = ctx->state[7] += h; - } -} -#ifdef __cplusplus -} -#endif - diff --git a/libs/signature/src/sha512.c b/libs/signature/src/sha512.c deleted file mode 100755 index 0d9741efb..000000000 --- a/libs/signature/src/sha512.c +++ /dev/null @@ -1,609 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "sha512.h" - -#include -#include - -#if USE_UNLOCKED_IO -# include "unlocked-io.h" -#endif - -#ifdef __cplusplus -namespace rocketmqSignature{ -#endif - -#ifdef WORDS_BIGENDIAN -# define SWAP(n) (n) -#else -# define SWAP(n) \ - u64or (u64or (u64or (u64shl (n, 56), \ - u64shl (u64and (n, u64lo (0x0000ff00)), 40)), \ - u64or (u64shl (u64and (n, u64lo (0x00ff0000)), 24), \ - u64shl (u64and (n, u64lo (0xff000000)), 8))), \ - u64or (u64or (u64and (u64shr (n, 8), u64lo (0xff000000)), \ - u64and (u64shr (n, 24), u64lo (0x00ff0000))), \ - u64or (u64and (u64shr (n, 40), u64lo (0x0000ff00)), \ - u64shr (n, 56)))) -#endif - -#define BLOCKSIZE 4096 -#if BLOCKSIZE % 128 != 0 -# error "invalid BLOCKSIZE" -#endif - -/* This array contains the bytes used to pad the buffer to the next - 128-byte boundary. */ -static const unsigned char fillbuf[128] = { 0x80, 0 /* , 0, 0, ... */ }; - - -/* - Takes a pointer to a 512 bit block of data (eight 64 bit ints) and - intializes it to the start constants of the SHA512 algorithm. This - must be called before using hash in the call to sha512_hash -*/ -void -sha512_init_ctx (struct sha512_ctx *ctx) -{ - ctx->state[0] = u64hilo (0x6a09e667, 0xf3bcc908); - ctx->state[1] = u64hilo (0xbb67ae85, 0x84caa73b); - ctx->state[2] = u64hilo (0x3c6ef372, 0xfe94f82b); - ctx->state[3] = u64hilo (0xa54ff53a, 0x5f1d36f1); - ctx->state[4] = u64hilo (0x510e527f, 0xade682d1); - ctx->state[5] = u64hilo (0x9b05688c, 0x2b3e6c1f); - ctx->state[6] = u64hilo (0x1f83d9ab, 0xfb41bd6b); - ctx->state[7] = u64hilo (0x5be0cd19, 0x137e2179); - - ctx->total[0] = ctx->total[1] = u64lo (0); - ctx->buflen = 0; -} - -void -sha384_init_ctx (struct sha512_ctx *ctx) -{ - ctx->state[0] = u64hilo (0xcbbb9d5d, 0xc1059ed8); - ctx->state[1] = u64hilo (0x629a292a, 0x367cd507); - ctx->state[2] = u64hilo (0x9159015a, 0x3070dd17); - ctx->state[3] = u64hilo (0x152fecd8, 0xf70e5939); - ctx->state[4] = u64hilo (0x67332667, 0xffc00b31); - ctx->state[5] = u64hilo (0x8eb44a87, 0x68581511); - ctx->state[6] = u64hilo (0xdb0c2e0d, 0x64f98fa7); - ctx->state[7] = u64hilo (0x47b5481d, 0xbefa4fa4); - - ctx->total[0] = ctx->total[1] = u64lo (0); - ctx->buflen = 0; -} - -/* Copy the value from V into the memory location pointed to by *CP, - If your architecture allows unaligned access, this is equivalent to - * (__typeof__ (v) *) cp = v */ -#ifdef WIN32 -static _inline void -#else -static __inline__ void -#endif -set_uint64 (char *cp, u64 v) -{ - memcpy (cp, &v, sizeof v); -} - -/* Put result from CTX in first 64 bytes following RESBUF. - The result must be in little endian byte order. */ -void * -sha512_read_ctx (const struct sha512_ctx *ctx, void *resbuf) -{ - int i; - char *r = (char*)resbuf; - - for (i = 0; i < 8; i++) - set_uint64 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); - - return resbuf; -} - -void * -sha384_read_ctx (const struct sha512_ctx *ctx, void *resbuf) -{ - int i; - char *r = (char*)resbuf; - - for (i = 0; i < 6; i++) - set_uint64 (r + i * sizeof ctx->state[0], SWAP (ctx->state[i])); - - return resbuf; -} - -/* Process the remaining bytes in the internal buffer and the usual - prolog according to the standard and write the result to RESBUF. */ -static void -sha512_conclude_ctx (struct sha512_ctx *ctx) -{ - /* Take yet unprocessed bytes into account. */ - size_t bytes = ctx->buflen; - size_t size = (bytes < 112) ? 128 / 8 : 128 * 2 / 8; - - /* Now count remaining bytes. */ - ctx->total[0] = u64plus (ctx->total[0], u64lo (bytes)); - if (u64lt (ctx->total[0], u64lo (bytes))) - ctx->total[1] = u64plus (ctx->total[1], u64lo (1)); - - /* Put the 128-bit file length in *bits* at the end of the buffer. - Use set_uint64 rather than a simple assignment, to avoid risk of - unaligned access. */ - set_uint64 ((char *) &ctx->buffer[size - 2], - SWAP (u64or (u64shl (ctx->total[1], 3), - u64shr (ctx->total[0], 61)))); - set_uint64 ((char *) &ctx->buffer[size - 1], - SWAP (u64shl (ctx->total[0], 3))); - - memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 8 - bytes); - - /* Process last bytes. */ - sha512_process_block (ctx->buffer, size * 8, ctx); -} - -void * -sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf) -{ - sha512_conclude_ctx (ctx); - return sha512_read_ctx (ctx, resbuf); -} - -void * -sha384_finish_ctx (struct sha512_ctx *ctx, void *resbuf) -{ - sha512_conclude_ctx (ctx); - return sha384_read_ctx (ctx, resbuf); -} - -/* Compute SHA512 message digest for bytes read from STREAM. The - resulting message digest number will be written into the 64 bytes - beginning at RESBLOCK. */ -int -sha512_stream (FILE *stream, void *resblock) -{ - struct sha512_ctx ctx; - char buffer[BLOCKSIZE + 72]; - size_t sum; - - /* Initialize the computation context. */ - sha512_init_ctx (&ctx); - - /* Iterate over full file contents. */ - while (1) - { - /* We read the file in blocks of BLOCKSIZE bytes. One call of the - computation function processes the whole buffer so that with the - next round of the loop another block can be read. */ - size_t n; - sum = 0; - - /* Read block. Take care for partial reads. */ - while (1) - { - n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); - - sum += n; - - if (sum == BLOCKSIZE) - break; - - if (n == 0) - { - /* Check for the error flag IFF N == 0, so that we don't - exit the loop after a partial read due to e.g., EAGAIN - or EWOULDBLOCK. */ - if (ferror (stream)) - return 1; - goto process_partial_block; - } - - /* We've read at least one byte, so ignore errors. But always - check for EOF, since feof may be true even though N > 0. - Otherwise, we could end up calling fread after EOF. */ - if (feof (stream)) - goto process_partial_block; - } - - /* Process buffer with BLOCKSIZE bytes. Note that - BLOCKSIZE % 128 == 0 - */ - sha512_process_block (buffer, BLOCKSIZE, &ctx); - } - - process_partial_block:; - - /* Process any remaining bytes. */ - if (sum > 0) - sha512_process_bytes (buffer, sum, &ctx); - - /* Construct result in desired memory. */ - sha512_finish_ctx (&ctx, resblock); - return 0; -} - -/* FIXME: Avoid code duplication */ -int -sha384_stream (FILE *stream, void *resblock) -{ - struct sha512_ctx ctx; - char buffer[BLOCKSIZE + 72]; - size_t sum; - - /* Initialize the computation context. */ - sha384_init_ctx (&ctx); - - /* Iterate over full file contents. */ - while (1) - { - /* We read the file in blocks of BLOCKSIZE bytes. One call of the - computation function processes the whole buffer so that with the - next round of the loop another block can be read. */ - size_t n; - sum = 0; - - /* Read block. Take care for partial reads. */ - while (1) - { - n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); - - sum += n; - - if (sum == BLOCKSIZE) - break; - - if (n == 0) - { - /* Check for the error flag IFF N == 0, so that we don't - exit the loop after a partial read due to e.g., EAGAIN - or EWOULDBLOCK. */ - if (ferror (stream)) - return 1; - goto process_partial_block; - } - - /* We've read at least one byte, so ignore errors. But always - check for EOF, since feof may be true even though N > 0. - Otherwise, we could end up calling fread after EOF. */ - if (feof (stream)) - goto process_partial_block; - } - - /* Process buffer with BLOCKSIZE bytes. Note that - BLOCKSIZE % 128 == 0 - */ - sha512_process_block (buffer, BLOCKSIZE, &ctx); - } - - process_partial_block:; - - /* Process any remaining bytes. */ - if (sum > 0) - sha512_process_bytes (buffer, sum, &ctx); - - /* Construct result in desired memory. */ - sha384_finish_ctx (&ctx, resblock); - return 0; -} - -/* Compute SHA512 message digest for LEN bytes beginning at BUFFER. The - result is always in little endian byte order, so that a byte-wise - output yields to the wanted ASCII representation of the message - digest. */ -void * -sha512_buffer (const char *buffer, size_t len, void *resblock) -{ - struct sha512_ctx ctx; - - /* Initialize the computation context. */ - sha512_init_ctx (&ctx); - - /* Process whole buffer but last len % 128 bytes. */ - sha512_process_bytes (buffer, len, &ctx); - - /* Put result in desired memory area. */ - return sha512_finish_ctx (&ctx, resblock); -} - -void * -sha384_buffer (const char *buffer, size_t len, void *resblock) -{ - struct sha512_ctx ctx; - - /* Initialize the computation context. */ - sha384_init_ctx (&ctx); - - /* Process whole buffer but last len % 128 bytes. */ - sha512_process_bytes (buffer, len, &ctx); - - /* Put result in desired memory area. */ - return sha384_finish_ctx (&ctx, resblock); -} - -void -sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx) -{ - /* When we already have some bits in our internal buffer concatenate - both inputs first. */ - if (ctx->buflen != 0) - { - size_t left_over = ctx->buflen; - size_t add = 256 - left_over > len ? len : 256 - left_over; - - memcpy (&((char *) ctx->buffer)[left_over], buffer, add); - ctx->buflen += add; - - if (ctx->buflen > 128) - { - sha512_process_block (ctx->buffer, ctx->buflen & ~127, ctx); - - ctx->buflen &= 127; - /* The regions in the following copy operation cannot overlap. */ - memcpy (ctx->buffer, - &((char *) ctx->buffer)[(left_over + add) & ~127], - ctx->buflen); - } - - buffer = (const char *) buffer + add; - len -= add; - } - - /* Process available complete blocks. */ - if (len >= 128) - { -#if !_STRING_ARCH_unaligned -# define alignof(type) offsetof (struct { char c; type x; }, x) -# define UNALIGNED_P(p) (((size_t) p) % alignof (u64) != 0) - if (UNALIGNED_P (buffer)) - while (len > 128) - { - sha512_process_block (memcpy (ctx->buffer, buffer, 128), 128, ctx); - buffer = (const char *) buffer + 128; - len -= 128; - } - else -#endif - { - sha512_process_block (buffer, len & ~127, ctx); - buffer = (const char *) buffer + (len & ~127); - len &= 127; - } - } - - /* Move remaining bytes in internal buffer. */ - if (len > 0) - { - size_t left_over = ctx->buflen; - - memcpy (&((char *) ctx->buffer)[left_over], buffer, len); - left_over += len; - if (left_over >= 128) - { - sha512_process_block (ctx->buffer, 128, ctx); - left_over -= 128; - memcpy (ctx->buffer, &ctx->buffer[16], left_over); - } - ctx->buflen = left_over; - } -} - -/* --- Code below is the primary difference between sha1.c and sha512.c --- */ - -/* SHA512 round constants */ -#define K(I) sha512_round_constants[I] -static u64 const sha512_round_constants[80] = { - u64init (0x428a2f98, 0xd728ae22), u64init (0x71374491, 0x23ef65cd), - u64init (0xb5c0fbcf, 0xec4d3b2f), u64init (0xe9b5dba5, 0x8189dbbc), - u64init (0x3956c25b, 0xf348b538), u64init (0x59f111f1, 0xb605d019), - u64init (0x923f82a4, 0xaf194f9b), u64init (0xab1c5ed5, 0xda6d8118), - u64init (0xd807aa98, 0xa3030242), u64init (0x12835b01, 0x45706fbe), - u64init (0x243185be, 0x4ee4b28c), u64init (0x550c7dc3, 0xd5ffb4e2), - u64init (0x72be5d74, 0xf27b896f), u64init (0x80deb1fe, 0x3b1696b1), - u64init (0x9bdc06a7, 0x25c71235), u64init (0xc19bf174, 0xcf692694), - u64init (0xe49b69c1, 0x9ef14ad2), u64init (0xefbe4786, 0x384f25e3), - u64init (0x0fc19dc6, 0x8b8cd5b5), u64init (0x240ca1cc, 0x77ac9c65), - u64init (0x2de92c6f, 0x592b0275), u64init (0x4a7484aa, 0x6ea6e483), - u64init (0x5cb0a9dc, 0xbd41fbd4), u64init (0x76f988da, 0x831153b5), - u64init (0x983e5152, 0xee66dfab), u64init (0xa831c66d, 0x2db43210), - u64init (0xb00327c8, 0x98fb213f), u64init (0xbf597fc7, 0xbeef0ee4), - u64init (0xc6e00bf3, 0x3da88fc2), u64init (0xd5a79147, 0x930aa725), - u64init (0x06ca6351, 0xe003826f), u64init (0x14292967, 0x0a0e6e70), - u64init (0x27b70a85, 0x46d22ffc), u64init (0x2e1b2138, 0x5c26c926), - u64init (0x4d2c6dfc, 0x5ac42aed), u64init (0x53380d13, 0x9d95b3df), - u64init (0x650a7354, 0x8baf63de), u64init (0x766a0abb, 0x3c77b2a8), - u64init (0x81c2c92e, 0x47edaee6), u64init (0x92722c85, 0x1482353b), - u64init (0xa2bfe8a1, 0x4cf10364), u64init (0xa81a664b, 0xbc423001), - u64init (0xc24b8b70, 0xd0f89791), u64init (0xc76c51a3, 0x0654be30), - u64init (0xd192e819, 0xd6ef5218), u64init (0xd6990624, 0x5565a910), - u64init (0xf40e3585, 0x5771202a), u64init (0x106aa070, 0x32bbd1b8), - u64init (0x19a4c116, 0xb8d2d0c8), u64init (0x1e376c08, 0x5141ab53), - u64init (0x2748774c, 0xdf8eeb99), u64init (0x34b0bcb5, 0xe19b48a8), - u64init (0x391c0cb3, 0xc5c95a63), u64init (0x4ed8aa4a, 0xe3418acb), - u64init (0x5b9cca4f, 0x7763e373), u64init (0x682e6ff3, 0xd6b2b8a3), - u64init (0x748f82ee, 0x5defb2fc), u64init (0x78a5636f, 0x43172f60), - u64init (0x84c87814, 0xa1f0ab72), u64init (0x8cc70208, 0x1a6439ec), - u64init (0x90befffa, 0x23631e28), u64init (0xa4506ceb, 0xde82bde9), - u64init (0xbef9a3f7, 0xb2c67915), u64init (0xc67178f2, 0xe372532b), - u64init (0xca273ece, 0xea26619c), u64init (0xd186b8c7, 0x21c0c207), - u64init (0xeada7dd6, 0xcde0eb1e), u64init (0xf57d4f7f, 0xee6ed178), - u64init (0x06f067aa, 0x72176fba), u64init (0x0a637dc5, 0xa2c898a6), - u64init (0x113f9804, 0xbef90dae), u64init (0x1b710b35, 0x131c471b), - u64init (0x28db77f5, 0x23047d84), u64init (0x32caab7b, 0x40c72493), - u64init (0x3c9ebe0a, 0x15c9bebc), u64init (0x431d67c4, 0x9c100d4c), - u64init (0x4cc5d4be, 0xcb3e42b6), u64init (0x597f299c, 0xfc657e2a), - u64init (0x5fcb6fab, 0x3ad6faec), u64init (0x6c44198c, 0x4a475817), -}; - -/* Round functions. */ -#define F2(A, B, C) u64or (u64and (A, B), u64and (C, u64or (A, B))) -#define F1(E, F, G) u64xor (G, u64and (E, u64xor (F, G))) - -/* Process LEN bytes of BUFFER, accumulating context into CTX. - It is assumed that LEN % 128 == 0. - Most of this code comes from GnuPG's cipher/sha1.c. */ - -void -sha512_process_block (const void *buffer, size_t len, struct sha512_ctx *ctx) -{ - u64 const *words = (u64 const *)buffer; - u64 const *endp = words + len / sizeof (u64); - u64 x[16]; - u64 a = ctx->state[0]; - u64 b = ctx->state[1]; - u64 c = ctx->state[2]; - u64 d = ctx->state[3]; - u64 e = ctx->state[4]; - u64 f = ctx->state[5]; - u64 g = ctx->state[6]; - u64 h = ctx->state[7]; - - /* First increment the byte count. FIPS PUB 180-2 specifies the possible - length of the file up to 2^128 bits. Here we only compute the - number of bytes. Do a double word increment. */ - ctx->total[0] = u64plus (ctx->total[0], u64lo (len)); - if (u64lt (ctx->total[0], u64lo (len))) - ctx->total[1] = u64plus (ctx->total[1], u64lo (1)); - -#define S0(x) u64xor (u64rol(x, 63), u64xor (u64rol (x, 56), u64shr (x, 7))) -#define S1(x) u64xor (u64rol (x, 45), u64xor (u64rol (x, 3), u64shr (x, 6))) -#define SS0(x) u64xor (u64rol (x, 36), u64xor (u64rol (x, 30), u64rol (x, 25))) -#define SS1(x) u64xor (u64rol(x, 50), u64xor (u64rol (x, 46), u64rol (x, 23))) - -#define M(I) (x[(I) & 15] \ - = u64plus (x[(I) & 15], \ - u64plus (S1 (x[((I) - 2) & 15]), \ - u64plus (x[((I) - 7) & 15], \ - S0 (x[((I) - 15) & 15]))))) - -#define R(A, B, C, D, E, F, G, H, K, M) \ - do \ - { \ - u64 t0 = u64plus (SS0 (A), F2 (A, B, C)); \ - u64 t1 = \ - u64plus (H, u64plus (SS1 (E), \ - u64plus (F1 (E, F, G), u64plus (K, M)))); \ - D = u64plus (D, t1); \ - H = u64plus (t0, t1); \ - } \ - while (0) - - while (words < endp) - { - int t; - /* FIXME: see sha1.c for a better implementation. */ - for (t = 0; t < 16; t++) - { - x[t] = SWAP (*words); - words++; - } - - R( a, b, c, d, e, f, g, h, K( 0), x[ 0] ); - R( h, a, b, c, d, e, f, g, K( 1), x[ 1] ); - R( g, h, a, b, c, d, e, f, K( 2), x[ 2] ); - R( f, g, h, a, b, c, d, e, K( 3), x[ 3] ); - R( e, f, g, h, a, b, c, d, K( 4), x[ 4] ); - R( d, e, f, g, h, a, b, c, K( 5), x[ 5] ); - R( c, d, e, f, g, h, a, b, K( 6), x[ 6] ); - R( b, c, d, e, f, g, h, a, K( 7), x[ 7] ); - R( a, b, c, d, e, f, g, h, K( 8), x[ 8] ); - R( h, a, b, c, d, e, f, g, K( 9), x[ 9] ); - R( g, h, a, b, c, d, e, f, K(10), x[10] ); - R( f, g, h, a, b, c, d, e, K(11), x[11] ); - R( e, f, g, h, a, b, c, d, K(12), x[12] ); - R( d, e, f, g, h, a, b, c, K(13), x[13] ); - R( c, d, e, f, g, h, a, b, K(14), x[14] ); - R( b, c, d, e, f, g, h, a, K(15), x[15] ); - R( a, b, c, d, e, f, g, h, K(16), M(16) ); - R( h, a, b, c, d, e, f, g, K(17), M(17) ); - R( g, h, a, b, c, d, e, f, K(18), M(18) ); - R( f, g, h, a, b, c, d, e, K(19), M(19) ); - R( e, f, g, h, a, b, c, d, K(20), M(20) ); - R( d, e, f, g, h, a, b, c, K(21), M(21) ); - R( c, d, e, f, g, h, a, b, K(22), M(22) ); - R( b, c, d, e, f, g, h, a, K(23), M(23) ); - R( a, b, c, d, e, f, g, h, K(24), M(24) ); - R( h, a, b, c, d, e, f, g, K(25), M(25) ); - R( g, h, a, b, c, d, e, f, K(26), M(26) ); - R( f, g, h, a, b, c, d, e, K(27), M(27) ); - R( e, f, g, h, a, b, c, d, K(28), M(28) ); - R( d, e, f, g, h, a, b, c, K(29), M(29) ); - R( c, d, e, f, g, h, a, b, K(30), M(30) ); - R( b, c, d, e, f, g, h, a, K(31), M(31) ); - R( a, b, c, d, e, f, g, h, K(32), M(32) ); - R( h, a, b, c, d, e, f, g, K(33), M(33) ); - R( g, h, a, b, c, d, e, f, K(34), M(34) ); - R( f, g, h, a, b, c, d, e, K(35), M(35) ); - R( e, f, g, h, a, b, c, d, K(36), M(36) ); - R( d, e, f, g, h, a, b, c, K(37), M(37) ); - R( c, d, e, f, g, h, a, b, K(38), M(38) ); - R( b, c, d, e, f, g, h, a, K(39), M(39) ); - R( a, b, c, d, e, f, g, h, K(40), M(40) ); - R( h, a, b, c, d, e, f, g, K(41), M(41) ); - R( g, h, a, b, c, d, e, f, K(42), M(42) ); - R( f, g, h, a, b, c, d, e, K(43), M(43) ); - R( e, f, g, h, a, b, c, d, K(44), M(44) ); - R( d, e, f, g, h, a, b, c, K(45), M(45) ); - R( c, d, e, f, g, h, a, b, K(46), M(46) ); - R( b, c, d, e, f, g, h, a, K(47), M(47) ); - R( a, b, c, d, e, f, g, h, K(48), M(48) ); - R( h, a, b, c, d, e, f, g, K(49), M(49) ); - R( g, h, a, b, c, d, e, f, K(50), M(50) ); - R( f, g, h, a, b, c, d, e, K(51), M(51) ); - R( e, f, g, h, a, b, c, d, K(52), M(52) ); - R( d, e, f, g, h, a, b, c, K(53), M(53) ); - R( c, d, e, f, g, h, a, b, K(54), M(54) ); - R( b, c, d, e, f, g, h, a, K(55), M(55) ); - R( a, b, c, d, e, f, g, h, K(56), M(56) ); - R( h, a, b, c, d, e, f, g, K(57), M(57) ); - R( g, h, a, b, c, d, e, f, K(58), M(58) ); - R( f, g, h, a, b, c, d, e, K(59), M(59) ); - R( e, f, g, h, a, b, c, d, K(60), M(60) ); - R( d, e, f, g, h, a, b, c, K(61), M(61) ); - R( c, d, e, f, g, h, a, b, K(62), M(62) ); - R( b, c, d, e, f, g, h, a, K(63), M(63) ); - R( a, b, c, d, e, f, g, h, K(64), M(64) ); - R( h, a, b, c, d, e, f, g, K(65), M(65) ); - R( g, h, a, b, c, d, e, f, K(66), M(66) ); - R( f, g, h, a, b, c, d, e, K(67), M(67) ); - R( e, f, g, h, a, b, c, d, K(68), M(68) ); - R( d, e, f, g, h, a, b, c, K(69), M(69) ); - R( c, d, e, f, g, h, a, b, K(70), M(70) ); - R( b, c, d, e, f, g, h, a, K(71), M(71) ); - R( a, b, c, d, e, f, g, h, K(72), M(72) ); - R( h, a, b, c, d, e, f, g, K(73), M(73) ); - R( g, h, a, b, c, d, e, f, K(74), M(74) ); - R( f, g, h, a, b, c, d, e, K(75), M(75) ); - R( e, f, g, h, a, b, c, d, K(76), M(76) ); - R( d, e, f, g, h, a, b, c, K(77), M(77) ); - R( c, d, e, f, g, h, a, b, K(78), M(78) ); - R( b, c, d, e, f, g, h, a, K(79), M(79) ); - - a = ctx->state[0] = u64plus (ctx->state[0], a); - b = ctx->state[1] = u64plus (ctx->state[1], b); - c = ctx->state[2] = u64plus (ctx->state[2], c); - d = ctx->state[3] = u64plus (ctx->state[3], d); - e = ctx->state[4] = u64plus (ctx->state[4], e); - f = ctx->state[5] = u64plus (ctx->state[5], f); - g = ctx->state[6] = u64plus (ctx->state[6], g); - h = ctx->state[7] = u64plus (ctx->state[7], h); - } -} - -#ifdef __cplusplus -} -#endif diff --git a/libs/signature/src/spas_client.c b/libs/signature/src/spas_client.c deleted file mode 100755 index c2885a21f..000000000 --- a/libs/signature/src/spas_client.c +++ /dev/null @@ -1,506 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include - -#include "base64.h" -#include "hmac.h" -#include "sha1.h" -#include "sha256.h" -#include "spas_client.h" - -#ifdef WIN32 -#include -#include -#else -#include -#endif -#ifdef SPAS_MT -#include -#endif - -#ifdef __cplusplus -namespace rocketmqSignature { -#endif - -#define SPAS_VERSION "SPAS_V1_0" - -static SPAS_CREDENTIAL g_credential; -static char g_path[SPAS_MAX_PATH]; -static int g_loaded = 0; -static unsigned int refresh = 10; -static time_t modified = 0; - -#ifdef SPAS_MT - -static pthread_mutex_t cred_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_once_t cred_once = PTHREAD_ONCE_INIT; -static pthread_key_t cred_key; - -#endif - -extern void *_mem_alloc(unsigned int size); -extern void *_mem_realloc(void *ptr, unsigned int old_size, - unsigned int new_size); -extern void _mem_free(void *ptr); -extern void _trim(char *str); - -void *_mem_alloc(unsigned int size) { - void *p = malloc(size); - if (p != NULL) { - memset(p, 0, size); - } - return p; -} - -void *_mem_realloc(void *ptr, unsigned int old_size, unsigned int new_size) { - void *p = realloc(ptr, new_size); - if (p != NULL && new_size > old_size) { - memset((unsigned int *)p + old_size, 0, new_size - old_size); - } - return p; -} - -void _mem_free(void *ptr) { free(ptr); } - -void _trim(char *str) { - int len = strlen(str); - int i; - int done = 0; - for (i = len - 1; i >= 0; i--) { - switch (str[i]) { - case ' ': - case '\t': - case '\r': - case '\n': - str[i] = '\0'; - break; - default: - done = 1; - break; - } - if (done) { - break; - } - } -} - -static int _load_credential(SPAS_CREDENTIAL *pcred, char *path) { - FILE *fp = NULL; - char buf[SPAS_MAX_KEY_LEN * 2]; - if (pcred == NULL || path == NULL) { - return ERROR_INVALID_PARAM; - } - fp = fopen(path, "r"); - if (fp == NULL) { - return ERROR_FILE_OPEN; - } - memset(pcred, 0, sizeof(SPAS_CREDENTIAL)); - while (fgets(buf, sizeof(buf), fp)) { - _trim(buf); - int len = strlen(SPAS_ACCESS_KEY_TAG); - if (strncmp(buf, SPAS_ACCESS_KEY_TAG, len) == 0 && buf[len] == '=') { - strncpy(pcred->access_key, buf + len + 1, SPAS_MAX_KEY_LEN - 1); - } else { - len = strlen(SPAS_SECRET_KEY_TAG); - if (strncmp(buf, SPAS_SECRET_KEY_TAG, len) == 0 && buf[len] == '=') { - strncpy(pcred->secret_key, buf + len + 1, SPAS_MAX_KEY_LEN - 1); - } - } - } - fclose(fp); - if (strlen(pcred->access_key) == 0 || strlen(pcred->secret_key) == 0) { - return ERROR_MISSING_KEY; - } - return SPAS_NO_ERROR; -} - -#ifndef WIN32 -static void _reload_credential(int sig) { - int ret; - SPAS_CREDENTIAL credential; - struct stat status; - struct sigaction act; - - if (sig != SIGALRM) { - return; - } - - memset(&act, 0, sizeof(act)); - act.sa_handler = _reload_credential; - sigaction(SIGALRM, &act, NULL); - alarm(refresh); - if (g_path[0] != '\0') { - ret = stat(g_path, &status); - if (ret != 0) { - return; - } - if (status.st_mtime == modified) { - return; - } - ret = _load_credential(&credential, g_path); - if (ret != SPAS_NO_ERROR) { - return; - } -#ifdef SPAS_MT - pthread_mutex_lock(&cred_mutex); -#endif - memcpy(&g_credential, &credential, sizeof(SPAS_CREDENTIAL)); -#ifdef SPAS_MT - pthread_mutex_unlock(&cred_mutex); -#endif - modified = status.st_mtime; - } -} - -static int _update_credential_by_alarm() { - struct sigaction act; - - memset(&act, 0, sizeof(act)); - act.sa_handler = _reload_credential; - sigaction(SIGALRM, &act, NULL); - alarm(refresh); - return SPAS_NO_ERROR; -} -#endif - -#ifdef SPAS_MT - -static void *_update_credential_entry(void *arg) { - int ret; - SPAS_CREDENTIAL credential; - struct stat status; - struct timeval tv; - while (1) { - tv.tv_sec = refresh; - tv.tv_usec = 0; - select(0, NULL, NULL, NULL, &tv); - if (g_path[0] != '\0') { - ret = stat(g_path, &status); - if (ret != 0) { - continue; - } - if (status.st_mtime == modified) { - continue; - } - ret = _load_credential(&credential, g_path); - if (ret != SPAS_NO_ERROR) { - continue; - } - pthread_mutex_lock(&cred_mutex); - memcpy(&g_credential, &credential, sizeof(SPAS_CREDENTIAL)); - pthread_mutex_unlock(&cred_mutex); - modified = status.st_mtime; - } - } - return NULL; -} - -static int _update_credential_by_thread() { - pthread_t tid; - int ret; - - ret = pthread_create(&tid, NULL, _update_credential_entry, NULL); - if (ret != 0) { - return ERROR_UPDATE_CREDENTIAL; - } - pthread_detach(tid); - return SPAS_NO_ERROR; -} - -int spas_load_credential(char *path, CREDENTIAL_UPDATE_MODE mode) { - int ret = SPAS_NO_ERROR; - SPAS_CREDENTIAL credential; - - if (g_loaded) { - return SPAS_NO_ERROR; - } - if (path == NULL) { - path = getenv(SPAS_CREDENTIAL_ENV); - if (path == NULL) { - return ERROR_NO_CREDENTIAL; - } - } - strncpy(g_path, path, SPAS_MAX_PATH - 1); - ret = _load_credential(&credential, path); - if (ret != SPAS_NO_ERROR) { - return ret; - } -#ifdef SPAS_MT - pthread_mutex_lock(&cred_mutex); -#endif - if (!g_loaded) { - memcpy(&g_credential, &credential, sizeof(SPAS_CREDENTIAL)); - g_loaded = 1; - } -#ifdef SPAS_MT - pthread_mutex_unlock(&cred_mutex); -#endif - switch (mode) { - case UPDATE_BY_ALARM: - ret = _update_credential_by_alarm(); - break; -#ifdef SPAS_MT - case UPDATE_BY_THREAD: - ret = _update_credential_by_thread(); - break; -#endif - case NO_UPDATE: - default: - ret = SPAS_NO_ERROR; - break; - } - return ret; -} - -#endif - -SPAS_CREDENTIAL *spas_get_credential(void) { - SPAS_CREDENTIAL *credential = - (SPAS_CREDENTIAL *)_mem_alloc(sizeof(SPAS_CREDENTIAL)); - if (credential != NULL) { -#ifdef SPAS_MT - pthread_mutex_lock(&cred_mutex); -#endif - memcpy(credential, &g_credential, sizeof(SPAS_CREDENTIAL)); -#ifdef SPAS_MT - pthread_mutex_unlock(&cred_mutex); -#endif - } - return credential; -} - -int spas_set_access_key(char *key) { - int len = 0; - if (key == NULL) { - return ERROR_INVALID_PARAM; - } - len = strlen(key); - if (len == 0 || len >= SPAS_MAX_KEY_LEN) { - return ERROR_KEY_LENGTH; - } -#ifdef SPAS_MT - pthread_mutex_lock(&cred_mutex); -#endif - memcpy(g_credential.access_key, key, len + 1); -#ifdef SPAS_MT - pthread_mutex_unlock(&cred_mutex); -#endif - return SPAS_NO_ERROR; -} - -int spas_set_secret_key(char *key) { - int len = 0; - if (key == NULL) { - return ERROR_INVALID_PARAM; - } - len = strlen(key); - if (len == 0 || len >= SPAS_MAX_KEY_LEN) { - return ERROR_KEY_LENGTH; - } -#ifdef SPAS_MT - pthread_mutex_lock(&cred_mutex); -#endif - memcpy(g_credential.secret_key, key, len + 1); -#ifdef SPAS_MT - pthread_mutex_unlock(&cred_mutex); -#endif - return SPAS_NO_ERROR; -} - -char *spas_get_access_key() { return g_credential.access_key; } - -char *spas_get_secret_key() { return g_credential.secret_key; } - -#ifdef SPAS_MT - -static void _free_thread_credential(void *credential) { - if (credential != NULL) { - _mem_free(credential); - } -} - -static void _init_credential_key(void) { - pthread_key_create(&cred_key, _free_thread_credential); -} - -static SPAS_CREDENTIAL *_get_thread_credential(void) { - int ret = 0; - SPAS_CREDENTIAL *credential = NULL; - ret = pthread_once(&cred_once, _init_credential_key); - if (ret != 0) { - return NULL; - } - credential = pthread_getspecific(cred_key); - if (credential == NULL) { - credential = _mem_alloc(sizeof(SPAS_CREDENTIAL)); - if (credential == NULL) { - return NULL; - } - ret = pthread_setspecific(cred_key, credential); - if (ret != 0) { - _mem_free(credential); - return NULL; - } - } - return credential; -} - -int spas_load_thread_credential(char *path) { - int ret = SPAS_NO_ERROR; - SPAS_CREDENTIAL *credential = NULL; - credential = _get_thread_credential(); - if (credential == NULL) { - return ERROR_MEM_ALLOC; - } - ret = _load_credential(credential, path); - if (ret != SPAS_NO_ERROR) { - memset(credential, 0, sizeof(SPAS_CREDENTIAL)); - return ret; - } - return SPAS_NO_ERROR; -} - -int spas_set_thread_access_key(char *key) { - int len = 0; - SPAS_CREDENTIAL *credential = NULL; - if (key == NULL) { - return ERROR_INVALID_PARAM; - } - len = strlen(key); - if (len == 0 || len >= SPAS_MAX_KEY_LEN) { - return ERROR_KEY_LENGTH; - } - credential = _get_thread_credential(); - if (credential == NULL) { - return ERROR_MEM_ALLOC; - } - memcpy(credential->access_key, key, len + 1); - return SPAS_NO_ERROR; -} - -int spas_set_thread_secret_key(char *key) { - int len = 0; - SPAS_CREDENTIAL *credential = NULL; - if (key == NULL) { - return ERROR_INVALID_PARAM; - } - len = strlen(key); - if (len == 0 || len >= SPAS_MAX_KEY_LEN) { - return ERROR_KEY_LENGTH; - } - credential = _get_thread_credential(); - if (credential == NULL) { - return ERROR_MEM_ALLOC; - } - memcpy(credential->secret_key, key, len + 1); - return SPAS_NO_ERROR; -} - -char *spas_get_thread_access_key(void) { - SPAS_CREDENTIAL *credential = _get_thread_credential(); - if (credential == NULL) { - return NULL; - } - return credential->access_key; -} - -char *spas_get_thread_secret_key(void) { - SPAS_CREDENTIAL *credential = _get_thread_credential(); - if (credential == NULL) { - return NULL; - } - return credential->secret_key; -} - -#endif - -char *spas_get_signature(const SPAS_PARAM_LIST *list, const char *key) { - return spas_get_signature2(list, key, SIGN_HMACSHA1); -} - -char *spas_get_signature2(const SPAS_PARAM_LIST *list, const char *key, - SPAS_SIGN_ALGORITHM algorithm) { - char *sign = NULL; - char *data = NULL; - if (list == NULL || key == NULL) { - return NULL; - } - data = param_list_to_str(list); - if (data == NULL) { - return NULL; - } - sign = spas_sign2(data, strlen(data), key, algorithm); - _mem_free(data); - return sign; -} - -char *spas_sign(const char *data, size_t size, const char *key) { - return spas_sign2(data, size, key, SIGN_HMACSHA1); -} - -char *spas_sign2(const char *data, size_t size, const char *key, - SPAS_SIGN_ALGORITHM algorithm) { - int ret; - int dsize = 0; - char *sha_buf = NULL; - char *base64_ret = NULL; - if (data == NULL || key == NULL) { - return NULL; - } - if (algorithm == SIGN_HMACSHA1) { - dsize = SHA1_DIGEST_SIZE; - sha_buf = (char *)_mem_alloc(dsize + 1); - if (sha_buf == NULL) { - return NULL; - } - ret = hmac_sha1(key, strlen(key), data, size, sha_buf); - if (ret < 0) { - _mem_free(sha_buf); - return NULL; - } - } else if (algorithm == SIGN_HMACSHA256) { - dsize = SHA256_DIGEST_SIZE; - sha_buf = (char *)_mem_alloc(dsize + 1); - if (sha_buf == NULL) { - return NULL; - } - ret = hmac_sha256(key, strlen(key), data, strlen(data), sha_buf); - if (ret < 0) { - _mem_free(sha_buf); - return NULL; - } - } else { - return NULL; - } - ret = base64_encode_alloc(sha_buf, dsize, &base64_ret); - _mem_free(sha_buf); - return base64_ret; -} - -void spas_mem_free(char *pSignature) { _mem_free(pSignature); } - -char *spas_get_version(void) { return SPAS_VERSION; } - -#ifdef __cplusplus -} -#endif diff --git a/package_rocketmq.mri b/package_rocketmq.mri deleted file mode 100644 index f19383ed1..000000000 --- a/package_rocketmq.mri +++ /dev/null @@ -1,25 +0,0 @@ -create librocketmq.a -addlib ../bin/lib/libboost_chrono.a -addlib ../bin/lib/libboost_date_time.a -addlib ../bin/lib/libboost_filesystem.a -addlib ../bin/lib/libboost_iostreams.a -addlib ../bin/lib/libboost_locale.a -addlib ../bin/lib/libboost_log.a -addlib ../bin/lib/libboost_log_setup.a -addlib ../bin/lib/libboost_regex.a -addlib ../bin/lib/libboost_serialization.a -addlib ../bin/lib/libboost_system.a -addlib ../bin/lib/libboost_thread.a -addlib ../bin/lib/libboost_wserialization.a -addlib ../bin/lib/libssl.a -addlib ../bin/lib/libcrypto.a -addlib ../bin/lib/libevent.a -addlib ../bin/lib/libevent_core.a -addlib ../bin/lib/libevent_extra.a -addlib ../bin/lib/libevent_pthreads.a -addlib ../bin/lib/libevent_openssl.a -addlib ../bin/lib/libjsoncpp.a -addlib ../bin/lib/libSignature.a -addlib ../bin/librocketmq.a -save -end diff --git a/project/CMakeLists.txt b/project/CMakeLists.txt deleted file mode 100755 index efd2a815d..000000000 --- a/project/CMakeLists.txt +++ /dev/null @@ -1,79 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. - -# source files -project(rocketmq-client) - -file(GLOB_RECURSE SRC_FILES ${CMAKE_SOURCE_DIR}/src/*) -list(REMOVE_ITEM SRC_FILES ${CMAKE_SOURCE_DIR}/src/dllmain.cpp) - -# subdirs -SET(SUB_DIRS) -file(GLOB children ${CMAKE_SOURCE_DIR}/src/*) -FOREACH (child ${children}) - IF (IS_DIRECTORY ${child}) - LIST(APPEND SUB_DIRS ${child}) - ENDIF () -ENDFOREACH () -LIST(APPEND SUB_DIRS ${CMAKE_SOURCE_DIR}/src) - -include_directories(${CMAKE_SOURCE_DIR}/include) -include_directories(${SUB_DIRS}) - -# libs_directories -file(GLOB LIB_DIRS ${CMAKE_SOURCE_DIR}/libs/*) -foreach (dir ${LIB_DIRS}) - if (IS_DIRECTORY ${dir}) - set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH};${dir}) - include_directories(${dir}/include) - endif () -endforeach () - -# static -if (BUILD_ROCKETMQ_STATIC) - add_library(rocketmq_static STATIC ${SRC_FILES}) - set_target_properties(rocketmq_static PROPERTIES OUTPUT_NAME "rocketmq") - add_dependencies(rocketmq_static Signature) - target_link_libraries(rocketmq_static Signature) - target_link_libraries(rocketmq_static ${JSONCPP_LIBRARIES}) - target_link_libraries(rocketmq_static ${LIBEVENT_LIBRARIES}) - target_link_libraries(rocketmq_static ${Boost_LIBRARIES}) - target_link_libraries(rocketmq_static ${OPENSSL_LIBRARIES}) - target_link_libraries(rocketmq_static ${deplibs}) -endif () - -# shared -if (BUILD_ROCKETMQ_SHARED) - set(CMAKE_SHARED_LINKER_FLAGS "-DBOOST_ALL_DYN_LINK -shared ") - add_library(rocketmq_shared SHARED ${SRC_FILES}) - set_target_properties(rocketmq_shared PROPERTIES OUTPUT_NAME "rocketmq") - add_dependencies(rocketmq_shared Signature) - target_link_libraries(rocketmq_shared Signature) - target_link_libraries(rocketmq_shared ${JSONCPP_LIBRARIES}) - target_link_libraries(rocketmq_shared ${LIBEVENT_LIBRARIES}) - target_link_libraries(rocketmq_shared ${Boost_LIBRARIES}) - target_link_libraries(rocketmq_shared ${OPENSSL_LIBRARIES}) - target_link_libraries(rocketmq_shared ${deplibs}) -endif () - -# install -if (BUILD_ROCKETMQ_STATIC) - install(TARGETS rocketmq_static DESTINATION lib) -endif () -if (BUILD_ROCKETMQ_SHARED) - install(TARGETS rocketmq_shared DESTINATION lib) -endif () -install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/ DESTINATION include/rocketmq) -install(DIRECTORY ${CMAKE_SOURCE_DIR}/doc/ DESTINATION doc) diff --git a/proto/BUILD.bazel b/proto/BUILD.bazel new file mode 100644 index 000000000..80a2b6d53 --- /dev/null +++ b/proto/BUILD.bazel @@ -0,0 +1,79 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_proto//proto:defs.bzl", "proto_library") +load("@rules_cc//cc:defs.bzl", "cc_proto_library") +load("@rules_proto_grpc//cpp:defs.bzl", "cpp_grpc_library", "cpp_grpc_compile") + +proto_library( + name = "apache_rocketmq_definition", + srcs = [ + "apache/rocketmq/v2/definition.proto", + ], + deps = [ + "@com_google_protobuf//:empty_proto", + "@com_google_protobuf//:field_mask_proto", + "@com_google_protobuf//:duration_proto", + "@com_google_protobuf//:timestamp_proto", + "@com_google_googleapis//google/rpc:code_proto", + "@com_google_googleapis//google/rpc:error_details_proto", + "@com_google_googleapis//google/rpc:status_proto", + ], + strip_import_prefix = "/proto", +) + +proto_library( + name = "apache_rocketmq_admin", + srcs = [ + "apache/rocketmq/v2/admin.proto", + ], + deps = [ + ":apache_rocketmq_definition", + "@com_google_protobuf//:field_mask_proto", + "@com_google_protobuf//:empty_proto", + ], + strip_import_prefix = "/proto", +) + +proto_library( + name = "apache_rocketmq_service", + srcs = [ + "apache/rocketmq/v2/service.proto", + ], + deps = [ + ":apache_rocketmq_definition", + "@com_google_protobuf//:any_proto", + "@com_google_protobuf//:duration_proto", + "@com_google_protobuf//:timestamp_proto", + "@com_google_googleapis//google/rpc:code_proto", + "@com_google_googleapis//google/rpc:error_details_proto", + "@com_google_googleapis//google/rpc:status_proto", + ], + strip_import_prefix = "/proto", +) + +cpp_grpc_library( + name = "rocketmq_grpc_library", + protos = [ + ":apache_rocketmq_definition", + ":apache_rocketmq_admin", + ":apache_rocketmq_service", + "@com_google_googleapis//google/rpc:code_proto", + "@com_google_googleapis//google/rpc:error_details_proto", + "@com_google_googleapis//google/rpc:status_proto", + ], + visibility = ["//visibility:public"] +) \ No newline at end of file diff --git a/proto/apache/rocketmq/v2/admin.proto b/proto/apache/rocketmq/v2/admin.proto new file mode 100644 index 000000000..7dbb7027d --- /dev/null +++ b/proto/apache/rocketmq/v2/admin.proto @@ -0,0 +1,43 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You 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. + +syntax = "proto3"; + +package apache.rocketmq.v2; + +option cc_enable_arenas = true; +option csharp_namespace = "Apache.Rocketmq.V2"; +option java_multiple_files = true; +option java_package = "apache.rocketmq.v2"; +option java_generate_equals_and_hash = true; +option java_string_check_utf8 = true; +option java_outer_classname = "MQAdmin"; + +message ChangeLogLevelRequest { + enum Level { + TRACE = 0; + DEBUG = 1; + INFO = 2; + WARN = 3; + ERROR = 4; + } + Level level = 1; +} + +message ChangeLogLevelResponse { string remark = 1; } + +service Admin { + rpc ChangeLogLevel(ChangeLogLevelRequest) returns (ChangeLogLevelResponse) {} +} \ No newline at end of file diff --git a/proto/apache/rocketmq/v2/definition.proto b/proto/apache/rocketmq/v2/definition.proto new file mode 100644 index 000000000..58bf06d29 --- /dev/null +++ b/proto/apache/rocketmq/v2/definition.proto @@ -0,0 +1,444 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You 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. + +syntax = "proto3"; + +import "google/protobuf/timestamp.proto"; +import "google/protobuf/duration.proto"; + +package apache.rocketmq.v2; + +option csharp_namespace = "Apache.Rocketmq.V2"; +option java_multiple_files = true; +option java_package = "apache.rocketmq.v2"; +option java_generate_equals_and_hash = true; +option java_string_check_utf8 = true; +option java_outer_classname = "MQDomain"; + +enum TransactionResolution { + TRANSACTION_RESOLUTION_UNSPECIFIED = 0; + COMMIT = 1; + ROLLBACK = 2; +} + +enum TransactionSource { + SOURCE_UNSPECIFIED = 0; + SOURCE_CLIENT = 1; + SOURCE_SERVER_CHECK = 2; +} + +enum Permission { + PERMISSION_UNSPECIFIED = 0; + NONE = 1; + READ = 2; + WRITE = 3; + READ_WRITE = 4; +} + +enum FilterType { + FILTER_TYPE_UNSPECIFIED = 0; + TAG = 1; + SQL = 2; +} + +message FilterExpression { + FilterType type = 1; + string expression = 2; +} + +message RetryPolicy { + int32 max_attempts = 1; + oneof strategy { + ExponentialBackoff exponential_backoff = 2; + CustomizedBackoff customized_backoff = 3; + } +} + +// https://en.wikipedia.org/wiki/Exponential_backoff +message ExponentialBackoff { + google.protobuf.Duration initial = 1; + google.protobuf.Duration max = 2; + float multiplier = 3; +} + +message CustomizedBackoff { + // To support classic backoff strategy which is arbitary defined by end users. + // Typical values are: `1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h` + repeated google.protobuf.Duration next = 1; +} + +message Resource { + string resource_namespace = 1; + + // Resource name identifier, which remains unique within the abstract resource + // namespace. + string name = 2; +} + +message SubscriptionEntry { + Resource topic = 1; + FilterExpression expression = 2; +} + +enum AddressScheme { + ADDRESS_SCHEME_UNSPECIFIED = 0; + IPv4 = 1; + IPv6 = 2; + DOMAIN_NAME = 3; +} + +message Address { + string host = 1; + int32 port = 2; +} + +message Endpoints { + AddressScheme scheme = 1; + repeated Address addresses = 2; +} + +message Broker { + // Name of the broker + string name = 1; + + // Broker index. Canonically, index = 0 implies that the broker is playing + // leader role while brokers with index > 0 play follower role. + int32 id = 2; + + // Address of the broker, complying with the following scheme + // 1. dns:[//authority/]host[:port] + // 2. ipv4:address[:port][,address[:port],...] – IPv4 addresses + // 3. ipv6:address[:port][,address[:port],...] – IPv6 addresses + Endpoints endpoints = 3; +} + +message MessageQueue { + Resource topic = 1; + int32 id = 2; + Permission permission = 3; + Broker broker = 4; + repeated MessageType accept_message_types = 5; +} + +enum MessageType { + MESSAGE_TYPE_UNSPECIFIED = 0; + + NORMAL = 1; + + // Sequenced message + FIFO = 2; + + // Messages that are delivered after the specified duration. + DELAY = 3; + + // Messages that are transactional. Only committed messages are delivered to + // subscribers. + TRANSACTION = 4; +} + +enum DigestType { + DIGEST_TYPE_UNSPECIFIED = 0; + + // CRC algorithm achieves goal of detecting random data error with lowest + // computation overhead. + CRC32 = 1; + + // MD5 algorithm achieves good balance between collision rate and computation + // overhead. + MD5 = 2; + + // SHA-family has substantially fewer collision with fair amount of + // computation. + SHA1 = 3; +} + +// When publishing messages to or subscribing messages from brokers, clients +// shall include or validate digests of message body to ensure data integrity. +// +// For message publishing, when an invalid digest were detected, brokers need +// respond client with BAD_REQUEST. +// +// For messages subscription, when an invalid digest were detected, consumers +// need to handle this case according to message type: +// 1) Standard messages should be negatively acknowledged instantly, causing +// immediate re-delivery; 2) FIFO messages require special RPC, to re-fetch +// previously acquired messages batch; +// +// Message consumption model also affects how invalid digest are handled. When +// messages are consumed in broadcasting way, +// TODO: define semantics of invalid-digest-when-broadcasting. +message Digest { + DigestType type = 1; + string checksum = 2; +} + +enum ClientType { + CLIENT_TYPE_UNSPECIFIED = 0; + PRODUCER = 1; + PUSH_CONSUMER = 2; + SIMPLE_CONSUMER = 3; +} + +enum Encoding { + ENCODING_UNSPECIFIED = 0; + + IDENTITY = 1; + + GZIP = 2; +} + +message SystemProperties { + // Tag, which is optional. + optional string tag = 1; + + // Message keys + repeated string keys = 2; + + // Message identifier, client-side generated, remains unique. + // if message_id is empty, the send message request will be aborted with + // status `INVALID_ARGUMENT` + string message_id = 3; + + // Message body digest + Digest body_digest = 4; + + // Message body encoding. Candidate options are identity, gzip, snappy etc. + Encoding body_encoding = 5; + + // Message type, normal, FIFO or transactional. + MessageType message_type = 6; + + // Message born time-point. + google.protobuf.Timestamp born_timestamp = 7; + + // Message born host. Valid options are IPv4, IPv6 or client host domain name. + string born_host = 8; + + // Time-point at which the message is stored in the broker, which is absent + // for message publishing. + optional google.protobuf.Timestamp store_timestamp = 9; + + // The broker that stores this message. It may be broker name, IP or arbitrary + // identifier that uniquely identify the server. + string store_host = 10; + + // Time-point at which broker delivers to clients, which is optional. + optional google.protobuf.Timestamp delivery_timestamp = 11; + + // If a message is acquired by way of POP, this field holds the receipt, + // which is absent for message publishing. + // Clients use the receipt to acknowledge or negatively acknowledge the + // message. + optional string receipt_handle = 12; + + // Message queue identifier in which a message is physically stored. + int32 queue_id = 13; + + // Message-queue offset at which a message is stored, which is absent for + // message publishing. + optional int64 queue_offset = 14; + + // Period of time servers would remain invisible once a message is acquired. + optional google.protobuf.Duration invisible_duration = 15; + + // Business code may failed to process messages for the moment. Hence, clients + // may request servers to deliver them again using certain back-off strategy, + // the attempt is 1 not 0 if message is delivered first time, and it is absent + // for message publishing. + optional int32 delivery_attempt = 16; + + // Define the group name of message in the same topic, which is optional. + optional string message_group = 17; + + // Trace context for each message, which is optional. + optional string trace_context = 18; + + // If a transactional message stay unresolved for more than + // `transaction_orphan_threshold`, it would be regarded as an + // orphan. Servers that manages orphan messages would pick up + // a capable publisher to resolve + optional google.protobuf.Duration orphaned_transaction_recovery_duration = 19; +} + +message Message { + Resource topic = 1; + + // User defined key-value pairs. + // If user_properties contain the reserved keys by RocketMQ, + // the send message request will be aborted with status `INVALID_ARGUMENT`. + // See below links for the reserved keys + // https://github.com/apache/rocketmq/blob/master/common/src/main/java/org/apache/rocketmq/common/message/MessageConst.java#L58 + map user_properties = 2; + + SystemProperties system_properties = 3; + + bytes body = 4; +} + +message Assignment { + MessageQueue message_queue = 1; +} + +enum Code { + // Success. + OK = 0; + // Format of access point is illegal. + ILLEGAL_ACCESS_POINT = 1; + // Format of topic is illegal. + ILLEGAL_TOPIC = 2; + // Format of consumer group is illegal. + ILLEGAL_CONSUMER_GROUP = 3; + // Format of message tag is illegal. + ILLEGAL_MESSAGE_TAG = 4; + // Format of message key is illegal. + ILLEGAL_MESSAGE_KEY = 5; + // Size of message keys exceeds the threshold. + MESSAGE_KEYS_TOO_LARGE = 6; + // Format of message group is illegal. + ILLEGAL_MESSAGE_GROUP = 7; + // Format of message property key is illegal. + ILLEGAL_MESSAGE_PROPERTY_KEY = 8; + // Message properties total size exceeds the threshold. + MESSAGE_PROPERTIES_TOO_LARGE = 9; + // Message body size exceeds the threshold. + MESSAGE_BODY_TOO_LARGE = 10; + + // User does not have the permission to operate. + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403 + FORBIDDEN = 403; + + // Code indicates that the client request has not been completed + // because it lacks valid authentication credentials for the + // requested resource. + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401 + UNAUTHORIZED = 401; + + // Topic resource does not exist. + TOPIC_NOT_FOUND = 13; + + // Consumer group resource does not exist. + CONSUMER_GROUP_NOT_FOUND = 14; + + // Not allowed to verify message. Chances are that you are verifying + // a FIFO message, as is violating FIFO semantics. + VERIFY_MESSAGE_FORBIDDEN = 15; + + // Failed to consume message. + FAILED_TO_CONSUME_MESSAGE = 16; + + // Message is corrupted. + MESSAGE_CORRUPTED = 17; + + // Too many requests are made in short period of duration. + // Requests are throttled. + TOO_MANY_REQUESTS = 18; + + // Expired receipt-handle is used when trying to acknowledge or change + // invisible duration of a message + RECEIPT_HANDLE_EXPIRED = 19; + + // Message property is not match the message type. + MESSAGE_PROPERTY_DOES_NOT_MATCH_MESSAGE_TYPE = 20; + + // Format of message id is illegal. + ILLEGAL_MESSAGE_ID = 21; + + // Transaction id is invalid. + INVALID_TRANSACTION_ID = 22; + + // Format of filter expression is illegal. + ILLEGAL_FILTER_EXPRESSION = 23; + + // Receipt handle of message is invalid. + INVALID_RECEIPT_HANDLE = 24; + + // Message persistence timeout. + MASTER_PERSISTENCE_TIMEOUT = 25; + + // Slave persistence timeout. + SLAVE_PERSISTENCE_TIMEOUT = 26; + + // The HA-mechanism is not working now. + HA_NOT_AVAILABLE = 27; + + // Operation is not allowed in current version. + VERSION_UNSUPPORTED = 28; + + // Message not found from server. + MESSAGE_NOT_FOUND = 29; + + // Message offset is illegal. + ILLEGAL_MESSAGE_OFFSET = 30; + + // Illegal message is for the sake of backward compatibility. In most case, + // more definitive code is better, e.g. `ILLEGAL_MESSAGE_TAG`. + ILLEGAL_MESSAGE = 31; + + // Client type could not be recognized. + UNRECOGNIZED_CLIENT_TYPE = 32; + + // Return different results for entries in composite request. + MULTIPLE_RESULTS = 33; + + // Code indicates that the server encountered an unexpected condition + // that prevented it from fulfilling the request. + // This error response is a generic "catch-all" response. + // Usually, this indicates the server cannot find a better alternative + // error code to response. Sometimes, server administrators log error + // responses like the 500 status code with more details about the request + // to prevent the error from happening again in the future. + // + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500 + INTERNAL_SERVER_ERROR = 500; + + // Code means that the server or client does not support the functionality + // required to fulfill the request. + NOT_IMPLEMENTED = 501; + + // Code indicates that the server, while acting as a gateway or proxy, + // did not get a response in time from the upstream server that + // it needed in order to complete the request. + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/504 + GATEWAY_TIMEOUT = 504; +} + +message Status { + Code code = 1; + string message = 2; +} + +enum Language { + LANGUAGE_UNSPECIFIED = 0; + JAVA = 1; + CPP = 2; + DOT_NET = 3; + GOLANG = 4; + RUST = 5; +} + +// User Agent +message UA { + // SDK language + Language language = 1; + + // SDK version + string version = 2; + + // Platform details, including OS name, version, arch etc. + string platform = 3; + + // Hostname of the node + string hostname = 4; +} \ No newline at end of file diff --git a/proto/apache/rocketmq/v2/service.proto b/proto/apache/rocketmq/v2/service.proto new file mode 100644 index 000000000..fa2a2f054 --- /dev/null +++ b/proto/apache/rocketmq/v2/service.proto @@ -0,0 +1,457 @@ +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You 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. + +syntax = "proto3"; + +import "google/protobuf/duration.proto"; + +import "apache/rocketmq/v2/definition.proto"; + +package apache.rocketmq.v2; + +option csharp_namespace = "Apache.Rocketmq.V2"; +option java_multiple_files = true; +option java_package = "apache.rocketmq.v2"; +option java_generate_equals_and_hash = true; +option java_string_check_utf8 = true; +option java_outer_classname = "MQService"; + +// Topics are destination of messages to publish to or subscribe from. Similar +// to domain names, they will be addressable after resolution through the +// provided access point. +// +// Access points are usually the addresses of name servers, which fulfill +// service discovery, load-balancing and other auxiliary services. Name servers +// receive periodic heartbeats from affiliate brokers and erase those which +// failed to maintain alive status. +// +// Name servers answer queries of QueryRouteRequest, responding clients with +// addressable message-queues, which they may directly publish messages to or +// subscribe messages from. +// +// QueryRouteRequest shall include source endpoints, aka, configured +// access-point, which annotates tenant-id, instance-id or other +// vendor-specific settings. Purpose-built name servers may respond customized +// results based on these particular requirements. +message QueryRouteRequest { + Resource topic = 1; + Endpoints endpoints = 2; +} + +message QueryRouteResponse { + Status status = 1; + + repeated MessageQueue message_queues = 2; +} + +message SendMessageRequest { + repeated Message messages = 1; +} + +message SendResultEntry { + Status status = 1; + string message_id = 2; + string transaction_id = 3; + int64 offset = 4; +} + +message SendMessageResponse { + Status status = 1; + + // Some implementation may have partial failure issues. Client SDK developers are expected to inspect + // each entry for best certainty. + repeated SendResultEntry entries = 2; +} + +message QueryAssignmentRequest { + Resource topic = 1; + Resource group = 2; + Endpoints endpoints = 3; +} + +message QueryAssignmentResponse { + Status status = 1; + repeated Assignment assignments = 2; +} + +message ReceiveMessageRequest { + Resource group = 1; + MessageQueue message_queue = 2; + FilterExpression filter_expression = 3; + int32 batch_size = 4; + // Required if client type is simple consumer. + optional google.protobuf.Duration invisible_duration = 5; + // For message auto renew and clean + bool auto_renew = 6; +} + +message ReceiveMessageResponse { + oneof content { + Status status = 1; + Message message = 2; + } +} + +message AckMessageEntry { + string message_id = 1; + string receipt_handle = 2; +} + +message AckMessageRequest { + Resource group = 1; + Resource topic = 2; + repeated AckMessageEntry entries = 3; +} + +message AckMessageResultEntry { + string message_id = 1; + string receipt_handle = 2; + + // Acknowledge result may be acquired through inspecting + // `status.code`; In case acknowledgement failed, `status.message` + // is the explanation of the failure. + Status status = 3; +} + +message AckMessageResponse { + // RPC tier status, which is used to represent RPC-level errors including + // authentication, authorization, throttling and other general failures. + Status status = 1; + + repeated AckMessageResultEntry entries = 2; +} + +message ForwardMessageToDeadLetterQueueRequest { + Resource group = 1; + Resource topic = 2; + string receipt_handle = 3; + string message_id = 4; + int32 delivery_attempt = 5; + int32 max_delivery_attempts = 6; +} + +message ForwardMessageToDeadLetterQueueResponse { + Status status = 1; +} + +message HeartbeatRequest { + optional Resource group = 1; + ClientType client_type = 2; +} + +message HeartbeatResponse { + Status status = 1; +} + +message EndTransactionRequest { + Resource topic = 1; + string message_id = 2; + string transaction_id = 3; + TransactionResolution resolution = 4; + TransactionSource source = 5; + string trace_context = 6; +} + +message EndTransactionResponse { + Status status = 1; +} + +message PrintThreadStackTraceCommand { + string nonce = 1; +} + +message ThreadStackTrace { + string nonce = 1; + optional string thread_stack_trace = 2; +} + +message VerifyMessageCommand { + string nonce = 1; + MessageQueue message_queue = 2; + Message message = 3; +} + +message VerifyMessageResult { + string nonce = 1; +} + +message RecoverOrphanedTransactionCommand { + MessageQueue message_queue = 1; + Message orphaned_transactional_message = 2; + string transaction_id = 3; +} + +message Publishing { + // Publishing settings below here is appointed by client, thus it is + // unnecessary for server to push at present. + // + // List of topics to which messages will publish to. + repeated Resource topics = 1; + + // Publishing settings below here are from server, it is essential for + // server to push. + // + // Body of message will be deflated if its size in bytes exceeds the + // threshold. + int32 compress_body_threshold = 2; + + // If the message body size exceeds `max_body_size`, broker servers would + // reject the request. As a result, it is advisable that Producer performs + // client-side check validation. + int32 max_body_size = 3; +} + +message Subscription { + // Subscription settings below here is appointed by client, thus it is + // unnecessary for server to push at present. + // + // Consumer group. + optional Resource group = 1; + + // Subscription for consumer. + repeated SubscriptionEntry subscriptions = 2; + + // Subscription settings below here are from server, it is essential for + // server to push. + // + // When FIFO flag is `true`, messages of the same message group are processed + // in first-in-first-out manner. + // + // Brokers will not deliver further messages of the same group utill prior + // ones are completely acknowledged. + optional bool fifo = 3; + + // Message receive batch size here is essential for push consumer. + optional int32 receive_batch_size = 4; + + // Long-polling timeout for `ReceiveMessageRequest`, which is essential for + // push consumer. + optional google.protobuf.Duration long_polling_timeout = 5; +} + +message Metric { + // Indicates that if client should export local metrics to server. + bool on = 1; + + // The endpoint that client metrics should be exported to, which is required if the switch is on. + optional Endpoints endpoints = 2; +} + +message Settings { + // Configurations for all clients. + optional ClientType client_type = 1; + + optional Endpoints access_point = 2; + + // If publishing of messages encounters throttling or server internal errors, + // publishers should implement automatic retries after progressive longer + // back-offs for consecutive errors. + // + // When processing message fails, `backoff_policy` describes an interval + // after which the message should be available to consume again. + // + // For FIFO messages, the interval should be relatively small because + // messages of the same message group would not be readily available utill + // the prior one depletes its lifecycle. + optional RetryPolicy backoff_policy = 3; + + // Request timeout for RPCs excluding long-polling. + optional google.protobuf.Duration request_timeout = 4; + + oneof pub_sub { + Publishing publishing = 5; + + Subscription subscription = 6; + } + + // User agent details + UA user_agent = 7; + + Metric metric = 8; +} + +message TelemetryCommand { + optional Status status = 1; + + oneof command { + // Client settings + Settings settings = 2; + + // These messages are from client. + // + // Report thread stack trace to server. + ThreadStackTrace thread_stack_trace = 3; + + // Report message verify result to server. + VerifyMessageResult verify_message_result = 4; + + // There messages are from server. + // + // Request client to recover the orphaned transaction message. + RecoverOrphanedTransactionCommand recover_orphaned_transaction_command = 5; + + // Request client to print thread stack trace. + PrintThreadStackTraceCommand print_thread_stack_trace_command = 6; + + // Request client to verify the consumption of the appointed message. + VerifyMessageCommand verify_message_command = 7; + } +} + +message NotifyClientTerminationRequest { + // Consumer group, which is absent for producer. + optional Resource group = 1; +} + +message NotifyClientTerminationResponse { + Status status = 1; +} + +message ChangeInvisibleDurationRequest { + Resource group = 1; + Resource topic = 2; + + // Unique receipt handle to identify message to change + string receipt_handle = 3; + + // New invisible duration + google.protobuf.Duration invisible_duration = 4; + + // For message tracing + string message_id = 5; +} + +message ChangeInvisibleDurationResponse { + Status status = 1; + + // Server may generate a new receipt handle for the message. + string receipt_handle = 2; +} + +// For all the RPCs in MessagingService, the following error handling policies +// apply: +// +// If the request doesn't bear a valid authentication credential, return a +// response with common.status.code == `UNAUTHENTICATED`. If the authenticated +// user is not granted with sufficient permission to execute the requested +// operation, return a response with common.status.code == `PERMISSION_DENIED`. +// If the per-user-resource-based quota is exhausted, return a response with +// common.status.code == `RESOURCE_EXHAUSTED`. If any unexpected server-side +// errors raise, return a response with common.status.code == `INTERNAL`. +service MessagingService { + // Queries the route entries of the requested topic in the perspective of the + // given endpoints. On success, servers should return a collection of + // addressable message-queues. Note servers may return customized route + // entries based on endpoints provided. + // + // If the requested topic doesn't exist, returns `NOT_FOUND`. + // If the specific endpoints is empty, returns `INVALID_ARGUMENT`. + rpc QueryRoute(QueryRouteRequest) returns (QueryRouteResponse) { + } + + // Producer or consumer sends HeartbeatRequest to servers periodically to + // keep-alive. Additionally, it also reports client-side configuration, + // including topic subscription, load-balancing group name, etc. + // + // Returns `OK` if success. + // + // If a client specifies a language that is not yet supported by servers, + // returns `INVALID_ARGUMENT` + rpc Heartbeat(HeartbeatRequest) returns (HeartbeatResponse) { + } + + // Delivers messages to brokers. + // Clients may further: + // 1. Refine a message destination to message-queues which fulfills parts of + // FIFO semantic; + // 2. Flag a message as transactional, which keeps it invisible to consumers + // until it commits; + // 3. Time a message, making it invisible to consumers till specified + // time-point; + // 4. And more... + // + // Returns message-id or transaction-id with status `OK` on success. + // + // If the destination topic doesn't exist, returns `NOT_FOUND`. + rpc SendMessage(SendMessageRequest) returns (SendMessageResponse) { + } + + // Queries the assigned route info of a topic for current consumer, + // the returned assignment result is decided by server-side load balancer. + // + // If the corresponding topic doesn't exist, returns `NOT_FOUND`. + // If the specific endpoints is empty, returns `INVALID_ARGUMENT`. + rpc QueryAssignment(QueryAssignmentRequest) returns (QueryAssignmentResponse) { + } + + // Receives messages from the server in batch manner, returns a set of + // messages if success. The received messages should be acked or redelivered + // after processed. + // + // If the pending concurrent receive requests exceed the quota of the given + // consumer group, returns `UNAVAILABLE`. If the upstream store server hangs, + // return `DEADLINE_EXCEEDED` in a timely manner. If the corresponding topic + // or consumer group doesn't exist, returns `NOT_FOUND`. If there is no new + // message in the specific topic, returns `OK` with an empty message set. + // Please note that client may suffer from false empty responses. + // + // If failed to receive message from remote, server must return only one + // `ReceiveMessageResponse` as the reply to the request, whose `Status` indicates + // the specific reason of failure, otherwise, the reply is considered successful. + rpc ReceiveMessage(ReceiveMessageRequest) returns (stream ReceiveMessageResponse) { + } + + // Acknowledges the message associated with the `receipt_handle` or `offset` + // in the `AckMessageRequest`, it means the message has been successfully + // processed. Returns `OK` if the message server remove the relevant message + // successfully. + // + // If the given receipt_handle is illegal or out of date, returns + // `INVALID_ARGUMENT`. + rpc AckMessage(AckMessageRequest) returns (AckMessageResponse) { + } + + // Forwards one message to dead letter queue if the max delivery attempts is + // exceeded by this message at client-side, return `OK` if success. + rpc ForwardMessageToDeadLetterQueue(ForwardMessageToDeadLetterQueueRequest) + returns (ForwardMessageToDeadLetterQueueResponse) { + } + + // Commits or rollback one transactional message. + rpc EndTransaction(EndTransactionRequest) returns (EndTransactionResponse) { + } + + // Once a client starts, it would immediately establishes bi-lateral stream + // RPCs with brokers, reporting its settings as the initiative command. + // + // When servers have need of inspecting client status, they would issue + // telemetry commands to clients. After executing received instructions, + // clients shall report command execution results through client-side streams. + rpc Telemetry(stream TelemetryCommand) returns (stream TelemetryCommand) { + } + + // Notify the server that the client is terminated. + rpc NotifyClientTermination(NotifyClientTerminationRequest) returns (NotifyClientTerminationResponse) { + } + + // Once a message is retrieved from consume queue on behalf of the group, it + // will be kept invisible to other clients of the same group for a period of + // time. The message is supposed to be processed within the invisible + // duration. If the client, which is in charge of the invisible message, is + // not capable of processing the message timely, it may use + // ChangeInvisibleDuration to lengthen invisible duration. + rpc ChangeInvisibleDuration(ChangeInvisibleDurationRequest) returns (ChangeInvisibleDurationResponse) { + } +} \ No newline at end of file diff --git a/rpm/build.sh b/rpm/build.sh deleted file mode 100644 index 3fb586983..000000000 --- a/rpm/build.sh +++ /dev/null @@ -1,33 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. -BASEDIR=$(dirname "$0") -if [[ ! -d ${BASEDIR}/rocketmq_x64/CENTOS/ ]]; then - echo "Can not find SPEC FILE" - exit 1 -fi -if [[ ! -d /root/rpmbuild/SOURCES/rocketmq/include ]]; then - mkdir -p /root/rpmbuild/SOURCES/rocketmq - mkdir -p /root/rpmbuild/SOURCES/rocketmq/include - mkdir -p /root/rpmbuild/SOURCES/rocketmq/bin - mkdir -p /root/rpmbuild/SPECS/ -fi -cp -R ${BASEDIR}/../include/* /root/rpmbuild/SOURCES/rocketmq/include -cp ${BASEDIR}/../bin/librocketmq.so /root/rpmbuild/SOURCES/rocketmq/bin -cp ${BASEDIR}/../bin/librocketmq.a /root/rpmbuild/SOURCES/rocketmq/bin - -cp ${BASEDIR}/rocketmq_x64/CENTOS/rocketmq-client-cpp.spec /root/rpmbuild/SPECS/ -rpmbuild -bb /root/rpmbuild/SPECS/rocketmq-client-cpp.spec - -cp /root/rpmbuild/RPMS/x86_64/*.rpm ${BASEDIR}/rocketmq_x64 diff --git a/rpm/rocketmq_x64/CENTOS/rocketmq-client-cpp.spec b/rpm/rocketmq_x64/CENTOS/rocketmq-client-cpp.spec deleted file mode 100644 index e24f2d47e..000000000 --- a/rpm/rocketmq_x64/CENTOS/rocketmq-client-cpp.spec +++ /dev/null @@ -1,73 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. - -Summary: A C++ Client of Apache RocketMQ - -Name: rocketmq-client-cpp -Version: 2.2.0 -Release: centos -Group: Apache -License: APLv2 -Source: https://github.com/apache/rocketmq-client-cpp -URL: http://rocketmq.apache.org/ -Distribution: Linux - -%define _prefix /usr/local - -AutoReqProv: no - -%description -A C++ Client of Apache RocketMQ - -%prep - -pwd - -cat /etc/redhat-release|sed -r 's/.* ([0-9]+)\..*/\1/' - -OS_VERSION=`cat /etc/redhat-release|sed -r 's/.* ([0-9]+)\..*/\1/'` - -echo "OS_VERSION=${OS_VERSION}" - - -%build - -%install -# create dirs -mkdir -p $RPM_BUILD_ROOT%{_prefix} - -# create dirs -mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib -mkdir -p $RPM_BUILD_ROOT%{_prefix}/include/rocketmq - -# copy files -cp -f ${RPM_SOURCE_DIR}/rocketmq/bin/librocketmq.so $RPM_BUILD_ROOT%{_prefix}/lib -cp -f ${RPM_SOURCE_DIR}/rocketmq/bin/librocketmq.a $RPM_BUILD_ROOT%{_prefix}/lib -cp -rf ${RPM_SOURCE_DIR}/rocketmq/include/* $RPM_BUILD_ROOT%{_prefix}/include/rocketmq - -%post -# As '/usr/local/lib' is not included in dynamic libraries on CentOS, it should be made explicit to dlopen() -echo "/usr/local/lib" > /etc/ld.so.conf.d/librocketmq.x86_64.conf -/sbin/ldconfig - -# package information -%files -# set file attribute here -%defattr(-, root, root, 0755) -%{_prefix}/lib -%{_prefix}/include - -%define debug_package %{nil} -%define __os_install_post %{nil} diff --git a/src/MQClientAPIImpl.cpp b/src/MQClientAPIImpl.cpp deleted file mode 100644 index 420a623fe..000000000 --- a/src/MQClientAPIImpl.cpp +++ /dev/null @@ -1,947 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "MQClientAPIImpl.h" -#include -#include -#include -#include -#include "CommunicationMode.h" -#include "Logging.h" -#include "MQDecoder.h" -#include "PullResultExt.h" - -namespace rocketmq { -//registerProcessor(CHECK_TRANSACTION_STATE, clientRemotingProcessor); - m_pRemotingClient->registerProcessor(RESET_CONSUMER_CLIENT_OFFSET, clientRemotingProcessor); - m_pRemotingClient->registerProcessor(GET_CONSUMER_STATUS_FROM_CLIENT, clientRemotingProcessor); - m_pRemotingClient->registerProcessor(GET_CONSUMER_RUNNING_INFO, clientRemotingProcessor); - m_pRemotingClient->registerProcessor(NOTIFY_CONSUMER_IDS_CHANGED, clientRemotingProcessor); - m_pRemotingClient->registerProcessor(CONSUME_MESSAGE_DIRECTLY, clientRemotingProcessor); - - m_topAddressing.reset(new TopAddressing(unitName)); -} - -MQClientAPIImpl::~MQClientAPIImpl() { - m_pRemotingClient = NULL; - m_topAddressing = NULL; -} - -void MQClientAPIImpl::stopAllTcpTransportThread() { - m_pRemotingClient->stopAllTcpTransportThread(); -} - -bool MQClientAPIImpl::writeDataToFile(string filename, string data, bool isSync) { - if (data.size() == 0) - return false; - - FILE* pFd = fopen(filename.c_str(), "w+"); - if (NULL == pFd) { - LOG_ERROR("fopen failed, filename:%s", filename.c_str()); - return false; - } - - int byte_write = 0; - int byte_left = data.size(); - const char* pData = data.c_str(); - while (byte_left > 0) { - byte_write = fwrite(pData, sizeof(char), byte_left, pFd); - if (byte_write == byte_left) { - if (ferror(pFd)) { - LOG_ERROR("write data fail, data len:" SIZET_FMT ", file:%s, msg:%s", data.size(), filename.c_str(), - strerror(errno)); - fclose(pFd); - return false; - } - } - byte_left -= byte_write; - pData += byte_write; - } - pData = NULL; - - if (isSync) { - LOG_INFO("fsync with filename:%s", filename.c_str()); - fflush(pFd); - } - fclose(pFd); - - return true; -} - -string MQClientAPIImpl::fetchNameServerAddr(const string& NSDomain) { - try { - string homeDir(UtilAll::getHomeDirectory()); - string storePath = homeDir + "/logs/rocketmq-cpp/snapshot"; - - boost::filesystem::path dir(storePath); - boost::system::error_code ec; - if (!boost::filesystem::exists(dir, ec)) { - if (!boost::filesystem::create_directory(dir, ec)) { - LOG_ERROR("create data dir:%s error", storePath.c_str()); - return ""; - } - } - string file(storePath); - string fileBak(storePath); - vector ret_; - int retSize = UtilAll::Split(ret_, m_mqClientId, "@"); - if (retSize == 2) { - file.append("/nameserver_addr-").append(ret_[retSize - 1]); - } else { - LOG_ERROR("split mqClientId:%s fail", m_mqClientId.c_str()); - file.append("/nameserver_addr-DEFAULT"); - } - boost::filesystem::path snapshot_file(file); - fileBak.append("/nameserver_addr.bak"); - const string addrs = m_topAddressing->fetchNSAddr(NSDomain); - if (addrs.empty()) { - if (m_nameSrvAddr.empty()) { - LOG_INFO("Load the name server snapshot local file:%s", file.c_str()); - if (boost::filesystem::exists(snapshot_file)) { - ifstream snapshot_file(file, ios::binary); - istreambuf_iterator beg(snapshot_file), end; - string filecontent(beg, end); - updateNameServerAddr(filecontent); - m_nameSrvAddr = filecontent; - } else { - LOG_WARN("The name server snapshot local file not exists"); - } - } - } else { - if (m_firstFetchNameSrv == true) { - // it is the first time, so need to create the name server snapshot - // local file - m_firstFetchNameSrv = false; - } - if (addrs.compare(m_nameSrvAddr) != 0) { - LOG_INFO("name server address changed, old: %s, new: %s", m_nameSrvAddr.c_str(), addrs.c_str()); - updateNameServerAddr(addrs); - m_nameSrvAddr = addrs; - } else { - if (!m_firstFetchNameSrv) - return m_nameSrvAddr; - } - // update the snapshot local file if nameSrv changes or - // m_firstFetchNameSrv==true - if (writeDataToFile(fileBak, addrs, true)) { - if (!UtilAll::ReplaceFile(fileBak, file)) - LOG_ERROR("could not rename bak file:%s", strerror(errno)); - } - } - - if (!boost::filesystem::exists(snapshot_file)) { - // the name server snapshot local file maybe deleted by force, create it - if (writeDataToFile(fileBak, m_nameSrvAddr, true)) { - if (!UtilAll::ReplaceFile(fileBak, file)) - LOG_ERROR("could not rename bak file:%s", strerror(errno)); - } - } - } catch (...) { - } - return m_nameSrvAddr; -} - -void MQClientAPIImpl::updateNameServerAddr(const string& addrs) { - if (m_pRemotingClient != NULL) - m_pRemotingClient->updateNameServerAddressList(addrs); -} - -void MQClientAPIImpl::callSignatureBeforeRequest(const string& addr, - RemotingCommand& request, - const SessionCredentials& session_credentials) { - ClientRPCHook rpcHook(session_credentials); - rpcHook.doBeforeRequest(addr, request); -} - -// Note: all request rules: throw exception if got broker error response, -// exclude getTopicRouteInfoFromNameServer and unregisterClient -void MQClientAPIImpl::createTopic(const string& addr, - const string& defaultTopic, - TopicConfig topicConfig, - const SessionCredentials& sessionCredentials) { - string topicWithProjectGroup = topicConfig.getTopicName(); - CreateTopicRequestHeader* requestHeader = new CreateTopicRequestHeader(); - requestHeader->topic = (topicWithProjectGroup); - requestHeader->defaultTopic = (defaultTopic); - requestHeader->readQueueNums = (topicConfig.getReadQueueNums()); - requestHeader->writeQueueNums = (topicConfig.getWriteQueueNums()); - requestHeader->perm = (topicConfig.getPerm()); - requestHeader->topicFilterType = (topicConfig.getTopicFilterType()); - - RemotingCommand request(UPDATE_AND_CREATE_TOPIC, requestHeader); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - unique_ptr response(m_pRemotingClient->invokeSync(addr, request)); - - if (response) { - switch (response->getCode()) { - case SUCCESS_VALUE: - return; - default: - break; - } - THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode()); - } - THROW_MQEXCEPTION(MQBrokerException, "response is null", -1); -} - -void MQClientAPIImpl::endTransactionOneway(std::string addr, - EndTransactionRequestHeader* requestHeader, - std::string remark, - const SessionCredentials& sessionCredentials) { - RemotingCommand request(END_TRANSACTION, requestHeader); - request.setRemark(remark); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - m_pRemotingClient->invokeOneway(addr, request); - return; -} - -SendResult MQClientAPIImpl::sendMessage(const string& addr, - const string& brokerName, - const MQMessage& msg, - const SendMessageRequestHeader& requestHeader, - int timeoutMillis, - int maxRetrySendTimes, - int communicationMode, - SendCallback* pSendCallback, - const SessionCredentials& sessionCredentials) { - // RemotingCommand request(SEND_MESSAGE, pRequestHeader); - // Using MQ V2 Protocol to end messages. - SendMessageRequestHeaderV2* pRequestHeaderV2 = new SendMessageRequestHeaderV2(requestHeader); - RemotingCommand request(SEND_MESSAGE_V2, pRequestHeaderV2); - string body = msg.getBody(); - request.SetBody(body.c_str(), body.length()); - request.setMsgBody(body); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - switch (communicationMode) { - case ComMode_ONEWAY: - m_pRemotingClient->invokeOneway(addr, request); - break; - case ComMode_ASYNC: - sendMessageAsync(addr, brokerName, msg, request, pSendCallback, timeoutMillis, maxRetrySendTimes, 1); - break; - case ComMode_SYNC: - return sendMessageSync(addr, brokerName, msg, request, timeoutMillis); - default: - break; - } - return SendResult(); -} - -void MQClientAPIImpl::sendHeartbeat(const string& addr, - HeartbeatData* pHeartbeatData, - const SessionCredentials& sessionCredentials) { - RemotingCommand request(HEART_BEAT, NULL); - - string body; - pHeartbeatData->Encode(body); - request.SetBody(body.data(), body.length()); - request.setMsgBody(body); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - if (m_pRemotingClient->invokeHeartBeat(addr, request)) { - LOG_DEBUG("sendHeartbeat to broker:%s success", addr.c_str()); - } else { - LOG_WARN("sendHeartbeat to broker:%s failed", addr.c_str()); - } -} - -void MQClientAPIImpl::unregisterClient(const string& addr, - const string& clientID, - const string& producerGroup, - const string& consumerGroup, - const SessionCredentials& sessionCredentials) { - LOG_INFO("unregisterClient to broker:%s", addr.c_str()); - RemotingCommand request(UNREGISTER_CLIENT, new UnregisterClientRequestHeader(clientID, producerGroup, consumerGroup)); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - unique_ptr response(m_pRemotingClient->invokeSync(addr, request)); - - if (response) { - switch (response->getCode()) { - case SUCCESS_VALUE: - LOG_INFO("unregisterClient to:%s success", addr.c_str()); - return; - default: - break; - } - LOG_WARN("unregisterClient fail:%s,%d", response->getRemark().c_str(), response->getCode()); - } -} - -// return NULL if got no response or error response -TopicRouteData* MQClientAPIImpl::getTopicRouteInfoFromNameServer(const string& topic, - int timeoutMillis, - const SessionCredentials& sessionCredentials) { - RemotingCommand request(GET_ROUTEINTO_BY_TOPIC, new GetRouteInfoRequestHeader(topic)); - callSignatureBeforeRequest("", request, sessionCredentials); - request.Encode(); - - unique_ptr pResponse(m_pRemotingClient->invokeSync("", request, timeoutMillis)); - - if (pResponse != NULL) { - if (((*(pResponse->GetBody())).getSize() == 0) || ((*(pResponse->GetBody())).getData() != NULL)) { - switch (pResponse->getCode()) { - case SUCCESS_VALUE: { - const MemoryBlock* pbody = pResponse->GetBody(); - if (pbody->getSize()) { - TopicRouteData* topicRoute = TopicRouteData::Decode(pbody); - return topicRoute; - } - } - case TOPIC_NOT_EXIST: { - if (DEFAULT_TOPIC.compare(topic) != 0) { - LOG_WARN("Get topic[%s] route failed [TOPIC_NOT_EXIST].", topic.c_str()); - } - return NULL; - } - default: - break; - } - LOG_WARN("%s,%d", pResponse->getRemark().c_str(), pResponse->getCode()); - return NULL; - } - } - if (DEFAULT_TOPIC.compare(topic) != 0) { - LOG_WARN("Get topic[%s] route failed [Null Response].", topic.c_str()); - } - return NULL; -} - -TopicList* MQClientAPIImpl::getTopicListFromNameServer(const SessionCredentials& sessionCredentials) { - RemotingCommand request(GET_ALL_TOPIC_LIST_FROM_NAMESERVER, NULL); - callSignatureBeforeRequest("", request, sessionCredentials); - request.Encode(); - - unique_ptr pResponse(m_pRemotingClient->invokeSync("", request)); - if (pResponse != NULL) { - if (((*(pResponse->GetBody())).getSize() == 0) || ((*(pResponse->GetBody())).getData() != NULL)) { - switch (pResponse->getCode()) { - case SUCCESS_VALUE: { - const MemoryBlock* pbody = pResponse->GetBody(); - if (pbody->getSize()) { - TopicList* topicList = TopicList::Decode(pbody); - return topicList; - } - } - default: - break; - } - - THROW_MQEXCEPTION(MQClientException, pResponse->getRemark(), pResponse->getCode()); - } - } - return NULL; -} - -int MQClientAPIImpl::wipeWritePermOfBroker(const string& namesrvAddr, const string& brokerName, int timeoutMillis) { - return 0; -} - -void MQClientAPIImpl::deleteTopicInBroker(const string& addr, const string& topic, int timeoutMillis) {} - -void MQClientAPIImpl::deleteTopicInNameServer(const string& addr, const string& topic, int timeoutMillis) {} - -void MQClientAPIImpl::deleteSubscriptionGroup(const string& addr, const string& groupName, int timeoutMillis) {} - -string MQClientAPIImpl::getKVConfigByValue(const string& projectNamespace, - const string& projectGroup, - int timeoutMillis) { - return ""; -} - -KVTable MQClientAPIImpl::getKVListByNamespace(const string& projectNamespace, int timeoutMillis) { - return KVTable(); -} - -void MQClientAPIImpl::deleteKVConfigByValue(const string& projectNamespace, - const string& projectGroup, - int timeoutMillis) {} - -SendResult MQClientAPIImpl::sendMessageSync(const string& addr, - const string& brokerName, - const MQMessage& msg, - RemotingCommand& request, - int timeoutMillis) { - // pResponse(m_pRemotingClient->invokeSync(addr, request, timeoutMillis)); - if (pResponse != NULL) { - try { - SendResult result = processSendResponse(brokerName, msg, pResponse.get()); - LOG_DEBUG("sendMessageSync success:%s to addr:%s,brokername:%s, send status:%d", msg.toString().c_str(), - addr.c_str(), brokerName.c_str(), (int)result.getSendStatus()); - return result; - } catch (std::exception& e) { - LOG_ERROR("send new error, broker:%s, details:%s", brokerName.c_str(), e.what()); - throw e; - } catch (...) { - LOG_ERROR("Unknown error, broker:%s", brokerName.c_str()); - } - } - THROW_MQEXCEPTION(MQClientException, "response is null", -1); -} - -void MQClientAPIImpl::sendMessageAsync(const string& addr, - const string& brokerName, - const MQMessage& msg, - RemotingCommand& request, - SendCallback* pSendCallback, - int64 timeoutMilliseconds, - int maxRetryTimes, - int retrySendTimes) { - int64 begin_time = UtilAll::currentTimeMillis(); - // cbw = std::make_shared(brokerName, msg, pSendCallback, this); - if (m_pRemotingClient->invokeAsync(addr, request, cbw, timeoutMilliseconds, maxRetryTimes, retrySendTimes) == false) { - LOG_WARN("invokeAsync failed to addr:%s,topic:%s, timeout:%lld, maxRetryTimes:%d, retrySendTimes:%d", addr.c_str(), - msg.getTopic().data(), timeoutMilliseconds, maxRetryTimes, retrySendTimes); - // when getTcp return false, need consider retrySendTimes - int retry_time = retrySendTimes + 1; - int64 time_out = timeoutMilliseconds - (UtilAll::currentTimeMillis() - begin_time); - while (retry_time < maxRetryTimes && time_out > 0) { - begin_time = UtilAll::currentTimeMillis(); - if (m_pRemotingClient->invokeAsync(addr, request, cbw, time_out, maxRetryTimes, retry_time) == false) { - retry_time += 1; - time_out = time_out - (UtilAll::currentTimeMillis() - begin_time); - LOG_WARN("invokeAsync retry failed to addr:%s,topic:%s, timeout:%lld, maxRetryTimes:%d, retrySendTimes:%d", - addr.c_str(), msg.getTopic().data(), time_out, maxRetryTimes, retry_time); - continue; - } else { - return; // invokeAsync success - } - } - - LOG_ERROR("sendMessageAsync failed to addr:%s,topic:%s, timeout:%lld, maxRetryTimes:%d, retrySendTimes:%d", - addr.c_str(), msg.getTopic().data(), time_out, maxRetryTimes, retrySendTimes); - - if (cbw && pSendCallback != nullptr) { - cbw->onException(); - // deleteAndZero(cbw); - } else { - THROW_MQEXCEPTION(MQClientException, "sendMessageAsync failed", -1); - } - } -} - -PullResult* MQClientAPIImpl::pullMessage(const string& addr, - PullMessageRequestHeader* pRequestHeader, - int timeoutMillis, - int communicationMode, - PullCallback* pullCallback, - void* pArg, - const SessionCredentials& sessionCredentials) { - RemotingCommand request(PULL_MESSAGE, pRequestHeader); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - switch (communicationMode) { - case ComMode_ONEWAY: - break; - case ComMode_ASYNC: - pullMessageAsync(addr, request, timeoutMillis, pullCallback, pArg); - break; - case ComMode_SYNC: - return pullMessageSync(addr, request, timeoutMillis); - default: - break; - } - - return NULL; -} - -void MQClientAPIImpl::pullMessageAsync(const string& addr, - RemotingCommand& request, - int timeoutMillis, - PullCallback* pullCallback, - void* pArg) { - // AsyncCallbackWrap* cbw = new PullCallbackWrap(pullCallback, this, pArg); - std::shared_ptr cbw = std::make_shared(pullCallback, this, pArg); - if (m_pRemotingClient->invokeAsync(addr, request, cbw, timeoutMillis) == false) { - LOG_ERROR("pullMessageAsync failed of addr:%s, mq:%s", addr.c_str(), - static_cast(pArg)->mq.toString().data()); - // deleteAndZero(cbw); - THROW_MQEXCEPTION(MQClientException, "pullMessageAsync failed", -1); - } -} - -PullResult* MQClientAPIImpl::pullMessageSync(const string& addr, RemotingCommand& request, int timeoutMillis) { - unique_ptr pResponse(m_pRemotingClient->invokeSync(addr, request, timeoutMillis)); - if (pResponse != NULL) { - if (((*(pResponse->GetBody())).getSize() == 0) || ((*(pResponse->GetBody())).getData() != NULL)) { - try { - PullResult* pullResult = processPullResponse(pResponse.get()); // pullMessage will handle - // exception from - // processPullResponse - return pullResult; - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - return NULL; - } - } - } - return NULL; -} - -SendResult MQClientAPIImpl::processSendResponse(const string& brokerName, - const MQMessage& msg, - RemotingCommand* pResponse) { - SendStatus sendStatus = SEND_OK; - int res = 0; - switch (pResponse->getCode()) { - case FLUSH_DISK_TIMEOUT: - sendStatus = SEND_FLUSH_DISK_TIMEOUT; - break; - case FLUSH_SLAVE_TIMEOUT: - sendStatus = SEND_FLUSH_SLAVE_TIMEOUT; - break; - case SLAVE_NOT_AVAILABLE: - sendStatus = SEND_SLAVE_NOT_AVAILABLE; - break; - case SUCCESS_VALUE: - sendStatus = SEND_OK; - break; - default: - res = -1; - break; - } - if (res == 0) { - SendMessageResponseHeader* responseHeader = (SendMessageResponseHeader*)pResponse->getCommandHeader(); - auto extFields = pResponse->getExtFields(); - bool traceOn = (extFields->count("TRACE_ON") && extFields->at("TRACE_ON") == "true"); - MQMessageQueue messageQueue(msg.getTopic(), brokerName, responseHeader->queueId); - string unique_msgId = msg.getProperty(MQMessage::PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX); - return SendResult(sendStatus, unique_msgId, responseHeader->msgId, messageQueue, responseHeader->queueOffset, - responseHeader->regionId, traceOn); - } - LOG_ERROR("processSendResponse error remark:%s, error code:%d", (pResponse->getRemark()).c_str(), - pResponse->getCode()); - THROW_MQEXCEPTION(MQClientException, pResponse->getRemark(), pResponse->getCode()); -} - -PullResult* MQClientAPIImpl::processPullResponse(RemotingCommand* pResponse) { - PullStatus pullStatus = NO_NEW_MSG; - switch (pResponse->getCode()) { - case SUCCESS_VALUE: - pullStatus = FOUND; - break; - case PULL_NOT_FOUND: - pullStatus = NO_NEW_MSG; - break; - case PULL_RETRY_IMMEDIATELY: - pullStatus = NO_MATCHED_MSG; - break; - case PULL_OFFSET_MOVED: - pullStatus = OFFSET_ILLEGAL; - break; - default: - THROW_MQEXCEPTION(MQBrokerException, pResponse->getRemark(), pResponse->getCode()); - break; - } - - PullMessageResponseHeader* responseHeader = static_cast(pResponse->getCommandHeader()); - - if (!responseHeader) { - LOG_ERROR("processPullResponse:responseHeader is NULL"); - THROW_MQEXCEPTION(MQClientException, "processPullResponse:responseHeader is NULL", -1); - } - //GetBody()); // response data judgement had been done outside - // of processPullResponse - if (bodyFromResponse.getSize() == 0) { - if (pullStatus != FOUND) { - return new PullResultExt(pullStatus, responseHeader->nextBeginOffset, responseHeader->minOffset, - responseHeader->maxOffset, (int)responseHeader->suggestWhichBrokerId); - } else { - THROW_MQEXCEPTION(MQClientException, "memoryBody size is 0, but pullStatus equals found", -1); - } - } else { - return new PullResultExt(pullStatus, responseHeader->nextBeginOffset, responseHeader->minOffset, - responseHeader->maxOffset, (int)responseHeader->suggestWhichBrokerId, bodyFromResponse); - } -} - -//topic = topic; - pRequestHeader->queueId = queueId; - - RemotingCommand request(GET_MIN_OFFSET, pRequestHeader); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - unique_ptr response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis)); - - if (response) { - switch (response->getCode()) { - case SUCCESS_VALUE: { - GetMinOffsetResponseHeader* responseHeader = (GetMinOffsetResponseHeader*)response->getCommandHeader(); - - int64 offset = responseHeader->offset; - return offset; - } - default: - break; - } - THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode()); - } - THROW_MQEXCEPTION(MQBrokerException, "response is null", -1); -} - -int64 MQClientAPIImpl::getMaxOffset(const string& addr, - const string& topic, - int queueId, - int timeoutMillis, - const SessionCredentials& sessionCredentials) { - GetMaxOffsetRequestHeader* pRequestHeader = new GetMaxOffsetRequestHeader(); - pRequestHeader->topic = topic; - pRequestHeader->queueId = queueId; - - RemotingCommand request(GET_MAX_OFFSET, pRequestHeader); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - unique_ptr response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis)); - - if (response) { - switch (response->getCode()) { - case SUCCESS_VALUE: { - GetMaxOffsetResponseHeader* responseHeader = (GetMaxOffsetResponseHeader*)response->getCommandHeader(); - - int64 offset = responseHeader->offset; - return offset; - } - default: - break; - } - THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode()); - } - THROW_MQEXCEPTION(MQBrokerException, "response is null", -1); -} - -int64 MQClientAPIImpl::searchOffset(const string& addr, - const string& topic, - int queueId, - uint64_t timestamp, - int timeoutMillis, - const SessionCredentials& sessionCredentials) { - SearchOffsetRequestHeader* pRequestHeader = new SearchOffsetRequestHeader(); - pRequestHeader->topic = topic; - pRequestHeader->queueId = queueId; - pRequestHeader->timestamp = timestamp; - - RemotingCommand request(SEARCH_OFFSET_BY_TIMESTAMP, pRequestHeader); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - unique_ptr response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis)); - - if (response) { - switch (response->getCode()) { - case SUCCESS_VALUE: { - SearchOffsetResponseHeader* responseHeader = (SearchOffsetResponseHeader*)response->getCommandHeader(); - - int64 offset = responseHeader->offset; - return offset; - } - default: - break; - } - THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode()); - } - THROW_MQEXCEPTION(MQBrokerException, "response is null", -1); -} - -MQMessageExt* MQClientAPIImpl::viewMessage(const string& addr, - int64 phyoffset, - int timeoutMillis, - const SessionCredentials& sessionCredentials) { - ViewMessageRequestHeader* pRequestHeader = new ViewMessageRequestHeader(); - pRequestHeader->offset = phyoffset; - - RemotingCommand request(VIEW_MESSAGE_BY_ID, pRequestHeader); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - unique_ptr response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis)); - - if (response) { - switch (response->getCode()) { - case SUCCESS_VALUE: { - } - default: - break; - } - THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode()); - } - THROW_MQEXCEPTION(MQBrokerException, "response is null", -1); -} - -int64 MQClientAPIImpl::getEarliestMsgStoretime(const string& addr, - const string& topic, - int queueId, - int timeoutMillis, - const SessionCredentials& sessionCredentials) { - GetEarliestMsgStoretimeRequestHeader* pRequestHeader = new GetEarliestMsgStoretimeRequestHeader(); - pRequestHeader->topic = topic; - pRequestHeader->queueId = queueId; - - RemotingCommand request(GET_EARLIEST_MSG_STORETIME, pRequestHeader); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - unique_ptr response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis)); - - if (response) { - switch (response->getCode()) { - case SUCCESS_VALUE: { - GetEarliestMsgStoretimeResponseHeader* responseHeader = - (GetEarliestMsgStoretimeResponseHeader*)response->getCommandHeader(); - - int64 timestamp = responseHeader->timestamp; - return timestamp; - } - default: - break; - } - THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode()); - } - THROW_MQEXCEPTION(MQBrokerException, "response is null", -1); -} - -void MQClientAPIImpl::getConsumerIdListByGroup(const string& addr, - const string& consumerGroup, - vector& cids, - int timeoutMillis, - const SessionCredentials& sessionCredentials) { - GetConsumerListByGroupRequestHeader* pRequestHeader = new GetConsumerListByGroupRequestHeader(); - pRequestHeader->consumerGroup = consumerGroup; - - RemotingCommand request(GET_CONSUMER_LIST_BY_GROUP, pRequestHeader); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - unique_ptr pResponse(m_pRemotingClient->invokeSync(addr, request, timeoutMillis)); - - if (pResponse != NULL) { - if ((pResponse->GetBody()->getSize() == 0) || (pResponse->GetBody()->getData() != NULL)) { - switch (pResponse->getCode()) { - case SUCCESS_VALUE: { - const MemoryBlock* pbody = pResponse->GetBody(); - if (pbody->getSize()) { - GetConsumerListByGroupResponseBody::Decode(pbody, cids); - return; - } - } - default: - break; - } - THROW_MQEXCEPTION(MQBrokerException, pResponse->getRemark(), pResponse->getCode()); - } - } - THROW_MQEXCEPTION(MQBrokerException, "response is null", -1); -} - -int64 MQClientAPIImpl::queryConsumerOffset(const string& addr, - QueryConsumerOffsetRequestHeader* pRequestHeader, - int timeoutMillis, - const SessionCredentials& sessionCredentials) { - RemotingCommand request(QUERY_CONSUMER_OFFSET, pRequestHeader); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - unique_ptr response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis)); - - if (response) { - switch (response->getCode()) { - case SUCCESS_VALUE: { - QueryConsumerOffsetResponseHeader* responseHeader = - (QueryConsumerOffsetResponseHeader*)response->getCommandHeader(); - int64 consumerOffset = responseHeader->offset; - return consumerOffset; - } - default: - break; - } - THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode()); - } - THROW_MQEXCEPTION(MQBrokerException, "response is null", -1); - return -1; -} - -void MQClientAPIImpl::updateConsumerOffset(const string& addr, - UpdateConsumerOffsetRequestHeader* pRequestHeader, - int timeoutMillis, - const SessionCredentials& sessionCredentials) { - RemotingCommand request(UPDATE_CONSUMER_OFFSET, pRequestHeader); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - unique_ptr response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis)); - - if (response) { - switch (response->getCode()) { - case SUCCESS_VALUE: { - return; - } - default: - break; - } - THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode()); - } - THROW_MQEXCEPTION(MQBrokerException, "response is null", -1); -} - -void MQClientAPIImpl::updateConsumerOffsetOneway(const string& addr, - UpdateConsumerOffsetRequestHeader* pRequestHeader, - int timeoutMillis, - const SessionCredentials& sessionCredentials) { - RemotingCommand request(UPDATE_CONSUMER_OFFSET, pRequestHeader); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - m_pRemotingClient->invokeOneway(addr, request); -} - -void MQClientAPIImpl::consumerSendMessageBack(const string addr, - MQMessageExt& msg, - const string& consumerGroup, - int delayLevel, - int timeoutMillis, - int maxReconsumeTimes, - const SessionCredentials& sessionCredentials) { - ConsumerSendMsgBackRequestHeader* pRequestHeader = new ConsumerSendMsgBackRequestHeader(); - pRequestHeader->group = consumerGroup; - pRequestHeader->offset = msg.getCommitLogOffset(); - pRequestHeader->delayLevel = delayLevel; - pRequestHeader->unitMode = false; - pRequestHeader->originTopic = msg.getTopic(); - pRequestHeader->originMsgId = msg.getMsgId(); - pRequestHeader->maxReconsumeTimes = maxReconsumeTimes; - - // string addr = socketAddress2IPPort(msg.getStoreHost()); - RemotingCommand request(CONSUMER_SEND_MSG_BACK, pRequestHeader); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - unique_ptr response(m_pRemotingClient->invokeSync(addr, request, timeoutMillis)); - - if (response) { - switch (response->getCode()) { - case SUCCESS_VALUE: { - return; - } - default: - break; - } - THROW_MQEXCEPTION(MQBrokerException, response->getRemark(), response->getCode()); - } - THROW_MQEXCEPTION(MQBrokerException, "response is null", -1); -} - -void MQClientAPIImpl::lockBatchMQ(const string& addr, - LockBatchRequestBody* requestBody, - vector& mqs, - int timeoutMillis, - const SessionCredentials& sessionCredentials) { - RemotingCommand request(LOCK_BATCH_MQ, NULL); - string body; - requestBody->Encode(body); - request.SetBody(body.data(), body.length()); - request.setMsgBody(body); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - unique_ptr pResponse(m_pRemotingClient->invokeSync(addr, request, timeoutMillis)); - - if (pResponse != NULL) { - if (((*(pResponse->GetBody())).getSize() == 0) || ((*(pResponse->GetBody())).getData() != NULL)) { - switch (pResponse->getCode()) { - case SUCCESS_VALUE: { - const MemoryBlock* pbody = pResponse->GetBody(); - if (pbody->getSize()) { - LockBatchResponseBody::Decode(pbody, mqs); - } - return; - } break; - default: - break; - } - THROW_MQEXCEPTION(MQBrokerException, pResponse->getRemark(), pResponse->getCode()); - } - } - THROW_MQEXCEPTION(MQBrokerException, "response is null", -1); -} - -void MQClientAPIImpl::unlockBatchMQ(const string& addr, - UnlockBatchRequestBody* requestBody, - int timeoutMillis, - const SessionCredentials& sessionCredentials) { - RemotingCommand request(UNLOCK_BATCH_MQ, NULL); - string body; - requestBody->Encode(body); - request.SetBody(body.data(), body.length()); - request.setMsgBody(body); - callSignatureBeforeRequest(addr, request, sessionCredentials); - request.Encode(); - - unique_ptr pResponse(m_pRemotingClient->invokeSync(addr, request, timeoutMillis)); - - if (pResponse != NULL) { - switch (pResponse->getCode()) { - case SUCCESS_VALUE: { - return; - } break; - default: - break; - } - THROW_MQEXCEPTION(MQBrokerException, pResponse->getRemark(), pResponse->getCode()); - } - THROW_MQEXCEPTION(MQBrokerException, "response is null", -1); -} - -//& cids, - int timeoutMillis, - const SessionCredentials& sessionCredentials); - - virtual int64 queryConsumerOffset(const string& addr, - QueryConsumerOffsetRequestHeader* pRequestHeader, - int timeoutMillis, - const SessionCredentials& sessionCredentials); - - virtual void updateConsumerOffset(const string& addr, - UpdateConsumerOffsetRequestHeader* pRequestHeader, - int timeoutMillis, - const SessionCredentials& sessionCredentials); - - virtual void updateConsumerOffsetOneway(const string& addr, - UpdateConsumerOffsetRequestHeader* pRequestHeader, - int timeoutMillis, - const SessionCredentials& sessionCredentials); - - virtual void consumerSendMessageBack(const string addr, - MQMessageExt& msg, - const string& consumerGroup, - int delayLevel, - int timeoutMillis, - int maxReconsumeTimes, - const SessionCredentials& sessionCredentials); - - virtual void lockBatchMQ(const string& addr, - LockBatchRequestBody* requestBody, - vector& mqs, - int timeoutMillis, - const SessionCredentials& sessionCredentials); - - virtual void unlockBatchMQ(const string& addr, - UnlockBatchRequestBody* requestBody, - int timeoutMillis, - const SessionCredentials& sessionCredentials); - - virtual void sendMessageAsync(const string& addr, - const string& brokerName, - const MQMessage& msg, - RemotingCommand& request, - SendCallback* pSendCallback, - int64 timeoutMilliseconds, - int maxRetryTimes = 1, - int retrySendTimes = 1); - - private: - SendResult sendMessageSync(const string& addr, - const string& brokerName, - const MQMessage& msg, - RemotingCommand& request, - int timeoutMillis); - /* - void sendMessageAsync(const string& addr, const string& brokerName, - const MQMessage& msg, RemotingCommand& request, - SendCallback* pSendCallback, int64 timeoutMilliseconds); - */ - PullResult* pullMessageSync(const string& addr, RemotingCommand& request, int timeoutMillis); - - void pullMessageAsync(const string& addr, - RemotingCommand& request, - int timeoutMillis, - PullCallback* pullCallback, - void* pArg); - - protected: - unique_ptr m_pRemotingClient; - - private: - unique_ptr m_topAddressing; - string m_nameSrvAddr; - bool m_firstFetchNameSrv; - string m_mqClientId; -}; -} // namespace rocketmq -// pDefaultTopicInfo(new TopicPublishInfo()); - m_topicPublishInfoTable[DEFAULT_TOPIC] = pDefaultTopicInfo; - m_pClientRemotingProcessor.reset(new ClientRemotingProcessor(this)); - m_pClientAPIImpl.reset(new MQClientAPIImpl(m_clientId, m_pClientRemotingProcessor.get(), pullThreadNum, - tcpConnectTimeout, tcpTransportTryLockTimeout, unitName, enableSsl, - sslPropertyFile)); - m_serviceState = CREATE_JUST; - LOG_DEBUG("MQClientFactory construct"); -} - -MQClientFactory::~MQClientFactory() { - LOG_INFO("MQClientFactory:%s destruct", m_clientId.c_str()); - - for (TRDMAP::iterator itp = m_topicRouteTable.begin(); itp != m_topicRouteTable.end(); ++itp) { - delete itp->second; - } - - m_producerTable.clear(); - m_consumerTable.clear(); - m_topicRouteTable.clear(); - m_brokerAddrTable.clear(); - m_topicPublishInfoTable.clear(); -} - -void MQClientFactory::start() { - switch (m_serviceState) { - case CREATE_JUST: - LOG_INFO("MQClientFactory:%s start", m_clientId.c_str()); - m_serviceState = START_FAILED; - // t) { - if ((getConsumerTableSize() == 0) && (getProducerTableSize() == 0)) { - return; - } - - set topicList; - //::iterator it = topicList.begin(); - for (; it != topicList.end(); ++it) { - updateTopicRouteInfoFromNameServer(*it, session_credentials); - } - } - - boost::system::error_code e; - t->expires_from_now(t->expires_from_now() + boost::posix_time::seconds(30), e); - t->async_wait(boost::bind(&MQClientFactory::updateTopicRouteInfo, this, ec, t)); -} - -TopicRouteData* MQClientFactory::getTopicRouteData(const string& topic) { - boost::lock_guard lock(m_topicRouteTableMutex); - if (m_topicRouteTable.find(topic) != m_topicRouteTable.end()) { - return m_topicRouteTable[topic]; - } - return NULL; -} - -void MQClientFactory::addTopicRouteData(const string& topic, TopicRouteData* pTopicRouteData) { - boost::lock_guard lock(m_topicRouteTableMutex); - if (m_topicRouteTable.find(topic) != m_topicRouteTable.end()) { - delete m_topicRouteTable[topic]; - m_topicRouteTable.erase(topic); - } - m_topicRouteTable[topic] = pTopicRouteData; -} - -boost::shared_ptr MQClientFactory::tryToFindTopicPublishInfo( - const string& topic, - const SessionCredentials& session_credentials) { - boost::lock_guard lock(m_topicPublishInfoLock); // add topicPublishInfoLock to avoid con-current - // excuting updateTopicRouteInfoFromNameServer - // when producer send msg before topicRouteInfo - // was got; - if (!isTopicInfoValidInTable(topic)) { - updateTopicRouteInfoFromNameServer(topic, session_credentials); - } - // pTopicPublishInfo; - return pTopicPublishInfo; - } - - return getTopicPublishInfoFromTable(topic); -} - -bool MQClientFactory::updateTopicRouteInfoFromNameServer(const string& topic, - const SessionCredentials& session_credentials, - bool isDefault /* = false */) { - boost::lock_guard lock(m_factoryLock); - unique_ptr pTopicRouteData; - LOG_DEBUG("updateTopicRouteInfoFromNameServer start. Topic:%s", topic.c_str()); - - if (isDefault) { - pTopicRouteData.reset( - m_pClientAPIImpl->getTopicRouteInfoFromNameServer(DEFAULT_TOPIC, 1000 * 5, session_credentials)); - if (pTopicRouteData != NULL) { - vector& queueDatas = pTopicRouteData->getQueueDatas(); - vector::iterator it = queueDatas.begin(); - for (; it != queueDatas.end(); ++it) { - int queueNums = std::min(4, it->readQueueNums); - it->readQueueNums = queueNums; - it->writeQueueNums = queueNums; - } - } - LOG_DEBUG("getTopicRouteInfoFromNameServer is null for topic :%s", topic.c_str()); - } else { - pTopicRouteData.reset(m_pClientAPIImpl->getTopicRouteInfoFromNameServer(topic, 1000 * 5, session_credentials)); - } - - if (pTopicRouteData != NULL) { - LOG_DEBUG("updateTopicRouteInfoFromNameServer has data"); - TopicRouteData* pTemp = getTopicRouteData(topic); - bool changed = true; - if (pTemp != NULL) { - changed = !(*pTemp == *pTopicRouteData); - } - - if (getConsumerTableSize() > 0) { - vector mqs; - topicRouteData2TopicSubscribeInfo(topic, pTopicRouteData.get(), mqs); - updateConsumerSubscribeTopicInfo(topic, mqs); - } - - if (changed) { - // brokerList = pTopicRouteData->getBrokerDatas(); - vector::iterator it = brokerList.begin(); - for (; it != brokerList.end(); ++it) { - LOG_INFO("updateTopicRouteInfoFromNameServer changed with broker name:%s", (*it).brokerName.c_str()); - addBrokerToAddrMap((*it).brokerName, (*it).brokerAddrs); - } - - // publishInfo(topicRouteData2TopicPublishInfo(topic, pTopicRouteData.get())); - addTopicInfoToTable(topic, publishInfo); // erase first, then add - } - - // MQClientFactory::topicRouteData2TopicPublishInfo(const string& topic, - TopicRouteData* pRoute) { - boost::shared_ptr info(new TopicPublishInfo()); - string OrderTopicConf = pRoute->getOrderTopicConf(); - // brokers; - UtilAll::Split(brokers, OrderTopicConf, ';'); - for (size_t i = 0; i < brokers.size(); i++) { - vector item; - UtilAll::Split(item, brokers[i], ':'); - size_t nums = (item.size() > 1) ? atoi(item[1].c_str()) : 0; - for (size_t i = 0; i < nums; i++) { - MQMessageQueue mq(topic, item[0], i); - info->updateMessageQueueList(mq); - } - } - } - //& queueDatas = pRoute->getQueueDatas(); - vector::iterator it = queueDatas.begin(); - for (; it != queueDatas.end(); ++it) { - QueueData& qd = (*it); - if (PermName::isWriteable(qd.perm)) { - string addr = findBrokerAddressInPublish(qd.brokerName); - if (addr.empty()) { - continue; - } - for (int i = 0; i < qd.writeQueueNums; i++) { - MQMessageQueue mq(topic, qd.brokerName, i); - info->updateMessageQueueList(mq); - } - } - } - } - return info; -} - -void MQClientFactory::topicRouteData2TopicSubscribeInfo(const string& topic, - TopicRouteData* pRoute, - vector& mqs) { - mqs.clear(); - vector& queueDatas = pRoute->getQueueDatas(); - vector::iterator it = queueDatas.begin(); - for (; it != queueDatas.end(); ++it) { - QueueData& qd = (*it); - if (PermName::isReadable(qd.perm)) { - for (int i = 0; i < qd.readQueueNums; i++) { - MQMessageQueue mq(topic, qd.brokerName, i); - mqs.push_back(mq); - } - } - } -} - -void MQClientFactory::shutdown() { - if (getConsumerTableSize() != 0) - return; - - if (getProducerTableSize() != 0) - return; - - switch (m_serviceState) { - case CREATE_JUST: - case RUNNING: { - if (m_consumer_async_service_thread) { - m_consumer_async_ioService.stop(); - m_consumer_async_service_thread->interrupt(); - m_consumer_async_service_thread->join(); - m_consumer_async_service_thread.reset(); - } - - if (m_async_service_thread) { - m_async_ioService.stop(); - m_async_service_thread->interrupt(); - m_async_service_thread->join(); - m_async_service_thread.reset(); - } - - if (m_pClientAPIImpl) { - m_pClientAPIImpl->stopAllTcpTransportThread(); // Note: stop all - // TcpTransport Threads - // and release all - // responseFuture - // conditions - m_pClientAPIImpl.reset(); - } - - m_serviceState = SHUTDOWN_ALREADY; - LOG_INFO("MQClientFactory:%s shutdown", m_clientId.c_str()); - break; - } - case SHUTDOWN_ALREADY: - break; - default: - break; - } - - MQClientManager::getInstance()->removeClientFactory(m_clientId); -} - -bool MQClientFactory::registerProducer(MQProducer* pProducer) { - string groupName = pProducer->getGroupName(); - string namesrvaddr = pProducer->getNamesrvAddr(); - if (groupName.empty()) { - return false; - } - - if (!addProducerToTable(groupName, pProducer)) { - return false; - } - - LOG_DEBUG("registerProducer success:%s", groupName.c_str()); - //getNamesrvDomain()); - if (!nameSrvDomain.empty()) - m_nameSrvDomain = nameSrvDomain; - pProducer->setNamesrvAddr(m_pClientAPIImpl->fetchNameServerAddr(m_nameSrvDomain)); - } else { - m_bFetchNSService = false; - m_pClientAPIImpl->updateNameServerAddr(namesrvaddr); - LOG_INFO("user specfied name server address: %s", namesrvaddr.c_str()); - } - return true; -} - -void MQClientFactory::unregisterProducer(MQProducer* pProducer) { - string groupName = pProducer->getGroupName(); - unregisterClient(groupName, "", pProducer->getSessionCredentials()); - - eraseProducerFromTable(groupName); -} - -bool MQClientFactory::registerConsumer(MQConsumer* pConsumer) { - string groupName = pConsumer->getGroupName(); - string namesrvaddr = pConsumer->getNamesrvAddr(); - if (groupName.empty()) { - return false; - } - - if (!addConsumerToTable(groupName, pConsumer)) { - return false; - } - LOG_DEBUG("registerConsumer success:%s", groupName.c_str()); - //getNamesrvDomain()); - if (!nameSrvDomain.empty()) - m_nameSrvDomain = nameSrvDomain; - pConsumer->setNamesrvAddr(m_pClientAPIImpl->fetchNameServerAddr(m_nameSrvDomain)); - } else { - m_bFetchNSService = false; - m_pClientAPIImpl->updateNameServerAddr(namesrvaddr); - LOG_INFO("user specfied name server address: %s", namesrvaddr.c_str()); - } - - return true; -} - -void MQClientFactory::unregisterConsumer(MQConsumer* pConsumer) { - string groupName = pConsumer->getGroupName(); - unregisterClient("", groupName, pConsumer->getSessionCredentials()); - - eraseConsumerFromTable(groupName); -} - -bool MQClientFactory::registerMQAdmin(MQAdmin* pAdmin) { - string groupName = pAdmin->getGroupName(); - string namesrvaddr = pAdmin->getNamesrvAddr(); - if (groupName.empty()) { - return false; - } - if (!addAdminToTable(groupName, pAdmin)) { - return false; - } - LOG_DEBUG("registerAdmin success:%s", groupName.c_str()); - //getNamesrvDomain()); - if (!nameSrvDomain.empty()) - m_nameSrvDomain = nameSrvDomain; - pAdmin->setNamesrvAddr(m_pClientAPIImpl->fetchNameServerAddr(m_nameSrvDomain)); - } else { - m_bFetchNSService = false; - m_pClientAPIImpl->updateNameServerAddr(namesrvaddr); - LOG_INFO("user specfied name server address: %s", namesrvaddr.c_str()); - } - return true; -} - -void MQClientFactory::unregisterMQAdmin(MQAdmin* pAdmin) { - string groupName = pAdmin->getGroupName(); - eraseAdminFromTable(groupName); -} - -MQProducer* MQClientFactory::selectProducer(const string& producerName) { - boost::lock_guard lock(m_producerTableMutex); - if (m_producerTable.find(producerName) != m_producerTable.end()) { - return m_producerTable[producerName]; - } - return NULL; -} - -bool MQClientFactory::getSessionCredentialFromProducerTable(SessionCredentials& sessionCredentials) { - boost::lock_guard lock(m_producerTableMutex); - for (MQPMAP::iterator it = m_producerTable.begin(); it != m_producerTable.end(); ++it) { - if (it->second) - sessionCredentials = it->second->getSessionCredentials(); - } - - if (sessionCredentials.isValid()) - return true; - - return false; -} - -bool MQClientFactory::addProducerToTable(const string& producerName, MQProducer* pMQProducer) { - boost::lock_guard lock(m_producerTableMutex); - if (m_producerTable.find(producerName) != m_producerTable.end()) - return false; - m_producerTable[producerName] = pMQProducer; - return true; -} - -void MQClientFactory::eraseProducerFromTable(const string& producerName) { - boost::lock_guard lock(m_producerTableMutex); - if (m_producerTable.find(producerName) != m_producerTable.end()) - m_producerTable.erase(producerName); -} - -int MQClientFactory::getProducerTableSize() { - boost::lock_guard lock(m_producerTableMutex); - return m_producerTable.size(); -} - -void MQClientFactory::insertProducerInfoToHeartBeatData(HeartbeatData* pHeartbeatData) { - boost::lock_guard lock(m_producerTableMutex); - for (MQPMAP::iterator it = m_producerTable.begin(); it != m_producerTable.end(); ++it) { - ProducerData producerData; - producerData.groupName = it->first; - pHeartbeatData->insertDataToProducerDataSet(producerData); - } -} - -MQConsumer* MQClientFactory::selectConsumer(const string& group) { - boost::lock_guard lock(m_consumerTableMutex); - if (m_consumerTable.find(group) != m_consumerTable.end()) { - return m_consumerTable[group]; - } - return NULL; -} - -bool MQClientFactory::getSessionCredentialFromConsumerTable(SessionCredentials& sessionCredentials) { - boost::lock_guard lock(m_consumerTableMutex); - for (MQCMAP::iterator it = m_consumerTable.begin(); it != m_consumerTable.end(); ++it) { - if (it->second) - sessionCredentials = it->second->getSessionCredentials(); - } - - if (sessionCredentials.isValid()) - return true; - - return false; -} - -bool MQClientFactory::getSessionCredentialFromConsumer(const string& consumerGroup, - SessionCredentials& sessionCredentials) { - boost::lock_guard lock(m_consumerTableMutex); - if (m_consumerTable.find(consumerGroup) != m_consumerTable.end()) { - sessionCredentials = m_consumerTable[consumerGroup]->getSessionCredentials(); - } - - if (sessionCredentials.isValid()) - return true; - - return false; -} - -bool MQClientFactory::addConsumerToTable(const string& consumerName, MQConsumer* pMQConsumer) { - boost::lock_guard lock(m_consumerTableMutex); - if (m_consumerTable.find(consumerName) != m_consumerTable.end()) - return false; - m_consumerTable[consumerName] = pMQConsumer; - return true; -} - -void MQClientFactory::eraseConsumerFromTable(const string& consumerName) { - boost::lock_guard lock(m_consumerTableMutex); - if (m_consumerTable.find(consumerName) != m_consumerTable.end()) - m_consumerTable.erase(consumerName); // do not need freee pConsumer, as it - // was allocated by user - else - LOG_WARN("could not find consumer:%s from table", consumerName.c_str()); -} - -bool MQClientFactory::addAdminToTable(const string& adminName, MQAdmin* pMQAdmin) { - boost::lock_guard lock(m_adminTableMutex); - if (m_adminTable.find(adminName) != m_adminTable.end()) - return false; - m_adminTable[adminName] = pMQAdmin; - return true; -} - -void MQClientFactory::eraseAdminFromTable(const string& adminName) { - boost::lock_guard lock(m_adminTableMutex); - if (m_adminTable.find(adminName) != m_adminTable.end()) - m_adminTable.erase(adminName); - else - LOG_WARN("could not find admin:%s from table", adminName.c_str()); -} - -int MQClientFactory::getConsumerTableSize() { - boost::lock_guard lock(m_consumerTableMutex); - return m_consumerTable.size(); -} - -void MQClientFactory::getTopicListFromConsumerSubscription(set& topicList) { - boost::lock_guard lock(m_consumerTableMutex); - for (MQCMAP::iterator it = m_consumerTable.begin(); it != m_consumerTable.end(); ++it) { - vector result; - it->second->getSubscriptions(result); - - vector::iterator iter = result.begin(); - for (; iter != result.end(); ++iter) { - topicList.insert((*iter).getTopic()); - } - } -} - -void MQClientFactory::updateConsumerSubscribeTopicInfo(const string& topic, vector mqs) { - boost::lock_guard lock(m_consumerTableMutex); - for (MQCMAP::iterator it = m_consumerTable.begin(); it != m_consumerTable.end(); ++it) { - it->second->updateTopicSubscribeInfo(topic, mqs); - } -} - -void MQClientFactory::insertConsumerInfoToHeartBeatData(HeartbeatData* pHeartbeatData) { - boost::lock_guard lock(m_consumerTableMutex); - for (MQCMAP::iterator it = m_consumerTable.begin(); it != m_consumerTable.end(); ++it) { - MQConsumer* pConsumer = it->second; - ConsumerData consumerData; - consumerData.groupName = pConsumer->getGroupName(); - consumerData.consumeType = pConsumer->getConsumeType(); - consumerData.messageModel = pConsumer->getMessageModel(); - consumerData.consumeFromWhere = pConsumer->getConsumeFromWhere(); - - // result; - pConsumer->getSubscriptions(result); - consumerData.subscriptionDataSet.swap(result); - - pHeartbeatData->insertDataToConsumerDataSet(consumerData); - } -} - -void MQClientFactory::addTopicInfoToTable(const string& topic, boost::shared_ptr pTopicPublishInfo) { - boost::lock_guard lock(m_topicPublishInfoTableMutex); - if (m_topicPublishInfoTable.find(topic) != m_topicPublishInfoTable.end()) { - m_topicPublishInfoTable.erase(topic); - } - m_topicPublishInfoTable[topic] = pTopicPublishInfo; -} - -void MQClientFactory::eraseTopicInfoFromTable(const string& topic) { - boost::lock_guard lock(m_topicPublishInfoTableMutex); - if (m_topicPublishInfoTable.find(topic) != m_topicPublishInfoTable.end()) { - m_topicPublishInfoTable.erase(topic); - } -} - -bool MQClientFactory::isTopicInfoValidInTable(const string& topic) { - boost::lock_guard lock(m_topicPublishInfoTableMutex); - if (m_topicPublishInfoTable.find(topic) != m_topicPublishInfoTable.end()) { - if (m_topicPublishInfoTable[topic]->ok()) - return true; - } - return false; -} - -boost::shared_ptr MQClientFactory::getTopicPublishInfoFromTable(const string& topic) { - boost::lock_guard lock(m_topicPublishInfoTableMutex); - if (m_topicPublishInfoTable.find(topic) != m_topicPublishInfoTable.end()) { - return m_topicPublishInfoTable[topic]; - } - boost::shared_ptr pTopicPublishInfo; - return pTopicPublishInfo; -} - -void MQClientFactory::getTopicListFromTopicPublishInfo(set& topicList) { - boost::lock_guard lock(m_topicPublishInfoTableMutex); - for (TPMap::iterator itp = m_topicPublishInfoTable.begin(); itp != m_topicPublishInfoTable.end(); ++itp) { - topicList.insert(itp->first); - } -} - -void MQClientFactory::clearBrokerAddrMap() { - boost::lock_guard lock(m_brokerAddrlock); - m_brokerAddrTable.clear(); -} - -bool MQClientFactory::isBrokerAddressInUse(const std::string& address) { - if (m_topicRouteTableMutex.try_lock()) { - boost::lock_guard lk(m_topicRouteTableMutex, boost::adopt_lock_t()); - for (TRDMAP::iterator it = m_topicRouteTable.begin(); it != m_topicRouteTable.end(); it++) { - TopicRouteData* topicRouteData = it->second; - vector& brokerData = topicRouteData->getBrokerDatas(); - for (vector::iterator next = brokerData.begin(); next != brokerData.end(); next++) { - map& brokerAddresses = next->brokerAddrs; - for (map::iterator entry = brokerAddresses.begin(); entry != brokerAddresses.end(); entry++) { - if (address == entry->second) { - return true; - } - } - } - } - return false; - } else { - LOG_WARN("Cannot lock m_topicRouteTableMutex. Assume %s is still in use", address.c_str()); - return true; - } -} -void MQClientFactory::addBrokerToAddrMap(const string& brokerName, map& brokerAddrs) { - boost::lock_guard lock(m_brokerAddrlock); - if (m_brokerAddrTable.find(brokerName) != m_brokerAddrTable.end()) { - m_brokerAddrTable.erase(brokerName); - } - m_brokerAddrTable[brokerName] = brokerAddrs; -} - -MQClientFactory::BrokerAddrMAP MQClientFactory::getBrokerAddrMap() { - boost::lock_guard lock(m_brokerAddrlock); - return m_brokerAddrTable; -} - -string MQClientFactory::findBrokerAddressInPublish(const string& brokerName) { - /*reslove the concurrent access m_brokerAddrTable by - findBrokerAddressInPublish(called by sendKernlImpl) And - sendHeartbeatToAllBroker, which leads hign RT of sendMsg - 1. change m_brokerAddrTable from hashMap to map; - 2. do not add m_factoryLock here, but copy m_brokerAddrTable, - this is used to avoid con-current access m_factoryLock by - findBrokerAddressInPublish(called by sendKernlImpl) And - updateTopicRouteInfoFromNameServer - - Note: after copying m_brokerAddrTable, updateTopicRouteInfoFromNameServer - modify m_brokerAddrTable imediatly, - after 1st send fail, producer will get topicPushlibshInfo again - before next try, so 2nd try will get correct broker to send ms; - */ - BrokerAddrMAP brokerTable(getBrokerAddrMap()); - string brokerAddr; - bool found = false; - - if (brokerTable.find(brokerName) != brokerTable.end()) { - map brokerMap(brokerTable[brokerName]); - map::iterator it1 = brokerMap.find(MASTER_ID); - if (it1 != brokerMap.end()) { - brokerAddr = it1->second; - found = true; - } - } - - brokerTable.clear(); - if (found) - return brokerAddr; - - return ""; -} - -FindBrokerResult* MQClientFactory::findBrokerAddressInSubscribe(const string& brokerName, - int brokerId, - bool onlyThisBroker) { - string brokerAddr; - bool slave = false; - bool found = false; - BrokerAddrMAP brokerTable(getBrokerAddrMap()); - - if (brokerTable.find(brokerName) != brokerTable.end()) { - map brokerMap(brokerTable[brokerName]); - if (!brokerMap.empty()) { - auto iter = brokerMap.find(brokerId); - if (iter != brokerMap.end()) { - brokerAddr = iter->second; - slave = (brokerId != MASTER_ID); - found = true; - } else if (!onlyThisBroker) { // not only from master - iter = brokerMap.begin(); - brokerAddr = iter->second; - slave = iter->first != MASTER_ID; - found = true; - } - } - } - - brokerTable.clear(); - - if (found) { - return new FindBrokerResult(brokerAddr, slave); - } - - return nullptr; -} - -FindBrokerResult* MQClientFactory::findBrokerAddressInAdmin(const string& brokerName) { - BrokerAddrMAP brokerTable(getBrokerAddrMap()); - bool found = false; - bool slave = false; - string brokerAddr; - - if (brokerTable.find(brokerName) != brokerTable.end()) { - map brokerMap(brokerTable[brokerName]); - map::iterator it1 = brokerMap.begin(); - if (it1 != brokerMap.end()) { - slave = (it1->first != MASTER_ID); - found = true; - brokerAddr = it1->second; - } - } - - brokerTable.clear(); - if (found) - return new FindBrokerResult(brokerAddr, slave); - - return NULL; -} - -void MQClientFactory::checkTransactionState(const std::string& addr, - const MQMessageExt& messageExt, - const CheckTransactionStateRequestHeader& checkRequestHeader) { - string group = messageExt.getProperty(MQMessage::PROPERTY_PRODUCER_GROUP); - if (!group.empty()) { - MQProducer* producer = selectProducer(group); - if (producer != nullptr) { - TransactionMQProducerImpl* transProducer = dynamic_cast(producer); - if (transProducer != nullptr) { - transProducer->checkTransactionState(addr, messageExt, checkRequestHeader.m_tranStateTableOffset, - checkRequestHeader.m_commitLogOffset, checkRequestHeader.m_msgId, - checkRequestHeader.m_transactionId, checkRequestHeader.m_offsetMsgId); - } else { - LOG_ERROR("checkTransactionState, producer not TransactionMQProducer failed, msg:%s", - messageExt.toString().data()); - } - } else { - LOG_ERROR("checkTransactionState, pick producer by group[%s] failed, msg:%s", group.data(), - messageExt.toString().data()); - } - } else { - LOG_ERROR("checkTransactionState, pick producer group failed, msg:%s", messageExt.toString().data()); - } -} - -MQClientAPIImpl* MQClientFactory::getMQClientAPIImpl() { - return m_pClientAPIImpl.get(); -} - -void MQClientFactory::cleanOfflineBrokers() { - LOG_DEBUG("Begin to clean offline brokers"); - boost::lock_guard lock(m_brokerAddrlock); - - for (BrokerAddrMAP::iterator it = m_brokerAddrTable.begin(); it != m_brokerAddrTable.end();) { - std::string brokerName = it->first; - map brokerIdAddressMap = it->second; - - for (map::iterator next = brokerIdAddressMap.begin(); next != brokerIdAddressMap.end();) { - if (!isBrokerAddressInUse(next->second)) { - LOG_INFO("Remove broker address: %s", (next->second).c_str()); - brokerIdAddressMap.erase(next++); - } else { - next++; - } - } - - if (brokerIdAddressMap.empty()) { - m_brokerAddrTable.erase(it++); - LOG_INFO("Broker name: %s is purged from client", brokerName.c_str()); - } else { - LOG_DEBUG("Broker: %s is alive", brokerName.c_str()); - it++; - } - } - - LOG_DEBUG("Exit of cleaning offline brokers"); -} - -void MQClientFactory::sendHeartbeatToAllBroker() { - BrokerAddrMAP brokerTable(getBrokerAddrMap()); - if (brokerTable.size() == 0) { - LOG_WARN("sendheartbeat brokeradd is empty"); - return; - } - - unique_ptr heartbeatData(prepareHeartbeatData()); - bool producerEmpty = heartbeatData->isProducerDataSetEmpty(); - bool consumerEmpty = heartbeatData->isConsumerDataSetEmpty(); - if (producerEmpty && consumerEmpty) { - LOG_WARN("sendheartbeat heartbeatData empty"); - brokerTable.clear(); - return; - } - - SessionCredentials session_credentials; - getSessionCredentialsFromOneOfProducerOrConsumer(session_credentials); - for (BrokerAddrMAP::iterator it = brokerTable.begin(); it != brokerTable.end(); ++it) { - map brokerMap(it->second); - map::iterator it1 = brokerMap.begin(); - for (; it1 != brokerMap.end(); ++it1) { - string& addr = it1->second; - if (consumerEmpty && it1->first != MASTER_ID) - continue; - - try { - m_pClientAPIImpl->sendHeartbeat(addr, heartbeatData.get(), session_credentials); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - } - } - } - brokerTable.clear(); -} - -void MQClientFactory::persistAllConsumerOffset(boost::system::error_code& ec, - boost::shared_ptr t) { - { - boost::lock_guard lock(m_consumerTableMutex); - if (m_consumerTable.size() > 0) { - for (MQCMAP::iterator it = m_consumerTable.begin(); it != m_consumerTable.end(); ++it) { - LOG_DEBUG("Client factory start persistAllConsumerOffset"); - it->second->persistConsumerOffset(); - } - } - } - - boost::system::error_code e; - t->expires_from_now(t->expires_from_now() + boost::posix_time::seconds(5), e); - t->async_wait(boost::bind(&MQClientFactory::persistAllConsumerOffset, this, ec, t)); -} - -HeartbeatData* MQClientFactory::prepareHeartbeatData() { - HeartbeatData* pHeartbeatData = new HeartbeatData(); - // clientID - pHeartbeatData->setClientID(m_clientId); - - // Consumer - insertConsumerInfoToHeartBeatData(pHeartbeatData); - - // Producer - insertProducerInfoToHeartBeatData(pHeartbeatData); - - return pHeartbeatData; -} - -void MQClientFactory::timerCB_sendHeartbeatToAllBroker(boost::system::error_code& ec, - boost::shared_ptr t) { - sendHeartbeatToAllBroker(); - - boost::system::error_code e; - t->expires_from_now(t->expires_from_now() + boost::posix_time::seconds(30), e); - t->async_wait(boost::bind(&MQClientFactory::timerCB_sendHeartbeatToAllBroker, this, ec, t)); -} - -void MQClientFactory::timerCB_cleanOfflineBrokers(boost::system::error_code& ec, - boost::shared_ptr t) { - cleanOfflineBrokers(); - - boost::system::error_code e; - t->expires_from_now(t->expires_from_now() + boost::posix_time::seconds(30), e); - t->async_wait(boost::bind(&MQClientFactory::timerCB_cleanOfflineBrokers, this, ec, t)); -} - -void MQClientFactory::fetchNameServerAddr(boost::system::error_code& ec, - boost::shared_ptr t) { - m_pClientAPIImpl->fetchNameServerAddr(m_nameSrvDomain); - - boost::system::error_code e; - t->expires_from_now(t->expires_from_now() + boost::posix_time::seconds(60 * 2), e); - t->async_wait(boost::bind(&MQClientFactory::fetchNameServerAddr, this, ec, t)); -} - -void MQClientFactory::startScheduledTask(bool startFetchNSService) { - boost::asio::io_service::work work(m_async_ioService); // avoid async io - // service stops after - // first timer timeout - // callback - - boost::system::error_code ec1; - boost::shared_ptr t1 = - boost::make_shared(m_async_ioService, boost::posix_time::seconds(3)); - t1->async_wait(boost::bind(&MQClientFactory::updateTopicRouteInfo, this, ec1, t1)); - - boost::system::error_code ec2; - boost::shared_ptr t2 = - boost::make_shared(m_async_ioService, boost::posix_time::milliseconds(10)); - t2->async_wait(boost::bind(&MQClientFactory::timerCB_sendHeartbeatToAllBroker, this, ec2, t2)); - - boost::system::error_code ec3; - boost::shared_ptr t3 = - boost::make_shared(m_async_ioService, boost::posix_time::seconds(3)); - t3->async_wait(boost::bind(&MQClientFactory::timerCB_cleanOfflineBrokers, this, ec3, t3)); - - if (startFetchNSService) { - boost::system::error_code ec5; - boost::shared_ptr t5 = - boost::make_shared(m_async_ioService, boost::posix_time::seconds(60 * 2)); - t5->async_wait(boost::bind(&MQClientFactory::fetchNameServerAddr, this, ec5, t5)); - } - - LOG_INFO("start scheduled task:%s", m_clientId.c_str()); - boost::system::error_code ec; - m_async_ioService.run(ec); -} - -void MQClientFactory::rebalanceImmediately() { - // m_consumer_async_service_thread will be only started once for all consumer - if (m_consumer_async_service_thread == NULL) { - doRebalance(); - m_consumer_async_service_thread.reset( - new boost::thread(boost::bind(&MQClientFactory::consumer_timerOperation, this))); - } -} - -void MQClientFactory::consumer_timerOperation() { - LOG_INFO("clientFactory:%s start consumer_timerOperation", m_clientId.c_str()); - boost::asio::io_service::work work(m_consumer_async_ioService); // avoid async io - // service stops after - // first timer timeout - // callback - - boost::system::error_code ec1; - boost::shared_ptr t1 = - boost::make_shared(m_consumer_async_ioService, boost::posix_time::seconds(10)); - t1->async_wait(boost::bind(&MQClientFactory::timerCB_doRebalance, this, ec1, t1)); - - boost::system::error_code ec2; - boost::shared_ptr t2 = - boost::make_shared(m_consumer_async_ioService, boost::posix_time::seconds(5)); - t2->async_wait(boost::bind(&MQClientFactory::persistAllConsumerOffset, this, ec2, t2)); - - boost::system::error_code ec; - m_consumer_async_ioService.run(ec); - LOG_INFO("clientFactory:%s stop consumer_timerOperation", m_clientId.c_str()); -} - -void MQClientFactory::timerCB_doRebalance(boost::system::error_code& ec, - boost::shared_ptr t) { - doRebalance(); - - boost::system::error_code e; - t->expires_from_now(t->expires_from_now() + boost::posix_time::seconds(10), e); - t->async_wait(boost::bind(&MQClientFactory::timerCB_doRebalance, this, ec, t)); -} - -void MQClientFactory::doRebalance() { - LOG_DEBUG("Client factory:%s start doRebalance", m_clientId.c_str()); - if (getConsumerTableSize() > 0) { - boost::lock_guard lock(m_consumerTableMutex); - for (MQCMAP::iterator it = m_consumerTable.begin(); it != m_consumerTable.end(); ++it) { - it->second->doRebalance(); - } - } - LOG_DEBUG("Client factory:%s finish doRebalance", m_clientId.c_str()); -} - -void MQClientFactory::doRebalanceByConsumerGroup(const string& consumerGroup) { - boost::lock_guard lock(m_consumerTableMutex); - if (m_consumerTable.find(consumerGroup) != m_consumerTable.end()) { - LOG_INFO("Client factory:%s start dorebalance for consumer:%s", m_clientId.c_str(), consumerGroup.c_str()); - MQConsumer* pMQConsumer = m_consumerTable[consumerGroup]; - pMQConsumer->doRebalance(); - } -} - -void MQClientFactory::endTransactionOneway(const MQMessageQueue& mq, - EndTransactionRequestHeader* requestHeader, - const SessionCredentials& sessionCredentials) { - string brokerAddr = findBrokerAddressInPublish(mq.getBrokerName()); - string remark = ""; - if (!brokerAddr.empty()) { - try { - getMQClientAPIImpl()->endTransactionOneway(brokerAddr, requestHeader, remark, sessionCredentials); - } catch (MQException& e) { - LOG_ERROR("endTransactionOneway exception:%s", e.what()); - throw e; - } - } else { - THROW_MQEXCEPTION(MQClientException, "The broker[" + mq.getBrokerName() + "] not exist", -1); - } -} - -void MQClientFactory::unregisterClient(const string& producerGroup, - const string& consumerGroup, - const SessionCredentials& sessionCredentials) { - BrokerAddrMAP brokerTable(getBrokerAddrMap()); - for (BrokerAddrMAP::iterator it = brokerTable.begin(); it != brokerTable.end(); ++it) { - map brokerMap(it->second); - map::iterator it1 = brokerMap.begin(); - for (; it1 != brokerMap.end(); ++it1) { - string& addr = it1->second; - m_pClientAPIImpl->unregisterClient(addr, m_clientId, producerGroup, consumerGroup, sessionCredentials); - } - } -} - -//& mqs, - const SessionCredentials& sessionCredentials) { - TopicRouteData* pTopicRouteData = getTopicRouteData(topic); - if (pTopicRouteData == NULL) { - updateTopicRouteInfoFromNameServer(topic, sessionCredentials); - pTopicRouteData = getTopicRouteData(topic); - } - if (pTopicRouteData != NULL) { - topicRouteData2TopicSubscribeInfo(topic, pTopicRouteData, mqs); - if (mqs.empty()) { - THROW_MQEXCEPTION(MQClientException, "Can not find Message Queue", -1); - } - return; - } - THROW_MQEXCEPTION(MQClientException, "Can not find Message Queue", -1); -} - -//getMinOffset(brokerAddr, mq.getTopic(), mq.getQueueId(), 1000 * 3, sessionCredentials); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - } - } - THROW_MQEXCEPTION(MQClientException, "The broker is not exist", -1); -} - -int64 MQClientFactory::maxOffset(const MQMessageQueue& mq, const SessionCredentials& sessionCredentials) { - string brokerAddr = findBrokerAddressInPublish(mq.getBrokerName()); - if (brokerAddr.empty()) { - updateTopicRouteInfoFromNameServer(mq.getTopic(), sessionCredentials); - brokerAddr = findBrokerAddressInPublish(mq.getBrokerName()); - } - - if (!brokerAddr.empty()) { - try { - return m_pClientAPIImpl->getMaxOffset(brokerAddr, mq.getTopic(), mq.getQueueId(), 1000 * 3, sessionCredentials); - } catch (MQException& e) { - THROW_MQEXCEPTION(MQClientException, "Invoke Broker exception", -1); - } - } - THROW_MQEXCEPTION(MQClientException, "The broker is not exist", -1); -} - -int64 MQClientFactory::searchOffset(const MQMessageQueue& mq, - int64 timestamp, - const SessionCredentials& sessionCredentials) { - string brokerAddr = findBrokerAddressInPublish(mq.getBrokerName()); - if (brokerAddr.empty()) { - updateTopicRouteInfoFromNameServer(mq.getTopic(), sessionCredentials); - brokerAddr = findBrokerAddressInPublish(mq.getBrokerName()); - } - - if (!brokerAddr.empty()) { - try { - return m_pClientAPIImpl->searchOffset(brokerAddr, mq.getTopic(), mq.getQueueId(), timestamp, 1000 * 3, - sessionCredentials); - } catch (MQException& e) { - THROW_MQEXCEPTION(MQClientException, "Invoke Broker exception", -1); - } - } - THROW_MQEXCEPTION(MQClientException, "The broker is not exist", -1); -} - -MQMessageExt* MQClientFactory::viewMessage(const string& msgId, const SessionCredentials& sessionCredentials) { - try { - return NULL; - } catch (MQException& e) { - THROW_MQEXCEPTION(MQClientException, "message id illegal", -1); - } -} - -int64 MQClientFactory::earliestMsgStoreTime(const MQMessageQueue& mq, const SessionCredentials& sessionCredentials) { - string brokerAddr = findBrokerAddressInPublish(mq.getBrokerName()); - if (brokerAddr.empty()) { - updateTopicRouteInfoFromNameServer(mq.getTopic(), sessionCredentials); - brokerAddr = findBrokerAddressInPublish(mq.getBrokerName()); - } - - if (!brokerAddr.empty()) { - try { - return m_pClientAPIImpl->getEarliestMsgStoretime(brokerAddr, mq.getTopic(), mq.getQueueId(), 1000 * 3, - sessionCredentials); - } catch (MQException& e) { - THROW_MQEXCEPTION(MQClientException, "Invoke Broker exception", -1); - } - } - THROW_MQEXCEPTION(MQClientException, "The broker is not exist", -1); -} - -QueryResult MQClientFactory::queryMessage(const string& topic, - const string& key, - int maxNum, - int64 begin, - int64 end, - const SessionCredentials& sessionCredentials) { - THROW_MQEXCEPTION(MQClientException, "queryMessage", -1); -} - -void MQClientFactory::findConsumerIds(const string& topic, - const string& group, - vector& cids, - const SessionCredentials& sessionCredentials) { - string brokerAddr; - TopicRouteData* pTopicRouteData = getTopicRouteData(topic); - if (pTopicRouteData == NULL) { - updateTopicRouteInfoFromNameServer(topic, sessionCredentials); - pTopicRouteData = getTopicRouteData(topic); - } - if (pTopicRouteData != NULL) { - brokerAddr = pTopicRouteData->selectBrokerAddr(); - } - - if (!brokerAddr.empty()) { - try { - LOG_INFO("getConsumerIdList from broker:%s", brokerAddr.c_str()); - return m_pClientAPIImpl->getConsumerIdListByGroup(brokerAddr, group, cids, 5000, sessionCredentials); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - } - } -} - -void MQClientFactory::resetOffset(const string& group, - const string& topic, - const map& offsetTable) { - MQConsumer* pConsumer = selectConsumer(group); - if (pConsumer) { - map::const_iterator it = offsetTable.begin(); - - for (; it != offsetTable.end(); ++it) { - MQMessageQueue mq = it->first; - boost::weak_ptr pullRequest = pConsumer->getRebalance()->getPullRequest(mq); - boost::shared_ptr pullreq = pullRequest.lock(); - // PullRequest* pullreq = pConsumer->getRebalance()->getPullRequest(mq); - if (pullreq) { - pullreq->setDropped(true); - LOG_INFO("resetOffset setDropped for mq:%s", mq.toString().data()); - pullreq->clearAllMsgs(); - pullreq->updateQueueMaxOffset(it->second); - } else { - LOG_ERROR("no corresponding pullRequest found for topic:%s", topic.c_str()); - } - } - - for (it = offsetTable.begin(); it != offsetTable.end(); ++it) { - MQMessageQueue mq = it->first; - if (topic == mq.getTopic()) { - LOG_INFO("offset sets to:%lld", it->second); - pConsumer->updateConsumeOffset(mq, it->second); - } - } - pConsumer->persistConsumerOffsetByResetOffset(); - - boost::this_thread::sleep_for(boost::chrono::milliseconds(10)); - - for (it = offsetTable.begin(); it != offsetTable.end(); ++it) { - MQMessageQueue mq = it->first; - if (topic == mq.getTopic()) { - LOG_DEBUG("resetOffset sets to:%lld for mq:%s", it->second, mq.toString().c_str()); - pConsumer->updateConsumeOffset(mq, it->second); - } - } - pConsumer->persistConsumerOffsetByResetOffset(); - - for (it = offsetTable.begin(); it != offsetTable.end(); ++it) { - MQMessageQueue mq = it->first; - if (topic == mq.getTopic()) { - pConsumer->removeConsumeOffset(mq); - } - } - - // do call pConsumer->doRebalance directly here, as it is conflict with - // timerCB_doRebalance; - doRebalanceByConsumerGroup(pConsumer->getGroupName()); - } else { - LOG_ERROR("no corresponding consumer found for group:%s", group.c_str()); - } -} - -ConsumerRunningInfo* MQClientFactory::consumerRunningInfo(const string& consumerGroup) { - MQConsumer* pConsumer = selectConsumer(consumerGroup); - if (pConsumer) { - ConsumerRunningInfo* runningInfo = pConsumer->getConsumerRunningInfo(); - if (runningInfo) { - runningInfo->setProperty(ConsumerRunningInfo::PROP_NAMESERVER_ADDR, pConsumer->getNamesrvAddr()); - if (pConsumer->getConsumeType() == CONSUME_PASSIVELY) { - runningInfo->setProperty(ConsumerRunningInfo::PROP_CONSUME_TYPE, "CONSUME_PASSIVELY"); - } else { - runningInfo->setProperty(ConsumerRunningInfo::PROP_CONSUME_TYPE, "CONSUME_ACTIVELY"); - } - runningInfo->setProperty( - ConsumerRunningInfo::PROP_CLIENT_VERSION, - MQVersion::GetVersionDesc(MQVersion::s_CurrentVersion)); // MQVersion::s_CurrentVersion )); - runningInfo->setProperty(ConsumerRunningInfo::PROP_CLIENT_SDK_VERSION, - pConsumer->getClientVersionString()); // in DefaultMQClient.cpp; - - return runningInfo; - } - } - - LOG_ERROR("no corresponding consumer found for group:%s", consumerGroup.c_str()); - return NULL; -} - -void MQClientFactory::getSessionCredentialsFromOneOfProducerOrConsumer(SessionCredentials& session_credentials) { - // Note: on the same MQClientFactory, all producers and consumers used the - // same - // sessionCredentials, - // So only need get sessionCredentials from the first one producer or consumer - // now. - // this function was only used by updateTopicRouteInfo() and - // sendHeartbeatToAllBrokers() now. - // if this strategy was changed in future, need get sessionCredentials for - // each - // producer and consumer. - getSessionCredentialFromProducerTable(session_credentials); - if (!session_credentials.isValid()) - getSessionCredentialFromConsumerTable(session_credentials); - - if (!session_credentials.isValid()) { - LOG_INFO( - "updateTopicRouteInfo: didn't get the session_credentials from any " - "producers and consumers, please re-intialize it if application needs authentication"); - } -} - -// -#include -#include -#include -#include -#include -#include "FindBrokerResult.h" -#include "MQAdmin.h" -#include "MQClientAPIImpl.h" -#include "MQClientException.h" -#include "MQConsumer.h" -#include "MQDecoder.h" -#include "MQMessageQueue.h" -#include "MQProducer.h" -#include "PermName.h" -#include "QueryResult.h" -#include "ServiceState.h" -#include "SocketUtil.h" -#include "TopicConfig.h" -#include "TopicRouteData.h" - -namespace rocketmq { -// topicRouteData2TopicPublishInfo(const string& topic, TopicRouteData* pRoute); - - void topicRouteData2TopicSubscribeInfo(const string& topic, TopicRouteData* pRoute, vector& mqs); - - FindBrokerResult* findBrokerAddressInSubscribe(const string& brokerName, int brokerId, bool onlyThisBroker); - - FindBrokerResult* findBrokerAddressInAdmin(const string& brokerName); - - virtual string findBrokerAddressInPublish(const string& brokerName); - - virtual boost::shared_ptr tryToFindTopicPublishInfo(const string& topic, - const SessionCredentials& session_credentials); - - void fetchSubscribeMessageQueues(const string& topic, - vector& mqs, - const SessionCredentials& session_credentials); - - bool updateTopicRouteInfoFromNameServer(const string& topic, - const SessionCredentials& session_credentials, - bool isDefault = false); - void rebalanceImmediately(); - void doRebalanceByConsumerGroup(const string& consumerGroup); - virtual void sendHeartbeatToAllBroker(); - - void cleanOfflineBrokers(); - - void findConsumerIds(const string& topic, - const string& group, - vector& cids, - const SessionCredentials& session_credentials); - void resetOffset(const string& group, const string& topic, const map& offsetTable); - ConsumerRunningInfo* consumerRunningInfo(const string& consumerGroup); - bool getSessionCredentialFromConsumer(const string& consumerGroup, SessionCredentials& sessionCredentials); - void addBrokerToAddrMap(const string& brokerName, map& brokerAddrs); - map> getBrokerAddrMap(); - void clearBrokerAddrMap(); - - bool isBrokerAddressInUse(const std::string& address); - - private: - void unregisterClient(const string& producerGroup, - const string& consumerGroup, - const SessionCredentials& session_credentials); - TopicRouteData* getTopicRouteData(const string& topic); - void addTopicRouteData(const string& topic, TopicRouteData* pTopicRouteData); - HeartbeatData* prepareHeartbeatData(); - - void startScheduledTask(bool startFetchNSService = true); - // t); - void updateTopicRouteInfo(boost::system::error_code& ec, boost::shared_ptr t); - void timerCB_sendHeartbeatToAllBroker(boost::system::error_code& ec, - boost::shared_ptr t); - - void timerCB_cleanOfflineBrokers(boost::system::error_code& ec, boost::shared_ptr t); - - // consumer related operation - void consumer_timerOperation(); - void persistAllConsumerOffset(boost::system::error_code& ec, boost::shared_ptr t); - void doRebalance(); - void timerCB_doRebalance(boost::system::error_code& ec, boost::shared_ptr t); - bool getSessionCredentialFromConsumerTable(SessionCredentials& sessionCredentials); - void eraseConsumerFromTable(const string& consumerName); - int getConsumerTableSize(); - void getTopicListFromConsumerSubscription(set& topicList); - void updateConsumerSubscribeTopicInfo(const string& topic, vector mqs); - void insertConsumerInfoToHeartBeatData(HeartbeatData* pHeartbeatData); - - // producer related operation - bool getSessionCredentialFromProducerTable(SessionCredentials& sessionCredentials); - void eraseProducerFromTable(const string& producerName); - int getProducerTableSize(); - void insertProducerInfoToHeartBeatData(HeartbeatData* pHeartbeatData); - - // admin related operation - void eraseAdminFromTable(const string& adminName); - - // topicPublishInfo related operation - void addTopicInfoToTable(const string& topic, boost::shared_ptr pTopicPublishInfo); - void eraseTopicInfoFromTable(const string& topic); - bool isTopicInfoValidInTable(const string& topic); - boost::shared_ptr getTopicPublishInfoFromTable(const string& topic); - void getTopicListFromTopicPublishInfo(set& topicList); - - void getSessionCredentialsFromOneOfProducerOrConsumer(SessionCredentials& session_credentials); - - protected: - string m_clientId; - unique_ptr m_pClientAPIImpl; - unique_ptr m_pClientRemotingProcessor; - - bool addProducerToTable(const string& producerName, MQProducer* pMQProducer); - bool addConsumerToTable(const string& consumerName, MQConsumer* pMQConsumer); - bool addAdminToTable(const string& adminName, MQAdmin* pMQAdmin); - - private: - string m_nameSrvDomain; // per clientId - ServiceState m_serviceState; - bool m_bFetchNSService; - - // MQProducer; - typedef map MQPMAP; - boost::mutex m_producerTableMutex; - MQPMAP m_producerTable; - - // MQConsumer; - typedef map MQCMAP; - // Changed to recursive mutex due to avoid deadlock issue: - boost::recursive_mutex m_consumerTableMutex; - MQCMAP m_consumerTable; - - // MQAdmin; - typedef map MQAMAP; - // Changed to recursive mutex due to avoid deadlock issue: - boost::recursive_mutex m_adminTableMutex; - MQAMAP m_adminTable; - - // TopicRouteData - typedef map TRDMAP; - boost::mutex m_topicRouteTableMutex; - TRDMAP m_topicRouteTable; - - //TopicPublishInfo> ; - typedef map> TPMap; - boost::mutex m_topicPublishInfoTableMutex; - TPMap m_topicPublishInfoTable; - boost::mutex m_factoryLock; - boost::mutex m_topicPublishInfoLock; - - boost::asio::io_service m_async_ioService; - unique_ptr m_async_service_thread; - - boost::asio::io_service m_consumer_async_ioService; - unique_ptr m_consumer_async_service_thread; -}; - -} // namespace rocketmq - -#endif diff --git a/src/MQClientManager.cpp b/src/MQClientManager.cpp deleted file mode 100644 index ad821119a..000000000 --- a/src/MQClientManager.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "MQClientManager.h" -#include "Logging.h" -#include -#include - -namespace rocketmq { -//second; - } else { - MQClientFactory* factory = new MQClientFactory(clientId, pullThreadNum, tcpConnectTimeout, - tcpTransportTryLockTimeout, unitName, enableSsl, sslPropertyFile); - m_factoryTable[clientId] = factory; - return factory; - } -} - -void MQClientManager::removeClientFactory(const string& clientId) { - FTMAP::iterator it = m_factoryTable.find(clientId); - if (it != m_factoryTable.end()) { - deleteAndZero(it->second); - m_factoryTable.erase(it); - } -} -// -#include -#include "Logging.h" -#include "MQClientFactory.h" - -namespace rocketmq { -// FTMAP; - FTMAP m_factoryTable; -}; - -//registerMQAdmin(this); - if (!registerOK) { - m_serviceState = CREATE_JUST; - THROW_MQEXCEPTION( - MQClientException, - "The admin group[" + getGroupName() + "] has been created before, specify another name please.", -1); - } - getFactory()->start(); - m_serviceState = RUNNING; - break; - } - case RUNNING: - case START_FAILED: - case SHUTDOWN_ALREADY: - break; - default: - break; - } -} - -void DefaultMQAdmin::shutdown() { - switch (m_serviceState) { - case RUNNING: { - LOG_INFO("DefaultMQAdmin:%s shutdown", m_GroupName.c_str()); - getFactory()->unregisterMQAdmin(this); - getFactory()->shutdown(); - m_serviceState = SHUTDOWN_ALREADY; - break; - } - case SHUTDOWN_ALREADY: - case CREATE_JUST: - break; - default: - break; - } -} -} // namespace rocketmq \ No newline at end of file diff --git a/src/client/DefaultMQAdmin.h b/src/client/DefaultMQAdmin.h deleted file mode 100644 index baa7e0f5b..000000000 --- a/src/client/DefaultMQAdmin.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef DEFAULTMQADMIN_H -#define DEFAULTMQADMIN_H -#include "MQAdmin.h" -#include "MQClientFactory.h" - -namespace rocketmq { -class DefaultMQAdmin : public MQAdmin { - public: - DefaultMQAdmin(const std::string& groupname); - ~DefaultMQAdmin(); - void start(); - void shutdown(); -}; -}; // namespace rocketmq -#endif // DEFAULTMQADMIN_H \ No newline at end of file diff --git a/src/common/Arg_helper.cpp b/src/common/Arg_helper.cpp deleted file mode 100644 index 934954e74..000000000 --- a/src/common/Arg_helper.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Arg_helper.h" -#include "UtilAll.h" - -namespace rocketmq { -// v; - UtilAll::Split(v, arg_str_, " "); - m_args.insert(m_args.end(), v.begin(), v.end()); -} - -string Arg_helper::get_option(int idx_) const { - if ((size_t)idx_ >= m_args.size()) { - return ""; - } - return m_args[idx_]; -} - -bool Arg_helper::is_enable_option(string opt_) const { - for (size_t i = 0; i < m_args.size(); ++i) { - if (opt_ == m_args[i]) { - return true; - } - } - return false; -} - -string Arg_helper::get_option_value(string opt_) const { - string ret = ""; - for (size_t i = 0; i < m_args.size(); ++i) { - if (opt_ == m_args[i]) { - size_t value_idx = ++i; - if (value_idx >= m_args.size()) { - return ret; - } - ret = m_args[value_idx]; - return ret; - } - } - return ret; -} - -//(m_pAsyncCallBack); - if (pCallback) { - unique_ptr exception( - new MQException("send msg failed due to wait response timeout or network error", -1, __FILE__, __LINE__)); - pCallback->onException(*exception); - if (pCallback->getSendCallbackType() == autoDeleteSendCallback) { - deleteAndZero(pCallback); - } - } -} - -void SendCallbackWrap::operationComplete(ResponseFuture* pResponseFuture, bool bProducePullRequest) { - unique_ptr pResponse(pResponseFuture->getCommand()); - - if (m_pAsyncCallBack == NULL) { - return; - } - int opaque = pResponseFuture->getOpaque(); - SendCallback* pCallback = static_cast(m_pAsyncCallBack); - - if (!pResponse) { - string err = "unknow reseaon"; - if (!pResponseFuture->isSendRequestOK()) { - err = "send request failed"; - - } else if (pResponseFuture->isTimeOut()) { - // pResponseFuture->setAsyncResponseFlag(); - err = "wait response timeout"; - } - if (pCallback) { - MQException exception(err, -1, __FILE__, __LINE__); - pCallback->onException(exception); - } - LOG_ERROR("send failed of:%d", pResponseFuture->getOpaque()); - } else { - try { - SendResult ret = m_pClientAPI->processSendResponse(m_brokerName, m_msg, pResponse.get()); - if (pCallback) { - LOG_DEBUG("operationComplete: processSendResponse success, opaque:%d, maxRetryTime:%d, retrySendTimes:%d", - opaque, pResponseFuture->getMaxRetrySendTimes(), pResponseFuture->getRetrySendTimes()); - pCallback->onSuccess(ret); - } - } catch (MQException& e) { - LOG_ERROR("operationComplete: processSendResponse exception: %s", e.what()); - - // broker may return exception, need consider retry send - int maxRetryTimes = pResponseFuture->getMaxRetrySendTimes(); - int retryTimes = pResponseFuture->getRetrySendTimes(); - if (pResponseFuture->getAsyncFlag() && retryTimes < maxRetryTimes && maxRetryTimes > 1) { - int64 left_timeout_ms = pResponseFuture->leftTime(); - string brokerAddr = pResponseFuture->getBrokerAddr(); - const RemotingCommand& requestCommand = pResponseFuture->getRequestCommand(); - retryTimes += 1; - LOG_WARN("retry send, opaque:%d, sendTimes:%d, maxRetryTimes:%d, left_timeout:%lld, brokerAddr:%s, msg:%s", - opaque, retryTimes, maxRetryTimes, left_timeout_ms, brokerAddr.data(), m_msg.toString().data()); - - bool exception_flag = false; - try { - m_pClientAPI->sendMessageAsync(pResponseFuture->getBrokerAddr(), m_brokerName, m_msg, - (RemotingCommand&)requestCommand, pCallback, left_timeout_ms, maxRetryTimes, - retryTimes); - } catch (MQClientException& e) { - LOG_ERROR("retry send exception:%s, opaque:%d, retryTimes:%d, msg:%s, not retry send again", e.what(), opaque, - retryTimes, m_msg.toString().data()); - exception_flag = true; - } - - if (exception_flag == false) { - return; // send retry again, here need return - } - } - - if (pCallback) { - MQException exception("process send response error", -1, __FILE__, __LINE__); - pCallback->onException(exception); - } - } - } - if (pCallback && pCallback->getSendCallbackType() == autoDeleteSendCallback) { - deleteAndZero(pCallback); - } -} - -//(pArg); -} - -PullCallbackWrap::~PullCallbackWrap() {} - -void PullCallbackWrap::onException() { - if (m_pAsyncCallBack == NULL) - return; - - PullCallback* pCallback = static_cast(m_pAsyncCallBack); - if (pCallback) { - MQException exception("wait response timeout", -1, __FILE__, __LINE__); - pCallback->onException(exception); - } else { - LOG_ERROR("PullCallback is NULL, AsyncPull could not continue"); - } -} - -void PullCallbackWrap::operationComplete(ResponseFuture* pResponseFuture, bool bProducePullRequest) { - unique_ptr pResponse(pResponseFuture->getCommand()); - if (m_pAsyncCallBack == NULL) { - LOG_ERROR("m_pAsyncCallBack is NULL, AsyncPull could not continue"); - return; - } - PullCallback* pCallback = static_cast(m_pAsyncCallBack); - if (!pResponse) { - string err = "unknow reseaon"; - if (!pResponseFuture->isSendRequestOK()) { - err = "send request failed"; - - } else if (pResponseFuture->isTimeOut()) { - // pResponseFuture->setAsyncResponseFlag(); - err = "wait response timeout"; - } - MQException exception(err, -1, __FILE__, __LINE__); - LOG_ERROR("Async pull exception of opaque:%d", pResponseFuture->getOpaque()); - if (pCallback && bProducePullRequest) - pCallback->onException(exception); - } else { - try { - if (m_pArg.pPullWrapper) { - unique_ptr pullResult(m_pClientAPI->processPullResponse(pResponse.get())); - PullResult result = m_pArg.pPullWrapper->processPullResult(m_pArg.mq, pullResult.get(), &m_pArg.subData); - if (pCallback) - pCallback->onSuccess(m_pArg.mq, result, bProducePullRequest); - } else { - LOG_ERROR("pPullWrapper had been destroyed with consumer"); - } - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - MQException exception("pullResult error", -1, __FILE__, __LINE__); - if (pCallback && bProducePullRequest) - pCallback->onException(exception); - } - } -} - -// -#include -#include -#include -#include "RocketMQClient.h" -#include "UtilAll.h" -//============================================================================== -/** Contains static methods for converting the byte order between different - endiannesses. -*/ -namespace rocketmq { - -class ROCKETMQCLIENT_API ByteOrder { - public: - //============================================================================== - /** Swaps the upper and lower bytes of a 16-bit integer. */ - static uint16 swap(uint16 value); - - /** Reverses the order of the 4 bytes in a 32-bit integer. */ - static uint32 swap(uint32 value); - - /** Reverses the order of the 8 bytes in a 64-bit integer. */ - static uint64 swap(uint64 value); - - //============================================================================== - /** Swaps the byte order of a 16-bit int if the CPU is big-endian */ - static uint16 swapIfBigEndian(uint16 value); - - /** Swaps the byte order of a 32-bit int if the CPU is big-endian */ - static uint32 swapIfBigEndian(uint32 value); - - /** Swaps the byte order of a 64-bit int if the CPU is big-endian */ - static uint64 swapIfBigEndian(uint64 value); - - /** Swaps the byte order of a 16-bit int if the CPU is little-endian */ - static uint16 swapIfLittleEndian(uint16 value); - - /** Swaps the byte order of a 32-bit int if the CPU is little-endian */ - static uint32 swapIfLittleEndian(uint32 value); - - /** Swaps the byte order of a 64-bit int if the CPU is little-endian */ - static uint64 swapIfLittleEndian(uint64 value); - - //============================================================================== - /** Turns 4 bytes into a little-endian integer. */ - static uint32 littleEndianInt(const void* bytes); - - /** Turns 8 bytes into a little-endian integer. */ - static uint64 littleEndianInt64(const void* bytes); - - /** Turns 2 bytes into a little-endian integer. */ - static uint16 littleEndianShort(const void* bytes); - - /** Turns 4 bytes into a big-endian integer. */ - static uint32 bigEndianInt(const void* bytes); - - /** Turns 8 bytes into a big-endian integer. */ - static uint64 bigEndianInt64(const void* bytes); - - /** Turns 2 bytes into a big-endian integer. */ - static uint16 bigEndianShort(const void* bytes); - - //============================================================================== - /** Converts 3 little-endian bytes into a signed 24-bit value (which is - * sign-extended to 32 bits). */ - static int littleEndian24Bit(const void* bytes); - - /** Converts 3 big-endian bytes into a signed 24-bit value (which is - * sign-extended to 32 bits). */ - static int bigEndian24Bit(const void* bytes); - - /** Copies a 24-bit number to 3 little-endian bytes. */ - static void littleEndian24BitToChars(int value, void* destBytes); - - /** Copies a 24-bit number to 3 big-endian bytes. */ - static void bigEndian24BitToChars(int value, void* destBytes); - - //============================================================================== - /** Returns true if the current CPU is big-endian. */ - static bool isBigEndian(); -}; - -//============================================================================== - -inline uint16 ByteOrder::swap(uint16 n) { - return static_cast((n << 8) | (n >> 8)); -} - -inline uint32 ByteOrder::swap(uint32 n) { - return (n << 24) | (n >> 24) | ((n & 0xff00) << 8) | ((n & 0xff0000) >> 8); -} - -inline uint64 ByteOrder::swap(uint64 value) { - return (((uint64)swap((uint32)value)) << 32) | swap((uint32)(value >> 32)); -} - -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ //__BYTE_ORDER__ is defined by GCC -inline uint16 ByteOrder::swapIfBigEndian(const uint16 v) { - return v; -} -inline uint32 ByteOrder::swapIfBigEndian(const uint32 v) { - return v; -} -inline uint64 ByteOrder::swapIfBigEndian(const uint64 v) { - return v; -} -inline uint16 ByteOrder::swapIfLittleEndian(const uint16 v) { - return swap(v); -} -inline uint32 ByteOrder::swapIfLittleEndian(const uint32 v) { - return swap(v); -} -inline uint64 ByteOrder::swapIfLittleEndian(const uint64 v) { - return swap(v); -} -inline uint32 ByteOrder::littleEndianInt(const void* const bytes) { - return *static_cast(bytes); -} -inline uint64 ByteOrder::littleEndianInt64(const void* const bytes) { - return *static_cast(bytes); -} -inline uint16 ByteOrder::littleEndianShort(const void* const bytes) { - return *static_cast(bytes); -} -inline uint32 ByteOrder::bigEndianInt(const void* const bytes) { - return swap(*static_cast(bytes)); -} -inline uint64 ByteOrder::bigEndianInt64(const void* const bytes) { - return swap(*static_cast(bytes)); -} -inline uint16 ByteOrder::bigEndianShort(const void* const bytes) { - return swap(*static_cast(bytes)); -} -inline bool ByteOrder::isBigEndian() { - return false; -} -#else -inline uint16 ByteOrder::swapIfBigEndian(const uint16 v) { - return swap(v); -} -inline uint32 ByteOrder::swapIfBigEndian(const uint32 v) { - return swap(v); -} -inline uint64 ByteOrder::swapIfBigEndian(const uint64 v) { - return swap(v); -} -inline uint16 ByteOrder::swapIfLittleEndian(const uint16 v) { - return v; -} -inline uint32 ByteOrder::swapIfLittleEndian(const uint32 v) { - return v; -} -inline uint64 ByteOrder::swapIfLittleEndian(const uint64 v) { - return v; -} -inline uint32 ByteOrder::littleEndianInt(const void* const bytes) { - return swap(*static_cast(bytes)); -} -inline uint64 ByteOrder::littleEndianInt64(const void* const bytes) { - return swap(*static_cast(bytes)); -} -inline uint16 ByteOrder::littleEndianShort(const void* const bytes) { - return swap(*static_cast(bytes)); -} -inline uint32 ByteOrder::bigEndianInt(const void* const bytes) { - return *static_cast(bytes); -} -inline uint64 ByteOrder::bigEndianInt64(const void* const bytes) { - return *static_cast(bytes); -} -inline uint16 ByteOrder::bigEndianShort(const void* const bytes) { - return *static_cast(bytes); -} -inline bool ByteOrder::isBigEndian() { - return true; -} -#endif - -inline int ByteOrder::littleEndian24Bit(const void* const bytes) { - return (((int)static_cast(bytes)[2]) << 16) | (((int)static_cast(bytes)[1]) << 8) | - ((int)static_cast(bytes)[0]); -} -inline int ByteOrder::bigEndian24Bit(const void* const bytes) { - return (((int)static_cast(bytes)[0]) << 16) | (((int)static_cast(bytes)[1]) << 8) | - ((int)static_cast(bytes)[2]); -} -inline void ByteOrder::littleEndian24BitToChars(const int value, void* const destBytes) { - static_cast(destBytes)[0] = (uint8)value; - static_cast(destBytes)[1] = (uint8)(value >> 8); - static_cast(destBytes)[2] = (uint8)(value >> 16); -} -inline void ByteOrder::bigEndian24BitToChars(const int value, void* const destBytes) { - static_cast(destBytes)[0] = (uint8)(value >> 16); - static_cast(destBytes)[1] = (uint8)(value >> 8); - static_cast(destBytes)[2] = (uint8)value; -} -} // namespace rocketmq -#endif // BYTEORDER_H_INCLUDED diff --git a/src/common/ClientRPCHook.cpp b/src/common/ClientRPCHook.cpp deleted file mode 100644 index a8244cf80..000000000 --- a/src/common/ClientRPCHook.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "ClientRPCHook.h" -#include "CommandHeader.h" -#include "Logging.h" -extern "C" { -#include "spas_client.h" -} -#include "string" - -namespace rocketmq { - -const string SessionCredentials::AccessKey = "AccessKey"; -const string SessionCredentials::SecretKey = "SecretKey"; -const string SessionCredentials::Signature = "Signature"; -const string SessionCredentials::SignatureMethod = "SignatureMethod"; -const string SessionCredentials::ONSChannelKey = "OnsChannel"; - -void ClientRPCHook::doBeforeRequest(const string& remoteAddr, RemotingCommand& request) { - CommandHeader* header = request.getCommandHeader(); - - map requestMap; - string totalMsg; - - requestMap.insert(pair(SessionCredentials::AccessKey, sessionCredentials.getAccessKey())); - requestMap.insert(pair(SessionCredentials::ONSChannelKey, sessionCredentials.getAuthChannel())); - - LOG_DEBUG("before insert declared filed,MAP SIZE is:" SIZET_FMT "", requestMap.size()); - if (header != NULL) { - header->SetDeclaredFieldOfCommandHeader(requestMap); - } - LOG_DEBUG("after insert declared filed, MAP SIZE is:" SIZET_FMT "", requestMap.size()); - - map::iterator it = requestMap.begin(); - for (; it != requestMap.end(); ++it) { - totalMsg.append(it->second); - } - const MemoryBlock* pBody = request.GetBody(); - if (pBody && pBody->getSize() > 0) { - const char* msg_body = const_cast(static_cast(pBody->getData())); - LOG_DEBUG("msgBody is:%s, msgBody length is:%d", msg_body, pBody->getSize()); - totalMsg.append(msg_body, pBody->getSize()); - } else if (request.getMsgBody().length() > 0) { - LOG_DEBUG("msgBody is:%s, msgBody length is:" SIZET_FMT "", request.getMsgBody().c_str(), - request.getMsgBody().length()); - totalMsg.append(request.getMsgBody()); - } - LOG_DEBUG("total msg info are:%s, size is:" SIZET_FMT "", totalMsg.c_str(), totalMsg.size()); - char* pSignature = - rocketmqSignature::spas_sign(totalMsg.c_str(), totalMsg.size(), sessionCredentials.getSecretKey().c_str()); - // char *pSignature = spas_sign(totalMsg.c_str(), - // sessionCredentials.getSecretKey().c_str()); - - if (pSignature != NULL) { - string signature(static_cast(pSignature)); - request.addExtField(SessionCredentials::Signature, signature); - request.addExtField(SessionCredentials::AccessKey, sessionCredentials.getAccessKey()); - request.addExtField(SessionCredentials::ONSChannelKey, sessionCredentials.getAuthChannel()); - rocketmqSignature::spas_mem_free(pSignature); - } else { - LOG_ERROR("signature for request failed"); - } -} -} // namespace rocketmq diff --git a/src/common/ClientRPCHook.h b/src/common/ClientRPCHook.h deleted file mode 100644 index 52fef3022..000000000 --- a/src/common/ClientRPCHook.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __CLIENTRPCHOOK_H__ -#define __CLIENTRPCHOOK_H__ - -#include "RemotingCommand.h" -#include "SessionCredentials.h" -namespace rocketmq { -class RPCHook { - public: - RPCHook() {} - virtual ~RPCHook() {} - virtual void doBeforeRequest(const string& remoteAddr, RemotingCommand& request) = 0; - virtual void doAfterResponse(RemotingCommand& request, RemotingCommand& response) = 0; -}; - -class ClientRPCHook : public RPCHook { - private: - SessionCredentials sessionCredentials; - - public: - ClientRPCHook(const SessionCredentials& session_credentials) : sessionCredentials(session_credentials) {} - virtual ~ClientRPCHook() {} - - virtual void doBeforeRequest(const string& remoteAddr, RemotingCommand& request); - - virtual void doAfterResponse(RemotingCommand& request, RemotingCommand& response) {} -}; -} // namespace rocketmq -#endif diff --git a/src/common/CommunicationMode.h b/src/common/CommunicationMode.h deleted file mode 100644 index b2cb60150..000000000 --- a/src/common/CommunicationMode.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __COMMUNICATIONMODE_H__ -#define __COMMUNICATIONMODE_H__ - -namespace rocketmq { -//createTopic(key, newTopic, queueNum, m_SessionCredentials); - } catch (MQException& e) { - LOG_ERROR(e.what()); - } -} - -int64 DefaultMQClient::earliestMsgStoreTime(const MQMessageQueue& mq) { - return getFactory()->earliestMsgStoreTime(mq, m_SessionCredentials); -} - -QueryResult DefaultMQClient::queryMessage(const string& topic, const string& key, int maxNum, int64 begin, int64 end) { - return getFactory()->queryMessage(topic, key, maxNum, begin, end, m_SessionCredentials); -} - -int64 DefaultMQClient::minOffset(const MQMessageQueue& mq) { - return getFactory()->minOffset(mq, m_SessionCredentials); -} - -int64 DefaultMQClient::maxOffset(const MQMessageQueue& mq) { - return getFactory()->maxOffset(mq, m_SessionCredentials); -} - -int64 DefaultMQClient::searchOffset(const MQMessageQueue& mq, uint64_t timestamp) { - return getFactory()->searchOffset(mq, timestamp, m_SessionCredentials); -} - -MQMessageExt* DefaultMQClient::viewMessage(const string& msgId) { - return getFactory()->viewMessage(msgId, m_SessionCredentials); -} - -vector DefaultMQClient::getTopicMessageQueueInfo(const string& topic) { - boost::weak_ptr weak_topicPublishInfo( - getFactory()->tryToFindTopicPublishInfo(topic, m_SessionCredentials)); - boost::shared_ptr topicPublishInfo(weak_topicPublishInfo.lock()); - if (topicPublishInfo) { - return topicPublishInfo->getMessageQueueList(); - } - THROW_MQEXCEPTION(MQClientException, "could not find MessageQueue Info of topic: [" + topic + "].", -1); -} - -void DefaultMQClient::start() { - if (getFactory() == NULL) { - m_clientFactory = MQClientManager::getInstance()->getMQClientFactory( - getMQClientId(), m_pullThreadNum, m_tcpConnectTimeout, m_tcpTransportTryLockTimeout, m_unitName, m_enableSsl, - m_sslPropertyFile); - } - LOG_INFO( - "MQClient " - "start,groupname:%s,clientID:%s,instanceName:%s,nameserveraddr:%s", - getGroupName().c_str(), getMQClientId().c_str(), getInstanceName().c_str(), getNamesrvAddr().c_str()); -} - -void DefaultMQClient::shutdown() { - m_clientFactory->shutdown(); - m_clientFactory = NULL; -} - -MQClientFactory* DefaultMQClient::getFactory() const { - return m_clientFactory; -} -void DefaultMQClient::setFactory(MQClientFactory* factory) { - m_clientFactory = factory; -} - -bool DefaultMQClient::isServiceStateOk() { - return m_serviceState == RUNNING; -} - -void DefaultMQClient::setLogLevel(elogLevel inputLevel) { - ALOG_ADAPTER->setLogLevel(inputLevel); -} - -elogLevel DefaultMQClient::getLogLevel() { - return ALOG_ADAPTER->getLogLevel(); -} - -void DefaultMQClient::setLogFileSizeAndNum(int fileNum, long perFileSize) { - ALOG_ADAPTER->setLogFileNumAndSize(fileNum, perFileSize); -} - -void DefaultMQClient::setTcpTransportPullThreadNum(int num) { - if (num > m_pullThreadNum) { - m_pullThreadNum = num; - } -} - -int DefaultMQClient::getTcpTransportPullThreadNum() const { - return m_pullThreadNum; -} - -void DefaultMQClient::setTcpTransportConnectTimeout(uint64_t timeout) { - m_tcpConnectTimeout = timeout; -} -uint64_t DefaultMQClient::getTcpTransportConnectTimeout() const { - return m_tcpConnectTimeout; -} - -void DefaultMQClient::setTcpTransportTryLockTimeout(uint64_t timeout) { - if (timeout < 1000) { - timeout = 1000; - } - m_tcpTransportTryLockTimeout = timeout / 1000; -} -uint64_t DefaultMQClient::getTcpTransportTryLockTimeout() const { - return m_tcpTransportTryLockTimeout; -} - -void DefaultMQClient::setUnitName(const std::string& unitName) { - m_unitName = unitName; -} -const string& DefaultMQClient::getUnitName() const { - return m_unitName; -} - -bool DefaultMQClient::getMessageTrace() const { - return m_messageTrace; -} - -void DefaultMQClient::setMessageTrace(bool mMessageTrace) { - m_messageTrace = mMessageTrace; -} - -void DefaultMQClient::setSessionCredentials(const string& input_accessKey, - const string& input_secretKey, - const string& input_onsChannel) { - m_SessionCredentials.setAccessKey(input_accessKey); - m_SessionCredentials.setSecretKey(input_secretKey); - m_SessionCredentials.setAuthChannel(input_onsChannel); -} - -const SessionCredentials& DefaultMQClient::getSessionCredentials() const { - return m_SessionCredentials; -} - -void DefaultMQClient::setEnableSsl(bool enableSsl) { - m_enableSsl = enableSsl; -} - -bool DefaultMQClient::getEnableSsl() const { - return m_enableSsl; -} - -void DefaultMQClient::setSslPropertyFile(const std::string& sslPropertyFile) { - m_sslPropertyFile = sslPropertyFile; -} - -const std::string& DefaultMQClient::getSslPropertyFile() const { - return m_sslPropertyFile; -} - -void DefaultMQClient::showClientConfigs() { - // LOG_WARN("*****************************************************************************"); - LOG_WARN("ClientID:%s", getMQClientId().c_str()); - LOG_WARN("GroupName:%s", m_GroupName.c_str()); - LOG_WARN("NameServer:%s", m_namesrvAddr.c_str()); - LOG_WARN("NameServerDomain:%s", m_namesrvDomain.c_str()); - LOG_WARN("NameSpace:%s", m_nameSpace.c_str()); - LOG_WARN("InstanceName:%s", m_instanceName.c_str()); - LOG_WARN("UnitName:%s", m_unitName.c_str()); - LOG_WARN("PullThreadNum:%d", m_pullThreadNum); - LOG_WARN("TcpConnectTimeout:%lld ms", m_tcpConnectTimeout); - LOG_WARN("TcpTransportTryLockTimeout:%lld s", m_tcpTransportTryLockTimeout); - LOG_WARN("EnableSsl:%s", m_enableSsl ? "true" : "false"); - LOG_WARN("SslPropertyFile:%s", m_sslPropertyFile.c_str()); - LOG_WARN("OpenMessageTrace:%s", m_messageTrace ? "true" : "false"); - // LOG_WARN("*****************************************************************************"); -} -// -#include "MQClientException.h" -#include "SubscriptionData.h" -#include "UtilAll.h" -namespace rocketmq { -//setSubString(SUB_ALL); - } else { - vector out; - UtilAll::Split(out, subString, "||"); - - if (out.empty()) { - THROW_MQEXCEPTION(MQClientException, "FilterAPI subString split error", -1); - } - - for (size_t i = 0; i < out.size(); i++) { - string tag = out[i]; - if (!tag.empty()) { - UtilAll::Trim(tag); - if (!tag.empty()) { - subscriptionData->putTagsSet(tag); - subscriptionData->putCodeSet(tag); - } - } - } - } - - return subscriptionData; - } -}; - -// -#include "MemoryOutputStream.h" -#include "big_endian.h" - -namespace rocketmq { -int64 InputStream::getNumBytesRemaining() { - int64 len = getTotalLength(); - - if (len >= 0) - len -= getPosition(); - - return len; -} - -char InputStream::readByte() { - char temp = 0; - read(&temp, 1); - return temp; -} - -bool InputStream::readBool() { - return readByte() != 0; -} - -short InputStream::readShortBigEndian() { - char temp[2]; - - if (read(temp, 2) == 2) { - short int v; - ReadBigEndian(temp, &v); - return v; - } - - return 0; -} - -int InputStream::readIntBigEndian() { - char temp[4]; - - if (read(temp, 4) == 4) { - int v; - ReadBigEndian(temp, &v); - return v; - } - return 0; -} - -int64 InputStream::readInt64BigEndian() { - char asBytes[8]; - uint64 asInt64; - - if (read(asBytes, 8) == 8) { - ReadBigEndian(asBytes, &asInt64); - return asInt64; - } - return 0; -} - -float InputStream::readFloatBigEndian() { - union { - int32 asInt; - float asFloat; - } n; - n.asInt = (int32)readIntBigEndian(); - return n.asFloat; -} - -double InputStream::readDoubleBigEndian() { - union { - int64 asInt; - double asDouble; - } n; - n.asInt = readInt64BigEndian(); - return n.asDouble; -} - -size_t InputStream::readIntoMemoryBlock(MemoryBlock& block, size_t numBytes) { - MemoryOutputStream mo(block, true); - return (size_t)mo.writeFromInputStream(*this, numBytes); -} - -//============================================================================== -void InputStream::skipNextBytes(int64 numBytesToSkip) { - if (numBytesToSkip > 0) { - const int skipBufferSize = (int)std::min(numBytesToSkip, (int64)16384); - char* temp = static_cast(std::malloc(skipBufferSize * sizeof(char))); - - while (numBytesToSkip > 0 && !isExhausted()) - numBytesToSkip -= read(temp, (int)std::min(numBytesToSkip, (int64)skipBufferSize)); - - std::free(temp); - } -} -} // namespace rocketmq diff --git a/src/common/InputStream.h b/src/common/InputStream.h deleted file mode 100644 index 8cf1b8482..000000000 --- a/src/common/InputStream.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INPUTSTREAM_H_INCLUDED -#define INPUTSTREAM_H_INCLUDED - -#include "dataBlock.h" -//============================================================================== -/** The base class for streams that read data. - - Input and output streams are used throughout the library - subclasses can - override - some or all of the virtual functions to implement their behaviour. - - @see OutputStream, MemoryInputStream, BufferedInputStream, FileInputStream -*/ -namespace rocketmq { -class ROCKETMQCLIENT_API InputStream { - public: - /** Destructor. */ - virtual ~InputStream() {} - - //============================================================================== - /** Returns the total number of bytes available for reading in this stream. - - Note that this is the number of bytes available from the start of the - stream, not from the current position. - - If the size of the stream isn't actually known, this will return -1. - - @see getNumBytesRemaining - */ - virtual int64 getTotalLength() = 0; - - /** Returns the number of bytes available for reading, or a negative value if - the remaining length is not known. - @see getTotalLength - */ - int64 getNumBytesRemaining(); - - /** Returns true if the stream has no more data to read. */ - virtual bool isExhausted() = 0; - - //============================================================================== - /** Reads some data from the stream into a memory buffer. - - This is the only read method that subclasses actually need to implement, - as the - InputStream base class implements the other read methods in terms of this - one (although - it's often more efficient for subclasses to implement them directly). - - @param destBuffer the destination buffer for the data. This must not - be null. - @param maxBytesToRead the maximum number of bytes to read - make sure - the - memory block passed in is big enough to contain - this - many bytes. This value must not be negative. - - @returns the actual number of bytes that were read, which may be less - than - maxBytesToRead if the stream is exhausted before it gets that - far - */ - virtual int read(void* destBuffer, int maxBytesToRead) = 0; - - /** Reads a byte from the stream. - If the stream is exhausted, this will return zero. - @see OutputStream::writeByte - */ - virtual char readByte(); - - /** Reads a boolean from the stream. - The bool is encoded as a single byte - non-zero for true, 0 for false. - If the stream is exhausted, this will return false. - @see OutputStream::writeBool - */ - virtual bool readBool(); - - /** Reads two bytes from the stream as a little-endian 16-bit value. - If the next two bytes read are byte1 and byte2, this returns (byte2 | - (byte1 << 8)). - If the stream is exhausted partway through reading the bytes, this will - return zero. - @see OutputStream::writeShortBigEndian, readShort - */ - virtual short readShortBigEndian(); - - /** Reads four bytes from the stream as a big-endian 32-bit value. - - If the next four bytes are byte1 to byte4, this returns - (byte4 | (byte3 << 8) | (byte2 << 16) | (byte1 << 24)). - - If the stream is exhausted partway through reading the bytes, this will - return zero. - - @see OutputStream::writeIntBigEndian, readInt - */ - virtual int readIntBigEndian(); - - /** Reads eight bytes from the stream as a big-endian 64-bit value. - - If the next eight bytes are byte1 to byte8, this returns - (byte8 | (byte7 << 8) | (byte6 << 16) | (byte5 << 24) | (byte4 << 32) | - (byte3 << 40) | (byte2 << 48) | (byte1 << 56)). - - If the stream is exhausted partway through reading the bytes, this will - return zero. - - @see OutputStream::writeInt64BigEndian, readInt64 - */ - virtual int64 readInt64BigEndian(); - - /** Reads four bytes as a 32-bit floating point value. - The raw 32-bit encoding of the float is read from the stream as a - big-endian int. - If the stream is exhausted partway through reading the bytes, this will - return zero. - @see OutputStream::writeFloatBigEndian, readDoubleBigEndian - */ - virtual float readFloatBigEndian(); - - /** Reads eight bytes as a 64-bit floating point value. - The raw 64-bit encoding of the double is read from the stream as a - big-endian int64. - If the stream is exhausted partway through reading the bytes, this will - return zero. - @see OutputStream::writeDoubleBigEndian, readFloatBigEndian - */ - virtual double readDoubleBigEndian(); - - //==============================================================================whole - // stream and turn it into a string. - /** Reads from the stream and appends the data to a MemoryBlock. - - @param destBlock the block to append the data onto - @param maxNumBytesToRead if this is a positive value, it sets a limit - to the number - of bytes that will be read - if it's negative, - data - will be read until the stream is exhausted. - @returns the number of bytes that were added to the memory block - */ - virtual size_t readIntoMemoryBlock(MemoryBlock& destBlock, size_t maxNumBytesToRead = -1); - - //============================================================================== - /** Returns the offset of the next byte that will be read from the stream. - @see setPosition - */ - virtual int64 getPosition() = 0; - - /** Tries to move the current read position of the stream. - - The position is an absolute number of bytes from the stream's start. - - Some streams might not be able to do this, in which case they should do - nothing and return false. Others might be able to manage it by resetting - themselves and skipping to the correct position, although this is - obviously a bit slow. - - @returns true if the stream manages to reposition itself correctly - @see getPosition - */ - virtual bool setPosition(int64 newPosition) = 0; - - /** Reads and discards a number of bytes from the stream. - - Some input streams might implement this efficiently, but the base - class will just keep reading data until the requisite number of bytes - have been done. - */ - virtual void skipNextBytes(int64 numBytesToSkip); - - protected: - //============================================================================== - InputStream() {} -}; -} // namespace rocketmq -#endif // INPUTSTREAM_H_INCLUDED diff --git a/src/common/MQVersion.h b/src/common/MQVersion.h deleted file mode 100644 index d36eab082..000000000 --- a/src/common/MQVersion.h +++ /dev/null @@ -1,1535 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __MQVERSION_H__ -#define __MQVERSION_H__ - -#include - -namespace rocketmq { -//(std::malloc(dataSize)); - memcpy(internalCopy, data, dataSize); - data = internalCopy; -} - -MemoryInputStream::~MemoryInputStream() { - std::free(internalCopy); -} - -int64 MemoryInputStream::getTotalLength() { - return (int64)dataSize; -} - -int MemoryInputStream::read(void* const buffer, const int howMany) { - const int num = std::min(howMany, (int)(dataSize - position)); - if (num <= 0) - return 0; - - memcpy((char*)buffer, (char*)data + position, (size_t)num); - position += (unsigned int)num; - return num; -} - -bool MemoryInputStream::isExhausted() { - return position >= dataSize; -} - -bool MemoryInputStream::setPosition(const int64 pos) { - if (pos < 0) - position = 0; - else - position = (int64)dataSize < pos ? (int64)dataSize : pos; - - return true; -} - -int64 MemoryInputStream::getPosition() { - return (int64)position; -} -} // namespace rocketmq diff --git a/src/common/MemoryInputStream.h b/src/common/MemoryInputStream.h deleted file mode 100644 index 2d3a365b3..000000000 --- a/src/common/MemoryInputStream.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef MEMORYINPUTSTREAM_H_INCLUDED -#define MEMORYINPUTSTREAM_H_INCLUDED - -#include "InputStream.h" - -namespace rocketmq { -//============================================================================== -/** - Allows a block of data to be accessed as a stream. - - This can either be used to refer to a shared block of memory, or can make - its - own internal copy of the data when the MemoryInputStream is created. -*/ -class ROCKETMQCLIENT_API MemoryInputStream : public InputStream { - public: - //============================================================================== - /** Creates a MemoryInputStream. - - @param sourceData the block of data to use as the stream's - source - @param sourceDataSize the number of bytes in the source data - block - @param keepInternalCopyOfData if false, the stream will just keep a - pointer to - the source data, so this data shouldn't be - changed - for the lifetime of the stream; if this - parameter is - true, the stream will make its own copy of - the - data and use that. - */ - MemoryInputStream(const void* sourceData, size_t sourceDataSize, bool keepInternalCopyOfData); - - /** Creates a MemoryInputStream. - - @param data a block of data to use as the stream's - source - @param keepInternalCopyOfData if false, the stream will just keep a - reference to - the source data, so this data shouldn't be - changed - for the lifetime of the stream; if this - parameter is - true, the stream will make its own copy of - the - data and use that. - */ - MemoryInputStream(const MemoryBlock& data, bool keepInternalCopyOfData); - - /** Destructor. */ - ~MemoryInputStream(); - - /** Returns a pointer to the source data block from which this stream is - * reading. */ - const void* getData() const { return data; } - - /** Returns the number of bytes of source data in the block from which this - * stream is reading. */ - size_t getDataSize() const { return dataSize; } - - //============================================================================== - int64 getPosition(); - bool setPosition(int64 pos); - int64 getTotalLength(); - bool isExhausted(); - int read(void* destBuffer, int maxBytesToRead); - - private: - //============================================================================== - const void* data; - size_t dataSize, position; - char* internalCopy; - - void createInternalCopy(); -}; -} // namespace rocketmq -#endif diff --git a/src/common/MemoryOutputStream.cpp b/src/common/MemoryOutputStream.cpp deleted file mode 100644 index d7366f534..000000000 --- a/src/common/MemoryOutputStream.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "MemoryOutputStream.h" - -namespace rocketmq { -MemoryOutputStream::MemoryOutputStream(const size_t initialSize) - : blockToUse(&internalBlock), externalData(NULL), position(0), size(0), availableSize(0) { - internalBlock.setSize(initialSize, false); -} - -MemoryOutputStream::MemoryOutputStream(MemoryBlock& memoryBlockToWriteTo, const bool appendToExistingBlockContent) - : blockToUse(&memoryBlockToWriteTo), externalData(NULL), position(0), size(0), availableSize(0) { - if (appendToExistingBlockContent) - position = size = memoryBlockToWriteTo.getSize(); -} - -MemoryOutputStream::MemoryOutputStream(void* destBuffer, size_t destBufferSize) - : blockToUse(NULL), externalData(destBuffer), position(0), size(0), availableSize(destBufferSize) {} - -MemoryOutputStream::~MemoryOutputStream() { - trimExternalBlockSize(); -} - -void MemoryOutputStream::flush() { - trimExternalBlockSize(); -} - -void MemoryOutputStream::trimExternalBlockSize() { - if (blockToUse != &internalBlock && blockToUse != NULL) - blockToUse->setSize(size, false); -} - -void MemoryOutputStream::preallocate(const size_t bytesToPreallocate) { - if (blockToUse != NULL) - blockToUse->ensureSize(bytesToPreallocate + 1); -} - -void MemoryOutputStream::reset() { - position = 0; - size = 0; -} - -char* MemoryOutputStream::prepareToWrite(size_t numBytes) { - size_t storageNeeded = position + numBytes; - - char* data; - - if (blockToUse != NULL) { - if (storageNeeded >= (unsigned int)(blockToUse->getSize())) - blockToUse->ensureSize((storageNeeded + std::min(storageNeeded / 2, (size_t)(1024 * 1024)) + 32) & ~31u); - - data = static_cast(blockToUse->getData()); - } else { - if (storageNeeded > availableSize) - return NULL; - - data = static_cast(externalData); - } - - char* const writePointer = data + position; - position += numBytes; - size = std::max(size, position); - return writePointer; -} - -bool MemoryOutputStream::write(const void* const buffer, size_t howMany) { - if (howMany == 0) - return true; - - if (char* dest = prepareToWrite(howMany)) { - memcpy(dest, buffer, howMany); - return true; - } - - return false; -} - -bool MemoryOutputStream::writeRepeatedByte(uint8 byte, size_t howMany) { - if (howMany == 0) - return true; - - if (char* dest = prepareToWrite(howMany)) { - memset(dest, byte, howMany); - return true; - } - - return false; -} - -MemoryBlock MemoryOutputStream::getMemoryBlock() const { - return MemoryBlock(getData(), getDataSize()); -} - -const void* MemoryOutputStream::getData() const { - if (blockToUse == NULL) - return externalData; - - if ((unsigned int)blockToUse->getSize() > size) - static_cast(blockToUse->getData())[size] = 0; - - return blockToUse->getData(); -} - -bool MemoryOutputStream::setPosition(int64 newPosition) { - if (newPosition <= (int64)size) { - // ok to seek backwards - if (newPosition < 0) - position = 0; - else - position = (int64)size < newPosition ? size : newPosition; - return true; - } - - // can't move beyond the end of the stream.. - return false; -} - -int64 MemoryOutputStream::writeFromInputStream(InputStream& source, int64 maxNumBytesToWrite) { - // before writing from an input, see if we can preallocate to make it more - // efficient.. - int64 availableData = source.getTotalLength() - source.getPosition(); - - if (availableData > 0) { - if (maxNumBytesToWrite > availableData || maxNumBytesToWrite < 0) - maxNumBytesToWrite = availableData; - - if (blockToUse != NULL) - preallocate(blockToUse->getSize() + (size_t)maxNumBytesToWrite); - } - - return OutputStream::writeFromInputStream(source, maxNumBytesToWrite); -} - -OutputStream& operator<<(OutputStream& stream, const MemoryOutputStream& streamToRead) { - const size_t dataSize = streamToRead.getDataSize(); - - if (dataSize > 0) - stream.write(streamToRead.getData(), dataSize); - - return stream; -} -} // namespace rocketmq diff --git a/src/common/MemoryOutputStream.h b/src/common/MemoryOutputStream.h deleted file mode 100644 index cc3245a5e..000000000 --- a/src/common/MemoryOutputStream.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef MEMORYOUTPUTSTREAM_H_INCLUDED -#define MEMORYOUTPUTSTREAM_H_INCLUDED - -#include "OutputStream.h" - -namespace rocketmq { -//============================================================================== -/** - Writes data to an internal memory buffer, which grows as required. - - The data that was written into the stream can then be accessed later as - a contiguous block of memory. -*/ -class ROCKETMQCLIENT_API MemoryOutputStream : public OutputStream { - public: - //============================================================================== - /** Creates an empty memory stream, ready to be written into. - @param initialSize the intial amount of capacity to allocate for writing - into - */ - MemoryOutputStream(size_t initialSize = 256); - - /** Creates a memory stream for writing into into a pre-existing MemoryBlock - object. - - Note that the destination block will always be larger than the amount of - data - that has been written to the stream, because the MemoryOutputStream keeps - some - spare capactity at its end. To trim the block's size down to fit the - actual - data, call flush(), or delete the MemoryOutputStream. - - @param memoryBlockToWriteTo the block into which new data will - be written. - @param appendToExistingBlockContent if this is true, the contents of - the block will be - kept, and new data will be - appended to it. If false, - the block will be cleared before - use - */ - MemoryOutputStream(MemoryBlock& memoryBlockToWriteTo, bool appendToExistingBlockContent); - - /** Creates a MemoryOutputStream that will write into a user-supplied, - fixed-size - block of memory. - When using this mode, the stream will write directly into this memory area - until - it's full, at which point write operations will fail. - */ - MemoryOutputStream(void* destBuffer, size_t destBufferSize); - - /** Destructor. - This will free any data that was written to it. - */ - ~MemoryOutputStream(); - - //============================================================================== - /** Returns a pointer to the data that has been written to the stream. - @see getDataSize - */ - const void* getData() const; - - /** Returns the number of bytes of data that have been written to the stream. - @see getData - */ - size_t getDataSize() const { return size; } - - /** Resets the stream, clearing any data that has been written to it so far. - */ - void reset(); - - /** Increases the internal storage capacity to be able to contain at least the - specified - amount of data without needing to be resized. - */ - void preallocate(size_t bytesToPreallocate); - - /** Returns a copy of the stream's data as a memory block. */ - MemoryBlock getMemoryBlock() const; - - //============================================================================== - /** If the stream is writing to a user-supplied MemoryBlock, this will trim - any excess - capacity off the block, so that its length matches the amount of actual - data that - has been written so far. - */ - void flush(); - - bool write(const void*, size_t); - int64 getPosition() { return (int64)position; } - bool setPosition(int64); - int64 writeFromInputStream(InputStream&, int64 maxNumBytesToWrite); - bool writeRepeatedByte(uint8 byte, size_t numTimesToRepeat); - - private: - //============================================================================== - MemoryBlock* const blockToUse; - MemoryBlock internalBlock; - void* externalData; - size_t position, size, availableSize; - - void trimExternalBlockSize(); - char* prepareToWrite(size_t); -}; - -/** Copies all the data that has been written to a MemoryOutputStream into - * another stream. */ -OutputStream& operator<<(OutputStream& stream, const MemoryOutputStream& streamToRead); -} // namespace rocketmq -#endif // MEMORYOUTPUTSTREAM_H_INCLUDED diff --git a/src/common/MessageAccessor.cpp b/src/common/MessageAccessor.cpp deleted file mode 100644 index 7b8714a9a..000000000 --- a/src/common/MessageAccessor.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "MessageAccessor.h" -#include -#include -#include "Logging.h" -#include "NameSpaceUtil.h" - -using namespace std; -namespace rocketmq { - -void MessageAccessor::withNameSpace(MQMessage& msg, const string& nameSpace) { - if (!nameSpace.empty()) { - string originTopic = msg.getTopic(); - string newTopic = nameSpace + NAMESPACE_SPLIT_FLAG + originTopic; - msg.setTopic(newTopic); - } -} - -void MessageAccessor::withoutNameSpaceSingle(MQMessageExt& msg, const string& nameSpace) { - if (!nameSpace.empty()) { - string originTopic = msg.getTopic(); - auto index = originTopic.find(nameSpace); - if (index != string::npos) { - string newTopic = - originTopic.substr(index + nameSpace.length() + NAMESPACE_SPLIT_FLAG.length(), originTopic.length()); - msg.setTopic(newTopic); - LOG_DEBUG("Find Name Space Prefix in MessageID[%s], OriginTopic[%s], NewTopic[%s]", msg.getMsgId().c_str(), - originTopic.c_str(), newTopic.c_str()); - } - } -} -void MessageAccessor::withoutNameSpace(vector& msgs, const string& nameSpace) { - if (!nameSpace.empty()) { - // for_each(msgs.cbegin(), msgs.cend(), bind2nd(&MessageAccessor::withoutNameSpaceSingle, nameSpace)); - for (auto iter = msgs.begin(); iter != msgs.end(); iter++) { - withoutNameSpaceSingle(*iter, nameSpace); - } - } -} -// -#include -#include "MQMessage.h" -#include "MQMessageExt.h" -namespace rocketmq { -//& msgs, const std::string& nameSpace); -}; - -//= ENDPOINT_PREFIX_LENGTH && nameServerAddr.find(ENDPOINT_PREFIX) != string::npos) { - return true; - } - return false; -} - -string NameSpaceUtil::formatNameServerURL(const string& nameServerAddr) { - auto index = nameServerAddr.find(ENDPOINT_PREFIX); - if (index != string::npos) { - LOG_DEBUG("Get Name Server from endpoint [%s]", - nameServerAddr.substr(ENDPOINT_PREFIX_LENGTH, nameServerAddr.length() - ENDPOINT_PREFIX_LENGTH).c_str()); - return nameServerAddr.substr(ENDPOINT_PREFIX_LENGTH, nameServerAddr.length() - ENDPOINT_PREFIX_LENGTH); - } - return nameServerAddr; -} - -string NameSpaceUtil::getNameSpaceFromNsURL(const string& nameServerAddr) { - LOG_DEBUG("Try to get Name Space from nameServerAddr [%s]", nameServerAddr.c_str()); - string nsAddr = formatNameServerURL(nameServerAddr); - string nameSpace; - auto index = nsAddr.find(NAMESPACE_PREFIX); - if (index != string::npos) { - auto indexDot = nsAddr.find('.'); - if (indexDot != string::npos && indexDot > index) { - nameSpace = nsAddr.substr(index, indexDot - index); - LOG_INFO("Get Name Space [%s] from nameServerAddr [%s]", nameSpace.c_str(), nameServerAddr.c_str()); - return nameSpace; - } - } - return ""; -} - -bool NameSpaceUtil::checkNameSpaceExistInNsURL(const string& nameServerAddr) { - if (!isEndPointURL(nameServerAddr)) { - LOG_DEBUG("This nameServerAddr [%s] is not a endpoint. should not get Name Space.", nameServerAddr.c_str()); - return false; - } - auto index = nameServerAddr.find(NAMESPACE_PREFIX); - if (index != string::npos) { - LOG_INFO("Find Name Space Prefix in nameServerAddr [%s]", nameServerAddr.c_str()); - return true; - } - return false; -} - -bool NameSpaceUtil::checkNameSpaceExistInNameServer(const string& nameServerAddr) { - auto index = nameServerAddr.find(NAMESPACE_PREFIX); - if (index != string::npos) { - LOG_INFO("Find Name Space Prefix in nameServerAddr [%s]", nameServerAddr.c_str()); - return true; - } - return false; -} - -string NameSpaceUtil::withoutNameSpace(const string& source, const string& nameSpace) { - if (!nameSpace.empty()) { - auto index = source.find(nameSpace); - if (index != string::npos) { - return source.substr(index + nameSpace.length() + NAMESPACE_SPLIT_FLAG.length(), source.length()); - } - } - return source; -} -string NameSpaceUtil::withNameSpace(const string& source, const string& ns) { - if (!ns.empty()) { - return ns + NAMESPACE_SPLIT_FLAG + source; - } - return source; -} - -bool NameSpaceUtil::hasNameSpace(const string& source, const string& ns) { - if (source.find(TraceConstant::TRACE_TOPIC) != string::npos) { - LOG_DEBUG("Find Trace Topic [%s]", source.c_str()); - return true; - } - if (!ns.empty() && source.length() >= ns.length() && source.find(ns) != string::npos) { - return true; - } - return false; -} -} // namespace rocketmq diff --git a/src/common/NameSpaceUtil.h b/src/common/NameSpaceUtil.h deleted file mode 100644 index 094fb49ca..000000000 --- a/src/common/NameSpaceUtil.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __NAMESPACEUTIL_H__ -#define __NAMESPACEUTIL_H__ - -#include - -using namespace std; - -static const string ENDPOINT_PREFIX = "http://"; -static const unsigned int ENDPOINT_PREFIX_LENGTH = ENDPOINT_PREFIX.length(); -static const string NAMESPACE_PREFIX = "MQ_INST_"; -static const int NAMESPACE_PREFIX_LENGTH = NAMESPACE_PREFIX.length(); -static const string NAMESPACE_SPLIT_FLAG = "%"; - -namespace rocketmq { -class NameSpaceUtil { - public: - static bool isEndPointURL(const string& nameServerAddr); - - static string formatNameServerURL(const string& nameServerAddr); - - static string getNameSpaceFromNsURL(const string& nameServerAddr); - - static bool checkNameSpaceExistInNsURL(const string& nameServerAddr); - - static bool checkNameSpaceExistInNameServer(const string& nameServerAddr); - - static string withNameSpace(const string& source, const string& ns); - - static string withoutNameSpace(const string& source, const string& ns); - - static bool hasNameSpace(const string& source, const string& ns); -}; - -} // namespace rocketmq -#endif //__NAMESPACEUTIL_H__ diff --git a/src/common/NamesrvConfig.h b/src/common/NamesrvConfig.h deleted file mode 100644 index 30bbb0e49..000000000 --- a/src/common/NamesrvConfig.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __NAMESRVCONFIG_H__ -#define __NAMESRVCONFIG_H__ - -#include -#include -#include "UtilAll.h" - -namespace rocketmq { -// -#include "big_endian.h" - -namespace rocketmq { -//============================================================================== -OutputStream::OutputStream() {} - -OutputStream::~OutputStream() {} - -//============================================================================== -bool OutputStream::writeBool(const bool b) { - return writeByte(b ? (char)1 : (char)0); -} - -bool OutputStream::writeByte(char byte) { - return write(&byte, 1); -} - -bool OutputStream::writeRepeatedByte(uint8 byte, size_t numTimesToRepeat) { - for (size_t i = 0; i < numTimesToRepeat; ++i) - if (!writeByte((char)byte)) - return false; - - return true; -} - -bool OutputStream::writeShortBigEndian(short value) { - unsigned short v; - char pShort[sizeof(v)]; - WriteBigEndian(pShort, (unsigned short)value); - return write(pShort, 2); -} - -bool OutputStream::writeIntBigEndian(int value) { - unsigned int v; - char pInt[sizeof(v)]; - WriteBigEndian(pInt, (unsigned int)value); - return write(pInt, 4); -} - -bool OutputStream::writeInt64BigEndian(int64 value) { - uint64 v; - char pUint64[sizeof(v)]; - WriteBigEndian(pUint64, (uint64)value); - return write(pUint64, 8); -} - -bool OutputStream::writeFloatBigEndian(float value) { - union { - int asInt; - float asFloat; - } n; - n.asFloat = value; - return writeIntBigEndian(n.asInt); -} - -bool OutputStream::writeDoubleBigEndian(double value) { - union { - int64 asInt; - double asDouble; - } n; - n.asDouble = value; - return writeInt64BigEndian(n.asInt); -} - -int64 OutputStream::writeFromInputStream(InputStream& source, int64 numBytesToWrite) { - if (numBytesToWrite < 0) - numBytesToWrite = std::numeric_limits::max(); - - int64 numWritten = 0; - - while (numBytesToWrite > 0) { - char buffer[8192]; - const int num = source.read(buffer, (int)std::min(numBytesToWrite, (int64)sizeof(buffer))); - - if (num <= 0) - break; - - write(buffer, (size_t)num); - - numBytesToWrite -= num; - numWritten += num; - } - - return numWritten; -} -} // namespace rocketmq diff --git a/src/common/OutputStream.h b/src/common/OutputStream.h deleted file mode 100644 index 6dd459ddb..000000000 --- a/src/common/OutputStream.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef OUTPUTSTREAM_H_INCLUDED -#define OUTPUTSTREAM_H_INCLUDED - -#include "InputStream.h" -namespace rocketmq { -//============================================================================== -/** - The base class for streams that write data to some kind of destination. - - Input and output streams are used throughout the library - subclasses can - override - some or all of the virtual functions to implement their behaviour. - - @see InputStream, MemoryOutputStream, FileOutputStream -*/ -class ROCKETMQCLIENT_API OutputStream { - protected: - //============================================================================== - OutputStream(); - - public: - /** Destructor. - - Some subclasses might want to do things like call flush() during their - destructors. - */ - virtual ~OutputStream(); - - //============================================================================== - /** If the stream is using a buffer, this will ensure it gets written - out to the destination. */ - virtual void flush() = 0; - - /** Tries to move the stream's output position. - - Not all streams will be able to seek to a new position - this will return - false if it fails to work. - - @see getPosition - */ - virtual bool setPosition(int64 newPosition) = 0; - - /** Returns the stream's current position. - - @see setPosition - */ - virtual int64 getPosition() = 0; - - //============================================================================== - /** Writes a block of data to the stream. - - When creating a subclass of OutputStream, this is the only write method - that needs to be overloaded - the base class has methods for writing other - types of data which use this to do the work. - - @param dataToWrite the target buffer to receive the data. This must - not be null. - @param numberOfBytes the number of bytes to write. - @returns false if the write operation fails for some reason - */ - virtual bool write(const void* dataToWrite, size_t numberOfBytes) = 0; - - //============================================================================== - /** Writes a single byte to the stream. - @returns false if the write operation fails for some reason - @see InputStream::readByte - */ - virtual bool writeByte(char byte); - - /** Writes a boolean to the stream as a single byte. - This is encoded as a binary byte (not as text) with a value of 1 or 0. - @returns false if the write operation fails for some reason - @see InputStream::readBool - */ - virtual bool writeBool(bool boolValue); - - /** Writes a 16-bit integer to the stream in a big-endian byte order. - This will write two bytes to the stream: (value >> 8), then (value & - 0xff). - @returns false if the write operation fails for some reason - @see InputStream::readShortBigEndian - */ - virtual bool writeShortBigEndian(short value); - - /** Writes a 32-bit integer to the stream in a big-endian byte order. - @returns false if the write operation fails for some reason - @see InputStream::readIntBigEndian - */ - virtual bool writeIntBigEndian(int value); - - /** Writes a 64-bit integer to the stream in a big-endian byte order. - @returns false if the write operation fails for some reason - @see InputStream::readInt64BigEndian - */ - virtual bool writeInt64BigEndian(int64 value); - - /** Writes a 32-bit floating point value to the stream in a binary format. - The binary 32-bit encoding of the float is written as a big-endian int. - @returns false if the write operation fails for some reason - @see InputStream::readFloatBigEndian - */ - virtual bool writeFloatBigEndian(float value); - - /** Writes a 64-bit floating point value to the stream in a binary format. - The eight raw bytes of the double value are written out as a big-endian - 64-bit int. - @see InputStream::readDoubleBigEndian - @returns false if the write operation fails for some reason - */ - virtual bool writeDoubleBigEndian(double value); - - /** Writes a byte to the output stream a given number of times. - @returns false if the write operation fails for some reason - */ - virtual bool writeRepeatedByte(uint8 byte, size_t numTimesToRepeat); - - /** Reads data from an input stream and writes it to this stream. - - @param source the stream to read from - @param maxNumBytesToWrite the number of bytes to read from the stream - (if this is - less than zero, it will keep reading until the - input - is exhausted) - @returns the number of bytes written - */ - virtual int64 writeFromInputStream(InputStream& source, int64 maxNumBytesToWrite); -}; -} // namespace rocketmq - -#endif // OUTPUTSTREAM_H_INCLUDED diff --git a/src/common/PermName.cpp b/src/common/PermName.cpp deleted file mode 100644 index 7484cc675..000000000 --- a/src/common/PermName.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "PermName.h" -#include "UtilAll.h" - -namespace rocketmq { -// - -namespace rocketmq { -// - -namespace rocketmq { -//groupName = groupName; - consumeEnable = true; - consumeFromMinEnable = true; - consumeBroadcastEnable = true; - retryQueueNums = 1; - retryMaxTimes = 5; - brokerId = MASTER_ID; - whichBrokerWhenConsumeSlowly = 1; - } - - string groupName; - bool consumeEnable; - bool consumeFromMinEnable; - bool consumeBroadcastEnable; - int retryQueueNums; - int retryMaxTimes; - int brokerId; - int whichBrokerWhenConsumeSlowly; -}; - -// -#include "UtilAll.h" -#include "sync_http_client.h" -#include "url.h" - -namespace rocketmq { -TopAddressing::TopAddressing(const std::string& unitName) : m_unitName(unitName) {} - -TopAddressing::~TopAddressing() {} - -int TopAddressing::IsIPAddr(const char* sValue) { - if (NULL == sValue) - return -1; - - while (*sValue != '\0') { - if ((*sValue < '0' || *sValue > '9') && (*sValue != '.')) - return -1; - sValue++; - } - return 0; -} - -void TopAddressing::updateNameServerAddressList(const string& adds) { - boost::lock_guard lock(m_addrLock); - vector out; - UtilAll::Split(out, adds, ";"); - if (out.size() > 0) - m_addrs.clear(); - for (size_t i = 0; i < out.size(); i++) { - string addr = out[i]; - UtilAll::Trim(addr); - - list::iterator findit = find(m_addrs.begin(), m_addrs.end(), addr); - if (findit == m_addrs.end()) { - string hostName; - short portNumber; - if (UtilAll::SplitURL(addr, hostName, portNumber)) { - LOG_INFO("updateNameServerAddressList:%s", addr.c_str()); - m_addrs.push_back(addr); - } - } - } -} - -string TopAddressing::fetchNSAddr(const string& NSDomain) { - LOG_DEBUG("fetchNSAddr begin"); - string nsAddr = NSDomain.empty() ? WS_ADDR : NSDomain; - if (!m_unitName.empty()) { - nsAddr = nsAddr + "-" + m_unitName + "?nofix=1"; - LOG_INFO("NSAddr is:%s", nsAddr.c_str()); - } - - std::string tmp_nameservers; - std::string nameservers; - Url url_s(nsAddr); - LOG_INFO("fetchNSAddr protocol: %s, port: %s, host:%s, path:%s, ", url_s.protocol_.c_str(), url_s.port_.c_str(), - url_s.host_.c_str(), url_s.path_.c_str()); - - bool ret = SyncfetchNsAddr(url_s, tmp_nameservers); - if (ret) { - nameservers = clearNewLine(tmp_nameservers); - if (nameservers.empty()) { - LOG_ERROR("fetchNSAddr with domain is empty"); - } else { - updateNameServerAddressList(nameservers); - } - } else { - LOG_ERROR("fetchNSAddr with domain failed, connect failure or wrong response"); - } - - return nameservers; -} - -string TopAddressing::clearNewLine(const string& str) { - string newString = str; - size_t index = newString.find("\r"); - if (index != string::npos) { - return newString.substr(0, index); - } - - index = newString.find("\n"); - if (index != string::npos) { - return newString.substr(0, index); - } - - return newString; -} -} // namespace rocketmq diff --git a/src/common/TopicConfig.cpp b/src/common/TopicConfig.cpp deleted file mode 100644 index 38ea138bd..000000000 --- a/src/common/TopicConfig.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "TopicConfig.h" -#include -#include -#include "PermName.h" - -namespace rocketmq { -//> m_topicName; - ss >> m_readQueueNums; - ss >> m_writeQueueNums; - ss >> m_perm; - - int type; - ss >> type; - m_topicFilterType = (TopicFilterType)type; - - return true; -} - -const string& TopicConfig::getTopicName() { - return m_topicName; -} - -void TopicConfig::setTopicName(const string& topicName) { - m_topicName = topicName; -} - -int TopicConfig::getReadQueueNums() { - return m_readQueueNums; -} - -void TopicConfig::setReadQueueNums(int readQueueNums) { - m_readQueueNums = readQueueNums; -} - -int TopicConfig::getWriteQueueNums() { - return m_writeQueueNums; -} - -void TopicConfig::setWriteQueueNums(int writeQueueNums) { - m_writeQueueNums = writeQueueNums; -} - -int TopicConfig::getPerm() { - return m_perm; -} - -void TopicConfig::setPerm(int perm) { - m_perm = perm; -} - -TopicFilterType TopicConfig::getTopicFilterType() { - return m_topicFilterType; -} - -void TopicConfig::setTopicFilterType(TopicFilterType topicFilterType) { - m_topicFilterType = topicFilterType; -} -// -#include "TopicFilterType.h" -#include "UtilAll.h" -namespace rocketmq { -// - -namespace rocketmq { -//(str); -} - -string UtilAll::bytes2string(const char* bytes, int len) { - if (bytes == NULL || len <= 0) { - return string(); - } - -#ifdef WIN32 - string buffer; - for (int i = 0; i < len; i++) { - char tmp[3]; - sprintf(tmp, "%02X", (unsigned char)bytes[i]); - buffer.append(tmp); - } - - return buffer; -#else - static const char hex_str[] = "0123456789ABCDEF"; - - char result[len * 2 + 1]; - - result[len * 2] = 0; - for (int i = 0; i < len; i++) { - result[i * 2 + 0] = hex_str[(bytes[i] >> 4) & 0x0F]; - result[i * 2 + 1] = hex_str[(bytes[i]) & 0x0F]; - } - - string buffer(result); - return buffer; -#endif -} - -bool UtilAll::SplitURL(const string& serverURL, string& addr, short& nPort) { - size_t pos = serverURL.find(':'); - if (pos == string::npos) { - return false; - } - - addr = serverURL.substr(0, pos); - if (0 == addr.compare("localhost")) { - addr = "127.0.0.1"; - } - - pos++; - string port = serverURL.substr(pos, serverURL.length() - pos); - nPort = atoi(port.c_str()); - if (nPort == 0) { - return false; - } - return true; -} - -int UtilAll::Split(vector& ret_, const string& strIn, const char sep) { - if (strIn.empty()) - return 0; - - string tmp; - string::size_type pos_begin = strIn.find_first_not_of(sep); - string::size_type comma_pos = 0; - - while (pos_begin != string::npos) { - comma_pos = strIn.find(sep, pos_begin); - if (comma_pos != string::npos) { - tmp = strIn.substr(pos_begin, comma_pos - pos_begin); - pos_begin = comma_pos + 1; - } else { - tmp = strIn.substr(pos_begin); - pos_begin = comma_pos; - } - - if (!tmp.empty()) { - ret_.push_back(tmp); - tmp.clear(); - } - } - return ret_.size(); -} -int UtilAll::Split(vector& ret_, const string& strIn, const string& sep) { - if (strIn.empty()) - return 0; - - string tmp; - string::size_type pos_begin = strIn.find_first_not_of(sep); - string::size_type comma_pos = 0; - - while (pos_begin != string::npos) { - comma_pos = strIn.find(sep, pos_begin); - if (comma_pos != string::npos) { - tmp = strIn.substr(pos_begin, comma_pos - pos_begin); - pos_begin = comma_pos + sep.length(); - } else { - tmp = strIn.substr(pos_begin); - pos_begin = comma_pos; - } - - if (!tmp.empty()) { - ret_.push_back(tmp); - tmp.clear(); - } - } - return ret_.size(); -} - -bool UtilAll::StringToInt32(const std::string& str, int32_t& out) { - out = 0; - if (str.empty()) { - return false; - } - - char* end = NULL; - errno = 0; - long l = strtol(str.c_str(), &end, 10); - /* Both checks are needed because INT_MAX == LONG_MAX is possible. */ - if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX)) - return false; - if (l < INT_MIN || (errno == ERANGE && l == LONG_MIN)) - return false; - if (*end != '\0') - return false; - out = l; - return true; -} - -bool UtilAll::StringToInt64(const std::string& str, int64_t& val) { - char* endptr = NULL; - errno = 0; /* To distinguish success/failure after call */ - val = strtoll(str.c_str(), &endptr, 10); - - /* Check for various possible errors */ - if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0)) { - return false; - } - /*no digit was found Or Further characters after number*/ - if (endptr == str.c_str()) { - return false; - } - /*no digit was found Or Further characters after number*/ - if (*endptr != '\0') { - return false; - } - /* If we got here, strtol() successfully parsed a number */ - return true; -} - -string UtilAll::getLocalHostName() { - if (s_localHostName.empty()) { - // boost::system::error_code error; - // s_localHostName = boost::asio::ip::host_name(error); - - char name[1024]; - boost::system::error_code ec; - if (boost::asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) { - return std::string(); - } - s_localHostName.append(name, strlen(name)); - } - return s_localHostName; -} - -string UtilAll::getLocalAddress() { - if (s_localIpAddress.empty()) { - boost::asio::io_service io_service; - boost::asio::ip::tcp::resolver resolver(io_service); - boost::asio::ip::tcp::resolver::query query(getLocalHostName(), ""); - boost::system::error_code error; - boost::asio::ip::tcp::resolver::iterator iter = resolver.resolve(query, error); - if (error) { - return ""; - } - boost::asio::ip::tcp::resolver::iterator end; // End marker. - boost::asio::ip::tcp::endpoint ep; - while (iter != end) { - ep = *iter++; - } - s_localIpAddress = ep.address().to_string(); - } - return s_localIpAddress; -} - -string UtilAll::getHomeDirectory() { -#ifndef WIN32 - char* homeEnv = getenv("HOME"); - string homeDir; - if (homeEnv == NULL) { - homeDir.append(getpwuid(getuid())->pw_dir); - } else { - homeDir.append(homeEnv); - } -#else - string homeDir(getenv("USERPROFILE")); -#endif - return homeDir; -} - -string UtilAll::getProcessName() { -#ifndef WIN32 - char buf[PATH_MAX + 1] = {0}; - int count = PATH_MAX + 1; - char procpath[PATH_MAX + 1] = {0}; - sprintf(procpath, "/proc/%d/exe", getpid()); - - if (access(procpath, F_OK) == -1) { - return ""; - } - - int retval = readlink(procpath, buf, count - 1); - if ((retval < 0 || retval >= count - 1)) { - return ""; - } - if (!strcmp(buf + retval - 10, " (deleted)")) - buf[retval - 10] = '\0'; // remove last " (deleted)" - else - buf[retval] = '\0'; - - char* process_name = strrchr(buf, '/'); - if (process_name) { - return std::string(process_name + 1); - } else { - return ""; - } -#else - TCHAR szFileName[MAX_PATH + 1]; - GetModuleFileName(NULL, szFileName, MAX_PATH + 1); - return std::string(szFileName); -#endif -} - -uint64_t UtilAll::currentTimeMillis() { - auto since_epoch = - std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); - return static_cast(since_epoch.count()); -} - -uint64_t UtilAll::currentTimeSeconds() { - auto since_epoch = - std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); - return static_cast(since_epoch.count()); -} - -bool UtilAll::deflate(std::string& input, std::string& out, int level) { - boost::iostreams::zlib_params zlibParams(level, boost::iostreams::zlib::deflated); - boost::iostreams::filtering_ostream compressingStream; - compressingStream.push(boost::iostreams::zlib_compressor(zlibParams)); - compressingStream.push(boost::iostreams::back_inserter(out)); - compressingStream << input; - boost::iostreams::close(compressingStream); - - return true; -} - -bool UtilAll::inflate(std::string& input, std::string& out) { - boost::iostreams::filtering_ostream decompressingStream; - decompressingStream.push(boost::iostreams::zlib_decompressor()); - decompressingStream.push(boost::iostreams::back_inserter(out)); - decompressingStream << input; - boost::iostreams::close(decompressingStream); - - return true; -} - -bool UtilAll::ReplaceFile(const std::string& from_path, const std::string& to_path) { -#ifdef WIN32 - // Try a simple move first. It will only succeed when |to_path| doesn't - // already exist. - if (::MoveFile(from_path.c_str(), to_path.c_str())) - return true; - // Try the full-blown replace if the move fails, as ReplaceFile will only - // succeed when |to_path| does exist. When writing to a network share, we may - // not be able to change the ACLs. Ignore ACL errors then - // (REPLACEFILE_IGNORE_MERGE_ERRORS). - if (::ReplaceFile(to_path.c_str(), from_path.c_str(), NULL, REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL)) { - return true; - } - return false; -#else - if (rename(from_path.c_str(), to_path.c_str()) == 0) - return true; - return false; -#endif -} - -std::map UtilAll::ReadProperties(const std::string& path) { - std::map property_map; - std::ifstream property_file; - property_file.open(path); - std::string line_buffer; - - if (property_file.is_open()) { - while (!property_file.eof()) { - std::getline(property_file, line_buffer); - std::size_t pos{0}; - pos = line_buffer.find('#'); - if (pos != string::npos) { - line_buffer = line_buffer.substr(0, pos); - } - if (line_buffer.empty()) { - continue; - } - pos = line_buffer.find('='); - if (pos != string::npos) { - std::string key = boost::trim_copy(line_buffer.substr(0, pos)); - std::string value = boost::trim_copy(line_buffer.substr(pos + 1)); - property_map[key] = value; - } - } - } - - return property_map; -} - -} // namespace rocketmq diff --git a/src/common/UtilAll.h b/src/common/UtilAll.h deleted file mode 100644 index b2bc1a397..000000000 --- a/src/common/UtilAll.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __UTILALL_H__ -#define __UTILALL_H__ - -#include -#include -#include -#include -#include -#ifndef WIN32 -#include -#include -#include -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "RocketMQClient.h" - -using namespace std; -namespace rocketmq { -// -inline void deleteAndZero(Type& pointer) { - delete pointer; - pointer = NULL; -} -#define EMPTY_STR_PTR(ptr) (ptr == NULL || ptr[0] == '\0') -#ifdef WIN32 -#define SIZET_FMT "%lu" -#else -#define SIZET_FMT "%zu" -#endif - -namespace detail { - -template -struct UseStdToString { - typedef std::false_type type; -}; - -template -struct UseStdToString { - typedef std::true_type type; -}; - -template -inline std::string to_string(const T& v, std::false_type) { - std::ostringstream stm; - stm << v; - return stm.str(); -} - -template -inline std::string to_string(const T& v, std::true_type) { - return std::to_string(v); -} - -template -inline std::string to_string(const T& v) { - return to_string(v, typename UseStdToString < T, - std::is_arithmetic::value && !std::is_same::type>::value > ::type{}); -} - -template <> -inline std::string to_string(const bool& v) { - return v ? "true" : "false"; -} - -} // namespace detail - -// - static string to_string(const T& n) { - return detail::to_string(n); - } - - static bool to_bool(std::string const& s) { return atoi(s.c_str()); } - - static bool SplitURL(const string& serverURL, string& addr, short& nPort); - static int Split(vector& ret_, const string& strIn, const char sep); - static int Split(vector& ret_, const string& strIn, const string& sep); - - static bool StringToInt32(const std::string& str, int32_t& out); - static bool StringToInt64(const std::string& str, int64_t& val); - - static string getLocalHostName(); - static string getLocalAddress(); - static string getHomeDirectory(); - - static string getProcessName(); - - static uint64_t currentTimeMillis(); - static uint64_t currentTimeSeconds(); - - static bool deflate(std::string& input, std::string& out, int level); - static bool inflate(std::string& input, std::string& out); - // Renames file |from_path| to |to_path|. Both paths must be on the same - // volume, or the function will fail. Destination file will be created - // if it doesn't exist. Prefer this function over Move when dealing with - // temporary files. On Windows it preserves attributes of the target file. - // Returns true on success. - // Returns false on failure.. - static bool ReplaceFile(const std::string& from_path, const std::string& to_path); - - static std::map ReadProperties(const std::string& path); - - private: - static std::string s_localHostName; - static std::string s_localIpAddress; -}; -// -#include -namespace rocketmq { - -const string Validators::validPatternStr = "^[a-zA-Z0-9_-]+$"; -const int Validators::CHARACTER_MAX_LENGTH = 255; -// CHARACTER_MAX_LENGTH) { - THROW_MQEXCEPTION(MQClientException, "the specified topic is longer than topic max length 255.", -1); - } - - if (topic == DEFAULT_TOPIC) { - THROW_MQEXCEPTION(MQClientException, "the topic[" + topic + "] is conflict with default topic.", -1); - } - - if (!regularExpressionMatcher(topic, validPatternStr)) { - string str; - str = "the specified topic[" + topic + "] contains illegal characters, allowing only" + validPatternStr; - - THROW_MQEXCEPTION(MQClientException, str.c_str(), -1); - } -} - -void Validators::checkGroup(const string& group) { - if (UtilAll::isBlank(group)) { - THROW_MQEXCEPTION(MQClientException, "the specified group is blank", -1); - } - - if (!regularExpressionMatcher(group, validPatternStr)) { - string str; - str = "the specified group[" + group + "] contains illegal characters, allowing only" + validPatternStr; - - THROW_MQEXCEPTION(MQClientException, str.c_str(), -1); - } - if ((int)group.length() > CHARACTER_MAX_LENGTH) { - THROW_MQEXCEPTION(MQClientException, "the specified group is longer than group max length 255.", -1); - } -} - -void Validators::checkMessage(const MQMessage& msg, int maxMessageSize) { - checkTopic(msg.getTopic()); - - string body = msg.getBody(); - // maxMessageSize) { - char info[256]; - sprintf(info, "the message body size over max value, MAX: %d", maxMessageSize); - THROW_MQEXCEPTION(MQClientException, info, -1); - } -} - -// -#include "MQClientException.h" -#include "MQMessage.h" -#include "UtilAll.h" -namespace rocketmq { -// -#include -#include "UtilAll.h" - -namespace rocketmq { -const char* VirtualEnvUtil::VIRTUAL_APPGROUP_PREFIX = "%%PROJECT_%s%%"; - -// -namespace rocketmq { -// -#include - -namespace rocketmq { - -BigEndianReader::BigEndianReader(const char* buf, size_t len) : ptr_(buf), end_(ptr_ + len) {} - -bool BigEndianReader::Skip(size_t len) { - if (ptr_ + len > end_) - return false; - ptr_ += len; - return true; -} - -bool BigEndianReader::ReadBytes(void* out, size_t len) { - if (ptr_ + len > end_) - return false; - memcpy(out, ptr_, len); - ptr_ += len; - return true; -} - -template -bool BigEndianReader::Read(T* value) { - if (ptr_ + sizeof(T) > end_) - return false; - ReadBigEndian(ptr_, value); - ptr_ += sizeof(T); - return true; -} - -bool BigEndianReader::ReadU8(uint8_t* value) { - return Read(value); -} - -bool BigEndianReader::ReadU16(uint16_t* value) { - return Read(value); -} - -bool BigEndianReader::ReadU32(uint32_t* value) { - return Read(value); -} - -bool BigEndianReader::ReadU64(uint64_t* value) { - return Read(value); -} - -BigEndianWriter::BigEndianWriter(char* buf, size_t len) : ptr_(buf), end_(ptr_ + len) {} - -bool BigEndianWriter::Skip(size_t len) { - if (ptr_ + len > end_) - return false; - ptr_ += len; - return true; -} - -bool BigEndianWriter::WriteBytes(const void* buf, size_t len) { - if (ptr_ + len > end_) - return false; - memcpy(ptr_, buf, len); - ptr_ += len; - return true; -} - -template -bool BigEndianWriter::Write(T value) { - if (ptr_ + sizeof(T) > end_) - return false; - WriteBigEndian(ptr_, value); - ptr_ += sizeof(T); - return true; -} - -bool BigEndianWriter::WriteU8(uint8_t value) { - return Write(value); -} - -bool BigEndianWriter::WriteU16(uint16_t value) { - return Write(value); -} - -bool BigEndianWriter::WriteU32(uint32_t value) { - return Write(value); -} - -bool BigEndianWriter::WriteU64(uint64_t value) { - return Write(value); -} - -} // namespace rocketmq diff --git a/src/common/big_endian.h b/src/common/big_endian.h deleted file mode 100644 index 57077ee65..000000000 --- a/src/common/big_endian.h +++ /dev/null @@ -1,102 +0,0 @@ - -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_BIG_ENDIAN_H_ -#define BASE_BIG_ENDIAN_H_ - -#include -#include - -namespace rocketmq { - -// Read an integer (signed or unsigned) from |buf| in Big Endian order. -// Note: this loop is unrolled with -O1 and above. -// NOTE(szym): glibc dns-canon.c use ntohs(*(uint16_t*)ptr) which is -// potentially unaligned. -// This would cause SIGBUS on ARMv5 or earlier and ARMv6-M. -template -inline void ReadBigEndian(const char buf[], T* out) { - *out = buf[0]; - for (size_t i = 1; i < sizeof(T); ++i) { - *out <<= 8; - // Must cast to uint8_t to avoid clobbering by sign extension. - *out |= static_cast(buf[i]); - } -} - -// Write an integer (signed or unsigned) |val| to |buf| in Big Endian order. -// Note: this loop is unrolled with -O1 and above. -template -inline void WriteBigEndian(char buf[], T val) { - for (size_t i = 0; i < sizeof(T); ++i) { - buf[sizeof(T) - i - 1] = static_cast(val & 0xFF); - val >>= 8; - } -} - -// Specializations to make clang happy about the (dead code) shifts above. -template <> -inline void ReadBigEndian(const char buf[], uint8_t* out) { - *out = buf[0]; -} - -template <> -inline void WriteBigEndian(char buf[], uint8_t val) { - buf[0] = static_cast(val); -} - -// Allows reading integers in network order (big endian) while iterating over -// an underlying buffer. All the reading functions advance the internal pointer. -class BigEndianReader { - public: - BigEndianReader(const char* buf, size_t len); - - const char* ptr() const { return ptr_; } - int remaining() const { return end_ - ptr_; } - - bool Skip(size_t len); - bool ReadBytes(void* out, size_t len); - bool ReadU8(uint8_t* value); - bool ReadU16(uint16_t* value); - bool ReadU32(uint32_t* value); - bool ReadU64(uint64_t* value); - - private: - // Hidden to promote type safety. - template - bool Read(T* v); - - const char* ptr_; - const char* end_; -}; - -// Allows writing integers in network order (big endian) while iterating over -// an underlying buffer. All the writing functions advance the internal pointer. -class BigEndianWriter { - public: - BigEndianWriter(char* buf, size_t len); - - char* ptr() const { return ptr_; } - int remaining() const { return end_ - ptr_; } - - bool Skip(size_t len); - bool WriteBytes(const void* buf, size_t len); - bool WriteU8(uint8_t value); - bool WriteU16(uint16_t value); - bool WriteU32(uint32_t value); - bool WriteU64(uint64_t value); - - private: - // Hidden to promote type safety. - template - bool Write(T v); - - char* ptr_; - char* end_; -}; - -} // namespace rocketmq - -#endif // BASE_BIG_ENDIAN_H_ diff --git a/src/common/dataBlock.cpp b/src/common/dataBlock.cpp deleted file mode 100644 index 87e98af49..000000000 --- a/src/common/dataBlock.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "dataBlock.h" -#include - -namespace rocketmq { - -MemoryBlock::MemoryBlock() : size(0), data(NULL) {} - -MemoryBlock::MemoryBlock(const int initialSize, const bool initialiseToZero) : size(0), data(NULL) { - if (initialSize > 0) { - size = initialSize; - data = static_cast(initialiseToZero ? std::calloc(initialSize, sizeof(char)) - : std::malloc(initialSize * sizeof(char))); - } -} - -MemoryBlock::MemoryBlock(const void* const dataToInitialiseFrom, const size_t sizeInBytes) - : size(sizeInBytes), data(NULL) { - if (size > 0) { - data = static_cast(std::malloc(size * sizeof(char))); - - if (dataToInitialiseFrom != NULL) - memcpy(data, dataToInitialiseFrom, size); - } -} - -MemoryBlock::MemoryBlock(const MemoryBlock& other) : size(other.size), data(NULL) { - if (size > 0) { - data = static_cast(std::malloc(size * sizeof(char))); - memcpy(data, other.data, size); - } -} - -MemoryBlock::MemoryBlock(MemoryBlock&& other) : size(other.size), data(other.data) { - other.size = 0; - other.data = NULL; -} - -MemoryBlock::~MemoryBlock() { - std::free(data); -} - -MemoryBlock& MemoryBlock::operator=(const MemoryBlock& other) { - if (this != &other) { - setSize(other.size, false); - memcpy(data, other.data, size); - } - - return *this; -} - -MemoryBlock& MemoryBlock::operator=(MemoryBlock&& other) { - if (this != &other) { - std::free(data); - - size = other.size; - data = other.data; - - other.size = 0; - other.data = NULL; - } - - return *this; -} - -//============================================================================== -bool MemoryBlock::operator==(const MemoryBlock& other) const { - return matches(other.data, other.size); -} - -bool MemoryBlock::operator!=(const MemoryBlock& other) const { - return !operator==(other); -} - -bool MemoryBlock::matches(const void* dataToCompare, int dataSize) const { - return size == dataSize && memcmp(data, dataToCompare, size) == 0; -} - -//============================================================================== -// this will resize the block to this size -void MemoryBlock::setSize(const int newSize, const bool initialiseToZero) { - if (size != newSize) { - if (newSize <= 0) { - reset(); - } else { - if (data != NULL) { - data = static_cast(data == NULL ? std::malloc(newSize * sizeof(char)) - : std::realloc(data, newSize * sizeof(char))); - - if (initialiseToZero && (newSize > size)) - memset(data + size, 0, newSize - size); - } else { - std::free(data); - data = static_cast(initialiseToZero ? std::calloc(newSize, sizeof(char)) - : std::malloc(newSize * sizeof(char))); - } - - size = newSize; - } - } -} - -void MemoryBlock::reset() { - std::free(data); - data = NULL; - size = 0; -} - -void MemoryBlock::ensureSize(const int minimumSize, const bool initialiseToZero) { - if (size < minimumSize) - setSize(minimumSize, initialiseToZero); -} - -//============================================================================== -void MemoryBlock::fillWith(const int value) { - memset(data, (int)value, size); -} - -void MemoryBlock::append(const void* const srcData, const int numBytes) { - if (numBytes > 0) { - const int oldSize = size; - setSize(size + numBytes); - memcpy(data + oldSize, srcData, numBytes); - } -} - -void MemoryBlock::replaceWith(const void* const srcData, const int numBytes) { - if (numBytes > 0) { - setSize(numBytes); - memcpy(data, srcData, numBytes); - } -} - -void MemoryBlock::insert(const void* const srcData, const int numBytes, int insertPosition) { - if (numBytes > 0) { - insertPosition = std::min(insertPosition, size); - const int trailingDataSize = size - insertPosition; - setSize(size + numBytes, false); - - if (trailingDataSize > 0) - memmove(data + insertPosition + numBytes, data + insertPosition, trailingDataSize); - - memcpy(data + insertPosition, srcData, numBytes); - } -} - -void MemoryBlock::removeSection(const int startByte, const int numBytesToRemove) { - if (startByte + numBytesToRemove >= size) { - setSize(startByte); - } else if (numBytesToRemove > 0) { - memmove(data + startByte, data + startByte + numBytesToRemove, size - (startByte + numBytesToRemove)); - - setSize(size - numBytesToRemove); - } -} - -void MemoryBlock::copyFrom(const void* const src, int offset, int num) { - const char* d = static_cast(src); - - if (offset < 0) { - d -= offset; - num += (size_t)-offset; - offset = 0; - } - - if ((size_t)offset + num > (unsigned int)size) - num = size - (size_t)offset; - - if (num > 0) - memcpy(data + offset, d, num); -} - -void MemoryBlock::copyTo(void* const dst, int offset, int num) const { - char* d = static_cast(dst); - - if (offset < 0) { - memset(d, 0, (size_t)-offset); - d -= offset; - num -= (size_t)-offset; - offset = 0; - } - - if ((size_t)offset + num > (unsigned int)size) { - const int newNum = (size_t)size - (size_t)offset; - memset(d + newNum, 0, num - newNum); - num = newNum; - } - - if (num > 0) - memcpy(d, data + offset, num); -} -} // namespace rocketmq diff --git a/src/common/dataBlock.h b/src/common/dataBlock.h deleted file mode 100644 index 7472927cd..000000000 --- a/src/common/dataBlock.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __DATABLOCK_H__ -#define __DATABLOCK_H__ - -#include -#include -#include -#include -#include - -#include "RocketMQClient.h" - -namespace rocketmq { - -class ROCKETMQCLIENT_API MemoryBlock { - public: - //============================================================================== - /** Create an uninitialised block with 0 size. */ - MemoryBlock(); - - /** Creates a memory block with a given initial size. - - @param initialSize the size of block to create - @param initialiseToZero whether to clear the memory or just leave it - uninitialised - */ - MemoryBlock(const int initialSize, bool initialiseToZero = false); - - /** Creates a memory block using a copy of a block of data. - - @param dataToInitialiseFrom some data to copy into this block - @param sizeInBytes how much space to use - */ - MemoryBlock(const void* dataToInitialiseFrom, size_t sizeInBytes); - - /** Creates a copy of another memory block. */ - MemoryBlock(const MemoryBlock&); - - MemoryBlock(MemoryBlock&&); - - /** Destructor. */ - ~MemoryBlock(); - - /** Copies another memory block onto this one. - This block will be resized and copied to exactly match the other one. - */ - MemoryBlock& operator=(const MemoryBlock&); - - MemoryBlock& operator=(MemoryBlock&&); - - //============================================================================== - /** Compares two memory blocks. - @returns true only if the two blocks are the same size and have identical - contents. - */ - bool operator==(const MemoryBlock& other) const; - - /** Compares two memory blocks. - @returns true if the two blocks are different sizes or have different - contents. - */ - bool operator!=(const MemoryBlock& other) const; - - //============================================================================== - /** Returns a void pointer to the data. - - Note that the pointer returned will probably become invalid when the - block is resized. - */ - char* getData() const { return data; } - - /** Returns a byte from the memory block. - This returns a reference, so you can also use it to set a byte. - */ - template - char& operator[](const Type offset) const { - return data[offset]; - } - - /** Returns true if the data in this MemoryBlock matches the raw bytes - * passed-in. */ - bool matches(const void* data, int dataSize) const; - - //============================================================================== - /** Returns the block's current allocated size, in bytes. */ - int getSize() const { return size; } - - /** Resizes the memory block. - - Any data that is present in both the old and new sizes will be retained. - When enlarging the block, the new space that is allocated at the end can - either be - cleared, or left uninitialised. - - @param newSize the new desired size for the block - @param initialiseNewSpaceToZero if the block gets enlarged, this - determines - whether to clear the new section or - just leave it - uninitialised - @see ensureSize - */ - void setSize(const int newSize, bool initialiseNewSpaceToZero = false); - - /** Increases the block's size only if it's smaller than a given size. - - @param minimumSize if the block is already bigger than - this size, no action - will be taken; otherwise it will be - increased to this size - @param initialiseNewSpaceToZero if the block gets enlarged, this - determines - whether to clear the new section or - just leave it - uninitialised - @see setSize - */ - void ensureSize(const int minimumSize, bool initialiseNewSpaceToZero = false); - - /** Frees all the blocks data, setting its size to 0. */ - void reset(); - - //============================================================================== - /** Fills the entire memory block with a repeated byte value. - This is handy for clearing a block of memory to zero. - */ - void fillWith(int valueToUse); - - /** Adds another block of data to the end of this one. - The data pointer must not be null. This block's size will be increased - accordingly. - */ - void append(const void* data, int numBytes); - - /** Resizes this block to the given size and fills its contents from the - supplied buffer. - The data pointer must not be null. - */ - void replaceWith(const void* data, int numBytes); - - /** Inserts some data into the block. - The dataToInsert pointer must not be null. This block's size will be - increased accordingly. - If the insert position lies outside the valid range of the block, it will - be clipped to - within the range before being used. - */ - void insert(const void* dataToInsert, int numBytesToInsert, int insertPosition); - - /** Chops out a section of the block. - - This will remove a section of the memory block and close the gap around - it, - shifting any subsequent data downwards and reducing the size of the block. - - If the range specified goes beyond the size of the block, it will be - clipped. - */ - void removeSection(int startByte, int numBytesToRemove); - - //============================================================================== - /** Copies data into this MemoryBlock from a memory address. - - @param srcData the memory location of the data to copy into - this block - @param destinationOffset the offset in this block at which the data - being copied should begin - @param numBytes how much to copy in (if this goes beyond the - size of the memory block, - it will be clipped so not to do anything - nasty) - */ - void copyFrom(const void* srcData, int destinationOffset, int numBytes); - - /** Copies data from this MemoryBlock to a memory address. - - @param destData the memory location to write to - @param sourceOffset the offset within this block from which the copied - data will be read - @param numBytes how much to copy (if this extends beyond the - limits of the memory block, - zeros will be used for that portion of the data) - */ - void copyTo(void* destData, int sourceOffset, int numBytes) const; - - private: - //============================================================================== - int size; - char* data; -}; -} // namespace rocketmq - -#endif diff --git a/src/common/sync_http_client.cpp b/src/common/sync_http_client.cpp deleted file mode 100644 index 52137b395..000000000 --- a/src/common/sync_http_client.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Logging.h" -#include "url.h" - -using boost::asio::deadline_timer; -using boost::asio::ip::tcp; -using boost::lambda::var; - -namespace { -void check_deadline(deadline_timer* deadline, tcp::socket* socket, const boost::system::error_code& ec) { - // Check whether the deadline has passed. We compare the deadline against - // the current time since a new asynchronous operation may have moved the - // deadline before this actor had a chance to run. - if (deadline->expires_at() <= deadline_timer::traits_type::now()) { - // The deadline has passed. The socket is closed so that any outstanding - // asynchronous operations are cancelled. This allows the blocked - // connect(), read_line() or write_line() functions to return. - boost::system::error_code ignored_ec; - socket->close(ignored_ec); - - // There is no longer an active deadline. The expiry is set to positive - // infinity so that the actor takes no action until a new deadline is set. - deadline->expires_at(boost::posix_time::pos_infin); - } - - // Put the actor back to sleep. - deadline->async_wait(boost::bind(&check_deadline, deadline, socket, boost::asio::placeholders::error)); -} -} // namespace - -namespace rocketmq { -bool SyncfetchNsAddr(const Url& url_s, std::string& body) { - bool ret = true; - try { - boost::asio::io_service io_service; - // Get a list of endpoints corresponding to the server name. - tcp::resolver resolver(io_service); - tcp::resolver::query query(url_s.host_, url_s.port_); - tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); - boost::system::error_code ec = boost::asio::error::would_block; - deadline_timer deadline(io_service); - // TODO hardcode - boost::posix_time::seconds timeout(3); - deadline.expires_from_now(timeout); - // Try each endpoint until we successfully establish a connection. - tcp::socket socket(io_service); - boost::system::error_code deadline_ec; - check_deadline(&deadline, &socket, deadline_ec); - - boost::asio::async_connect(socket, endpoint_iterator, boost::lambda::var(ec) = boost::lambda::_1); - - do { - io_service.run_one(); - } while (ec == boost::asio::error::would_block); - - if (ec || !socket.is_open()) { - LOG_ERROR("socket connect failure, connect timeout or connect failure"); - return false; - } - - // Form the request. We specify the "Connection: close" header so that the - // server will close the socket after transmitting the response. This will - // allow us to treat all data up until the EOF as the content. - boost::asio::streambuf request; - std::ostream request_stream(&request); - request_stream << "GET " << url_s.path_ << " HTTP/1.0\r\n"; - request_stream << "Host: " << url_s.host_ << "\r\n"; - request_stream << "Accept: */*\r\n"; - request_stream << "Connection: close\r\n\r\n"; - - // Send the request. - boost::asio::write(socket, request); - - // Read the response status line. The response streambuf will automatically - // grow to accommodate the entire line. The growth may be limited by passing - // a maximum size to the streambuf constructor. - boost::asio::streambuf response; - boost::asio::read_until(socket, response, "\r\n"); - - // Check that response is OK. - std::istream response_stream(&response); - std::string http_version; - response_stream >> http_version; - unsigned int status_code; - response_stream >> status_code; - std::string status_message; - std::getline(response_stream, status_message); - if (!response_stream || http_version.substr(0, 5) != "HTTP/") { - LOG_INFO("Invalid response %s\n", status_message.c_str()); - return false; - } - - if (status_code != 200) { - LOG_INFO("Response returned with status code %d ", status_code); - return false; - } - - // Read the response headers, which are terminated by a blank line. - boost::asio::read_until(socket, response, "\r\n\r\n"); - - // Process the response headers. - std::string header; - while (std::getline(response_stream, header) && header != "\r") - ; - - // Write whatever content we already have to output. - if (response.size() > 0) { - boost::asio::streambuf::const_buffers_type cbt = response.data(); - body.clear(); - body.insert(body.begin(), boost::asio::buffers_begin(cbt), boost::asio::buffers_end(cbt)); - } - - // Read until EOF, writing data to output as we go. - boost::system::error_code error; - while (boost::asio::read(socket, response, boost::asio::transfer_at_least(1), error)) - std::cout << &response; - if (error != boost::asio::error::eof) - throw boost::system::system_error(error); - - } catch (std::exception& e) { - LOG_ERROR("Exception: %s", e.what()); - ret = false; - } - - return ret; -} -} // namespace rocketmq diff --git a/src/common/url.cpp b/src/common/url.cpp deleted file mode 100644 index d63203721..000000000 --- a/src/common/url.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "url.h" -#include -#include -#include -#include -#include - -namespace rocketmq { - -Url::Url(const std::string& url_s) { - parse(url_s); -} - -void Url::parse(const std::string& url_s) { - const std::string prot_end("://"); - auto prot_i = std::search(url_s.begin(), url_s.end(), prot_end.begin(), prot_end.end()); - protocol_.reserve(std::distance(url_s.begin(), prot_i)); - std::transform(url_s.begin(), prot_i, std::back_inserter(protocol_), - std::ptr_fun(tolower)); // protocol is icase - - if (prot_i == url_s.end()) - return; - - std::advance(prot_i, prot_end.length()); - - auto path_i = find(prot_i, url_s.end(), ':'); - std::string::const_iterator path_end_i; - if (path_i == url_s.end()) { - // not include port, use default port - port_ = "80"; - path_i = std::find(prot_i, url_s.end(), '/'); - path_end_i = path_i; - } else { - auto port_i = find(path_i + 1, url_s.end(), '/'); - port_.insert(port_.begin(), path_i + 1, port_i); - path_end_i = path_i + port_.length() + 1; - } - - host_.reserve(distance(prot_i, path_i)); - std::transform(prot_i, path_i, std::back_inserter(host_), std::ptr_fun(tolower)); // host is icase} - - auto query_i = find(path_end_i, url_s.end(), '?'); - path_.assign(path_end_i, query_i); - if (query_i != url_s.end()) - ++query_i; - query_.assign(query_i, url_s.end()); -} - -} // namespace rocketmq diff --git a/src/consumer/AllocateMQStrategy.h b/src/consumer/AllocateMQStrategy.h deleted file mode 100644 index e24966c84..000000000 --- a/src/consumer/AllocateMQStrategy.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __ALLOCATEMESSAGEQUEUESTRATEGY_H__ -#define __ALLOCATEMESSAGEQUEUESTRATEGY_H__ - -#include "Logging.h" -#include "MQClientException.h" -#include "MQMessageQueue.h" - -namespace rocketmq { -//& mqAll, - std::vector& cidAll, - std::vector& outReuslt) = 0; -}; - -//& mqAll, - std::vector& cidAll, - std::vector& outReuslt) { - outReuslt.clear(); - if (currentCID.empty()) { - THROW_MQEXCEPTION(MQClientException, "currentCID is empty", -1); - } - - if (mqAll.empty()) { - THROW_MQEXCEPTION(MQClientException, "mqAll is empty", -1); - } - - if (cidAll.empty()) { - THROW_MQEXCEPTION(MQClientException, "cidAll is empty", -1); - } - - int index = -1; - int cidAllSize = cidAll.size(); - for (int i = 0; i < cidAllSize; i++) { - if (cidAll[i] == currentCID) { - index = i; - break; - } - } - - if (index == -1) { - LOG_ERROR("could not find clientId from Broker"); - return; - } - - int mqAllSize = mqAll.size(); - int mod = mqAllSize % cidAllSize; - int averageSize = - mqAllSize <= cidAllSize ? 1 : (mod > 0 && index < mod ? mqAllSize / cidAllSize + 1 : mqAllSize / cidAllSize); - int startIndex = (mod > 0 && index < mod) ? index * averageSize : index * averageSize + mod; - int range = (std::min)(averageSize, mqAllSize - startIndex); - LOG_INFO( - "range is:%d, index is:%d, mqAllSize is:%d, averageSize is:%d, " - "startIndex is:%d", - range, index, mqAllSize, averageSize, startIndex); - //= 0) // example: range is:-1, index is:1, mqAllSize is:1, - // averageSize is:1, startIndex is:2 - { - for (int i = 0; i < range; i++) { - if ((startIndex + i) >= 0) { - outReuslt.push_back(mqAll.at((startIndex + i) % mqAllSize)); - } - } - } - } -}; - -// -#endif - -#include "ConsumeMsgService.h" -#include "DefaultMQPushConsumer.h" -#include "Logging.h" -#include "MessageAccessor.h" -#include "StatsServerManager.h" -#include "UtilAll.h" - -namespace rocketmq { - -//getMessageListenerType(); -} - -void ConsumeMessageConcurrentlyService::submitConsumeRequest(boost::weak_ptr pullRequest, - vector& msgs) { - boost::shared_ptr request = pullRequest.lock(); - if (!request) { - LOG_WARN("Pull request has been released"); - return; - } - if (request->isDropped()) { - LOG_INFO("Pull request for %s is dropped, which will be released in next re-balance.", - request->m_messageQueue.toString().c_str()); - return; - } - if (!request->isDropped() && !m_ioService.stopped()) { - m_ioService.post(boost::bind(&ConsumeMessageConcurrentlyService::ConsumeRequest, this, request, msgs)); - } else { - LOG_INFO("IOService stopped or Pull request for %s is dropped, will not post ConsumeRequest.", - request->m_messageQueue.toString().c_str()); - } -} - -void ConsumeMessageConcurrentlyService::submitConsumeRequestLater(boost::weak_ptr pullRequest, - vector& msgs, - int millis) { - if (msgs.empty()) { - return; - } - boost::shared_ptr request = pullRequest.lock(); - if (!request) { - LOG_WARN("Pull request has been released"); - return; - } - if (request->isDropped()) { - LOG_INFO("Pull request is set as dropped with mq:%s, need release in next rebalance.", - (request->m_messageQueue).toString().c_str()); - return; - } - if (!request->isDropped() && !m_ioService.stopped()) { - boost::asio::deadline_timer* t = - new boost::asio::deadline_timer(m_ioService, boost::posix_time::milliseconds(millis)); - t->async_wait( - boost::bind(&(ConsumeMessageConcurrentlyService::static_submitConsumeRequest), this, t, request, msgs)); - LOG_INFO("Submit Message to Consumer [%s] Later and Sleep [%d]ms.", (request->m_messageQueue).toString().c_str(), - millis); - } else { - LOG_INFO("IOService stopped or Pull request for %s is dropped, will not post delay ConsumeRequest.", - request->m_messageQueue.toString().c_str()); - } -} - -void ConsumeMessageConcurrentlyService::static_submitConsumeRequest(void* context, - boost::asio::deadline_timer* t, - boost::weak_ptr pullRequest, - vector& msgs) { - boost::shared_ptr request = pullRequest.lock(); - if (!request) { - LOG_WARN("Pull request has been released"); - return; - } - ConsumeMessageConcurrentlyService* pService = (ConsumeMessageConcurrentlyService*)context; - if (pService) { - pService->triggersubmitConsumeRequestLater(t, request, msgs); - } -} - -void ConsumeMessageConcurrentlyService::triggersubmitConsumeRequestLater(boost::asio::deadline_timer* t, - boost::weak_ptr pullRequest, - vector& msgs) { - boost::shared_ptr request = pullRequest.lock(); - if (!request) { - LOG_WARN("Pull request has been released"); - return; - } - submitConsumeRequest(request, msgs); - deleteAndZero(t); -} - -void ConsumeMessageConcurrentlyService::ConsumeRequest(boost::weak_ptr pullRequest, - vector& msgs) { - boost::shared_ptr request = pullRequest.lock(); - if (!request) { - LOG_WARN("Pull request has been released"); - return; - } - if (request->isDropped()) { - LOG_WARN("the pull request for %s Had been dropped before", request->m_messageQueue.toString().c_str()); - request->clearAllMsgs(); // add clear operation to avoid bad state when - // dropped pullRequest returns normal - return; - } - if (msgs.empty()) { - LOG_WARN("the msg of pull result is NULL,its mq:%s", (request->m_messageQueue).toString().c_str()); - return; - } - ConsumeMessageContext consumeMessageContext; - DefaultMQPushConsumerImpl* pConsumer = dynamic_cast(m_pConsumer); - std::string groupName = pConsumer->getGroupName(); - if (pConsumer) { - if (pConsumer->getMessageTrace() && pConsumer->hasConsumeMessageHook()) { - consumeMessageContext.setDefaultMQPushConsumer(pConsumer); - consumeMessageContext.setConsumerGroup(groupName); - consumeMessageContext.setMessageQueue(request->m_messageQueue); - consumeMessageContext.setMsgList(msgs); - consumeMessageContext.setSuccess(false); - consumeMessageContext.setNameSpace(pConsumer->getNameSpace()); - pConsumer->executeConsumeMessageHookBefore(&consumeMessageContext); - } - } - ConsumeStatus status = CONSUME_SUCCESS; - if (m_pMessageListener != NULL) { - resetRetryTopic(msgs); - request->setLastConsumeTimestamp(UtilAll::currentTimeMillis()); - LOG_DEBUG("=====Receive Messages,Topic[%s], MsgId[%s],Body[%s],RetryTimes[%d]", msgs[0].getTopic().c_str(), - msgs[0].getMsgId().c_str(), msgs[0].getBody().c_str(), msgs[0].getReconsumeTimes()); - if (m_pConsumer->isUseNameSpaceMode()) { - MessageAccessor::withoutNameSpace(msgs, m_pConsumer->getNameSpace()); - } - - if (pConsumer->getMessageTrace() && pConsumer->hasConsumeMessageHook()) { - // For open trace message, consume message one by one. - for (size_t i = 0; i < msgs.size(); ++i) { - LOG_DEBUG("=====Trace Receive Messages,Topic[%s], MsgId[%s],Body[%s],RetryTimes[%d]", - msgs[i].getTopic().c_str(), msgs[i].getMsgId().c_str(), msgs[i].getBody().c_str(), - msgs[i].getReconsumeTimes()); - std::vector msgInner; - msgInner.push_back(msgs[i]); - if (status != CONSUME_SUCCESS) { - // all the Messages behind should be set to failed. - status = RECONSUME_LATER; - consumeMessageContext.setMsgIndex(i); - consumeMessageContext.setStatus("RECONSUME_LATER"); - consumeMessageContext.setSuccess(false); - pConsumer->executeConsumeMessageHookAfter(&consumeMessageContext); - continue; - } - uint64 startTimeStamp = UtilAll::currentTimeMillis(); - try { - status = m_pMessageListener->consumeMessage(msgInner); - } catch (...) { - status = RECONSUME_LATER; - LOG_ERROR("Consumer's code is buggy. Un-caught exception raised"); - } - uint64 consumerRT = UtilAll::currentTimeMillis() - startTimeStamp; - StatsServerManager::getInstance()->getConsumeStatServer()->incConsumeRT(request->m_messageQueue.getTopic(), - groupName, consumerRT); - consumeMessageContext.setMsgIndex(i); // indicate message position,not support batch consumer - if (status == CONSUME_SUCCESS) { - consumeMessageContext.setStatus("CONSUME_SUCCESS"); - consumeMessageContext.setSuccess(true); - } else { - status = RECONSUME_LATER; - consumeMessageContext.setStatus("RECONSUME_LATER"); - consumeMessageContext.setSuccess(false); - } - pConsumer->executeConsumeMessageHookAfter(&consumeMessageContext); - } - } else { - uint64 startTimeStamp = UtilAll::currentTimeMillis(); - try { - status = m_pMessageListener->consumeMessage(msgs); - } catch (...) { - status = RECONSUME_LATER; - LOG_ERROR("Consumer's code is buggy. Un-caught exception raised"); - } - uint64 consumerRT = UtilAll::currentTimeMillis() - startTimeStamp; - StatsServerManager::getInstance()->getConsumeStatServer()->incConsumeRT(request->m_messageQueue.getTopic(), - groupName, consumerRT, msgs.size()); - } - } - - int ackIndex = -1; - switch (status) { - case CONSUME_SUCCESS: - ackIndex = msgs.size(); - break; - case RECONSUME_LATER: - ackIndex = -1; - break; - default: - break; - } - - std::vector localRetryMsgs; - switch (m_pConsumer->getMessageModel()) { - case BROADCASTING: { - // Note: broadcasting reconsume should do by application, as it has big - // affect to broker cluster - if (ackIndex != (int)msgs.size()) - LOG_WARN("BROADCASTING, the message consume failed, drop it:%s", (request->m_messageQueue).toString().c_str()); - break; - } - case CLUSTERING: { - // status consumer tps - if (ackIndex == -1) { - StatsServerManager::getInstance()->getConsumeStatServer()->incConsumeFailedTPS( - request->m_messageQueue.getTopic(), groupName, msgs.size()); - } else { - StatsServerManager::getInstance()->getConsumeStatServer()->incConsumeOKTPS(request->m_messageQueue.getTopic(), - groupName, msgs.size()); - } - - // send back msg to broker; - for (size_t i = ackIndex + 1; i < msgs.size(); i++) { - LOG_DEBUG("consume fail, MQ is:%s, its msgId is:%s, index is:" SIZET_FMT ", reconsume times is:%d", - (request->m_messageQueue).toString().c_str(), msgs[i].getMsgId().c_str(), i, - msgs[i].getReconsumeTimes()); - if (m_pConsumer->getConsumeType() == CONSUME_PASSIVELY) { - string brokerName = request->m_messageQueue.getBrokerName(); - if (m_pConsumer->isUseNameSpaceMode()) { - MessageAccessor::withNameSpace(msgs[i], m_pConsumer->getNameSpace()); - } - if (!m_pConsumer->sendMessageBack(msgs[i], 0, brokerName)) { - LOG_WARN("Send message back fail, MQ is:%s, its msgId is:%s, index is:%d, re-consume times is:%d", - (request->m_messageQueue).toString().c_str(), msgs[i].getMsgId().c_str(), i, - msgs[i].getReconsumeTimes()); - msgs[i].setReconsumeTimes(msgs[i].getReconsumeTimes() + 1); - localRetryMsgs.push_back(msgs[i]); - } - } - } - break; - } - default: - break; - } - - if (!localRetryMsgs.empty()) { - LOG_ERROR("Client side re-consume launched due to both message consuming and SDK send-back retry failure"); - for (std::vector::iterator itOrigin = msgs.begin(); itOrigin != msgs.end();) { - bool remove = false; - for (std::vector::iterator itRetry = localRetryMsgs.begin(); itRetry != localRetryMsgs.end(); - itRetry++) { - if (itRetry->getQueueOffset() == itOrigin->getQueueOffset()) { - remove = true; - break; - } - } - if (remove) { - itOrigin = msgs.erase(itOrigin); - } else { - itOrigin++; - } - } - } - // update offset - int64 offset = request->removeMessage(msgs); - if (offset >= 0) { - m_pConsumer->updateConsumeOffset(request->m_messageQueue, offset); - } else { - LOG_WARN("Note: Get local offset for mq:%s failed, may be it is updated before. skip..", - (request->m_messageQueue).toString().c_str()); - } - if (!localRetryMsgs.empty()) { - // submitConsumeRequest(request, localTryMsgs); - LOG_INFO("Send [%d ]messages back to mq:%s failed, call reconsume again after 1s.", localRetryMsgs.size(), - (request->m_messageQueue).toString().c_str()); - submitConsumeRequestLater(request, localRetryMsgs, 1000); - } -} // namespace rocketmq - -void ConsumeMessageConcurrentlyService::resetRetryTopic(vector& msgs) { - string groupTopic = UtilAll::getRetryTopic(m_pConsumer->getGroupName()); - for (size_t i = 0; i < msgs.size(); i++) { - MQMessageExt& msg = msgs[i]; - string retryTopic = msg.getProperty(MQMessage::PROPERTY_RETRY_TOPIC); - if (!retryTopic.empty() && groupTopic.compare(msg.getTopic()) == 0) { - msg.setTopic(retryTopic); - } - } -} - -// -#include -#include "ConsumeMessageContext.h" -#include "DefaultMQPushConsumerImpl.h" -#include "Logging.h" -#include "MQClientException.h" -#include "NameSpaceUtil.h" -#include "TraceConstant.h" -#include "TraceContext.h" -#include "TraceTransferBean.h" -#include "TraceUtil.h" -#include "UtilAll.h" -namespace rocketmq { - -class TraceMessageConsumeCallback : public SendCallback { - virtual void onSuccess(SendResult& sendResult) { - LOG_DEBUG("TraceMessageConsumeCallback, MsgId:[%s],OffsetMsgId[%s]", sendResult.getMsgId().c_str(), - sendResult.getOffsetMsgId().c_str()); - } - virtual void onException(MQException& e) {} -}; -static TraceMessageConsumeCallback* consumeTraceCallback = new TraceMessageConsumeCallback(); -std::string ConsumeMessageHookImpl::getHookName() { - return "RocketMQConsumeMessageHookImpl"; -} - -void ConsumeMessageHookImpl::executeHookBefore(ConsumeMessageContext* context) { - if (context == NULL || context->getMsgList().empty()) { - return; - } - TraceContext* traceContext = new TraceContext(); - context->setTraceContext(traceContext); - traceContext->setTraceType(SubBefore); - traceContext->setGroupName(NameSpaceUtil::withoutNameSpace(context->getConsumerGroup(), context->getNameSpace())); - std::vector beans; - - std::vector msgs = context->getMsgList(); - std::vector::iterator it = msgs.begin(); - for (; it != msgs.end(); ++it) { - std::string traceOn = it->getProperty(MQMessage::PROPERTY_TRACE_SWITCH); - if (traceOn != "" && traceOn == "false") { - continue; - } - TraceBean bean; - bean.setTopic((*it).getTopic()); - bean.setMsgId((*it).getMsgId()); - bean.setTags((*it).getTags()); - bean.setKeys((*it).getKeys()); - bean.setStoreHost((*it).getStoreHostString()); - bean.setStoreTime((*it).getStoreTimestamp()); - bean.setBodyLength((*it).getStoreSize()); - bean.setRetryTimes((*it).getReconsumeTimes()); - std::string regionId = (*it).getProperty(MQMessage::PROPERTY_MSG_REGION); - if (regionId.empty()) { - regionId = TraceConstant::DEFAULT_REDION; - } - traceContext->setRegionId(regionId); - traceContext->setTraceBean(bean); - } - traceContext->setTimeStamp(UtilAll::currentTimeMillis()); - - std::string topic = TraceConstant::TRACE_TOPIC + traceContext->getRegionId(); - - TraceTransferBean ben = TraceUtil::CovertTraceContextToTransferBean(traceContext); - MQMessage message(topic, ben.getTransData()); - message.setKeys(ben.getTransKey()); - - // send trace message async. - context->getDefaultMQPushConsumer()->submitSendTraceRequest(message, consumeTraceCallback); - return; -} - -void ConsumeMessageHookImpl::executeHookAfter(ConsumeMessageContext* context) { - if (context == NULL || context->getMsgList().empty()) { - return; - } - - std::shared_ptr subBeforeContext = context->getTraceContext(); - TraceContext subAfterContext; - subAfterContext.setTraceType(SubAfter); - subAfterContext.setRegionId(subBeforeContext->getRegionId()); - subAfterContext.setGroupName(subBeforeContext->getGroupName()); - subAfterContext.setRequestId(subBeforeContext->getRequestId()); - subAfterContext.setStatus(context->getSuccess()); - int costTime = static_cast(UtilAll::currentTimeMillis() - subBeforeContext->getTimeStamp()); - subAfterContext.setCostTime(costTime); - subAfterContext.setTraceBeanIndex(context->getMsgIndex()); - TraceBean bean = subBeforeContext->getTraceBeans()[subAfterContext.getTraceBeanIndex()]; - subAfterContext.setTraceBean(bean); - - std::string topic = TraceConstant::TRACE_TOPIC + subAfterContext.getRegionId(); - TraceTransferBean ben = TraceUtil::CovertTraceContextToTransferBean(&subAfterContext); - MQMessage message(topic, ben.getTransData()); - message.setKeys(ben.getTransKey()); - - // send trace message async. - context->getDefaultMQPushConsumer()->submitSendTraceRequest(message, consumeTraceCallback); - return; -} -} // namespace rocketmq diff --git a/src/consumer/ConsumeMessageHookImpl.h b/src/consumer/ConsumeMessageHookImpl.h deleted file mode 100644 index 30852bac0..000000000 --- a/src/consumer/ConsumeMessageHookImpl.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __ROCKETMQ_CONSUME_MESSAGE_RPC_HOOK_IMPL_H__ -#define __ROCKETMQ_CONSUME_MESSAGE_RPC_HOOK_IMPL_H__ - -#include -#include "ConsumeMessageContext.h" -#include "ConsumeMessageHook.h" -namespace rocketmq { -class ConsumeMessageHookImpl : public ConsumeMessageHook { - public: - virtual ~ConsumeMessageHookImpl() {} - virtual std::string getHookName(); - virtual void executeHookBefore(ConsumeMessageContext* context); - virtual void executeHookAfter(ConsumeMessageContext* context); -}; -} // namespace rocketmq -#endif \ No newline at end of file diff --git a/src/consumer/ConsumeMessageOrderlyService.cpp b/src/consumer/ConsumeMessageOrderlyService.cpp deleted file mode 100644 index 9ee8b82c6..000000000 --- a/src/consumer/ConsumeMessageOrderlyService.cpp +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ -#if !defined(WIN32) && !defined(__APPLE__) -#include -#endif - -#include -#include "ConsumeMsgService.h" -#include "DefaultMQPushConsumer.h" -#include "Logging.h" -#include "Rebalance.h" -#include "StatsServerManager.h" -#include "UtilAll.h" - -namespace rocketmq { - -//getRebalance()->lockAll(); - - boost::system::error_code e; - t->expires_at(t->expires_at() + boost::posix_time::milliseconds(PullRequest::RebalanceLockInterval), e); - t->async_wait(boost::bind(&ConsumeMessageOrderlyService::lockMQPeriodically, this, ec, t)); -} - -void ConsumeMessageOrderlyService::unlockAllMQ() { - m_pConsumer->getRebalance()->unlockAll(false); -} - -bool ConsumeMessageOrderlyService::lockOneMQ(const MQMessageQueue& mq) { - return m_pConsumer->getRebalance()->lock(mq); -} - -void ConsumeMessageOrderlyService::stopThreadPool() { - m_shutdownInprogress = true; - m_ioService.stop(); - m_async_ioService.stop(); - m_async_service_thread->interrupt(); - m_async_service_thread->join(); - m_threadpool.join_all(); -} - -MessageListenerType ConsumeMessageOrderlyService::getConsumeMsgSerivceListenerType() { - return m_pMessageListener->getMessageListenerType(); -} - -void ConsumeMessageOrderlyService::submitConsumeRequest(boost::weak_ptr pullRequest, - vector& msgs) { - boost::shared_ptr request = pullRequest.lock(); - if (!request) { - LOG_WARN("Pull request has been released"); - return; - } - m_ioService.post(boost::bind(&ConsumeMessageOrderlyService::ConsumeRequest, this, request)); -} - -void ConsumeMessageOrderlyService::static_submitConsumeRequestLater(void* context, - boost::weak_ptr pullRequest, - bool tryLockMQ, - boost::asio::deadline_timer* t) { - boost::shared_ptr request = pullRequest.lock(); - if (!request) { - LOG_WARN("Pull request has been released"); - return; - } - LOG_INFO("submit consumeRequest later for mq:%s", request->m_messageQueue.toString().c_str()); - vector msgs; - ConsumeMessageOrderlyService* orderlyService = (ConsumeMessageOrderlyService*)context; - orderlyService->submitConsumeRequest(request, msgs); - if (tryLockMQ) { - orderlyService->lockOneMQ(request->m_messageQueue); - } - if (t) - deleteAndZero(t); -} - -void ConsumeMessageOrderlyService::ConsumeRequest(boost::weak_ptr pullRequest) { - boost::shared_ptr request = pullRequest.lock(); - if (!request) { - LOG_WARN("Pull request has been released"); - return; - } - bool bGetMutex = false; - boost::unique_lock lock(request->getPullRequestCriticalSection(), boost::try_to_lock); - if (!lock.owns_lock()) { - if (!lock.timed_lock(boost::get_system_time() + boost::posix_time::seconds(1))) { - LOG_ERROR("ConsumeRequest of:%s get timed_mutex timeout", request->m_messageQueue.toString().c_str()); - return; - } else { - bGetMutex = true; - } - } else { - bGetMutex = true; - } - if (!bGetMutex) { - // LOG_INFO("pullrequest of mq:%s consume inprogress", - // request->m_messageQueue.toString().c_str()); - return; - } - if (!request || request->isDropped()) { - LOG_WARN("the pull result is NULL or Had been dropped"); - request->clearAllMsgs(); // add clear operation to avoid bad state when - // dropped pullRequest returns normal - return; - } - - if (m_pMessageListener) { - if ((request->isLocked() && !request->isLockExpired()) || m_pConsumer->getMessageModel() == BROADCASTING) { - // DefaultMQPushConsumer* pConsumer = (DefaultMQPushConsumer*)m_pConsumer; - uint64_t beginTime = UtilAll::currentTimeMillis(); - bool continueConsume = true; - while (continueConsume) { - if ((UtilAll::currentTimeMillis() - beginTime) > m_MaxTimeConsumeContinuously) { - LOG_INFO("Continuely consume %s more than 60s, consume it 1s later", - request->m_messageQueue.toString().c_str()); - tryLockLaterAndReconsumeDelay(request, false, 1000); - break; - } - vector msgs; - // request->takeMessages(msgs, pConsumer->getConsumeMessageBatchMaxSize()); - request->takeMessages(msgs, 1); - if (!msgs.empty()) { - request->setLastConsumeTimestamp(UtilAll::currentTimeMillis()); - if (m_pConsumer->isUseNameSpaceMode()) { - MessageAccessor::withoutNameSpace(msgs, m_pConsumer->getNameSpace()); - } - ConsumeMessageContext consumeMessageContext; - DefaultMQPushConsumerImpl* pConsumer = dynamic_cast(m_pConsumer); - std::string groupName = pConsumer->getGroupName(); - if (pConsumer) { - if (pConsumer->getMessageTrace() && pConsumer->hasConsumeMessageHook()) { - consumeMessageContext.setDefaultMQPushConsumer(pConsumer); - consumeMessageContext.setConsumerGroup(pConsumer->getGroupName()); - consumeMessageContext.setMessageQueue(request->m_messageQueue); - consumeMessageContext.setMsgList(msgs); - consumeMessageContext.setSuccess(false); - consumeMessageContext.setNameSpace(pConsumer->getNameSpace()); - pConsumer->executeConsumeMessageHookBefore(&consumeMessageContext); - } - } - uint64 startTimeStamp = UtilAll::currentTimeMillis(); - ConsumeStatus consumeStatus = m_pMessageListener->consumeMessage(msgs); - - uint64 consumerRT = UtilAll::currentTimeMillis() - startTimeStamp; - StatsServerManager::getInstance()->getConsumeStatServer()->incConsumeRT(request->m_messageQueue.getTopic(), - groupName, consumerRT); - if (consumeStatus == RECONSUME_LATER) { - StatsServerManager::getInstance()->getConsumeStatServer()->incConsumeFailedTPS( - request->m_messageQueue.getTopic(), groupName, 1); - - if (pConsumer) { - consumeMessageContext.setMsgIndex(0); - consumeMessageContext.setStatus("RECONSUME_LATER"); - consumeMessageContext.setSuccess(false); - pConsumer->executeConsumeMessageHookAfter(&consumeMessageContext); - } - if (msgs[0].getReconsumeTimes() <= 15) { - msgs[0].setReconsumeTimes(msgs[0].getReconsumeTimes() + 1); - request->makeMessageToCosumeAgain(msgs); - continueConsume = false; - tryLockLaterAndReconsumeDelay(request, false, 1000); - } else { - // need change to reconsumer delay level and print log. - LOG_INFO("Local Consume failed [%d] times, change [%s] delay to 5s.", msgs[0].getReconsumeTimes(), - msgs[0].getMsgId().c_str()); - msgs[0].setReconsumeTimes(msgs[0].getReconsumeTimes() + 1); - continueConsume = false; - request->makeMessageToCosumeAgain(msgs); - tryLockLaterAndReconsumeDelay(request, false, 5000); - } - } else { - StatsServerManager::getInstance()->getConsumeStatServer()->incConsumeOKTPS( - request->m_messageQueue.getTopic(), groupName, 1); - if (pConsumer) { - consumeMessageContext.setMsgIndex(0); - consumeMessageContext.setStatus("CONSUME_SUCCESS"); - consumeMessageContext.setSuccess(true); - pConsumer->executeConsumeMessageHookAfter(&consumeMessageContext); - } - m_pConsumer->updateConsumeOffset(request->m_messageQueue, request->commit()); - } - } else { - continueConsume = false; - } - msgs.clear(); - if (m_shutdownInprogress) { - LOG_INFO("shutdown inprogress, break the consuming"); - return; - } - } - LOG_DEBUG("consume once exit of mq:%s", request->m_messageQueue.toString().c_str()); - } else { - LOG_ERROR("message queue:%s was not locked", request->m_messageQueue.toString().c_str()); - tryLockLaterAndReconsumeDelay(request, true, 1000); - } - } -} -void ConsumeMessageOrderlyService::tryLockLaterAndReconsumeDelay(boost::weak_ptr pullRequest, - bool tryLockMQ, - int millisDelay) { - boost::shared_ptr request = pullRequest.lock(); - if (!request) { - LOG_WARN("Pull request has been released"); - return; - } - int retryTimer = millisDelay; - if (millisDelay >= 30000 || millisDelay <= 1000) { - retryTimer = 1000; - } - boost::asio::deadline_timer* t = - new boost::asio::deadline_timer(m_async_ioService, boost::posix_time::milliseconds(retryTimer)); - t->async_wait( - boost::bind(&ConsumeMessageOrderlyService::static_submitConsumeRequestLater, this, request, tryLockMQ, t)); -} - -} // namespace rocketmq diff --git a/src/consumer/ConsumeMsgService.h b/src/consumer/ConsumeMsgService.h deleted file mode 100644 index 8745bae1d..000000000 --- a/src/consumer/ConsumeMsgService.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _CONSUMEMESSAGESERVICE_H_ -#define _CONSUMEMESSAGESERVICE_H_ - -#include -#include -#include -#include -#include -#include -#include "DefaultMQPushConsumerImpl.h" -#include "Logging.h" -#include "MQConsumer.h" -#include "MQMessageListener.h" -#include "PullRequest.h" -namespace rocketmq { -// class MQConsumer; -// request, vector& msgs) {} - virtual MessageListenerType getConsumeMsgSerivceListenerType() { return messageListenerDefaultly; } -}; - -class ConsumeMessageConcurrentlyService : public ConsumeMsgService { - public: - ConsumeMessageConcurrentlyService(MQConsumer*, int threadCount, MQMessageListener* msgListener); - virtual ~ConsumeMessageConcurrentlyService(); - virtual void start(); - virtual void shutdown(); - virtual void submitConsumeRequest(boost::weak_ptr request, vector& msgs); - virtual MessageListenerType getConsumeMsgSerivceListenerType(); - virtual void stopThreadPool(); - - void ConsumeRequest(boost::weak_ptr request, vector& msgs); - void submitConsumeRequestLater(boost::weak_ptr request, vector& msgs, int millis); - - void triggersubmitConsumeRequestLater(boost::asio::deadline_timer* t, - boost::weak_ptr pullRequest, - vector& msgs); - static void static_submitConsumeRequest(void* context, - boost::asio::deadline_timer* t, - boost::weak_ptr pullRequest, - vector& msgs); - - private: - void resetRetryTopic(vector& msgs); - - private: - MQConsumer* m_pConsumer; - MQMessageListener* m_pMessageListener; - boost::asio::io_service m_ioService; - boost::thread_group m_threadpool; - boost::asio::io_service::work m_ioServiceWork; -}; - -class ConsumeMessageOrderlyService : public ConsumeMsgService { - public: - ConsumeMessageOrderlyService(MQConsumer*, int threadCount, MQMessageListener* msgListener); - virtual ~ConsumeMessageOrderlyService(); - virtual void start(); - virtual void shutdown(); - virtual void submitConsumeRequest(boost::weak_ptr request, vector& msgs); - virtual void stopThreadPool(); - virtual MessageListenerType getConsumeMsgSerivceListenerType(); - - void boost_asio_work(); - // void tryLockLaterAndReconsume(boost::weak_ptr request, bool tryLockMQ); - void tryLockLaterAndReconsumeDelay(boost::weak_ptr request, bool tryLockMQ, int millisDelay); - static void static_submitConsumeRequestLater(void* context, - boost::weak_ptr request, - bool tryLockMQ, - boost::asio::deadline_timer* t); - void ConsumeRequest(boost::weak_ptr request); - void lockMQPeriodically(boost::system::error_code& ec, boost::asio::deadline_timer* t); - void unlockAllMQ(); - bool lockOneMQ(const MQMessageQueue& mq); - - private: - MQConsumer* m_pConsumer; - bool m_shutdownInprogress; - MQMessageListener* m_pMessageListener; - uint64_t m_MaxTimeConsumeContinuously; - boost::asio::io_service m_ioService; - boost::thread_group m_threadpool; - boost::asio::io_service::work m_ioServiceWork; - boost::asio::io_service m_async_ioService; - boost::scoped_ptr m_async_service_thread; -}; - -//start(); -} - -void DefaultMQPullConsumer::shutdown() { - impl->shutdown(); -} -std::string DefaultMQPullConsumer::version() { - std::string versions = impl->getClientVersionString(); - /*versions.append(", PROTOCOL VERSION: ") - .append(MQVersion::GetVersionDesc(MQVersion::s_CurrentVersion)) - .append(", LANGUAGE: ") - .append(MQVersion::s_CurrentLanguage);*/ - return versions; -} -// start mqclient set -const std::string& DefaultMQPullConsumer::getNamesrvAddr() const { - return impl->getNamesrvAddr(); -} - -void DefaultMQPullConsumer::setNamesrvAddr(const std::string& namesrvAddr) { - impl->setNamesrvAddr(namesrvAddr); -} - -const std::string& DefaultMQPullConsumer::getNamesrvDomain() const { - return impl->getNamesrvDomain(); -} - -void DefaultMQPullConsumer::setNamesrvDomain(const std::string& namesrvDomain) { - impl->setNamesrvDomain(namesrvDomain); -} -void DefaultMQPullConsumer::setSessionCredentials(const std::string& accessKey, - const std::string& secretKey, - const std::string& accessChannel) { - impl->setSessionCredentials(accessKey, secretKey, accessChannel); -} - -const SessionCredentials& DefaultMQPullConsumer::getSessionCredentials() const { - return impl->getSessionCredentials(); -} -const std::string& DefaultMQPullConsumer::getInstanceName() const { - return impl->getInstanceName(); -} - -void DefaultMQPullConsumer::setInstanceName(const std::string& instanceName) { - impl->setInstanceName(instanceName); -} - -const std::string& DefaultMQPullConsumer::getNameSpace() const { - return impl->getNameSpace(); -} - -void DefaultMQPullConsumer::setNameSpace(const std::string& nameSpace) { - impl->setNameSpace(nameSpace); -} -const std::string& DefaultMQPullConsumer::getGroupName() const { - return impl->getGroupName(); -} - -void DefaultMQPullConsumer::setGroupName(const std::string& groupName) { - impl->setGroupName(groupName); -} - -void DefaultMQPullConsumer::setEnableSsl(bool enableSsl) { - impl->setEnableSsl(enableSsl); -} - -bool DefaultMQPullConsumer::getEnableSsl() const { - return impl->getEnableSsl(); -} - -void DefaultMQPullConsumer::setSslPropertyFile(const std::string& sslPropertyFile) { - impl->setSslPropertyFile(sslPropertyFile); -} - -const std::string& DefaultMQPullConsumer::getSslPropertyFile() const { - return impl->getSslPropertyFile(); -} - -void DefaultMQPullConsumer::setLogLevel(elogLevel inputLevel) { - impl->setLogLevel(inputLevel); -} - -elogLevel DefaultMQPullConsumer::getLogLevel() { - return impl->getLogLevel(); -} -void DefaultMQPullConsumer::setLogFileSizeAndNum(int fileNum, long perFileSize) { - impl->setLogFileSizeAndNum(fileNum, perFileSize); -} - -// void DefaultMQPullConsumer::setUnitName(std::string unitName) { -// impl->setUnitName(unitName); -// } -// const std::string& DefaultMQPullConsumer::getUnitName() const { -// return impl->getUnitName(); -// } - -void DefaultMQPullConsumer::fetchSubscribeMessageQueues(const std::string& topic, std::vector& mqs) { - impl->fetchSubscribeMessageQueues(topic, mqs); -} - -void DefaultMQPullConsumer::persistConsumerOffset() { - impl->persistConsumerOffset(); -} -void DefaultMQPullConsumer::persistConsumerOffsetByResetOffset() { - impl->persistConsumerOffsetByResetOffset(); -} -void DefaultMQPullConsumer::updateTopicSubscribeInfo(const std::string& topic, std::vector& info) { - impl->updateTopicSubscribeInfo(topic, info); -} - -ConsumeFromWhere DefaultMQPullConsumer::getConsumeFromWhere() { - return impl->getConsumeFromWhere(); -} -void DefaultMQPullConsumer::getSubscriptions(std::vector& subData) { - impl->getSubscriptions(subData); -} -void DefaultMQPullConsumer::updateConsumeOffset(const MQMessageQueue& mq, int64 offset) { - impl->updateConsumeOffset(mq, offset); -} -void DefaultMQPullConsumer::removeConsumeOffset(const MQMessageQueue& mq) { - impl->removeConsumeOffset(mq); -} - -void DefaultMQPullConsumer::registerMessageQueueListener(const std::string& topic, MQueueListener* pListener) { - impl->registerMessageQueueListener(topic, pListener); -} -PullResult DefaultMQPullConsumer::pull(const MQMessageQueue& mq, - const std::string& subExpression, - int64 offset, - int maxNums) { - return impl->pull(mq, subExpression, offset, maxNums); -} -void DefaultMQPullConsumer::pull(const MQMessageQueue& mq, - const std::string& subExpression, - int64 offset, - int maxNums, - PullCallback* pPullCallback) { - impl->pull(mq, subExpression, offset, maxNums, pPullCallback); -} - -PullResult DefaultMQPullConsumer::pullBlockIfNotFound(const MQMessageQueue& mq, - const std::string& subExpression, - int64 offset, - int maxNums) { - return impl->pullBlockIfNotFound(mq, subExpression, offset, maxNums); -} -void DefaultMQPullConsumer::pullBlockIfNotFound(const MQMessageQueue& mq, - const std::string& subExpression, - int64 offset, - int maxNums, - PullCallback* pPullCallback) { - impl->pullBlockIfNotFound(mq, subExpression, offset, maxNums, pPullCallback); -} - -int64 DefaultMQPullConsumer::fetchConsumeOffset(const MQMessageQueue& mq, bool fromStore) { - return impl->fetchConsumeOffset(mq, fromStore); -} - -void DefaultMQPullConsumer::fetchMessageQueuesInBalance(const std::string& topic, std::vector mqs) { - impl->fetchMessageQueuesInBalance(topic, mqs); -} -void DefaultMQPullConsumer::persistConsumerOffset4PullConsumer(const MQMessageQueue& mq) { - // impl->persistConsumerOffsetByResetOffset(mq); -} - -//registerConsumer(this); - if (!registerOK) { - m_serviceState = CREATE_JUST; - THROW_MQEXCEPTION( - MQClientException, - "The cousumer group[" + getGroupName() + "] has been created before, specify another name please.", -1); - } - - //load(); - } catch (MQClientException& e) { - bStartFailed = true; - errorMsg = std::string(e.what()); - } - - getFactory()->start(); - m_serviceState = RUNNING; - if (bStartFailed) { - shutdown(); - THROW_MQEXCEPTION(MQClientException, errorMsg, -1); - } - break; - } - case RUNNING: - case START_FAILED: - case SHUTDOWN_ALREADY: - break; - default: - break; - } -} - -void DefaultMQPullConsumerImpl::shutdown() { - switch (m_serviceState) { - case RUNNING: { - LOG_INFO("DefaultMQPullConsumerImpl:%s shutdown", m_GroupName.c_str()); - persistConsumerOffset(); - getFactory()->unregisterConsumer(this); - getFactory()->shutdown(); - m_serviceState = SHUTDOWN_ALREADY; - break; - } - case SHUTDOWN_ALREADY: - case CREATE_JUST: - break; - default: - break; - } -} - -bool DefaultMQPullConsumerImpl::sendMessageBack(MQMessageExt& msg, int delayLevel, string& brokerName) { - return true; -} - -void DefaultMQPullConsumerImpl::fetchSubscribeMessageQueues(const string& topic, vector& mqs) { - mqs.clear(); - try { - const string localTopic = NameSpaceUtil::withNameSpace(topic, getNameSpace()); - getFactory()->fetchSubscribeMessageQueues(localTopic, mqs, getSessionCredentials()); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - } -} - -void DefaultMQPullConsumerImpl::updateTopicSubscribeInfo(const string& topic, vector& info) {} - -void DefaultMQPullConsumerImpl::registerMessageQueueListener(const string& topic, MQueueListener* pListener) { - m_registerTopics.insert(topic); - if (pListener) { - m_pMessageQueueListener = pListener; - } -} - -PullResult DefaultMQPullConsumerImpl::pull(const MQMessageQueue& mq, - const string& subExpression, - int64 offset, - int maxNums) { - return pullSyncImpl(mq, subExpression, offset, maxNums, false); -} - -void DefaultMQPullConsumerImpl::pull(const MQMessageQueue& mq, - const string& subExpression, - int64 offset, - int maxNums, - PullCallback* pPullCallback) { - pullAsyncImpl(mq, subExpression, offset, maxNums, false, pPullCallback); -} - -PullResult DefaultMQPullConsumerImpl::pullBlockIfNotFound(const MQMessageQueue& mq, - const string& subExpression, - int64 offset, - int maxNums) { - return pullSyncImpl(mq, subExpression, offset, maxNums, true); -} - -void DefaultMQPullConsumerImpl::pullBlockIfNotFound(const MQMessageQueue& mq, - const string& subExpression, - int64 offset, - int maxNums, - PullCallback* pPullCallback) { - pullAsyncImpl(mq, subExpression, offset, maxNums, true, pPullCallback); -} - -PullResult DefaultMQPullConsumerImpl::pullSyncImpl(const MQMessageQueue& mq, - const string& subExpression, - int64 offset, - int maxNums, - bool block) { - if (offset < 0) - THROW_MQEXCEPTION(MQClientException, "offset < 0", -1); - - if (maxNums <= 0) - THROW_MQEXCEPTION(MQClientException, "maxNums <= 0", -1); - - // pSData(FilterAPI::buildSubscriptionData(mq.getTopic(), subExpression)); - - int timeoutMillis = block ? 1000 * 30 : 1000 * 10; - - try { - unique_ptr pullResult(m_pPullAPIWrapper->pullKernelImpl(mq, // 1 - pSData->getSubString(), // 2 - 0L, // 3 - offset, // 4 - maxNums, // 5 - sysFlag, // 6 - 0, // 7 - 1000 * 20, // 8 - timeoutMillis, // 9 - ComMode_SYNC, // 10 - NULL, //processPullResult(mq, pullResult.get(), pSData.get()); - if (m_useNameSpaceMode) { - MessageAccessor::withoutNameSpace(pr.msgFoundList, m_nameSpace); - } - return pr; - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - } - return PullResult(BROKER_TIMEOUT); -} - -void DefaultMQPullConsumerImpl::pullAsyncImpl(const MQMessageQueue& mq, - const string& subExpression, - int64 offset, - int maxNums, - bool block, - PullCallback* pPullCallback) { - if (offset < 0) - THROW_MQEXCEPTION(MQClientException, "offset < 0", -1); - - if (maxNums <= 0) - THROW_MQEXCEPTION(MQClientException, "maxNums <= 0", -1); - - if (!pPullCallback) - THROW_MQEXCEPTION(MQClientException, "pPullCallback is null", -1); - - // pSData(FilterAPI::buildSubscriptionData(mq.getTopic(), subExpression)); - - int timeoutMillis = block ? 1000 * 30 : 1000 * 10; - - // pullResult(m_pPullAPIWrapper->pullKernelImpl(mq, // 1 - pSData->getSubString(), // 2 - 0L, // 3 - offset, // 4 - maxNums, // 5 - sysFlag, // 6 - 0, // 7 - 1000 * 20, // 8 - timeoutMillis, // 9 - ComMode_ASYNC, // 10 - pPullCallback, getSessionCredentials(), &arg)); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - } -} - -void DefaultMQPullConsumerImpl::subscriptionAutomatically(const string& topic) { - SubscriptionData* pSdata = m_pRebalance->getSubscriptionData(topic); - if (pSdata == NULL) { - unique_ptr subscriptionData(FilterAPI::buildSubscriptionData(topic, SUB_ALL)); - m_pRebalance->setSubscriptionData(topic, subscriptionData.release()); - } -} - -void DefaultMQPullConsumerImpl::updateConsumeOffset(const MQMessageQueue& mq, int64 offset) { - m_pOffsetStore->updateOffset(mq, offset); -} - -void DefaultMQPullConsumerImpl::removeConsumeOffset(const MQMessageQueue& mq) { - m_pOffsetStore->removeOffset(mq); -} - -int64 DefaultMQPullConsumerImpl::fetchConsumeOffset(const MQMessageQueue& mq, bool fromStore) { - return m_pOffsetStore->readOffset(mq, fromStore ? READ_FROM_STORE : MEMORY_FIRST_THEN_STORE, getSessionCredentials()); -} - -void DefaultMQPullConsumerImpl::persistConsumerOffset() { - /*As do not execute rebalance for pullConsumer now, requestTable is always - empty - map requestTable = - m_pRebalance->getPullRequestTable(); - map::iterator it = requestTable.begin(); - vector mqs; - for (; it != requestTable.end(); ++it) - { - if (it->second) - { - mqs.push_back(it->first); - } - } - m_pOffsetStore->persistAll(mqs);*/ -} - -void DefaultMQPullConsumerImpl::persistConsumerOffsetByResetOffset() {} - -void DefaultMQPullConsumerImpl::persistConsumerOffset4PullConsumer(const MQMessageQueue& mq) { - if (isServiceStateOk()) { - m_pOffsetStore->persist(mq, getSessionCredentials()); - } -} - -void DefaultMQPullConsumerImpl::fetchMessageQueuesInBalance(const string& topic, vector mqs) {} - -void DefaultMQPullConsumerImpl::checkConfig() { - string groupname = getGroupName(); - // check consumerGroup - Validators::checkGroup(groupname); - - // consumerGroup - if (!groupname.compare(DEFAULT_CONSUMER_GROUP)) { - THROW_MQEXCEPTION(MQClientException, "consumerGroup can not equal DEFAULT_CONSUMER", -1); - } - - if (getMessageModel() != BROADCASTING && getMessageModel() != CLUSTERING) { - THROW_MQEXCEPTION(MQClientException, "messageModel is valid ", -1); - } -} - -void DefaultMQPullConsumerImpl::doRebalance() {} - -void DefaultMQPullConsumerImpl::copySubscription() { - set::iterator it = m_registerTopics.begin(); - for (; it != m_registerTopics.end(); ++it) { - unique_ptr subscriptionData(FilterAPI::buildSubscriptionData((*it), SUB_ALL)); - m_pRebalance->setSubscriptionData((*it), subscriptionData.release()); - } -} - -ConsumeType DefaultMQPullConsumerImpl::getConsumeType() { - return CONSUME_ACTIVELY; -} - -ConsumeFromWhere DefaultMQPullConsumerImpl::getConsumeFromWhere() { - return CONSUME_FROM_LAST_OFFSET; -} - -void DefaultMQPullConsumerImpl::getSubscriptions(vector& result) { - set::iterator it = m_registerTopics.begin(); - for (; it != m_registerTopics.end(); ++it) { - SubscriptionData ms(*it, SUB_ALL); - result.push_back(ms); - } -} - -bool DefaultMQPullConsumerImpl::producePullMsgTask(boost::weak_ptr pullRequest) { - return true; -} - -Rebalance* DefaultMQPullConsumerImpl::getRebalance() const { - return NULL; -} -// we should deal with name space before producer start. -bool DefaultMQPullConsumerImpl::dealWithNameSpace() { - string ns = getNameSpace(); - if (ns.empty()) { - string nsAddr = getNamesrvAddr(); - if (!NameSpaceUtil::checkNameSpaceExistInNameServer(nsAddr)) { - return true; - } - ns = NameSpaceUtil::getNameSpaceFromNsURL(nsAddr); - // reset namespace - setNameSpace(ns); - } - // reset group name - if (!NameSpaceUtil::hasNameSpace(getGroupName(), ns)) { - string fullGID = NameSpaceUtil::withNameSpace(getGroupName(), ns); - setGroupName(fullGID); - } - set tmpTopics; - for (auto iter = m_registerTopics.begin(); iter != m_registerTopics.end(); iter++) { - string topic = *iter; - if (!NameSpaceUtil::hasNameSpace(topic, ns)) { - LOG_INFO("Update Subscribe Topic[%s] with NameSpace:%s", topic.c_str(), ns.c_str()); - topic = NameSpaceUtil::withNameSpace(topic, ns); - // let other mode to known, the name space model opened. - m_useNameSpaceMode = true; - } - tmpTopics.insert(topic); - } - m_registerTopics.swap(tmpTopics); - return true; -} -// -#include -#include "MQConsumer.h" -#include "MQMessageQueue.h" -#include "MQueueListener.h" -#include "RocketMQClient.h" - -namespace rocketmq { -class Rebalance; -class SubscriptionData; -class OffsetStore; -class PullAPIWrapper; -class ConsumerRunningInfo; -//& mqs); - virtual void doRebalance(); - virtual void persistConsumerOffset(); - virtual void persistConsumerOffsetByResetOffset(); - virtual void updateTopicSubscribeInfo(const std::string& topic, std::vector& info); - virtual ConsumeType getConsumeType(); - virtual ConsumeFromWhere getConsumeFromWhere(); - virtual void getSubscriptions(std::vector&); - virtual void updateConsumeOffset(const MQMessageQueue& mq, int64 offset); - virtual void removeConsumeOffset(const MQMessageQueue& mq); - virtual bool producePullMsgTask(boost::weak_ptr pullRequest); - virtual Rebalance* getRebalance() const; - // mqs); - - // temp persist consumer offset interface, only valid with - // RemoteBrokerOffsetStore, updateConsumeOffset should be called before. - void persistConsumerOffset4PullConsumer(const MQMessageQueue& mq); - - private: - void checkConfig(); - void copySubscription(); - bool dealWithNameSpace(); - - PullResult pullSyncImpl(const MQMessageQueue& mq, - const std::string& subExpression, - int64 offset, - int maxNums, - bool block); - - void pullAsyncImpl(const MQMessageQueue& mq, - const std::string& subExpression, - int64 offset, - int maxNums, - bool block, - PullCallback* pPullCallback); - - void subscriptionAutomatically(const std::string& topic); - - private: - std::set m_registerTopics; - - MQueueListener* m_pMessageQueueListener; - OffsetStore* m_pOffsetStore; - Rebalance* m_pRebalance; - PullAPIWrapper* m_pPullAPIWrapper; -}; -// -#include "DefaultMQPushConsumerImpl.h" - -namespace rocketmq { - -DefaultMQPushConsumer::DefaultMQPushConsumer(const std::string& groupName) { - impl = new DefaultMQPushConsumerImpl(groupName); -} - -DefaultMQPushConsumer::~DefaultMQPushConsumer() { - delete impl; -} -void DefaultMQPushConsumer::start() { - impl->start(); -} - -void DefaultMQPushConsumer::shutdown() { - impl->shutdown(); -} -std::string DefaultMQPushConsumer::version() { - std::string versions = impl->getClientVersionString(); - /*versions.append(", PROTOCOL VERSION: ") - .append(MQVersion::GetVersionDesc(MQVersion::s_CurrentVersion)) - .append(", LANGUAGE: ") - .append(MQVersion::s_CurrentLanguage);*/ - return versions; -} -// ConsumeType DefaultMQPushConsumer::getConsumeType() { -// return impl->getConsumeType(); -//} - -ConsumeFromWhere DefaultMQPushConsumer::getConsumeFromWhere() { - return impl->getConsumeFromWhere(); -} -void DefaultMQPushConsumer::setConsumeFromWhere(ConsumeFromWhere consumeFromWhere) { - impl->setConsumeFromWhere(consumeFromWhere); -} - -void DefaultMQPushConsumer::registerMessageListener(MQMessageListener* pMessageListener) { - impl->registerMessageListener(pMessageListener); -} -MessageListenerType DefaultMQPushConsumer::getMessageListenerType() { - return impl->getMessageListenerType(); -} -void DefaultMQPushConsumer::subscribe(const std::string& topic, const std::string& subExpression) { - impl->subscribe(topic, subExpression); -} - -void DefaultMQPushConsumer::setConsumeMessageBatchMaxSize(int consumeMessageBatchMaxSize) { - impl->setConsumeMessageBatchMaxSize(consumeMessageBatchMaxSize); -} -int DefaultMQPushConsumer::getConsumeMessageBatchMaxSize() const { - return impl->getConsumeMessageBatchMaxSize(); -} - -/* - set consuming thread count, default value is cpu cores -*/ -void DefaultMQPushConsumer::setConsumeThreadCount(int threadCount) { - impl->setConsumeThreadCount(threadCount); -} -int DefaultMQPushConsumer::getConsumeThreadCount() const { - return impl->getConsumeThreadCount(); -} -void DefaultMQPushConsumer::setMaxReconsumeTimes(int maxReconsumeTimes) { - impl->setMaxReconsumeTimes(maxReconsumeTimes); -} -int DefaultMQPushConsumer::getMaxReconsumeTimes() const { - return impl->getMaxReconsumeTimes(); -} - -/* - set pullMsg thread count, default value is cpu cores -*/ -void DefaultMQPushConsumer::setPullMsgThreadPoolCount(int threadCount) { - impl->setPullMsgThreadPoolCount(threadCount); -} -int DefaultMQPushConsumer::getPullMsgThreadPoolCount() const { - return impl->getPullMsgThreadPoolCount(); -} - -/* - set max cache msg size perQueue in memory if consumer could not consume msgs - immediately - default maxCacheMsgSize perQueue is 1000, set range is:1~65535 -*/ -void DefaultMQPushConsumer::setMaxCacheMsgSizePerQueue(int maxCacheSize) { - impl->setMaxCacheMsgSizePerQueue(maxCacheSize); -} -int DefaultMQPushConsumer::getMaxCacheMsgSizePerQueue() const { - return impl->getMaxCacheMsgSizePerQueue(); -} - -MessageModel DefaultMQPushConsumer::getMessageModel() const { - return impl->getMessageModel(); -} -void DefaultMQPushConsumer::setMessageModel(MessageModel messageModel) { - impl->setMessageModel(messageModel); -} - -const std::string& DefaultMQPushConsumer::getNamesrvAddr() const { - return impl->getNamesrvAddr(); -} - -void DefaultMQPushConsumer::setNamesrvAddr(const std::string& namesrvAddr) { - impl->setNamesrvAddr(namesrvAddr); -} - -const std::string& DefaultMQPushConsumer::getNamesrvDomain() const { - return impl->getNamesrvDomain(); -} - -void DefaultMQPushConsumer::setNamesrvDomain(const std::string& namesrvDomain) { - impl->setNamesrvDomain(namesrvDomain); -} -void DefaultMQPushConsumer::setSessionCredentials(const std::string& accessKey, - const std::string& secretKey, - const std::string& accessChannel) { - impl->setSessionCredentials(accessKey, secretKey, accessChannel); -} - -const SessionCredentials& DefaultMQPushConsumer::getSessionCredentials() const { - return impl->getSessionCredentials(); -} -const std::string& DefaultMQPushConsumer::getInstanceName() const { - return impl->getInstanceName(); -} - -void DefaultMQPushConsumer::setInstanceName(const std::string& instanceName) { - impl->setInstanceName(instanceName); -} - -const std::string& DefaultMQPushConsumer::getNameSpace() const { - return impl->getNameSpace(); -} - -void DefaultMQPushConsumer::setNameSpace(const std::string& nameSpace) { - impl->setNameSpace(nameSpace); -} -const std::string& DefaultMQPushConsumer::getGroupName() const { - return impl->getGroupName(); -} - -void DefaultMQPushConsumer::setGroupName(const std::string& groupName) { - impl->setGroupName(groupName); -} - -void DefaultMQPushConsumer::setEnableSsl(bool enableSsl) { - impl->setEnableSsl(enableSsl); -} - -bool DefaultMQPushConsumer::getEnableSsl() const { - return impl->getEnableSsl(); -} - -void DefaultMQPushConsumer::setSslPropertyFile(const std::string& sslPropertyFile) { - impl->setSslPropertyFile(sslPropertyFile); -} - -const std::string& DefaultMQPushConsumer::getSslPropertyFile() const { - return impl->getSslPropertyFile(); -} - -void DefaultMQPushConsumer::setLogLevel(elogLevel inputLevel) { - impl->setLogLevel(inputLevel); -} - -elogLevel DefaultMQPushConsumer::getLogLevel() { - return impl->getLogLevel(); -} -void DefaultMQPushConsumer::setLogFileSizeAndNum(int fileNum, long perFileSize) { - impl->setLogFileSizeAndNum(fileNum, perFileSize); -} - -void DefaultMQPushConsumer::setUnitName(std::string unitName) { - impl->setUnitName(unitName); -} -const std::string& DefaultMQPushConsumer::getUnitName() const { - return impl->getUnitName(); -} - -void DefaultMQPushConsumer::setTcpTransportPullThreadNum(int num) { - impl->setTcpTransportPullThreadNum(num); -} -int DefaultMQPushConsumer::getTcpTransportPullThreadNum() const { - return impl->getTcpTransportPullThreadNum(); -} - -void DefaultMQPushConsumer::setTcpTransportConnectTimeout(uint64_t timeout) { - impl->setTcpTransportConnectTimeout(timeout); -} -uint64_t DefaultMQPushConsumer::getTcpTransportConnectTimeout() const { - return impl->getTcpTransportConnectTimeout(); -} -void DefaultMQPushConsumer::setTcpTransportTryLockTimeout(uint64_t timeout) { - impl->setTcpTransportTryLockTimeout(timeout); -} -uint64_t DefaultMQPushConsumer::getTcpTransportTryLockTimeout() const { - return impl->getTcpTransportTryLockTimeout(); -} -void DefaultMQPushConsumer::setAsyncPull(bool asyncFlag) { - impl->setAsyncPull(asyncFlag); -} -void DefaultMQPushConsumer::setMessageTrace(bool messageTrace) { - impl->setMessageTrace(messageTrace); -} -bool DefaultMQPushConsumer::getMessageTrace() const { - return impl->getMessageTrace(); -} -} // namespace rocketmq diff --git a/src/consumer/DefaultMQPushConsumerImpl.cpp b/src/consumer/DefaultMQPushConsumerImpl.cpp deleted file mode 100644 index c7ee30e60..000000000 --- a/src/consumer/DefaultMQPushConsumerImpl.cpp +++ /dev/null @@ -1,1193 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "DefaultMQPushConsumerImpl.h" -#include "CommunicationMode.h" -#include "ConsumeMessageHookImpl.h" -#include "ConsumeMsgService.h" -#include "ConsumerRunningInfo.h" -#include "FilterAPI.h" -#include "Logging.h" -#include "MQClientAPIImpl.h" -#include "MQClientFactory.h" -#include "NameSpaceUtil.h" -#include "OffsetStore.h" -#include "PullAPIWrapper.h" -#include "PullSysFlag.h" -#include "Rebalance.h" -#include "StatsServerManager.h" -#include "UtilAll.h" -#include "Validators.h" -#include "task_queue.h" - -namespace rocketmq { - -class AsyncPullCallback : public PullCallback { - public: - AsyncPullCallback(DefaultMQPushConsumerImpl* pushConsumer, boost::weak_ptr request) - : m_callbackOwner(pushConsumer), m_pullRequest(request), m_bShutdown(false) {} - - virtual ~AsyncPullCallback() { m_callbackOwner = NULL; } - - virtual void onSuccess(MQMessageQueue& mq, PullResult& result, bool bProducePullRequest) { - boost::shared_ptr pullRequest = m_pullRequest.lock(); - if (!pullRequest) { - LOG_WARN("Pull request for[%s] has been released", mq.toString().c_str()); - return; - } - - if (m_bShutdown) { - LOG_INFO("pullrequest for:%s in shutdown, return", (pullRequest->m_messageQueue).toString().c_str()); - return; - } - if (pullRequest->isDropped()) { - LOG_INFO("Pull request for queue[%s] has been set as dropped. Will NOT pull this queue any more", - pullRequest->m_messageQueue.toString().c_str()); - return; - } - switch (result.pullStatus) { - case FOUND: { - if (pullRequest->isDropped()) { - LOG_INFO("[Dropped]Remove pullmsg event of mq:%s", (pullRequest->m_messageQueue).toString().c_str()); - break; - } - - uint64 pullRT = UtilAll::currentTimeMillis() - pullRequest->getLastPullTimestamp(); - StatsServerManager::getInstance()->getConsumeStatServer()->incPullRT( - pullRequest->m_messageQueue.getTopic(), m_callbackOwner->getGroupName(), pullRT); - pullRequest->setNextOffset(result.nextBeginOffset); - pullRequest->putMessage(result.msgFoundList); - if (!result.msgFoundList.empty()) { - StatsServerManager::getInstance()->getConsumeStatServer()->incPullTPS( - pullRequest->m_messageQueue.getTopic(), m_callbackOwner->getGroupName(), result.msgFoundList.size()); - } - m_callbackOwner->getConsumerMsgService()->submitConsumeRequest(pullRequest, result.msgFoundList); - - if (bProducePullRequest) { - m_callbackOwner->producePullMsgTask(pullRequest); - } else { - LOG_INFO("[bProducePullRequest = false]Stop pullmsg event of mq:%s", - (pullRequest->m_messageQueue).toString().c_str()); - } - - LOG_DEBUG("FOUND:%s with size:" SIZET_FMT ", nextBeginOffset:%lld", - (pullRequest->m_messageQueue).toString().c_str(), result.msgFoundList.size(), result.nextBeginOffset); - - break; - } - case NO_NEW_MSG: { - if (pullRequest->isDropped()) { - LOG_INFO("[Dropped]Remove pullmsg event of mq:%s", (pullRequest->m_messageQueue).toString().c_str()); - break; - } - pullRequest->setNextOffset(result.nextBeginOffset); - - if ((pullRequest->getCacheMsgCount() == 0) && (result.nextBeginOffset >= 0)) { - m_callbackOwner->updateConsumeOffset(pullRequest->m_messageQueue, result.nextBeginOffset); - } - if (bProducePullRequest) { - m_callbackOwner->producePullMsgTask(pullRequest); - } else { - LOG_INFO("[bProducePullRequest = false]Stop pullmsg event of mq:%s", - (pullRequest->m_messageQueue).toString().c_str()); - } - LOG_DEBUG("NO_NEW_MSG:%s,nextBeginOffset:%lld", pullRequest->m_messageQueue.toString().c_str(), - result.nextBeginOffset); - break; - } - case NO_MATCHED_MSG: { - if (pullRequest->isDropped()) { - LOG_INFO("[Dropped]Remove pullmsg event of mq:%s", (pullRequest->m_messageQueue).toString().c_str()); - break; - } - pullRequest->setNextOffset(result.nextBeginOffset); - - if ((pullRequest->getCacheMsgCount() == 0) && (result.nextBeginOffset >= 0)) { - m_callbackOwner->updateConsumeOffset(pullRequest->m_messageQueue, result.nextBeginOffset); - } - if (bProducePullRequest) { - m_callbackOwner->producePullMsgTask(pullRequest); - } else { - LOG_INFO("[bProducePullRequest = false]Stop pullmsg event of mq:%s", - (pullRequest->m_messageQueue).toString().c_str()); - } - LOG_DEBUG("NO_MATCHED_MSG:%s,nextBeginOffset:%lld", pullRequest->m_messageQueue.toString().c_str(), - result.nextBeginOffset); - break; - } - case OFFSET_ILLEGAL: { - if (pullRequest->isDropped()) { - LOG_INFO("[Dropped]Remove pullmsg event of mq:%s", (pullRequest->m_messageQueue).toString().c_str()); - break; - } - pullRequest->setNextOffset(result.nextBeginOffset); - if (bProducePullRequest) { - m_callbackOwner->producePullMsgTask(pullRequest); - } else { - LOG_INFO("[bProducePullRequest = false]Stop pullmsg event of mq:%s", - (pullRequest->m_messageQueue).toString().c_str()); - } - - LOG_DEBUG("OFFSET_ILLEGAL:%s,nextBeginOffset:%lld", pullRequest->m_messageQueue.toString().c_str(), - result.nextBeginOffset); - break; - } - case BROKER_TIMEOUT: { - if (pullRequest->isDropped()) { - LOG_INFO("[Dropped]Remove pullmsg event of mq:%s", (pullRequest->m_messageQueue).toString().c_str()); - break; - } - LOG_ERROR("impossible BROKER_TIMEOUT Occurs"); - pullRequest->setNextOffset(result.nextBeginOffset); - if (bProducePullRequest) { - m_callbackOwner->producePullMsgTask(pullRequest); - } else { - LOG_INFO("[bProducePullRequest = false]Stop pullmsg event of mq:%s", - (pullRequest->m_messageQueue).toString().c_str()); - } - break; - } - } - } - - virtual void onException(MQException& e) { - boost::shared_ptr pullRequest = m_pullRequest.lock(); - if (!pullRequest) { - LOG_WARN("Pull request has been released."); - return; - } - std::string queueName = pullRequest->m_messageQueue.toString(); - if (m_bShutdown) { - LOG_INFO("pullrequest for:%s in shutdown, return", queueName.c_str()); - return; - } - if (pullRequest->isDropped()) { - LOG_INFO("[Dropped]Remove pullmsg event of mq:%s", queueName.c_str()); - return; - } - LOG_WARN("Pullrequest for:%s occurs exception, reproduce it after 1s.", queueName.c_str()); - m_callbackOwner->producePullMsgTaskLater(pullRequest, 1000); - } - - void setShutdownStatus() { m_bShutdown = true; } - - const boost::weak_ptr& getPullRequest() const { return m_pullRequest; } - - void setPullRequest(boost::weak_ptr& pullRequest) { m_pullRequest = pullRequest; } - - private: - DefaultMQPushConsumerImpl* m_callbackOwner; - boost::weak_ptr m_pullRequest; - bool m_bShutdown; -}; - -static boost::mutex m_asyncCallbackLock; - -DefaultMQPushConsumerImpl::DefaultMQPushConsumerImpl() {} -DefaultMQPushConsumerImpl::DefaultMQPushConsumerImpl(const string& groupname) - : m_consumeFromWhere(CONSUME_FROM_LAST_OFFSET), - m_pOffsetStore(NULL), - m_pRebalance(NULL), - m_pPullAPIWrapper(NULL), - m_consumerService(NULL), - m_pMessageListener(NULL), - m_consumeMessageBatchMaxSize(1), - m_maxMsgCacheSize(1000), - m_pullmsgQueue(NULL) { - //second); - } - m_PullCallback.clear(); - m_subTopics.clear(); -} - -bool DefaultMQPushConsumerImpl::sendMessageBack(MQMessageExt& msg, int delayLevel, string& brokerName) { - string brokerAddr; - if (!brokerName.empty()) - brokerAddr = getFactory()->findBrokerAddressInPublish(brokerName); - else - brokerAddr = socketAddress2IPPort(msg.getStoreHost()); - try { - getFactory()->getMQClientAPIImpl()->consumerSendMessageBack(brokerAddr, msg, getGroupName(), delayLevel, 3000, - getMaxReconsumeTimes(), getSessionCredentials()); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - return false; - } - return true; -} - -void DefaultMQPushConsumerImpl::fetchSubscribeMessageQueues(const string& topic, vector& mqs) { - mqs.clear(); - try { - getFactory()->fetchSubscribeMessageQueues(topic, mqs, getSessionCredentials()); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - } -} - -void DefaultMQPushConsumerImpl::doRebalance() { - if (isServiceStateOk()) { - try { - m_pRebalance->doRebalance(); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - } - } -} - -void DefaultMQPushConsumerImpl::persistConsumerOffset() { - if (isServiceStateOk()) { - m_pRebalance->persistConsumerOffset(); - } -} - -void DefaultMQPushConsumerImpl::persistConsumerOffsetByResetOffset() { - if (isServiceStateOk()) { - m_pRebalance->persistConsumerOffsetByResetOffset(); - } -} - -void DefaultMQPushConsumerImpl::start() { -#ifndef WIN32 - /* Ignore the SIGPIPE */ - struct sigaction sa; - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = SIG_IGN; - sa.sa_flags = 0; - sigaction(SIGPIPE, &sa, 0); -#endif - LOG_WARN("###Current Push Consumer@%s", getClientVersionString().c_str()); - // deal with name space before start - dealWithNameSpace(); - logConfigs(); - switch (m_serviceState) { - case CREATE_JUST: { - m_serviceState = START_FAILED; - // Start status server - StatsServerManager::getInstance()->getConsumeStatServer()->start(); - DefaultMQClient::start(); - dealWithMessageTrace(); - LOG_INFO("DefaultMQPushConsumerImpl:%s start", m_GroupName.c_str()); - - //getMessageListenerType() == messageListenerOrderly) { - LOG_INFO("start orderly consume service:%s", getGroupName().c_str()); - m_consumerService = new ConsumeMessageOrderlyService(this, m_consumeThreadCount, m_pMessageListener); - } else // for backward compatible, defaultly and concurrently listeners - // are allocating ConsumeMessageConcurrentlyService - { - LOG_INFO("start concurrently consume service:%s", getGroupName().c_str()); - m_consumerService = new ConsumeMessageConcurrentlyService(this, m_consumeThreadCount, m_pMessageListener); - } - } - - m_pullmsgQueue = new TaskQueue(m_pullMsgThreadPoolNum); - m_pullmsgThread.reset( - new boost::thread(boost::bind(&DefaultMQPushConsumerImpl::runPullMsgQueue, this, m_pullmsgQueue))); - - copySubscription(); - - //registerConsumer(this); - if (!registerOK) { - m_serviceState = CREATE_JUST; - THROW_MQEXCEPTION( - MQClientException, - "The cousumer group[" + getGroupName() + "] has been created before, specify another name please.", -1); - } - - //load(); - } catch (MQClientException& e) { - bStartFailed = true; - errorMsg = std::string(e.what()); - } - m_consumerService->start(); - - getFactory()->start(); - - updateTopicSubscribeInfoWhenSubscriptionChanged(); - getFactory()->sendHeartbeatToAllBroker(); - - m_serviceState = RUNNING; - if (bStartFailed) { - shutdown(); - THROW_MQEXCEPTION(MQClientException, errorMsg, -1); - } - break; - } - case RUNNING: - case START_FAILED: - case SHUTDOWN_ALREADY: - break; - default: - break; - } - - getFactory()->rebalanceImmediately(); -} - -void DefaultMQPushConsumerImpl::shutdown() { - switch (m_serviceState) { - case RUNNING: { - LOG_INFO("DefaultMQPushConsumerImpl shutdown"); - - // Shutdown status server - StatsServerManager::getInstance()->getConsumeStatServer()->shutdown(); - shutdownMessageTraceInnerProducer(); - m_async_ioService.stop(); - m_async_service_thread->interrupt(); - m_async_service_thread->join(); - m_pullmsgQueue->close(); - m_pullmsgThread->interrupt(); - m_pullmsgThread->join(); - m_consumerService->shutdown(); - persistConsumerOffset(); - shutdownAsyncPullCallBack(); // delete aync pullMsg resources - getFactory()->unregisterConsumer(this); - getFactory()->shutdown(); - m_serviceState = SHUTDOWN_ALREADY; - break; - } - case CREATE_JUST: - case SHUTDOWN_ALREADY: - break; - default: - break; - } -} - -void DefaultMQPushConsumerImpl::registerMessageListener(MQMessageListener* pMessageListener) { - if (NULL != pMessageListener) { - m_pMessageListener = pMessageListener; - } -} - -MessageListenerType DefaultMQPushConsumerImpl::getMessageListenerType() { - if (NULL != m_pMessageListener) { - return m_pMessageListener->getMessageListenerType(); - } - return messageListenerDefaultly; -} - -ConsumeMsgService* DefaultMQPushConsumerImpl::getConsumerMsgService() const { - return m_consumerService; -} - -OffsetStore* DefaultMQPushConsumerImpl::getOffsetStore() const { - return m_pOffsetStore; -} - -Rebalance* DefaultMQPushConsumerImpl::getRebalance() const { - return m_pRebalance; -} - -void DefaultMQPushConsumerImpl::subscribe(const string& topic, const string& subExpression) { - m_subTopics[topic] = subExpression; -} - -void DefaultMQPushConsumerImpl::checkConfig() { - string groupname = getGroupName(); - // check consumerGroup - Validators::checkGroup(groupname); - - // consumerGroup - if (!groupname.compare(DEFAULT_CONSUMER_GROUP)) { - THROW_MQEXCEPTION(MQClientException, "consumerGroup can not equal DEFAULT_CONSUMER", -1); - } - - if (getMessageModel() != BROADCASTING && getMessageModel() != CLUSTERING) { - THROW_MQEXCEPTION(MQClientException, "messageModel is valid ", -1); - } - - if (m_pMessageListener == NULL) { - THROW_MQEXCEPTION(MQClientException, "messageListener is null ", -1); - } -} - -void DefaultMQPushConsumerImpl::copySubscription() { - map::iterator it = m_subTopics.begin(); - for (; it != m_subTopics.end(); ++it) { - LOG_INFO("buildSubscriptionData,:%s,%s", it->first.c_str(), it->second.c_str()); - unique_ptr pSData(FilterAPI::buildSubscriptionData(it->first, it->second)); - - m_pRebalance->setSubscriptionData(it->first, pSData.release()); - } - - switch (getMessageModel()) { - case BROADCASTING: - break; - case CLUSTERING: { - string retryTopic = UtilAll::getRetryTopic(getGroupName()); - - // pSData(FilterAPI::buildSubscriptionData(retryTopic, SUB_ALL)); - - m_pRebalance->setSubscriptionData(retryTopic, pSData.release()); - break; - } - default: - break; - } -} - -void DefaultMQPushConsumerImpl::updateTopicSubscribeInfo(const string& topic, vector& info) { - m_pRebalance->setTopicSubscribeInfo(topic, info); -} - -void DefaultMQPushConsumerImpl::updateTopicSubscribeInfoWhenSubscriptionChanged() { - map& subTable = m_pRebalance->getSubscriptionInner(); - map::iterator it = subTable.begin(); - for (; it != subTable.end(); ++it) { - bool btopic = getFactory()->updateTopicRouteInfoFromNameServer(it->first, getSessionCredentials()); - if (btopic == false) { - LOG_WARN("The topic:[%s] not exist", it->first.c_str()); - } - } -} - -ConsumeType DefaultMQPushConsumerImpl::getConsumeType() { - return CONSUME_PASSIVELY; -} - -ConsumeFromWhere DefaultMQPushConsumerImpl::getConsumeFromWhere() { - return m_consumeFromWhere; -} - -void DefaultMQPushConsumerImpl::setConsumeFromWhere(ConsumeFromWhere consumeFromWhere) { - m_consumeFromWhere = consumeFromWhere; -} - -void DefaultMQPushConsumerImpl::getSubscriptions(vector& result) { - map& subTable = m_pRebalance->getSubscriptionInner(); - map::iterator it = subTable.begin(); - for (; it != subTable.end(); ++it) { - result.push_back(*(it->second)); - } -} - -void DefaultMQPushConsumerImpl::updateConsumeOffset(const MQMessageQueue& mq, int64 offset) { - if (offset >= 0) { - m_pOffsetStore->updateOffset(mq, offset); - } else { - LOG_ERROR("updateConsumeOffset of mq:%s error", mq.toString().c_str()); - } -} - -void DefaultMQPushConsumerImpl::removeConsumeOffset(const MQMessageQueue& mq) { - m_pOffsetStore->removeOffset(mq); -} - -void DefaultMQPushConsumerImpl::static_triggerNextPullRequest(void* context, - boost::asio::deadline_timer* t, - boost::weak_ptr pullRequest) { - if (pullRequest.expired()) { - LOG_WARN("Pull request has been released before."); - return; - } - DefaultMQPushConsumerImpl* pDefaultMQPushConsumerImpl = (DefaultMQPushConsumerImpl*)context; - if (pDefaultMQPushConsumerImpl) { - pDefaultMQPushConsumerImpl->triggerNextPullRequest(t, pullRequest); - } -} - -void DefaultMQPushConsumerImpl::triggerNextPullRequest(boost::asio::deadline_timer* t, - boost::weak_ptr pullRequest) { - // delete first to avoild memleak - deleteAndZero(t); - boost::shared_ptr request = pullRequest.lock(); - if (!request) { - LOG_WARN("Pull request has been released before."); - return; - } - producePullMsgTask(request); -} - -bool DefaultMQPushConsumerImpl::producePullMsgTaskLater(boost::weak_ptr pullRequest, int millis) { - boost::shared_ptr request = pullRequest.lock(); - if (!request) { - LOG_INFO("Pull request is invalid. Maybe it is dropped before."); - return false; - } - if (request->isDropped()) { - LOG_INFO("[Dropped]Remove pullmsg event of mq:%s", request->m_messageQueue.toString().c_str()); - return false; - } - if (m_pullmsgQueue->bTaskQueueStatusOK() && isServiceStateOk()) { - boost::asio::deadline_timer* t = - new boost::asio::deadline_timer(m_async_ioService, boost::posix_time::milliseconds(millis)); - t->async_wait(boost::bind(&(DefaultMQPushConsumerImpl::static_triggerNextPullRequest), this, t, request)); - LOG_INFO("Produce Pull request [%s] Later and Sleep [%d]ms.", (request->m_messageQueue).toString().c_str(), millis); - return true; - } else { - LOG_WARN("Service or TaskQueue shutdown, produce PullRequest of mq:%s failed", - request->m_messageQueue.toString().c_str()); - return false; - } -} - -bool DefaultMQPushConsumerImpl::producePullMsgTask(boost::weak_ptr pullRequest) { - boost::shared_ptr request = pullRequest.lock(); - if (!request) { - LOG_WARN("Pull request has been released."); - return false; - } - if (request->isDropped()) { - LOG_INFO("[Dropped]Remove pullmsg event of mq:%s", request->m_messageQueue.toString().c_str()); - return false; - } - if (m_pullmsgQueue->bTaskQueueStatusOK() && isServiceStateOk()) { - if (m_asyncPull) { - m_pullmsgQueue->produce(TaskBinder::gen(&DefaultMQPushConsumerImpl::pullMessageAsync, this, request)); - } else { - m_pullmsgQueue->produce(TaskBinder::gen(&DefaultMQPushConsumerImpl::pullMessage, this, request)); - } - } else { - LOG_WARN("produce PullRequest of mq:%s failed", request->m_messageQueue.toString().c_str()); - return false; - } - return true; -} - -void DefaultMQPushConsumerImpl::runPullMsgQueue(TaskQueue* pTaskQueue) { - pTaskQueue->run(); -} - -void DefaultMQPushConsumerImpl::pullMessage(boost::weak_ptr pullRequest) { - boost::shared_ptr request = pullRequest.lock(); - if (!request) { - LOG_ERROR("Pull request is released, return"); - return; - } - if (request->isDropped()) { - LOG_WARN("Pull request is set drop with mq:%s, return", (request->m_messageQueue).toString().c_str()); - // request->removePullMsgEvent(); - return; - } - - MQMessageQueue& messageQueue = request->m_messageQueue; - if (m_consumerService->getConsumeMsgSerivceListenerType() == messageListenerOrderly) { - if (!request->isLocked() || request->isLockExpired()) { - if (!m_pRebalance->lock(messageQueue)) { - request->setLastPullTimestamp(UtilAll::currentTimeMillis()); - producePullMsgTaskLater(request, 1000); - return; - } - } - } - - if (request->getCacheMsgCount() > m_maxMsgCacheSize) { - LOG_INFO("Sync Pull request for %s has Cached with %d Messages and The Max size is %d, Sleep 1s.", - (request->m_messageQueue).toString().c_str(), request->getCacheMsgCount(), m_maxMsgCacheSize); - request->setLastPullTimestamp(UtilAll::currentTimeMillis()); - // Retry 1s, - producePullMsgTaskLater(request, 1000); - return; - } - - bool commitOffsetEnable = false; - int64 commitOffsetValue = 0; - if (CLUSTERING == getMessageModel()) { - commitOffsetValue = m_pOffsetStore->readOffset(messageQueue, READ_FROM_MEMORY, getSessionCredentials()); - if (commitOffsetValue > 0) { - commitOffsetEnable = true; - } - } - - string subExpression; - SubscriptionData* pSdata = m_pRebalance->getSubscriptionData(messageQueue.getTopic()); - if (pSdata == NULL) { - LOG_INFO("Can not get SubscriptionData of Pull request for [%s], Sleep 1s.", - (request->m_messageQueue).toString().c_str()); - producePullMsgTaskLater(request, 1000); - return; - } - subExpression = pSdata->getSubString(); - - int sysFlag = PullSysFlag::buildSysFlag(commitOffsetEnable, // commitOffset - false, // suspend - !subExpression.empty(), // subscription - false); // class filter - if (request->isDropped()) { - LOG_WARN("Pull request is set as dropped with mq:%s, return", (request->m_messageQueue).toString().c_str()); - return; - } - try { - uint64 startTimeStamp = UtilAll::currentTimeMillis(); - request->setLastPullTimestamp(startTimeStamp); - unique_ptr result(m_pPullAPIWrapper->pullKernelImpl(messageQueue, // 1 - subExpression, // 2 - pSdata->getSubVersion(), // 3 - request->getNextOffset(), // 4 - 32, // 5 - sysFlag, // 6 - commitOffsetValue, // 7 - 1000 * 15, // 8 - 1000 * 30, // 9 - ComMode_SYNC, // 10 - NULL, getSessionCredentials())); - - PullResult pullResult = m_pPullAPIWrapper->processPullResult(messageQueue, result.get(), pSdata); - switch (pullResult.pullStatus) { - case FOUND: { - uint64 pullRT = UtilAll::currentTimeMillis() - startTimeStamp; - StatsServerManager::getInstance()->getConsumeStatServer()->incPullRT(messageQueue.getTopic(), getGroupName(), - pullRT); - if (request->isDropped()) { - LOG_INFO("Get pull result but the queue has been marked as dropped. Queue: %s", - messageQueue.toString().c_str()); - break; - } - // and this request is dropped, and then received pulled msgs. - request->setNextOffset(pullResult.nextBeginOffset); - request->putMessage(pullResult.msgFoundList); - if (!pullResult.msgFoundList.empty()) { - StatsServerManager::getInstance()->getConsumeStatServer()->incPullTPS(messageQueue.getTopic(), getGroupName(), - pullResult.msgFoundList.size()); - } - m_consumerService->submitConsumeRequest(request, pullResult.msgFoundList); - producePullMsgTask(request); - - LOG_DEBUG("FOUND:%s with size:" SIZET_FMT ",nextBeginOffset:%lld", messageQueue.toString().c_str(), - pullResult.msgFoundList.size(), pullResult.nextBeginOffset); - - break; - } - case NO_NEW_MSG: { - if (request->isDropped()) { - LOG_INFO("Get pull result but the queue has been marked as dropped. Queue: %s", - messageQueue.toString().c_str()); - break; - } - request->setNextOffset(pullResult.nextBeginOffset); - if ((request->getCacheMsgCount() == 0) && (pullResult.nextBeginOffset >= 0)) { - updateConsumeOffset(messageQueue, pullResult.nextBeginOffset); - } - producePullMsgTask(request); - LOG_DEBUG("NO_NEW_MSG:%s,nextBeginOffset:%lld", messageQueue.toString().c_str(), pullResult.nextBeginOffset); - break; - } - case NO_MATCHED_MSG: { - if (request->isDropped()) { - LOG_INFO("Get pull result but the queue has been marked as dropped. Queue: %s", - messageQueue.toString().c_str()); - break; - } - request->setNextOffset(pullResult.nextBeginOffset); - if ((request->getCacheMsgCount() == 0) && (pullResult.nextBeginOffset >= 0)) { - updateConsumeOffset(messageQueue, pullResult.nextBeginOffset); - } - producePullMsgTask(request); - - LOG_DEBUG("NO_MATCHED_MSG:%s,nextBeginOffset:%lld", messageQueue.toString().c_str(), - pullResult.nextBeginOffset); - break; - } - case OFFSET_ILLEGAL: { - if (request->isDropped()) { - LOG_INFO("Get pull result but the queue has been marked as dropped. Queue: %s", - messageQueue.toString().c_str()); - break; - } - request->setNextOffset(pullResult.nextBeginOffset); - producePullMsgTask(request); - - LOG_DEBUG("OFFSET_ILLEGAL:%s,nextBeginOffset:%lld", messageQueue.toString().c_str(), - pullResult.nextBeginOffset); - break; - } - case BROKER_TIMEOUT: { // as BROKER_TIMEOUT is defined by client, broker - // will not returns this status, so this case - // could not be entered. - LOG_ERROR("impossible BROKER_TIMEOUT Occurs"); - request->setNextOffset(pullResult.nextBeginOffset); - producePullMsgTask(request); - break; - } - } - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - LOG_WARN("Pull %s occur exception, restart 1s later.", messageQueue.toString().c_str()); - producePullMsgTaskLater(request, 1000); - } -} - -AsyncPullCallback* DefaultMQPushConsumerImpl::getAsyncPullCallBack(boost::weak_ptr pullRequest, - MQMessageQueue msgQueue) { - boost::shared_ptr request = pullRequest.lock(); - if (!request) { - return NULL; - } - boost::lock_guard lock(m_asyncCallbackLock); - if (m_asyncPull && request) { - PullMAP::iterator it = m_PullCallback.find(msgQueue); - if (it == m_PullCallback.end()) { - LOG_INFO("new pull callback for mq:%s", msgQueue.toString().c_str()); - m_PullCallback[msgQueue] = new AsyncPullCallback(this, request); - } - AsyncPullCallback* asyncPullCallback = m_PullCallback[msgQueue]; - if (asyncPullCallback) { - // maybe the pull request has dropped before, replace event time. - asyncPullCallback->setPullRequest(pullRequest); - } - return asyncPullCallback; - } - - return NULL; -} - -void DefaultMQPushConsumerImpl::shutdownAsyncPullCallBack() { - boost::lock_guard lock(m_asyncCallbackLock); - if (m_asyncPull) { - PullMAP::iterator it = m_PullCallback.begin(); - for (; it != m_PullCallback.end(); ++it) { - if (it->second) { - it->second->setShutdownStatus(); - } else { - LOG_ERROR("could not find asyncPullCallback for:%s", it->first.toString().c_str()); - } - } - } -} - -void DefaultMQPushConsumerImpl::pullMessageAsync(boost::weak_ptr pullRequest) { - boost::shared_ptr request = pullRequest.lock(); - if (!request) { - LOG_ERROR("Pull request is released, return"); - return; - } - if (request->isDropped()) { - LOG_WARN("Pull request is set drop with mq:%s, return", (request->m_messageQueue).toString().c_str()); - return; - } - MQMessageQueue& messageQueue = request->m_messageQueue; - if (m_consumerService->getConsumeMsgSerivceListenerType() == messageListenerOrderly) { - if (!request->isLocked() || request->isLockExpired()) { - if (!m_pRebalance->lock(messageQueue)) { - request->setLastPullTimestamp(UtilAll::currentTimeMillis()); - // Retry later. - producePullMsgTaskLater(request, 1000); - return; - } - } - } - - if (request->getCacheMsgCount() > m_maxMsgCacheSize) { - LOG_INFO("Pull request for [%s] has Cached with %d Messages and The Max size is %d, Sleep 3s.", - (request->m_messageQueue).toString().c_str(), request->getCacheMsgCount(), m_maxMsgCacheSize); - request->setLastPullTimestamp(UtilAll::currentTimeMillis()); - // Retry 3s, - producePullMsgTaskLater(request, 3000); - return; - } - - bool commitOffsetEnable = false; - int64 commitOffsetValue = 0; - if (CLUSTERING == getMessageModel()) { - commitOffsetValue = m_pOffsetStore->readOffset(messageQueue, READ_FROM_MEMORY, getSessionCredentials()); - if (commitOffsetValue > 0) { - commitOffsetEnable = true; - } - } - - string subExpression; - SubscriptionData* pSdata = (m_pRebalance->getSubscriptionData(messageQueue.getTopic())); - if (pSdata == NULL) { - LOG_INFO("Can not get SubscriptionData of Pull request for [%s], Sleep 1s.", - (request->m_messageQueue).toString().c_str()); - // Subscribe data error, retry later. - producePullMsgTaskLater(request, 1000); - return; - } - subExpression = pSdata->getSubString(); - - int sysFlag = PullSysFlag::buildSysFlag(commitOffsetEnable, // commitOffset - true, // suspend - !subExpression.empty(), // subscription - false); // class filter - - AsyncArg arg; - arg.mq = messageQueue; - arg.subData = *pSdata; - arg.pPullWrapper = m_pPullAPIWrapper; - if (request->isDropped()) { - LOG_WARN("Pull request is set as dropped with mq:%s, return", request->m_messageQueue.toString().c_str()); - return; - } - try { - request->setLastPullTimestamp(UtilAll::currentTimeMillis()); - AsyncPullCallback* pullCallback = getAsyncPullCallBack(request, messageQueue); - if (pullCallback == NULL) { - LOG_WARN("Can not get pull callback for:%s, Maybe this pull request has been released.", - request->m_messageQueue.toString().c_str()); - return; - } - m_pPullAPIWrapper->pullKernelImpl(messageQueue, // 1 - subExpression, // 2 - pSdata->getSubVersion(), // 3 - request->getNextOffset(), // 4 - 32, // 5 - sysFlag, // 6 - commitOffsetValue, // 7 - 1000 * 15, // 8 - m_asyncPullTimeout, // 9 - ComMode_ASYNC, // 10 - pullCallback, // 11 - getSessionCredentials(), // 12 - &arg); // 13 - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - if (request->isDropped()) { - LOG_WARN("Pull request is set as dropped with mq:%s, return", (request->m_messageQueue).toString().c_str()); - return; - } - LOG_INFO("Pull %s occur exception, restart 1s later.", (request->m_messageQueue).toString().c_str()); - producePullMsgTaskLater(request, 1000); - } -} - -void DefaultMQPushConsumerImpl::setAsyncPull(bool asyncFlag) { - if (asyncFlag) { - LOG_INFO("set pushConsumer:%s to async default pull mode", getGroupName().c_str()); - } else { - LOG_INFO("set pushConsumer:%s to sync pull mode", getGroupName().c_str()); - } - m_asyncPull = asyncFlag; -} - -void DefaultMQPushConsumerImpl::setConsumeThreadCount(int threadCount) { - if (threadCount > 0) { - m_consumeThreadCount = threadCount; - } else { - LOG_ERROR("setConsumeThreadCount with invalid value"); - } -} - -int DefaultMQPushConsumerImpl::getConsumeThreadCount() const { - return m_consumeThreadCount; -} -void DefaultMQPushConsumerImpl::setMaxReconsumeTimes(int maxReconsumeTimes) { - if (maxReconsumeTimes > 0) { - m_maxReconsumeTimes = maxReconsumeTimes; - } else { - LOG_ERROR("set maxReconsumeTimes with invalid value"); - } -} - -int DefaultMQPushConsumerImpl::getMaxReconsumeTimes() const { - if (m_maxReconsumeTimes >= 0) { - return m_maxReconsumeTimes; - } - // return 16 as default; - return 16; -} - -void DefaultMQPushConsumerImpl::setPullMsgThreadPoolCount(int threadCount) { - m_pullMsgThreadPoolNum = threadCount; -} - -int DefaultMQPushConsumerImpl::getPullMsgThreadPoolCount() const { - return m_pullMsgThreadPoolNum; -} - -int DefaultMQPushConsumerImpl::getConsumeMessageBatchMaxSize() const { - return m_consumeMessageBatchMaxSize; -} - -void DefaultMQPushConsumerImpl::setConsumeMessageBatchMaxSize(int consumeMessageBatchMaxSize) { - if (consumeMessageBatchMaxSize >= 1) - m_consumeMessageBatchMaxSize = consumeMessageBatchMaxSize; -} - -void DefaultMQPushConsumerImpl::setMaxCacheMsgSizePerQueue(int maxCacheSize) { - if (maxCacheSize > 0 && maxCacheSize < 65535) { - LOG_INFO("set maxCacheSize to:%d for consumer:%s", maxCacheSize, getGroupName().c_str()); - m_maxMsgCacheSize = maxCacheSize; - } -} - -int DefaultMQPushConsumerImpl::getMaxCacheMsgSizePerQueue() const { - return m_maxMsgCacheSize; -} - -ConsumerRunningInfo* DefaultMQPushConsumerImpl::getConsumerRunningInfo() { - auto* info = new ConsumerRunningInfo(); - if (m_consumerService->getConsumeMsgSerivceListenerType() == messageListenerOrderly) { - info->setProperty(ConsumerRunningInfo::PROP_CONSUME_ORDERLY, "true"); - } else { - info->setProperty(ConsumerRunningInfo::PROP_CONSUME_ORDERLY, "false"); - } - info->setProperty(ConsumerRunningInfo::PROP_THREADPOOL_CORE_SIZE, UtilAll::to_string(m_consumeThreadCount)); - info->setProperty(ConsumerRunningInfo::PROP_CONSUMER_START_TIMESTAMP, UtilAll::to_string(m_startTime)); - - std::vector result; - getSubscriptions(result); - info->setSubscriptionSet(result); - - for (const auto& it : result) { - ConsumeStats consumeStat; - // we should get it from status service. - consumeStat = - StatsServerManager::getInstance()->getConsumeStatServer()->getConsumeStats(it.getTopic(), this->getGroupName()); - info->setStatusTable(it.getTopic(), consumeStat); - } - - std::map> requestTable = m_pRebalance->getPullRequestTable(); - - for (const auto& it : requestTable) { - if (!it.second->isDropped()) { - MessageQueue queue((it.first).getTopic(), (it.first).getBrokerName(), (it.first).getQueueId()); - ProcessQueueInfo processQueue; - processQueue.cachedMsgMinOffset = it.second->getCacheMinOffset(); - processQueue.cachedMsgMaxOffset = it.second->getCacheMaxOffset(); - processQueue.cachedMsgCount = it.second->getCacheMsgCount(); - processQueue.setCommitOffset( - m_pOffsetStore->readOffset(it.first, MEMORY_FIRST_THEN_STORE, getSessionCredentials())); - processQueue.setDroped(it.second->isDropped()); - processQueue.setLocked(it.second->isLocked()); - processQueue.lastLockTimestamp = it.second->getLastLockTimestamp(); - processQueue.lastPullTimestamp = it.second->getLastPullTimestamp(); - processQueue.lastConsumeTimestamp = it.second->getLastConsumeTimestamp(); - info->setMqTable(queue, processQueue); - } - } - - return info; -} -// we should deal with name space before producer start. -bool DefaultMQPushConsumerImpl::dealWithNameSpace() { - string ns = getNameSpace(); - if (ns.empty()) { - string nsAddr = getNamesrvAddr(); - if (!NameSpaceUtil::checkNameSpaceExistInNameServer(nsAddr)) { - return true; - } - ns = NameSpaceUtil::getNameSpaceFromNsURL(nsAddr); - // reset namespace - setNameSpace(ns); - } - // reset group name - if (!NameSpaceUtil::hasNameSpace(getGroupName(), ns)) { - string fullGID = NameSpaceUtil::withNameSpace(getGroupName(), ns); - setGroupName(fullGID); - } - map subTmp; - map::iterator it = m_subTopics.begin(); - for (; it != m_subTopics.end(); ++it) { - string topic = it->first; - string subs = it->second; - if (!NameSpaceUtil::hasNameSpace(topic, ns)) { - LOG_INFO("Update Subscribe[%s:%s] with NameSpace:%s", it->first.c_str(), it->second.c_str(), ns.c_str()); - topic = NameSpaceUtil::withNameSpace(topic, ns); - // let other mode to known, the name space model opened. - m_useNameSpaceMode = true; - } - subTmp[topic] = subs; - } - m_subTopics.swap(subTmp); - - return true; -} -void DefaultMQPushConsumerImpl::logConfigs() { - showClientConfigs(); - - LOG_WARN("MessageModel:%d", m_messageModel); - LOG_WARN("MessageModel:%s", m_messageModel == BROADCASTING ? "BROADCASTING" : "CLUSTERING"); - - LOG_WARN("ConsumeFromWhere:%d", m_consumeFromWhere); - switch (m_consumeFromWhere) { - case CONSUME_FROM_FIRST_OFFSET: - LOG_WARN("ConsumeFromWhere:%s", "CONSUME_FROM_FIRST_OFFSET"); - break; - case CONSUME_FROM_LAST_OFFSET: - LOG_WARN("ConsumeFromWhere:%s", "CONSUME_FROM_LAST_OFFSET"); - break; - - case CONSUME_FROM_TIMESTAMP: - LOG_WARN("ConsumeFromWhere:%s", "CONSUME_FROM_TIMESTAMP"); - break; - case CONSUME_FROM_LAST_OFFSET_AND_FROM_MIN_WHEN_BOOT_FIRST: - LOG_WARN("ConsumeFromWhere:%s", "CONSUME_FROM_LAST_OFFSET_AND_FROM_MIN_WHEN_BOOT_FIRST"); - break; - case CONSUME_FROM_MAX_OFFSET: - LOG_WARN("ConsumeFromWhere:%s", "CONSUME_FROM_MAX_OFFSET"); - break; - case CONSUME_FROM_MIN_OFFSET: - LOG_WARN("ConsumeFromWhere:%s", "CONSUME_FROM_MAX_OFFSET"); - break; - default: - LOG_WARN("ConsumeFromWhere:%s", "UnKnown."); - break; - } - LOG_WARN("ConsumeThreadCount:%d", m_consumeThreadCount); - LOG_WARN("ConsumeMessageBatchMaxSize:%d", m_consumeMessageBatchMaxSize); - LOG_WARN("MaxMsgCacheSizePerQueue:%d", m_maxMsgCacheSize); - LOG_WARN("MaxReconsumeTimes:%d", m_maxReconsumeTimes); - LOG_WARN("PullMsgThreadPoolNum:%d", m_pullMsgThreadPoolNum); - LOG_WARN("AsyncPullMode:%s", m_asyncPull ? "true" : "false"); - LOG_WARN("AsyncPullTimeout:%d ms", m_asyncPullTimeout); -} -// we should create trace message poll before producer send messages. -bool DefaultMQPushConsumerImpl::dealWithMessageTrace() { - if (!getMessageTrace()) { - LOG_INFO("Message Trace set to false, Will not send trace messages."); - return false; - } - // Try to create default producer inner. - LOG_INFO("DefaultMQPushConsumer Open message trace.."); - - createMessageTraceInnerProducer(); - std::shared_ptr hook(new ConsumeMessageHookImpl()); - registerConsumeMessageHook(hook); - return true; -} - -void DefaultMQPushConsumerImpl::createMessageTraceInnerProducer() { - m_DefaultMQProducerImpl = std::make_shared(getGroupName()); - m_DefaultMQProducerImpl->setMessageTrace(false); - m_DefaultMQProducerImpl->setInstanceName("MESSAGE_TRACE_" + getInstanceName()); - const SessionCredentials& session = getSessionCredentials(); - m_DefaultMQProducerImpl->setSessionCredentials(session.getAccessKey(), session.getSecretKey(), - session.getAuthChannel()); - if (!getNamesrvAddr().empty()) { - m_DefaultMQProducerImpl->setNamesrvAddr(getNamesrvAddr()); - } - m_DefaultMQProducerImpl->setNameSpace(getNameSpace()); - // m_DefaultMQProducerImpl->setNamesrvDomain(getNamesrvDomain()); - m_DefaultMQProducerImpl->start(); -} -void DefaultMQPushConsumerImpl::shutdownMessageTraceInnerProducer() { - if (!getMessageTrace()) { - return; - } - if (m_DefaultMQProducerImpl) { - LOG_INFO("Shutdown Message Trace Inner Producer In Consumer."); - m_DefaultMQProducerImpl->shutdown(); - } -} -bool DefaultMQPushConsumerImpl::hasConsumeMessageHook() { - return !m_consumeMessageHookList.empty(); -} - -void DefaultMQPushConsumerImpl::registerConsumeMessageHook(std::shared_ptr& hook) { - m_consumeMessageHookList.push_back(hook); - LOG_INFO("Register ConsumeMessageHook success,hookname is %s", hook->getHookName().c_str()); -} - -void DefaultMQPushConsumerImpl::executeConsumeMessageHookBefore(ConsumeMessageContext* context) { - if (!m_consumeMessageHookList.empty()) { - std::vector>::iterator it = m_consumeMessageHookList.begin(); - for (; it != m_consumeMessageHookList.end(); ++it) { - try { - (*it)->executeHookBefore(context); - } catch (exception e) { - } - } - } -} - -void DefaultMQPushConsumerImpl::executeConsumeMessageHookAfter(ConsumeMessageContext* context) { - if (!m_consumeMessageHookList.empty()) { - std::vector>::iterator it = m_consumeMessageHookList.begin(); - for (; it != m_consumeMessageHookList.end(); ++it) { - try { - (*it)->executeHookAfter(context); - } catch (exception e) { - } - } - } -} - -void DefaultMQPushConsumerImpl::submitSendTraceRequest(MQMessage& msg, SendCallback* pSendCallback) { - if (getMessageTrace()) { - try { - LOG_DEBUG("=====Send Trace Messages,Topic[%s],Key[%s],Body[%s]", msg.getTopic().c_str(), msg.getKeys().c_str(), - msg.getBody().c_str()); - // m_DefaultMQProducerImpl->submitSendTraceRequest(msg, pSendCallback); - m_DefaultMQProducerImpl->send(msg, pSendCallback, false); - } catch (exception e) { - LOG_INFO(e.what()); - } - } -} - -void DefaultMQPushConsumerImpl::setDefaultMqProducerImpl(DefaultMQProducerImpl* DefaultMqProducerImpl) { - m_DefaultMQProducerImpl.reset(DefaultMqProducerImpl); -} -} // namespace rocketmq diff --git a/src/consumer/DefaultMQPushConsumerImpl.h b/src/consumer/DefaultMQPushConsumerImpl.h deleted file mode 100644 index 34fb30739..000000000 --- a/src/consumer/DefaultMQPushConsumerImpl.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __DEFAULTMQPUSHCONSUMERIMPL_H__ -#define __DEFAULTMQPUSHCONSUMERIMPL_H__ - -#include -#include -#include -#include -#include -#include -#include -#include "AsyncCallback.h" -#include "ConsumeMessageContext.h" -#include "ConsumeMessageHook.h" -#include "DefaultMQProducerImpl.h" -#include "MQConsumer.h" -#include "MQMessageListener.h" -#include "MQMessageQueue.h" - -namespace rocketmq { - -class Rebalance; -class SubscriptionData; -class OffsetStore; -class PullAPIWrapper; -class PullRequest; -class ConsumeMsgService; -class TaskQueue; -class TaskThread; -class AsyncPullCallback; -class ConsumerRunningInfo; -//& mqs); - virtual void doRebalance(); - virtual void persistConsumerOffset(); - virtual void persistConsumerOffsetByResetOffset(); - virtual void updateTopicSubscribeInfo(const std::string& topic, std::vector& info); - virtual ConsumeType getConsumeType(); - virtual ConsumeFromWhere getConsumeFromWhere(); - void setConsumeFromWhere(ConsumeFromWhere consumeFromWhere); - virtual void getSubscriptions(std::vector&); - virtual void updateConsumeOffset(const MQMessageQueue& mq, int64 offset); - virtual void removeConsumeOffset(const MQMessageQueue& mq); - virtual PullResult pull(const MQMessageQueue& mq, const std::string& subExpression, int64 offset, int maxNums) { - return PullResult(); - } - virtual void pull(const MQMessageQueue& mq, - const std::string& subExpression, - int64 offset, - int maxNums, - PullCallback* pPullCallback) {} - virtual ConsumerRunningInfo* getConsumerRunningInfo(); - //); - virtual bool producePullMsgTaskLater(boost::weak_ptr, int millis); - static void static_triggerNextPullRequest(void* context, - boost::asio::deadline_timer* t, - boost::weak_ptr); - void triggerNextPullRequest(boost::asio::deadline_timer* t, boost::weak_ptr); - void runPullMsgQueue(TaskQueue* pTaskQueue); - void pullMessage(boost::weak_ptr pullrequest); - void pullMessageAsync(boost::weak_ptr pullrequest); - void setAsyncPull(bool asyncFlag); - AsyncPullCallback* getAsyncPullCallBack(boost::weak_ptr, MQMessageQueue msgQueue); - void shutdownAsyncPullCallBack(); - - /* - for orderly consume, set the pull num of message size by each pullMsg, - default value is 1; - */ - void setConsumeMessageBatchMaxSize(int consumeMessageBatchMaxSize); - int getConsumeMessageBatchMaxSize() const; - - /* - set consuming thread count, default value is cpu cores - */ - void setConsumeThreadCount(int threadCount); - int getConsumeThreadCount() const; - void setMaxReconsumeTimes(int maxReconsumeTimes); - int getMaxReconsumeTimes() const; - - /* - set pullMsg thread count, default value is cpu cores - */ - void setPullMsgThreadPoolCount(int threadCount); - int getPullMsgThreadPoolCount() const; - - /* - set max cache msg size perQueue in memory if consumer could not consume msgs - immediately - default maxCacheMsgSize perQueue is 1000, set range is:1~65535 - */ - void setMaxCacheMsgSizePerQueue(int maxCacheSize); - int getMaxCacheMsgSizePerQueue() const; - void submitSendTraceRequest(MQMessage& msg, SendCallback* pSendCallback); - bool hasConsumeMessageHook(); - - void registerConsumeMessageHook(std::shared_ptr& hook); - void setDefaultMqProducerImpl(DefaultMQProducerImpl* DefaultMqProducerImpl); - void executeConsumeMessageHookBefore(ConsumeMessageContext* context); - void executeConsumeMessageHookAfter(ConsumeMessageContext* context); - - private: - void checkConfig(); - void copySubscription(); - void updateTopicSubscribeInfoWhenSubscriptionChanged(); - bool dealWithNameSpace(); - void logConfigs(); - - bool dealWithMessageTrace(); - void createMessageTraceInnerProducer(); - void shutdownMessageTraceInnerProducer(); - - private: - uint64_t m_startTime; - ConsumeFromWhere m_consumeFromWhere; - std::map m_subTopics; - int m_consumeThreadCount; - OffsetStore* m_pOffsetStore; - Rebalance* m_pRebalance; - PullAPIWrapper* m_pPullAPIWrapper; - ConsumeMsgService* m_consumerService; - MQMessageListener* m_pMessageListener; - int m_consumeMessageBatchMaxSize; - int m_maxMsgCacheSize; - int m_maxReconsumeTimes = -1; - boost::asio::io_service m_async_ioService; - boost::scoped_ptr m_async_service_thread; - - typedef std::map PullMAP; - PullMAP m_PullCallback; - bool m_asyncPull; - int m_asyncPullTimeout; - int m_pullMsgThreadPoolNum; - - private: - TaskQueue* m_pullmsgQueue; - std::unique_ptr m_pullmsgThread; - - // used for trace - std::vector > m_consumeMessageHookList; - std::shared_ptr m_DefaultMQProducerImpl; -}; -// -#include - -#include -#include -#include -#include -#include -#include -namespace rocketmq { - -//selectConsumer(groupName); - if (pConsumer) { - LOG_INFO("new LocalFileOffsetStore"); - string directoryName = UtilAll::getLocalAddress() + "@" + pConsumer->getInstanceName(); - m_storePath = ".rocketmq_offsets/" + directoryName + "/" + groupName; - string homeDir(UtilAll::getHomeDirectory()); - m_storeFile = homeDir + "/" + m_storePath + "/offsets.Json"; - - string storePath(homeDir); - storePath.append("/").append(m_storePath); - boost::filesystem::path dir(storePath); - boost::system::error_code ec; - if (!boost::filesystem::exists(dir, ec)) { - if (!boost::filesystem::create_directories(dir, ec)) { - LOG_ERROR("create offset store dir:%s error", storePath.c_str()); - string errorMsg("create offset store dir fail: "); - errorMsg.append(storePath); - THROW_MQEXCEPTION(MQClientException, errorMsg, -1); - } - } - } -} - -LocalFileOffsetStore::~LocalFileOffsetStore() {} - -void LocalFileOffsetStore::load() { - std::ifstream ifs(m_storeFile.c_str(), std::ios::in); - if (ifs.good()) { - if (ifs.is_open()) { - if (ifs.peek() != std::ifstream::traits_type::eof()) { - map m_offsetTable_tmp; - boost::system::error_code e; - try { - boost::archive::text_iarchive ia(ifs); - ia >> m_offsetTable_tmp; - } catch (...) { - LOG_ERROR( - "load offset store file failed, please check whether file: %s is " - "cleared by operator, if so, delete this offsets.Json file and " - "then restart consumer", - m_storeFile.c_str()); - ifs.close(); - string errorMsg("load offset store file: "); - errorMsg.append(m_storeFile) - .append( - " failed, please check whether offsets.Json is cleared by " - "operator, if so, delete this offsets.Json file and then " - "restart consumer"); - THROW_MQEXCEPTION(MQClientException, errorMsg, -1); - } - ifs.close(); - - for (map::iterator it = m_offsetTable_tmp.begin(); it != m_offsetTable_tmp.end(); ++it) { - // LOG_INFO("it->first:%s, it->second:%lld", it->first.c_str(), - // it->second); - Json::Reader reader; - Json::Value object; - reader.parse(it->first.c_str(), object); - MQMessageQueue mq(object["topic"].asString(), object["brokerName"].asString(), object["queueId"].asInt()); - updateOffset(mq, it->second); - } - m_offsetTable_tmp.clear(); - } else { - LOG_ERROR( - "open offset store file failed, please check whether file: %s is " - "cleared by operator, if so, delete this offsets.Json file and " - "then restart consumer", - m_storeFile.c_str()); - THROW_MQEXCEPTION(MQClientException, - "open offset store file failed, please check whether " - "offsets.Json is cleared by operator, if so, delete " - "this offsets.Json file and then restart consumer", - -1); - } - } else { - LOG_ERROR( - "open offset store file failed, please check whether file:%s is " - "deleted by operator and then restart consumer", - m_storeFile.c_str()); - THROW_MQEXCEPTION(MQClientException, - "open offset store file failed, please check " - "directory:%s is deleted by operator or offset.Json " - "file is cleared by operator, and then restart " - "consumer", - -1); - } - } else { - LOG_WARN( - "offsets.Json file not exist, maybe this is the first time " - "consumation"); - } -} - -void LocalFileOffsetStore::updateOffset(const MQMessageQueue& mq, int64 offset) { - boost::lock_guard lock(m_lock); - m_offsetTable[mq] = offset; -} - -int64 LocalFileOffsetStore::readOffset(const MQMessageQueue& mq, - ReadOffsetType type, - const SessionCredentials& session_credentials) { - switch (type) { - case MEMORY_FIRST_THEN_STORE: - case READ_FROM_MEMORY: { - boost::lock_guard lock(m_lock); - MQ2OFFSET::iterator it = m_offsetTable.find(mq); - if (it != m_offsetTable.end()) { - return it->second; - } else if (READ_FROM_MEMORY == type) { - return -1; - } - } - case READ_FROM_STORE: { - try { - load(); - } catch (MQException& e) { - LOG_ERROR("catch exception when load local file"); - return -1; - } - boost::lock_guard lock(m_lock); - MQ2OFFSET::iterator it = m_offsetTable.find(mq); - if (it != m_offsetTable.end()) { - return it->second; - } - } - default: - break; - } - LOG_ERROR("can not readOffset from offsetStore.json, maybe first time consumation"); - return -1; -} - -void LocalFileOffsetStore::persist(const MQMessageQueue& mq, const SessionCredentials& session_credentials) {} - -void LocalFileOffsetStore::persistAll(const std::vector& mqs) { - boost::lock_guard lock(m_lock); - - map m_offsetTable_tmp; - vector::const_iterator it = mqs.begin(); - for (; it != mqs.end(); ++it) { - MessageQueue mq_tmp((*it).getTopic(), (*it).getBrokerName(), (*it).getQueueId()); - string mqKey = mq_tmp.toJson().toStyledString(); - m_offsetTable_tmp[mqKey] = m_offsetTable[*it]; - } - - std::ofstream s; - string storefile_bak(m_storeFile); - storefile_bak.append(".bak"); - s.open(storefile_bak.c_str(), std::ios::out); - if (s.is_open()) { - try { - boost::archive::text_oarchive oa(s); - // Boost is nervous that archiving non-const class instances which might - // cause a problem with object tracking if different tracked objects use - // the same address. - oa << const_cast&>(m_offsetTable_tmp); - } catch (...) { - LOG_ERROR("persist offset store file:%s failed", m_storeFile.c_str()); - s.close(); - THROW_MQEXCEPTION(MQClientException, "persistAll:open offset store file failed", -1); - } - s.close(); - if (!UtilAll::ReplaceFile(storefile_bak, m_storeFile)) - LOG_ERROR("could not rename bak file:%s", strerror(errno)); - m_offsetTable_tmp.clear(); - } else { - LOG_ERROR("open offset store file:%s failed", m_storeFile.c_str()); - m_offsetTable_tmp.clear(); - THROW_MQEXCEPTION(MQClientException, "persistAll:open offset store file failed", -1); - } -} - -void LocalFileOffsetStore::removeOffset(const MQMessageQueue& mq) {} - -// lock(m_lock); - m_offsetTable[mq] = offset; -} - -int64 RemoteBrokerOffsetStore::readOffset(const MQMessageQueue& mq, - ReadOffsetType type, - const SessionCredentials& session_credentials) { - switch (type) { - case MEMORY_FIRST_THEN_STORE: - case READ_FROM_MEMORY: { - boost::lock_guard lock(m_lock); - - MQ2OFFSET::iterator it = m_offsetTable.find(mq); - if (it != m_offsetTable.end()) { - return it->second; - } else if (READ_FROM_MEMORY == type) { - return -1; - } - } - case READ_FROM_STORE: { - try { - int64 brokerOffset = fetchConsumeOffsetFromBroker(mq, session_credentials); - // lock(m_lock); - offsetTable = m_offsetTable; - } - - MQ2OFFSET::iterator it = offsetTable.find(mq); - if (it != offsetTable.end()) { - try { - updateConsumeOffsetToBroker(mq, it->second, session_credentials); - } catch (MQException& e) { - LOG_ERROR("updateConsumeOffsetToBroker %s ,offset:[%lld] error", mq.toString().c_str(), it->second); - } - } -} - -void RemoteBrokerOffsetStore::persistAll(const std::vector& mq) {} - -void RemoteBrokerOffsetStore::removeOffset(const MQMessageQueue& mq) { - boost::lock_guard lock(m_lock); - if (m_offsetTable.find(mq) != m_offsetTable.end()) - m_offsetTable.erase(mq); -} - -void RemoteBrokerOffsetStore::updateConsumeOffsetToBroker(const MQMessageQueue& mq, - int64 offset, - const SessionCredentials& session_credentials) { - unique_ptr pFindBrokerResult(m_pClientFactory->findBrokerAddressInAdmin(mq.getBrokerName())); - - if (pFindBrokerResult == NULL) { - m_pClientFactory->updateTopicRouteInfoFromNameServer(mq.getTopic(), session_credentials); - pFindBrokerResult.reset(m_pClientFactory->findBrokerAddressInAdmin(mq.getBrokerName())); - } - - if (pFindBrokerResult != NULL) { - UpdateConsumerOffsetRequestHeader* pRequestHeader = new UpdateConsumerOffsetRequestHeader(); - pRequestHeader->topic = mq.getTopic(); - pRequestHeader->consumerGroup = m_groupName; - pRequestHeader->queueId = mq.getQueueId(); - pRequestHeader->commitOffset = offset; - - try { - LOG_INFO("oneway updateConsumeOffsetToBroker of mq:%s, its offset is:%lld", mq.toString().c_str(), offset); - return m_pClientFactory->getMQClientAPIImpl()->updateConsumerOffsetOneway( - pFindBrokerResult->brokerAddr, pRequestHeader, 1000 * 5, session_credentials); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - } - } - LOG_WARN("The broker not exist"); -} - -int64 RemoteBrokerOffsetStore::fetchConsumeOffsetFromBroker(const MQMessageQueue& mq, - const SessionCredentials& session_credentials) { - unique_ptr pFindBrokerResult(m_pClientFactory->findBrokerAddressInAdmin(mq.getBrokerName())); - - if (pFindBrokerResult == NULL) { - m_pClientFactory->updateTopicRouteInfoFromNameServer(mq.getTopic(), session_credentials); - pFindBrokerResult.reset(m_pClientFactory->findBrokerAddressInAdmin(mq.getBrokerName())); - } - - if (pFindBrokerResult != NULL) { - QueryConsumerOffsetRequestHeader* pRequestHeader = new QueryConsumerOffsetRequestHeader(); - pRequestHeader->topic = mq.getTopic(); - pRequestHeader->consumerGroup = m_groupName; - pRequestHeader->queueId = mq.getQueueId(); - - return m_pClientFactory->getMQClientAPIImpl()->queryConsumerOffset(pFindBrokerResult->brokerAddr, pRequestHeader, - 1000 * 5, session_credentials); - } else { - LOG_ERROR("The broker not exist when fetchConsumeOffsetFromBroker"); - THROW_MQEXCEPTION(MQClientException, "The broker not exist", -1); - } -} -// -#include -#include -#include -#include "MQMessageQueue.h" -#include "SessionCredentials.h" - -namespace rocketmq { -class MQClientFactory; -//& mq) = 0; - virtual void removeOffset(const MQMessageQueue& mq) = 0; - - protected: - std::string m_groupName; - typedef std::map MQ2OFFSET; - MQ2OFFSET m_offsetTable; - MQClientFactory* m_pClientFactory; - boost::mutex m_lock; -}; - -//& mq); - virtual void removeOffset(const MQMessageQueue& mq); - - private: - std::string m_storePath; - std::string m_storeFile; -}; - -//& mq); - virtual void removeOffset(const MQMessageQueue& mq); - - private: - void updateConsumeOffsetToBroker(const MQMessageQueue& mq, - int64 offset, - const SessionCredentials& session_credentials); - int64 fetchConsumeOffsetFromBroker(const MQMessageQueue& mq, const SessionCredentials& session_credentials); -}; -// lock(m_lock); - m_pullFromWhichNodeTable[mq] = brokerId; -} - -int PullAPIWrapper::recalculatePullFromWhichNode(const MQMessageQueue& mq) { - boost::lock_guard lock(m_lock); - if (m_pullFromWhichNodeTable.find(mq) != m_pullFromWhichNodeTable.end()) { - return m_pullFromWhichNodeTable[mq]; - } - return MASTER_ID; -} - -PullResult PullAPIWrapper::processPullResult(const MQMessageQueue& mq, - PullResult* pullResult, - SubscriptionData* subscriptionData) { - PullResultExt* pResultExt = static_cast(pullResult); - if (pResultExt == NULL) { - string errMsg("The pullResult NULL of"); - errMsg.append(mq.toString()); - THROW_MQEXCEPTION(MQClientException, errMsg, -1); - } - - //suggestWhichBrokerId); - - vector msgFilterList; - if (pResultExt->pullStatus == FOUND) { - // msgAllList; - MQDecoder::decodes(&pResultExt->msgMemBlock, msgAllList); - - //getTagsSet().empty()) { - msgFilterList.reserve(msgAllList.size()); - vector::iterator it = msgAllList.begin(); - for (; it != msgAllList.end(); ++it) { - string msgTag = (*it).getTags(); - if (subscriptionData->containTag(msgTag)) { - msgFilterList.push_back(*it); - } - } - } else { - msgFilterList.swap(msgAllList); - } - } - - return PullResult(pResultExt->pullStatus, pResultExt->nextBeginOffset, pResultExt->minOffset, pResultExt->maxOffset, - msgFilterList); -} - -PullResult* PullAPIWrapper::pullKernelImpl(const MQMessageQueue& mq, // 1 - const string& subExpression, // 2 - int64 subVersion, // 3 - int64 offset, // 4 - int maxNums, // 5 - int sysFlag, // 6 - int64 commitOffset, // 7 - int brokerSuspendMaxTimeMillis, // 8 - int timeoutMillis, // 9 - int communicationMode, // 10 - PullCallback* pullCallback, - const SessionCredentials& session_credentials, - void* pArg /*= NULL*/) { - unique_ptr pFindBrokerResult( - m_MQClientFactory->findBrokerAddressInSubscribe(mq.getBrokerName(), recalculatePullFromWhichNode(mq), false)); - //updateTopicRouteInfoFromNameServer(mq.getTopic(), session_credentials); - pFindBrokerResult.reset( - m_MQClientFactory->findBrokerAddressInSubscribe(mq.getBrokerName(), recalculatePullFromWhichNode(mq), false)); - } - - if (pFindBrokerResult != NULL) { - int sysFlagInner = sysFlag; - - if (pFindBrokerResult->slave) { - sysFlagInner = PullSysFlag::clearCommitOffsetFlag(sysFlagInner); - } - - PullMessageRequestHeader* pRequestHeader = new PullMessageRequestHeader(); - pRequestHeader->consumerGroup = m_consumerGroup; - pRequestHeader->topic = mq.getTopic(); - pRequestHeader->queueId = mq.getQueueId(); - pRequestHeader->queueOffset = offset; - pRequestHeader->maxMsgNums = maxNums; - pRequestHeader->sysFlag = sysFlagInner; - pRequestHeader->commitOffset = commitOffset; - pRequestHeader->suspendTimeoutMillis = brokerSuspendMaxTimeMillis; - pRequestHeader->subscription = subExpression; - pRequestHeader->subVersion = subVersion; - - return m_MQClientFactory->getMQClientAPIImpl()->pullMessage(pFindBrokerResult->brokerAddr, pRequestHeader, - timeoutMillis, communicationMode, pullCallback, pArg, - session_credentials); - } - THROW_MQEXCEPTION(MQClientException, "The broker not exist", -1); -} - -} // namespace rocketmq diff --git a/src/consumer/PullAPIWrapper.h b/src/consumer/PullAPIWrapper.h deleted file mode 100644 index dca370a36..000000000 --- a/src/consumer/PullAPIWrapper.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef _PULLAPIWRAPPER_H_ -#define _PULLAPIWRAPPER_H_ - -#include -#include -#include "AsyncCallback.h" -#include "MQMessageQueue.h" -#include "SessionCredentials.h" -#include "SubscriptionData.h" - -namespace rocketmq { -class MQClientFactory; -// m_pullFromWhichNodeTable; -}; - -// lock(m_pullRequestLock); - if (this != &other) { - m_groupname = other.m_groupname; - m_nextOffset = other.m_nextOffset; - m_bDropped.store(other.m_bDropped.load()); - m_queueOffsetMax = other.m_queueOffsetMax; - m_messageQueue = other.m_messageQueue; - m_msgTreeMap = other.m_msgTreeMap; - m_msgTreeMapTemp = other.m_msgTreeMapTemp; - m_lastPullTimestamp = other.m_lastPullTimestamp; - m_lastConsumeTimestamp = other.m_lastConsumeTimestamp; - } - return *this; -} - -void PullRequest::putMessage(vector& msgs) { - boost::lock_guard lock(m_pullRequestLock); - - vector::iterator it = msgs.begin(); - for (; it != msgs.end(); it++) { - m_msgTreeMap[it->getQueueOffset()] = *it; - m_queueOffsetMax = (std::max)(m_queueOffsetMax, it->getQueueOffset()); - } - LOG_DEBUG("PullRequest: putMessage m_queueOffsetMax:%lld ", m_queueOffsetMax); -} - -void PullRequest::getMessage(vector& msgs) { - boost::lock_guard lock(m_pullRequestLock); - - map::iterator it = m_msgTreeMap.begin(); - for (; it != m_msgTreeMap.end(); it++) { - msgs.push_back(it->second); - } -} - -int64 PullRequest::getCacheMinOffset() { - boost::lock_guard lock(m_pullRequestLock); - if (m_msgTreeMap.empty()) { - return 0; - } else { - map::iterator it = m_msgTreeMap.begin(); - MQMessageExt msg = it->second; - return msg.getQueueOffset(); - } -} - -int64 PullRequest::getCacheMaxOffset() { - return m_queueOffsetMax; -} - -int PullRequest::getCacheMsgCount() { - boost::lock_guard lock(m_pullRequestLock); - return m_msgTreeMap.size() + m_msgTreeMapTemp.size(); -} - -void PullRequest::getMessageByQueueOffset(vector& msgs, int64 minQueueOffset, int64 maxQueueOffset) { - boost::lock_guard lock(m_pullRequestLock); - - int64 it = minQueueOffset; - for (; it <= maxQueueOffset; it++) { - msgs.push_back(m_msgTreeMap[it]); - } -} - -int64 PullRequest::removeMessage(vector& msgs) { - boost::lock_guard lock(m_pullRequestLock); - - int64 result = -1; - LOG_DEBUG("m_queueOffsetMax is:%lld", m_queueOffsetMax); - if (!m_msgTreeMap.empty()) { - result = m_queueOffsetMax + 1; - LOG_DEBUG(" offset result is:%lld, m_queueOffsetMax is:%lld, msgs size:" SIZET_FMT "", result, m_queueOffsetMax, - msgs.size()); - vector::iterator it = msgs.begin(); - for (; it != msgs.end(); it++) { - LOG_DEBUG("remove these msg from m_msgTreeMap, its offset:%lld", it->getQueueOffset()); - m_msgTreeMap.erase(it->getQueueOffset()); - } - - if (!m_msgTreeMap.empty()) { - map::iterator it = m_msgTreeMap.begin(); - result = it->first; - LOG_INFO("cache msg size:" SIZET_FMT " of pullRequest:%s, return offset result is:%lld", m_msgTreeMap.size(), - m_messageQueue.toString().c_str(), result); - } - } - - return result; -} - -void PullRequest::clearAllMsgs() { - boost::lock_guard lock(m_pullRequestLock); - - if (isDropped()) { - LOG_DEBUG("clear m_msgTreeMap as PullRequest had been dropped."); - m_msgTreeMap.clear(); - m_msgTreeMapTemp.clear(); - } -} - -void PullRequest::updateQueueMaxOffset(int64 queueOffset) { - // following 2 cases which may set queueOffset smaller than m_queueOffsetMax: - // 1. resetOffset cmd - // 2. during rebalance, if configured with CONSUMER_FROM_FIRST_OFFSET, when - // readOffset called by computePullFromWhere was failed, m_nextOffset will be - // setted to 0 - m_queueOffsetMax = queueOffset; -} - -void PullRequest::setDropped(bool dropped) { - int temp = (dropped == true ? 1 : 0); - m_bDropped.store(temp); - /* - m_queueOffsetMax = 0; - m_nextOffset = 0; - //the reason why not clear m_queueOffsetMax and m_nextOffset is due to - ConsumeMsgService and drop mq are concurrent running. - consider following situation: - 1>. ConsumeMsgService running - 2>. dorebalance, drop mq, reset m_nextOffset and m_queueOffsetMax - 3>. ConsumeMsgService calls removeMessages, if no other msgs in - m_msgTreeMap, m_queueOffsetMax(0)+1 will return; - 4>. updateOffset with 1, which is more smaller than correct offset. - */ -} - -bool PullRequest::isDropped() const { - return m_bDropped.load() == 1; -} - -int64 PullRequest::getNextOffset() { - boost::lock_guard lock(m_pullRequestLock); - return m_nextOffset; -} - -void PullRequest::setLocked(bool Locked) { - int temp = (Locked == true ? 1 : 0); - m_bLocked.store(temp); -} - -bool PullRequest::isLocked() const { - return m_bLocked.load() == 1; -} - -bool PullRequest::isLockExpired() const { - return (UtilAll::currentTimeMillis() - m_lastLockTimestamp) > RebalanceLockMaxLiveTime; -} - -void PullRequest::setLastLockTimestamp(int64 time) { - m_lastLockTimestamp = time; -} - -int64 PullRequest::getLastLockTimestamp() const { - return m_lastLockTimestamp; -} - -void PullRequest::setLastPullTimestamp(uint64 time) { - m_lastPullTimestamp = time; -} - -uint64 PullRequest::getLastPullTimestamp() const { - return m_lastPullTimestamp; -} - -bool PullRequest::isPullRequestExpired() const { - uint64 interval = m_lastPullTimestamp + MAX_PULL_IDLE_TIME; - if (interval <= UtilAll::currentTimeMillis()) { - LOG_WARN("PullRequest for [%s] has been expired %lld ms,m_lastPullTimestamp = %lld ms", - m_messageQueue.toString().c_str(), UtilAll::currentTimeMillis() - m_lastPullTimestamp, - m_lastPullTimestamp); - return true; - } - return false; -} - -void PullRequest::setLastConsumeTimestamp(uint64 time) { - m_lastConsumeTimestamp = time; -} - -uint64 PullRequest::getLastConsumeTimestamp() const { - return m_lastConsumeTimestamp; -} - -void PullRequest::setTryUnlockTimes(int time) { - m_lastLockTimestamp = time; -} - -int PullRequest::getTryUnlockTimes() const { - return m_lastLockTimestamp; -} - -void PullRequest::setNextOffset(int64 nextoffset) { - boost::lock_guard lock(m_pullRequestLock); - m_nextOffset = nextoffset; -} - -string PullRequest::getGroupName() const { - return m_groupname; -} - -boost::timed_mutex& PullRequest::getPullRequestCriticalSection() { - return m_consumeLock; -} - -void PullRequest::takeMessages(vector& msgs, int batchSize) { - boost::lock_guard lock(m_pullRequestLock); - for (int i = 0; i != batchSize; i++) { - map::iterator it = m_msgTreeMap.begin(); - if (it != m_msgTreeMap.end()) { - msgs.push_back(it->second); - m_msgTreeMapTemp[it->first] = it->second; - m_msgTreeMap.erase(it); - } - } -} - -void PullRequest::makeMessageToCosumeAgain(vector& msgs) { - boost::lock_guard lock(m_pullRequestLock); - for (unsigned int it = 0; it != msgs.size(); ++it) { - m_msgTreeMap[msgs[it].getQueueOffset()] = msgs[it]; - m_msgTreeMapTemp.erase(msgs[it].getQueueOffset()); - } -} - -int64 PullRequest::commit() { - boost::lock_guard lock(m_pullRequestLock); - if (!m_msgTreeMapTemp.empty()) { - int64 offset = (--m_msgTreeMapTemp.end())->first; - m_msgTreeMapTemp.clear(); - return offset + 1; - } else { - return -1; - } -} - -// -#include -#include -#include "MQMessageExt.h" -#include "MQMessageQueue.h" -#include "UtilAll.h" -namespace rocketmq { -//& msgs); - void getMessage(vector& msgs); - int64 getCacheMinOffset(); - int64 getCacheMaxOffset(); - int getCacheMsgCount(); - void getMessageByQueueOffset(vector& msgs, int64 minQueueOffset, int64 maxQueueOffset); - int64 removeMessage(vector& msgs); - void clearAllMsgs(); - - PullRequest& operator=(const PullRequest& other); - - void setDropped(bool dropped); - bool isDropped() const; - - int64 getNextOffset(); - void setNextOffset(int64 nextoffset); - - string getGroupName() const; - - void updateQueueMaxOffset(int64 queueOffset); - - void setLocked(bool Locked); - bool isLocked() const; - bool isLockExpired() const; - void setLastLockTimestamp(int64 time); - int64 getLastLockTimestamp() const; - void setLastPullTimestamp(uint64 time); - uint64 getLastPullTimestamp() const; - bool isPullRequestExpired() const; - void setLastConsumeTimestamp(uint64 time); - uint64 getLastConsumeTimestamp() const; - void setTryUnlockTimes(int time); - int getTryUnlockTimes() const; - void takeMessages(vector& msgs, int batchSize); - int64 commit(); - void makeMessageToCosumeAgain(vector& msgs); - boost::timed_mutex& getPullRequestCriticalSection(); - bool removePullMsgEvent(bool force = false); - bool addPullMsgEvent(); - /** - * Check if there is an in-flight pull request. - */ - bool hasInFlightPullRequest() const; - - public: - MQMessageQueue m_messageQueue; - static const uint64 RebalanceLockInterval; // ms - static const uint64 RebalanceLockMaxLiveTime; // ms - static const uint64 MAX_PULL_IDLE_TIME; // ms - - private: - string m_groupname; - int64 m_nextOffset; - int64 m_queueOffsetMax; - boost::atomic m_bDropped; - boost::atomic m_bLocked; - map m_msgTreeMap; - map m_msgTreeMapTemp; - boost::mutex m_pullRequestLock; - uint64 m_lastLockTimestamp; // ms - // uint64 m_tryUnlockTimes; - uint64 m_lastPullTimestamp; - uint64 m_lastConsumeTimestamp; - boost::timed_mutex m_consumeLock; -}; -//& src) - : pullStatus(pullStatus), nextBeginOffset(nextBeginOffset), minOffset(minOffset), maxOffset(maxOffset) { - msgFoundList.reserve(src.size()); - for (size_t i = 0; i < src.size(); i++) { - msgFoundList.push_back(src[i]); - } -} - -PullResult::~PullResult() { - msgFoundList.clear(); -} - -//(messageBinary)) {} - - PullResultExt(PullStatus pullStatus, - int64 nextBeginOffset, - int64 minOffset, - int64 maxOffset, - int suggestWhichBrokerId) - : PullResult(pullStatus, nextBeginOffset, minOffset, maxOffset), suggestWhichBrokerId(suggestWhichBrokerId) {} - - virtual ~PullResultExt() {} - - public: - int suggestWhichBrokerId; - MemoryBlock msgMemBlock; -}; - -} // namespace rocketmq diff --git a/src/consumer/Rebalance.cpp b/src/consumer/Rebalance.cpp deleted file mode 100644 index 18c8b2f8d..000000000 --- a/src/consumer/Rebalance.cpp +++ /dev/null @@ -1,659 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "Rebalance.h" -#include "DefaultMQPushConsumerImpl.h" -#include "LockBatchBody.h" -#include "Logging.h" -#include "MQClientAPIImpl.h" -#include "MQClientFactory.h" -#include "OffsetStore.h" - -namespace rocketmq { -//::iterator it = m_subscriptionData.begin(); - for (; it != m_subscriptionData.end(); ++it) { - deleteAndZero(it->second); - } - m_subscriptionData.clear(); - } - { - /* - MQ2PULLREQ::iterator it = m_requestQueueTable.begin(); - for (; it != m_requestQueueTable.end(); ++it) { - delete it->second; - it->second = NULL; - } - m_requestQueueTable.clear();*/ - } - m_topicSubscribeInfoTable.clear(); - m_pConsumer = NULL; - m_pClientFactory = NULL; - deleteAndZero(m_pAllocateMQStrategy); -} - -void Rebalance::doRebalance() { - LOG_DEBUG("start doRebalance"); - try { - map::iterator it = m_subscriptionData.begin(); - for (; it != m_subscriptionData.end(); ++it) { - string topic = (it->first); - LOG_DEBUG("current topic is:%s", topic.c_str()); - // mqs - vector mqAll; - if (!getTopicSubscribeInfo(topic, mqAll)) { - continue; - } - if (mqAll.empty()) { - if (!UtilAll::startsWith_retry(topic)) { - std::string msg("#doRebalance. mqAll for topic:"); - msg.append(topic); - msg.append(" is empty"); - LOG_ERROR("Queues to allocate are empty. Msg: %s", msg.c_str()); - // to check, return error or throw exception - THROW_MQEXCEPTION(MQClientException, msg, -1); - } - } - - //getMessageModel()) { - case BROADCASTING: { - bool changed = updateRequestTableInRebalance(topic, mqAll); - if (changed) { - messageQueueChanged(topic, mqAll, mqAll); - } - break; - } - case CLUSTERING: { - vector cidAll; - m_pClientFactory->findConsumerIds(topic, m_pConsumer->getGroupName(), cidAll, - m_pConsumer->getSessionCredentials()); - - if (cidAll.empty()) { - LOG_ERROR("[ERROR] Get empty consumer IDs. Consumer Group: %s, Topic: %s", - m_pConsumer->getGroupName().c_str(), topic.c_str()); - // Should skip this round of re-balance immediately if consumer ID set is empty. - THROW_MQEXCEPTION(MQClientException, "doRebalance the cidAll is empty", -1); - } - // log - for (int i = 0; i < (int)cidAll.size(); ++i) { - LOG_DEBUG("client id:%s of topic:%s", cidAll[i].c_str(), topic.c_str()); - } - // allocateResult; - try { - m_pAllocateMQStrategy->allocate(m_pConsumer->getMQClientId(), mqAll, cidAll, allocateResult); - } catch (MQException& e) { - std::string errMsg("Allocate message queue for ConsumerGroup["); - errMsg.append(m_pConsumer->getGroupName()); - errMsg.append("],Topic["); - errMsg.append(topic); - errMsg.append("] failed. "); - LOG_ERROR("%s", errMsg.c_str()); - THROW_MQEXCEPTION(MQClientException, errMsg, -1); - } - - // log - for (int i = 0; i < (int)allocateResult.size(); ++i) { - LOG_DEBUG("allocate mq:%s", allocateResult[i].toString().c_str()); - } - - //getGroupName() << ", Topic: " << topic - << ", Current Consumer ID: " << m_pConsumer->getMQClientId() << "] is changed.\n" - << "Total Queue :#" << mqAll.size() << ", Total Consumer :#" << cidAll.size() - << ", Allocated Queues are: \n"; - - for (vector::size_type i = 0; i < allocateResult.size(); ++i) { - ss << allocateResult[i].toString() << "\n"; - } - // Log allocation result. - LOG_INFO("%s", ss.str().c_str()); - - messageQueueChanged(topic, mqAll, allocateResult); - break; - } - } - default: - break; - } - } - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - } -} - -void Rebalance::persistConsumerOffset() { - DefaultMQPushConsumerImpl* pConsumer = static_cast(m_pConsumer); - OffsetStore* pOffsetStore = pConsumer->getOffsetStore(); - vector mqs; - { - boost::lock_guard lock(m_requestTableMutex); - MQ2PULLREQ::iterator it = m_requestQueueTable.begin(); - for (; it != m_requestQueueTable.end(); ++it) { - if (it->second && (!it->second->isDropped())) { - mqs.push_back(it->first); - } - } - } - - if (pConsumer->getMessageModel() == BROADCASTING) { - pOffsetStore->persistAll(mqs); - } else { - vector::iterator it2 = mqs.begin(); - for (; it2 != mqs.end(); ++it2) { - pOffsetStore->persist(*it2, m_pConsumer->getSessionCredentials()); - } - } -} - -void Rebalance::persistConsumerOffsetByResetOffset() { - DefaultMQPushConsumerImpl* pConsumer = static_cast(m_pConsumer); - OffsetStore* pOffsetStore = pConsumer->getOffsetStore(); - vector mqs; - { - boost::lock_guard lock(m_requestTableMutex); - MQ2PULLREQ::iterator it = m_requestQueueTable.begin(); - for (; it != m_requestQueueTable.end(); ++it) { - if (it->second) { // even if it was dropped, also need update offset when - // rcv resetOffset cmd - mqs.push_back(it->first); - } - } - } - vector::iterator it2 = mqs.begin(); - for (; it2 != mqs.end(); ++it2) { - pOffsetStore->persist(*it2, m_pConsumer->getSessionCredentials()); - } -} - -SubscriptionData* Rebalance::getSubscriptionData(const string& topic) { - if (m_subscriptionData.find(topic) != m_subscriptionData.end()) { - return m_subscriptionData[topic]; - } - return NULL; -} - -map& Rebalance::getSubscriptionInner() { - return m_subscriptionData; -} - -void Rebalance::setSubscriptionData(const string& topic, SubscriptionData* pdata) { - if (pdata != NULL && m_subscriptionData.find(topic) == m_subscriptionData.end()) - m_subscriptionData[topic] = pdata; -} - -void Rebalance::setTopicSubscribeInfo(const string& topic, vector& mqs) { - if (m_subscriptionData.find(topic) != m_subscriptionData.end()) { - { - boost::lock_guard lock(m_topicSubscribeInfoTableMutex); - if (m_topicSubscribeInfoTable.find(topic) != m_topicSubscribeInfoTable.end()) - m_topicSubscribeInfoTable.erase(topic); - m_topicSubscribeInfoTable[topic] = mqs; - } - // log - vector::iterator it = mqs.begin(); - for (; it != mqs.end(); ++it) { - LOG_DEBUG("topic [%s] has :%s", topic.c_str(), (*it).toString().c_str()); - } - } -} - -bool Rebalance::getTopicSubscribeInfo(const string& topic, vector& mqs) { - boost::lock_guard lock(m_topicSubscribeInfoTableMutex); - if (m_topicSubscribeInfoTable.find(topic) != m_topicSubscribeInfoTable.end()) { - mqs = m_topicSubscribeInfoTable[topic]; - return true; - } - return false; -} - -void Rebalance::addPullRequest(MQMessageQueue mq, boost::shared_ptr pPullRequest) { - boost::lock_guard lock(m_requestTableMutex); - m_requestQueueTable[mq] = pPullRequest; -} - -void Rebalance::removePullRequest(MQMessageQueue mq) { - boost::lock_guard lock(m_requestTableMutex); - if (m_requestQueueTable.find(mq) != m_requestQueueTable.end()) { - m_requestQueueTable.erase(mq); - } -} -bool Rebalance::isPullRequestExist(MQMessageQueue mq) { - boost::lock_guard lock(m_requestTableMutex); - if (m_requestQueueTable.find(mq) != m_requestQueueTable.end()) { - return true; - } - return false; -} -boost::weak_ptr Rebalance::getPullRequest(MQMessageQueue mq) { - boost::lock_guard lock(m_requestTableMutex); - if (m_requestQueueTable.find(mq) != m_requestQueueTable.end()) { - return m_requestQueueTable[mq]; - } - return boost::weak_ptr(); -} - -map> Rebalance::getPullRequestTable() { - boost::lock_guard lock(m_requestTableMutex); - return m_requestQueueTable; -} - -void Rebalance::unlockAll(bool oneWay) { - map*> brokerMqs; - MQ2PULLREQ requestQueueTable = getPullRequestTable(); - for (MQ2PULLREQ::iterator it = requestQueueTable.begin(); it != requestQueueTable.end(); ++it) { - if (!(it->second->isDropped())) { - if (brokerMqs.find(it->first.getBrokerName()) == brokerMqs.end()) { - vector* mqs = new vector; - brokerMqs[it->first.getBrokerName()] = mqs; - } else { - brokerMqs[it->first.getBrokerName()]->push_back(it->first); - } - } - } - LOG_INFO("unLockAll " SIZET_FMT " broker mqs", brokerMqs.size()); - for (map*>::iterator itb = brokerMqs.begin(); itb != brokerMqs.end(); ++itb) { - unique_ptr pFindBrokerResult( - m_pClientFactory->findBrokerAddressInSubscribe(itb->first, MASTER_ID, true)); - if (!pFindBrokerResult) { - LOG_ERROR("unlockAll findBrokerAddressInSubscribe ret null for broker:%s", itb->first.data()); - continue; - } - unique_ptr unlockBatchRequest(new UnlockBatchRequestBody()); - vector mqs(*(itb->second)); - unlockBatchRequest->setClientId(m_pConsumer->getMQClientId()); - unlockBatchRequest->setConsumerGroup(m_pConsumer->getGroupName()); - unlockBatchRequest->setMqSet(mqs); - - try { - m_pClientFactory->getMQClientAPIImpl()->unlockBatchMQ(pFindBrokerResult->brokerAddr, unlockBatchRequest.get(), - 1000, m_pConsumer->getSessionCredentials()); - for (unsigned int i = 0; i != mqs.size(); ++i) { - boost::weak_ptr pullreq = getPullRequest(mqs[i]); - if (!pullreq.expired()) { - LOG_INFO("unlockBatchMQ success of mq:%s", mqs[i].toString().c_str()); - pullreq.lock()->setLocked(false); - } else { - LOG_ERROR("unlockBatchMQ fails of mq:%s", mqs[i].toString().c_str()); - } - } - } catch (MQException& e) { - LOG_ERROR("unlockBatchMQ fails"); - } - deleteAndZero(itb->second); - } - brokerMqs.clear(); -} - -void Rebalance::unlock(MQMessageQueue mq) { - unique_ptr pFindBrokerResult( - m_pClientFactory->findBrokerAddressInSubscribe(mq.getBrokerName(), MASTER_ID, true)); - if (!pFindBrokerResult) { - LOG_ERROR("unlock findBrokerAddressInSubscribe ret null for broker:%s", mq.getBrokerName().data()); - return; - } - unique_ptr unlockBatchRequest(new UnlockBatchRequestBody()); - vector mqs; - mqs.push_back(mq); - unlockBatchRequest->setClientId(m_pConsumer->getMQClientId()); - unlockBatchRequest->setConsumerGroup(m_pConsumer->getGroupName()); - unlockBatchRequest->setMqSet(mqs); - - try { - m_pClientFactory->getMQClientAPIImpl()->unlockBatchMQ(pFindBrokerResult->brokerAddr, unlockBatchRequest.get(), 1000, - m_pConsumer->getSessionCredentials()); - for (unsigned int i = 0; i != mqs.size(); ++i) { - boost::weak_ptr pullreq = getPullRequest(mqs[i]); - if (!pullreq.expired()) { - LOG_INFO("unlock success of mq:%s", mqs[i].toString().c_str()); - pullreq.lock()->setLocked(false); - } else { - LOG_ERROR("unlock fails of mq:%s", mqs[i].toString().c_str()); - } - } - } catch (MQException& e) { - LOG_ERROR("unlock fails of mq:%s", mq.toString().c_str()); - } -} - -void Rebalance::lockAll() { - map*> brokerMqs; - MQ2PULLREQ requestQueueTable = getPullRequestTable(); - for (MQ2PULLREQ::iterator it = requestQueueTable.begin(); it != requestQueueTable.end(); ++it) { - if (!(it->second->isDropped())) { - string brokerKey = it->first.getBrokerName() + it->first.getTopic(); - if (brokerMqs.find(brokerKey) == brokerMqs.end()) { - vector* mqs = new vector; - brokerMqs[brokerKey] = mqs; - brokerMqs[brokerKey]->push_back(it->first); - } else { - brokerMqs[brokerKey]->push_back(it->first); - } - } - } - LOG_INFO("LockAll " SIZET_FMT " broker mqs", brokerMqs.size()); - for (map*>::iterator itb = brokerMqs.begin(); itb != brokerMqs.end(); ++itb) { - string brokerName = (*(itb->second))[0].getBrokerName(); - unique_ptr pFindBrokerResult( - m_pClientFactory->findBrokerAddressInSubscribe(brokerName, MASTER_ID, true)); - if (!pFindBrokerResult) { - LOG_ERROR("lockAll findBrokerAddressInSubscribe ret null for broker:%s", brokerName.data()); - continue; - } - unique_ptr lockBatchRequest(new LockBatchRequestBody()); - lockBatchRequest->setClientId(m_pConsumer->getMQClientId()); - lockBatchRequest->setConsumerGroup(m_pConsumer->getGroupName()); - lockBatchRequest->setMqSet(*(itb->second)); - LOG_INFO("try to lock:" SIZET_FMT " mqs of broker:%s", itb->second->size(), itb->first.c_str()); - try { - vector messageQueues; - m_pClientFactory->getMQClientAPIImpl()->lockBatchMQ(pFindBrokerResult->brokerAddr, lockBatchRequest.get(), - messageQueues, 1000, m_pConsumer->getSessionCredentials()); - for (unsigned int i = 0; i != messageQueues.size(); ++i) { - boost::weak_ptr pullreq = getPullRequest(messageQueues[i]); - if (!pullreq.expired()) { - LOG_INFO("lockBatchMQ success of mq:%s", messageQueues[i].toString().c_str()); - pullreq.lock()->setLocked(true); - pullreq.lock()->setLastLockTimestamp(UtilAll::currentTimeMillis()); - } else { - LOG_ERROR("lockBatchMQ fails of mq:%s", messageQueues[i].toString().c_str()); - } - } - messageQueues.clear(); - } catch (MQException& e) { - LOG_ERROR("lockBatchMQ fails"); - } - deleteAndZero(itb->second); - } - brokerMqs.clear(); -} - -bool Rebalance::lock(MQMessageQueue mq) { - unique_ptr pFindBrokerResult( - m_pClientFactory->findBrokerAddressInSubscribe(mq.getBrokerName(), MASTER_ID, true)); - if (!pFindBrokerResult) { - LOG_ERROR("lock findBrokerAddressInSubscribe ret null for broker:%s", mq.getBrokerName().data()); - return false; - } - unique_ptr lockBatchRequest(new LockBatchRequestBody()); - lockBatchRequest->setClientId(m_pConsumer->getMQClientId()); - lockBatchRequest->setConsumerGroup(m_pConsumer->getGroupName()); - vector in_mqSet; - in_mqSet.push_back(mq); - lockBatchRequest->setMqSet(in_mqSet); - bool lockResult = false; - - try { - vector messageQueues; - LOG_DEBUG("try to lock mq:%s", mq.toString().c_str()); - m_pClientFactory->getMQClientAPIImpl()->lockBatchMQ(pFindBrokerResult->brokerAddr, lockBatchRequest.get(), - messageQueues, 1000, m_pConsumer->getSessionCredentials()); - if (messageQueues.size() == 0) { - LOG_ERROR("lock mq on broker:%s failed", pFindBrokerResult->brokerAddr.c_str()); - return false; - } - for (unsigned int i = 0; i != messageQueues.size(); ++i) { - boost::weak_ptr pullreq = getPullRequest(messageQueues[i]); - if (!pullreq.expired()) { - LOG_INFO("lock success of mq:%s", messageQueues[i].toString().c_str()); - pullreq.lock()->setLocked(true); - pullreq.lock()->setLastLockTimestamp(UtilAll::currentTimeMillis()); - lockResult = true; - } else { - LOG_ERROR("lock fails of mq:%s", messageQueues[i].toString().c_str()); - } - } - messageQueues.clear(); - return lockResult; - } catch (MQException& e) { - LOG_ERROR("lock fails of mq:%s", mq.toString().c_str()); - return false; - } -} - -//& mqsSelf) { - return false; -} - -int64 RebalancePull::computePullFromWhere(const MQMessageQueue& mq) { - return 0; -} - -void RebalancePull::messageQueueChanged(const string& topic, - vector& mqAll, - vector& mqDivided) {} - -void RebalancePull::removeUnnecessaryMessageQueue(const MQMessageQueue& mq) {} - -//& mqsSelf) { - LOG_DEBUG("updateRequestTableInRebalance for Topic[%s] Enter", topic.c_str()); - - // 1. Clear no in charge of - // 1. set dropped - // 2. clear local message - // 3. clear offset - // 4. remove request table - // 5. set flag for route changed - // 2. Check and clear dropped/invalid pullrequest(timeout and so on) - // 3. Add new mq in charge of - // 1. new pullrequest - // 2. init next pull offset - // 3. int offset - // 4. add request table - // 5. set flag for route changed - // 4. Start long pull for request - if (mqsSelf.empty()) { - LOG_WARN("allocated queue is empty for topic:%s", topic.c_str()); - } - - bool changed = false; - - //first; - if (mqtemp.getTopic().compare(topic) == 0) { - if (mqsSelf.empty() || (std::find(mqsSelf.begin(), mqsSelf.end(), mqtemp) == mqsSelf.end())) { - // if not response , set to dropped - LOG_INFO("Drop mq:%s,because not responsive", mqtemp.toString().c_str()); - itDel->second->setDropped(true); - // remove offset table to avoid offset backup - removeUnnecessaryMessageQueue(mqtemp); - itDel->second->clearAllMsgs(); - removePullRequest(mqtemp); - changed = true; - } else if (itDel->second->isPullRequestExpired()) { - // if pull expired , set to dropped, eg: if add pull task error, the pull request will be expired. - LOG_INFO("Drop mq:%s according Pull timeout.", mqtemp.toString().c_str()); - itDel->second->setDropped(true); - removeUnnecessaryMessageQueue(mqtemp); - itDel->second->clearAllMsgs(); - removePullRequest(mqtemp); - changed = true; - } - } - } - - //> pullRequestsToAdd; - vector::iterator itAdd = mqsSelf.begin(); - for (; itAdd != mqsSelf.end(); ++itAdd) { - if (isPullRequestExist(*itAdd)) { - // have check the expired pull request, re-add it. - continue; - } - boost::shared_ptr pullRequest = boost::make_shared(m_pConsumer->getGroupName()); - pullRequest->m_messageQueue = *itAdd; - int64 nextOffset = computePullFromWhere(*itAdd); - if (nextOffset >= 0) { - pullRequest->setNextOffset(nextOffset); - pullRequest->setDropped(false); - changed = true; - addPullRequest(*itAdd, pullRequest); - pullRequestsToAdd.push_back(pullRequest); - LOG_INFO("Add mq:%s, request initial offset:%ld", (*itAdd).toString().c_str(), nextOffset); - } else { - LOG_WARN( - "Failed to add pull request for %s due to failure of querying consume offset, request initial offset:%ld", - (*itAdd).toString().c_str(), nextOffset); - } - } - - for (vector>::iterator itAdded = pullRequestsToAdd.begin(); - itAdded != pullRequestsToAdd.end(); ++itAdded) { - LOG_INFO("Start to pull %s, offset:%ld, GroupName %s", (*itAdded)->m_messageQueue.toString().c_str(), - (*itAdded)->getNextOffset(), (*itAdded)->getGroupName().c_str()); - if (!m_pConsumer->producePullMsgTask(*itAdded)) { - LOG_WARN( - "Failed to producer pull message task for %s, Remove it from Request table and wait for next #Rebalance.", - (*itAdded)->m_messageQueue.toString().c_str()); - // remove from request table, and wait for next rebalance. - (*itAdded)->setDropped(true); - removePullRequest((*itAdded)->m_messageQueue); - } - } - - LOG_DEBUG("updateRequestTableInRebalance Topic[%s] exit", topic.c_str()); - return changed; -} - -int64 RebalancePush::computePullFromWhere(const MQMessageQueue& mq) { - int64 result = -1; - DefaultMQPushConsumerImpl* pConsumer = dynamic_cast(m_pConsumer); - if (!pConsumer) { - LOG_ERROR("Cast consumer pointer to DefaultMQPushConsumer pointer failed when computePullFromWhere %s", - mq.toString().c_str()); - return result; - } - ConsumeFromWhere consumeFromWhere = pConsumer->getConsumeFromWhere(); - OffsetStore* pOffsetStore = pConsumer->getOffsetStore(); - switch (consumeFromWhere) { - case CONSUME_FROM_LAST_OFFSET: { - int64 lastOffset = pOffsetStore->readOffset(mq, READ_FROM_STORE, m_pConsumer->getSessionCredentials()); - if (lastOffset >= 0) { - LOG_INFO("CONSUME_FROM_LAST_OFFSET, lastOffset of mq:%s is:%lld", mq.toString().c_str(), lastOffset); - result = lastOffset; - } else if (-1 == lastOffset) { - LOG_WARN("CONSUME_FROM_LAST_OFFSET, lastOffset of mq:%s is -1", mq.toString().c_str()); - if (UtilAll::startsWith_retry(mq.getTopic())) { - LOG_INFO("CONSUME_FROM_LAST_OFFSET, lastOffset of mq:%s is 0", mq.toString().c_str()); - result = 0; - } else { - try { - result = pConsumer->maxOffset(mq); - LOG_INFO("CONSUME_FROM_LAST_OFFSET, maxOffset of mq:%s is:%lld", mq.toString().c_str(), result); - } catch (MQException& e) { - LOG_ERROR("CONSUME_FROM_LAST_OFFSET error, lastOffset of mq:%s is -1", mq.toString().c_str()); - result = -1; - } - } - } else { - LOG_ERROR("CONSUME_FROM_LAST_OFFSET error, lastOffset of mq:%s is -1", mq.toString().c_str()); - result = -1; - } - break; - } - case CONSUME_FROM_FIRST_OFFSET: { - int64 lastOffset = pOffsetStore->readOffset(mq, READ_FROM_STORE, m_pConsumer->getSessionCredentials()); - if (lastOffset >= 0) { - LOG_INFO("CONSUME_FROM_FIRST_OFFSET, lastOffset of mq:%s is:%lld", mq.toString().c_str(), lastOffset); - result = lastOffset; - } else if (-1 == lastOffset) { - LOG_INFO("CONSUME_FROM_FIRST_OFFSET, lastOffset of mq:%s, return 0", mq.toString().c_str()); - result = 0; - } else { - LOG_ERROR("CONSUME_FROM_FIRST_OFFSET, lastOffset of mq:%s, return -1", mq.toString().c_str()); - result = -1; - } - break; - } - case CONSUME_FROM_TIMESTAMP: { - int64 lastOffset = pOffsetStore->readOffset(mq, READ_FROM_STORE, m_pConsumer->getSessionCredentials()); - if (lastOffset >= 0) { - LOG_INFO("CONSUME_FROM_TIMESTAMP, lastOffset of mq:%s is:%lld", mq.toString().c_str(), lastOffset); - result = lastOffset; - } else if (-1 == lastOffset) { - if (UtilAll::startsWith_retry(mq.getTopic())) { - try { - result = pConsumer->maxOffset(mq); - LOG_INFO("CONSUME_FROM_TIMESTAMP, maxOffset of mq:%s is:%lld", mq.toString().c_str(), result); - } catch (MQException& e) { - LOG_ERROR("CONSUME_FROM_TIMESTAMP error, lastOffset of mq:%s is -1", mq.toString().c_str()); - result = -1; - } - } else { - try { - } catch (MQException& e) { - LOG_ERROR("CONSUME_FROM_TIMESTAMP error, lastOffset of mq:%s, return 0", mq.toString().c_str()); - result = -1; - } - } - } else { - LOG_ERROR("CONSUME_FROM_TIMESTAMP error, lastOffset of mq:%s, return -1", mq.toString().c_str()); - result = -1; - } - break; - } - default: - break; - } - return result; -} - -void RebalancePush::messageQueueChanged(const string& topic, - vector& mqAll, - vector& mqDivided) {} - -void RebalancePush::removeUnnecessaryMessageQueue(const MQMessageQueue& mq) { - // DefaultMQPushConsumer *pConsumer = static_cast(m_pConsumer); - DefaultMQPushConsumerImpl* pConsumer = dynamic_cast(m_pConsumer); - if (!pConsumer) { - LOG_ERROR("Cast MQConsumer* to DefaultMQPushConsumer* failed when remove %s", mq.toString().c_str()); - return; - } - OffsetStore* pOffsetStore = pConsumer->getOffsetStore(); - - pOffsetStore->persist(mq, m_pConsumer->getSessionCredentials()); - pOffsetStore->removeOffset(mq); - if (pConsumer->getMessageListenerType() == messageListenerOrderly) { - unlock(mq); - } -} - -// -#include - -namespace rocketmq { -class MQClientFactory; - -//& mqAll, - vector& mqDivided) = 0; - - virtual void removeUnnecessaryMessageQueue(const MQMessageQueue& mq) = 0; - - virtual int64 computePullFromWhere(const MQMessageQueue& mq) = 0; - - virtual bool updateRequestTableInRebalance(const string& topic, vector& mqsSelf) = 0; - - public: - void doRebalance(); - - void persistConsumerOffset(); - - void persistConsumerOffsetByResetOffset(); - - //& getSubscriptionInner(); - - //& mqs); - - bool getTopicSubscribeInfo(const string& topic, vector& mqs); - - void addPullRequest(MQMessageQueue mq, boost::shared_ptr pPullRequest); - void removePullRequest(MQMessageQueue mq); - bool isPullRequestExist(MQMessageQueue mq); - boost::weak_ptr getPullRequest(MQMessageQueue mq); - - map> getPullRequestTable(); - - void lockAll(); - - bool lock(MQMessageQueue mq); - - void unlockAll(bool oneWay = false); - - void unlock(MQMessageQueue mq); - - protected: - map m_subscriptionData; - - boost::mutex m_topicSubscribeInfoTableMutex; - map> m_topicSubscribeInfoTable; - typedef map> MQ2PULLREQ; - MQ2PULLREQ m_requestQueueTable; - boost::mutex m_requestTableMutex; - - AllocateMQStrategy* m_pAllocateMQStrategy; - MQConsumer* m_pConsumer; - MQClientFactory* m_pClientFactory; -}; - -//& mqAll, - vector& mqDivided); - - virtual void removeUnnecessaryMessageQueue(const MQMessageQueue& mq); - - virtual int64 computePullFromWhere(const MQMessageQueue& mq); - - virtual bool updateRequestTableInRebalance(const string& topic, vector& mqsSelf); -}; - -//& mqAll, - vector& mqDivided); - - virtual void removeUnnecessaryMessageQueue(const MQMessageQueue& mq); - - virtual int64 computePullFromWhere(const MQMessageQueue& mq); - - virtual bool updateRequestTableInRebalance(const string& topic, vector& mqsSelf); -}; - -// -#include -#include -#include "Logging.h" -#include "UtilAll.h" -namespace rocketmq { -//& SubscriptionData::getTagsSet() { - return m_tagSet; -} - -bool SubscriptionData::operator==(const SubscriptionData& other) const { - if (!m_subString.compare(other.m_subString)) { - return false; - } - if (m_subVersion != other.m_subVersion) { - return false; - } - if (m_tagSet.size() != other.m_tagSet.size()) { - return false; - } - if (!m_topic.compare(other.m_topic)) { - return false; - } - return true; -} - -bool SubscriptionData::operator<(const SubscriptionData& other) const { - int ret = m_topic.compare(other.m_topic); - if (ret < 0) { - return true; - } else if (ret == 0) { - ret = m_subString.compare(other.m_subString); - if (ret < 0) { - return true; - } else { - return false; - } - } else { - return false; - } -} - -void SubscriptionData::putCodeSet(const string& tag) { - int value = atoi(tag.c_str()); - m_codeSet.push_back(value); -} - -Json::Value SubscriptionData::toJson() const { - Json::Value outJson; - outJson["subString"] = m_subString; - outJson["subVersion"] = UtilAll::to_string(m_subVersion); - outJson["topic"] = m_topic; - - { - vector::const_iterator it = m_tagSet.begin(); - for (; it != m_tagSet.end(); it++) { - outJson["tagsSet"].append(*it); - } - } - - { - vector::const_iterator it = m_codeSet.begin(); - for (; it != m_codeSet.end(); it++) { - outJson["codeSet"].append(*it); - } - } - return outJson; -} - -// -#include "UtilAll.h" -#include "json/json.h" - -namespace rocketmq { -//& getTagsSet(); - - void putCodeSet(const string& tag); - - bool operator==(const SubscriptionData& other) const; - bool operator<(const SubscriptionData& other) const; - - Json::Value toJson() const; - - private: - string m_topic; - string m_subString; - int64 m_subVersion; - vector m_tagSet; - vector m_codeSet; -}; -//setTopic(topic); - } - return (CMessage*)mqMessage; -} -int DestroyMessage(CMessage* msg) { - if (msg == NULL) { - return NULL_POINTER; - } - delete (MQMessage*)msg; - return OK; -} -int SetMessageTopic(CMessage* msg, const char* topic) { - if (msg == NULL) { - return NULL_POINTER; - } - ((MQMessage*)msg)->setTopic(topic); - return OK; -} -int SetMessageTags(CMessage* msg, const char* tags) { - if (msg == NULL) { - return NULL_POINTER; - } - ((MQMessage*)msg)->setTags(tags); - return OK; -} -int SetMessageKeys(CMessage* msg, const char* keys) { - if (msg == NULL) { - return NULL_POINTER; - } - ((MQMessage*)msg)->setKeys(keys); - return OK; -} - -/** - * DO NOT USE THIS FUNCTION, IT IS ERROR-PRONE. - */ -int SetMessageBody(CMessage* msg, const char* body) { - if (msg == NULL) { - return NULL_POINTER; - } - ((MQMessage*)msg)->setBody(body); - return OK; -} -int SetByteMessageBody(CMessage* msg, const char* body, int len) { - if (msg == NULL) { - return NULL_POINTER; - } - ((MQMessage*)msg)->setBody(body, len); - return OK; -} -int SetMessageProperty(CMessage* msg, const char* key, const char* value) { - if (msg == NULL) { - return NULL_POINTER; - } - ((MQMessage*)msg)->setProperty(key, value); - return OK; -} -int SetDelayTimeLevel(CMessage* msg, int level) { - if (msg == NULL) { - return NULL_POINTER; - } - ((MQMessage*)msg)->setDelayTimeLevel(level); - return OK; -} -const char* GetOriginMessageTopic(CMessage* msg) { - if (msg == NULL) { - return NULL; - } - return ((MQMessage*)msg)->getTopic().c_str(); -} -const char* GetOriginMessageTags(CMessage* msg) { - if (msg == NULL) { - return NULL; - } - return ((MQMessage*)msg)->getTags().c_str(); -} -const char* GetOriginMessageKeys(CMessage* msg) { - if (msg == NULL) { - return NULL; - } - return ((MQMessage*)msg)->getKeys().c_str(); -} -const char* GetOriginMessageBody(CMessage* msg) { - if (msg == NULL) { - return NULL; - } - return ((MQMessage*)msg)->getBody().c_str(); -} -int GetOriginMessageBodyLength(CMessage* msg) { - if (NULL == msg) { - return 0; - } - return reinterpret_cast(msg)->getBody().length(); -} -const char* GetOriginMessageProperty(CMessage* msg, const char* key) { - if (msg == NULL) { - return NULL; - } - return ((MQMessage*)msg)->getProperty(key).c_str(); -} -int GetOriginDelayTimeLevel(CMessage* msg) { - if (msg == NULL) { - return -1; - } - return ((MQMessage*)msg)->getDelayTimeLevel(); -} -#ifdef __cplusplus -}; -#endif diff --git a/src/extern/CMessageExt.cpp b/src/extern/CMessageExt.cpp deleted file mode 100644 index a85a27d12..000000000 --- a/src/extern/CMessageExt.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "CMessageExt.h" -#include "CCommon.h" -#include "MQMessageExt.h" - -#ifdef __cplusplus -extern "C" { -#endif -using namespace rocketmq; -const char* GetMessageTopic(CMessageExt* msg) { - if (msg == NULL) { - return NULL; - } - return ((MQMessageExt*)msg)->getTopic().c_str(); -} -const char* GetMessageTags(CMessageExt* msg) { - if (msg == NULL) { - return NULL; - } - return ((MQMessageExt*)msg)->getTags().c_str(); -} -const char* GetMessageKeys(CMessageExt* msg) { - if (msg == NULL) { - return NULL; - } - return ((MQMessageExt*)msg)->getKeys().c_str(); -} -const char* GetMessageBody(CMessageExt* msg) { - if (msg == NULL) { - return NULL; - } - return ((MQMessageExt*)msg)->getBody().c_str(); -} - -int GetMessageBodyLength(CMessageExt* msgExt) { - if (NULL == msgExt) { - return 0; - } - return reinterpret_cast(msgExt)->getBody().length(); -} - -const char* GetMessageProperty(CMessageExt* msg, const char* key) { - if (msg == NULL) { - return NULL; - } - return ((MQMessageExt*)msg)->getProperty(key).c_str(); -} -const char* GetMessageId(CMessageExt* msg) { - if (msg == NULL) { - return NULL; - } - return ((MQMessageExt*)msg)->getMsgId().c_str(); -} - -int GetMessageDelayTimeLevel(CMessageExt* msg) { - if (msg == NULL) { - return NULL_POINTER; - } - return ((MQMessageExt*)msg)->getDelayTimeLevel(); -} - -int GetMessageQueueId(CMessageExt* msg) { - if (msg == NULL) { - return NULL_POINTER; - } - return ((MQMessageExt*)msg)->getQueueId(); -} - -int GetMessageReconsumeTimes(CMessageExt* msg) { - if (msg == NULL) { - return NULL_POINTER; - } - return ((MQMessageExt*)msg)->getReconsumeTimes(); -} - -int GetMessageStoreSize(CMessageExt* msg) { - if (msg == NULL) { - return NULL_POINTER; - } - return ((MQMessageExt*)msg)->getStoreSize(); -} - -long long GetMessageBornTimestamp(CMessageExt* msg) { - if (msg == NULL) { - return NULL_POINTER; - } - return ((MQMessageExt*)msg)->getBornTimestamp(); -} - -long long GetMessageStoreTimestamp(CMessageExt* msg) { - if (msg == NULL) { - return NULL_POINTER; - } - return ((MQMessageExt*)msg)->getStoreTimestamp(); -} - -long long GetMessageQueueOffset(CMessageExt* msg) { - if (msg == NULL) { - return NULL_POINTER; - } - return ((MQMessageExt*)msg)->getQueueOffset(); -} - -long long GetMessageCommitLogOffset(CMessageExt* msg) { - if (msg == NULL) { - return NULL_POINTER; - } - return ((MQMessageExt*)msg)->getCommitLogOffset(); -} - -long long GetMessagePreparedTransactionOffset(CMessageExt* msg) { - if (msg == NULL) { - return NULL_POINTER; - } - return ((MQMessageExt*)msg)->getPreparedTransactionOffset(); -} - -const char* GetMessageStoreHost(CMessageExt* msg) { - if (msg == NULL) { - return NULL; - } - return ((MQMessageExt*) msg)->getStoreHostString().c_str(); -} - -const char* GetMessageBornHost(CMessageExt* msg) { - if (msg == NULL) { - return NULL; - } - return ((MQMessageExt*) msg)->getBornHostString().c_str(); -} -#ifdef __cplusplus -}; -#endif diff --git a/src/extern/CProducer.cpp b/src/extern/CProducer.cpp deleted file mode 100644 index 7b22cd1cd..000000000 --- a/src/extern/CProducer.cpp +++ /dev/null @@ -1,859 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "CProducer.h" -#include -#include -#include -#include -#include "AsyncCallback.h" -#include "CBatchMessage.h" -#include "CCommon.h" -#include "CMQException.h" -#include "CMessage.h" -#include "CSendResult.h" -#include "DefaultMQProducer.h" -#include "MQClient.h" -#include "MQClientErrorContainer.h" -#include "TransactionListener.h" -#include "TransactionMQProducer.h" -#include "TransactionSendResult.h" -#include "UtilAll.h" - -#ifdef __cplusplus -extern "C" { -#endif -using namespace rocketmq; -using namespace std; -class MyLocalTransactionExecuterInner { - public: - MyLocalTransactionExecuterInner(CLocalTransactionExecutorCallback executor, CMessage* msg, void* userData) - : m_ExcutorCallback(executor), message(msg), data(userData) {} - ~MyLocalTransactionExecuterInner() {} - CLocalTransactionExecutorCallback m_ExcutorCallback; - CMessage* message; - void* data; -}; -class LocalTransactionListenerInner : public TransactionListener { - public: - LocalTransactionListenerInner() {} - - LocalTransactionListenerInner(CProducer* producer, CLocalTransactionCheckerCallback pCallback, void* data) { - m_CheckerCallback = pCallback; - m_producer = producer; - m_data = data; - } - - ~LocalTransactionListenerInner() {} - - LocalTransactionState executeLocalTransaction(const MQMessage& message, void* arg) { - if (m_CheckerCallback == NULL) { - return LocalTransactionState::UNKNOWN; - } - (void)(message); - MyLocalTransactionExecuterInner* executerInner = (MyLocalTransactionExecuterInner*)arg; - CTransactionStatus status = - executerInner->m_ExcutorCallback(m_producer, executerInner->message, executerInner->data); - switch (status) { - case E_COMMIT_TRANSACTION: - return LocalTransactionState::COMMIT_MESSAGE; - - case E_ROLLBACK_TRANSACTION: - return LocalTransactionState::ROLLBACK_MESSAGE; - - default: - return LocalTransactionState::UNKNOWN; - } - } - - LocalTransactionState checkLocalTransaction(const MQMessageExt& msg) { - if (m_CheckerCallback == NULL) { - return LocalTransactionState::UNKNOWN; - } - CMessageExt* msgExt = (CMessageExt*)(&msg); - // CMessage *msg = (CMessage *) (&message); - CTransactionStatus status = m_CheckerCallback(m_producer, msgExt, m_data); - switch (status) { - case E_COMMIT_TRANSACTION: - return LocalTransactionState::COMMIT_MESSAGE; - - case E_ROLLBACK_TRANSACTION: - return LocalTransactionState::ROLLBACK_MESSAGE; - - default: - return LocalTransactionState::UNKNOWN; - } - } - - private: - CLocalTransactionCheckerCallback m_CheckerCallback; - CProducer* m_producer; - void* m_data; -}; - -class SelectMessageQueueInner : public MessageQueueSelector { - public: - MQMessageQueue select(const std::vector& mqs, const MQMessage& msg, void* arg) { - int index = 0; - std::string shardingKey = rocketmq::UtilAll::to_string((char*)arg); - - index = std::hash{}(shardingKey) % mqs.size(); - return mqs[index % mqs.size()]; - } -}; - -class SelectMessageQueue : public MessageQueueSelector { - public: - SelectMessageQueue(QueueSelectorCallback callback) { m_pCallback = callback; } - - MQMessageQueue select(const std::vector& mqs, const MQMessage& msg, void* arg) { - CMessage* message = (CMessage*)&msg; - // Get the index of sending MQMessageQueue through callback function. - int index = m_pCallback(mqs.size(), message, arg); - return mqs[index]; - } - - private: - QueueSelectorCallback m_pCallback; -}; -class COnSendCallback : public AutoDeleteSendCallBack { - public: - COnSendCallback(COnSendSuccessCallback cSendSuccessCallback, - COnSendExceptionCallback cSendExceptionCallback, - void* message, - void* userData) { - m_cSendSuccessCallback = cSendSuccessCallback; - m_cSendExceptionCallback = cSendExceptionCallback; - m_message = message; - m_userData = userData; - } - - virtual ~COnSendCallback() {} - - virtual void onSuccess(SendResult& sendResult) { - CSendResult result; - result.sendStatus = CSendStatus((int)sendResult.getSendStatus()); - result.offset = sendResult.getQueueOffset(); - strncpy(result.msgId, sendResult.getMsgId().c_str(), MAX_MESSAGE_ID_LENGTH - 1); - result.msgId[MAX_MESSAGE_ID_LENGTH - 1] = 0; - m_cSendSuccessCallback(result, (CMessage*)m_message, m_userData); - } - - virtual void onException(MQException& e) { - CMQException exception; - exception.error = e.GetError(); - exception.line = e.GetLine(); - strncpy(exception.msg, e.what(), MAX_EXEPTION_MSG_LENGTH - 1); - strncpy(exception.file, e.GetFile(), MAX_EXEPTION_FILE_LENGTH - 1); - m_cSendExceptionCallback(exception, (CMessage*)m_message, m_userData); - } - - private: - COnSendSuccessCallback m_cSendSuccessCallback; - COnSendExceptionCallback m_cSendExceptionCallback; - void* m_message; - void* m_userData; -}; - -class CSendCallback : public AutoDeleteSendCallBack { - public: - CSendCallback(CSendSuccessCallback cSendSuccessCallback, CSendExceptionCallback cSendExceptionCallback) { - m_cSendSuccessCallback = cSendSuccessCallback; - m_cSendExceptionCallback = cSendExceptionCallback; - } - - virtual ~CSendCallback() {} - - virtual void onSuccess(SendResult& sendResult) { - CSendResult result; - result.sendStatus = CSendStatus((int)sendResult.getSendStatus()); - result.offset = sendResult.getQueueOffset(); - strncpy(result.msgId, sendResult.getMsgId().c_str(), MAX_MESSAGE_ID_LENGTH - 1); - result.msgId[MAX_MESSAGE_ID_LENGTH - 1] = 0; - m_cSendSuccessCallback(result); - } - - virtual void onException(MQException& e) { - CMQException exception; - exception.error = e.GetError(); - exception.line = e.GetLine(); - strncpy(exception.msg, e.what(), MAX_EXEPTION_MSG_LENGTH - 1); - strncpy(exception.file, e.GetFile(), MAX_EXEPTION_FILE_LENGTH - 1); - m_cSendExceptionCallback(exception); - } - - private: - CSendSuccessCallback m_cSendSuccessCallback; - CSendExceptionCallback m_cSendExceptionCallback; -}; -#ifndef CAPI_C_PRODUCER_TYPE_COMMON -#define CAPI_C_PRODUCER_TYPE_COMMON 0 -#endif - -#ifndef CAPI_C_PRODUCER_TYPE_ORDERLY -#define CAPI_C_PRODUCER_TYPE_ORDERLY 1 -#endif - -#ifndef CAPI_C_PRODUCER_TYPE_TRANSACTION -#define CAPI_C_PRODUCER_TYPE_TRANSACTION 2 -#endif -typedef struct __DefaultProducer__ { - DefaultMQProducer* innerProducer; - TransactionMQProducer* innerTransactionProducer; - LocalTransactionListenerInner* listenerInner; - int producerType; - char* version; -} DefaultProducer; -CProducer* CreateProducer(const char* groupId) { - if (groupId == NULL) { - return NULL; - } - DefaultProducer* defaultMQProducer = new DefaultProducer(); - defaultMQProducer->producerType = CAPI_C_PRODUCER_TYPE_COMMON; - defaultMQProducer->innerProducer = new DefaultMQProducer(groupId); - defaultMQProducer->version = new char[MAX_SDK_VERSION_LENGTH]; - strncpy(defaultMQProducer->version, defaultMQProducer->innerProducer->version().c_str(), MAX_SDK_VERSION_LENGTH - 1); - defaultMQProducer->version[MAX_SDK_VERSION_LENGTH - 1] = 0; - defaultMQProducer->innerTransactionProducer = NULL; - defaultMQProducer->listenerInner = NULL; - return (CProducer*)defaultMQProducer; -} - -CProducer* CreateOrderlyProducer(const char* groupId) { - if (groupId == NULL) { - return NULL; - } - DefaultProducer* defaultMQProducer = new DefaultProducer(); - defaultMQProducer->producerType = CAPI_C_PRODUCER_TYPE_ORDERLY; - defaultMQProducer->innerProducer = new DefaultMQProducer(groupId); - - defaultMQProducer->version = new char[MAX_SDK_VERSION_LENGTH]; - strncpy(defaultMQProducer->version, defaultMQProducer->innerProducer->version().c_str(), MAX_SDK_VERSION_LENGTH - 1); - defaultMQProducer->version[MAX_SDK_VERSION_LENGTH - 1] = 0; - defaultMQProducer->innerTransactionProducer = NULL; - defaultMQProducer->listenerInner = NULL; - return (CProducer*)defaultMQProducer; -} - -CProducer* CreateTransactionProducer(const char* groupId, CLocalTransactionCheckerCallback callback, void* userData) { - if (groupId == NULL) { - return NULL; - } - DefaultProducer* defaultMQProducer = new DefaultProducer(); - defaultMQProducer->producerType = CAPI_C_PRODUCER_TYPE_TRANSACTION; - defaultMQProducer->innerProducer = NULL; - defaultMQProducer->innerTransactionProducer = new TransactionMQProducer(groupId); - defaultMQProducer->listenerInner = - new LocalTransactionListenerInner((CProducer*)defaultMQProducer, callback, userData); - defaultMQProducer->innerTransactionProducer->setTransactionListener(defaultMQProducer->listenerInner); - - defaultMQProducer->version = new char[MAX_SDK_VERSION_LENGTH]; - strncpy(defaultMQProducer->version, defaultMQProducer->innerTransactionProducer->version().c_str(), - MAX_SDK_VERSION_LENGTH - 1); - defaultMQProducer->version[MAX_SDK_VERSION_LENGTH - 1] = 0; - return (CProducer*)defaultMQProducer; -} -int DestroyProducer(CProducer* pProducer) { - if (pProducer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)pProducer; - if (defaultMQProducer->version != NULL) { - delete[] defaultMQProducer->version; - defaultMQProducer->version = NULL; - } - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - if (defaultMQProducer->innerTransactionProducer != NULL) { - delete defaultMQProducer->innerTransactionProducer; - defaultMQProducer->innerTransactionProducer = NULL; - } - } else { - if (defaultMQProducer->innerProducer != NULL) { - delete defaultMQProducer->innerProducer; - defaultMQProducer->innerProducer = NULL; - } - } - delete reinterpret_cast(pProducer); - return OK; -} -int StartProducer(CProducer* producer) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->start(); - } else { - defaultMQProducer->innerProducer->start(); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} -int ShutdownProducer(CProducer* producer) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->shutdown(); - } else { - defaultMQProducer->innerProducer->shutdown(); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} -const char* ShowProducerVersion(CProducer* producer) { - if (producer == NULL) { - return DEFAULT_SDK_VERSION; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - - return defaultMQProducer->version; -} -int SetProducerNameServerAddress(CProducer* producer, const char* namesrv) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->setNamesrvAddr(namesrv); - } else { - defaultMQProducer->innerProducer->setNamesrvAddr(namesrv); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} -int SetProducerNameServerDomain(CProducer* producer, const char* domain) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->setNamesrvDomain(domain); - } else { - defaultMQProducer->innerProducer->setNamesrvDomain(domain); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} -int SendMessageSync(CProducer* producer, CMessage* msg, CSendResult* result) { - // CSendResult sendResult; - if (producer == NULL || msg == NULL || result == NULL) { - return NULL_POINTER; - } - try { - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - MQMessage* message = (MQMessage*)msg; - SendResult sendResult = defaultMQProducer->innerProducer->send(*message); - switch (sendResult.getSendStatus()) { - case SEND_OK: - result->sendStatus = E_SEND_OK; - break; - case SEND_FLUSH_DISK_TIMEOUT: - result->sendStatus = E_SEND_FLUSH_DISK_TIMEOUT; - break; - case SEND_FLUSH_SLAVE_TIMEOUT: - result->sendStatus = E_SEND_FLUSH_SLAVE_TIMEOUT; - break; - case SEND_SLAVE_NOT_AVAILABLE: - result->sendStatus = E_SEND_SLAVE_NOT_AVAILABLE; - break; - default: - result->sendStatus = E_SEND_OK; - break; - } - result->offset = sendResult.getQueueOffset(); - strncpy(result->msgId, sendResult.getMsgId().c_str(), MAX_MESSAGE_ID_LENGTH - 1); - result->msgId[MAX_MESSAGE_ID_LENGTH - 1] = 0; - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_SEND_SYNC_FAILED; - } - return OK; -} - -int SendBatchMessage(CProducer* producer, CBatchMessage* batcMsg, CSendResult* result) { - // CSendResult sendResult; - if (producer == NULL || batcMsg == NULL || result == NULL) { - return NULL_POINTER; - } - try { - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - vector* message = (vector*)batcMsg; - SendResult sendResult = defaultMQProducer->innerProducer->send(*message); - switch (sendResult.getSendStatus()) { - case SEND_OK: - result->sendStatus = E_SEND_OK; - break; - case SEND_FLUSH_DISK_TIMEOUT: - result->sendStatus = E_SEND_FLUSH_DISK_TIMEOUT; - break; - case SEND_FLUSH_SLAVE_TIMEOUT: - result->sendStatus = E_SEND_FLUSH_SLAVE_TIMEOUT; - break; - case SEND_SLAVE_NOT_AVAILABLE: - result->sendStatus = E_SEND_SLAVE_NOT_AVAILABLE; - break; - default: - result->sendStatus = E_SEND_OK; - break; - } - result->offset = sendResult.getQueueOffset(); - strncpy(result->msgId, sendResult.getMsgId().c_str(), MAX_MESSAGE_ID_LENGTH - 1); - result->msgId[MAX_MESSAGE_ID_LENGTH - 1] = 0; - } catch (exception& e) { - return PRODUCER_SEND_SYNC_FAILED; - } - return OK; -} - -int SendMessageAsync(CProducer* producer, - CMessage* msg, - CSendSuccessCallback cSendSuccessCallback, - CSendExceptionCallback cSendExceptionCallback) { - if (producer == NULL || msg == NULL || cSendSuccessCallback == NULL || cSendExceptionCallback == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - MQMessage* message = (MQMessage*)msg; - CSendCallback* cSendCallback = new CSendCallback(cSendSuccessCallback, cSendExceptionCallback); - - try { - defaultMQProducer->innerProducer->send(*message, cSendCallback); - } catch (exception& e) { - if (cSendCallback != NULL) { - if (std::type_index(typeid(e)) == std::type_index(typeid(MQException))) { - MQException& mqe = (MQException&)e; - cSendCallback->onException(mqe); - } - delete cSendCallback; - cSendCallback = NULL; - } - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_SEND_ASYNC_FAILED; - } - return OK; -} - -int SendAsync(CProducer* producer, - CMessage* msg, - COnSendSuccessCallback onSuccess, - COnSendExceptionCallback onException, - void* usrData) { - if (producer == NULL || msg == NULL || onSuccess == NULL || onException == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - MQMessage* message = (MQMessage*)msg; - COnSendCallback* cSendCallback = new COnSendCallback(onSuccess, onException, (void*)msg, usrData); - - try { - defaultMQProducer->innerProducer->send(*message, cSendCallback); - } catch (exception& e) { - if (cSendCallback != NULL) { - if (std::type_index(typeid(e)) == std::type_index(typeid(MQException))) { - MQException& mqe = (MQException&)e; - cSendCallback->onException(mqe); - } - delete cSendCallback; - cSendCallback = NULL; - } - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_SEND_ASYNC_FAILED; - } - return OK; -} - -int SendMessageOneway(CProducer* producer, CMessage* msg) { - if (producer == NULL || msg == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - MQMessage* message = (MQMessage*)msg; - try { - defaultMQProducer->innerProducer->sendOneway(*message); - } catch (exception& e) { - return PRODUCER_SEND_ONEWAY_FAILED; - } - return OK; -} - -int SendMessageOnewayOrderly(CProducer* producer, CMessage* msg, QueueSelectorCallback selector, void* arg) { - if (producer == NULL || msg == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - MQMessage* message = (MQMessage*)msg; - try { - SelectMessageQueue selectMessageQueue(selector); - defaultMQProducer->innerProducer->sendOneway(*message, &selectMessageQueue, arg); - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_SEND_ONEWAY_FAILED; - } - return OK; -} - -int SendMessageOrderlyAsync(CProducer* producer, - CMessage* msg, - QueueSelectorCallback callback, - void* arg, - CSendSuccessCallback cSendSuccessCallback, - CSendExceptionCallback cSendExceptionCallback) { - if (producer == NULL || msg == NULL || callback == NULL || cSendSuccessCallback == NULL || - cSendExceptionCallback == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - MQMessage* message = (MQMessage*)msg; - CSendCallback* cSendCallback = new CSendCallback(cSendSuccessCallback, cSendExceptionCallback); - - try { - // Constructing SelectMessageQueue objects through function pointer callback - SelectMessageQueue selectMessageQueue(callback); - defaultMQProducer->innerProducer->send(*message, &selectMessageQueue, arg, cSendCallback); - } catch (exception& e) { - printf("%s\n", e.what()); - // std::count<innerProducer->send(*message, &selectMessageQueue, arg, autoRetryTimes); - // Convert SendStatus to CSendStatus - result->sendStatus = CSendStatus((int)sendResult.getSendStatus()); - result->offset = sendResult.getQueueOffset(); - strncpy(result->msgId, sendResult.getMsgId().c_str(), MAX_MESSAGE_ID_LENGTH - 1); - result->msgId[MAX_MESSAGE_ID_LENGTH - 1] = 0; - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_SEND_ORDERLY_FAILED; - } - return OK; -} -int SendMessageOrderlyByShardingKey(CProducer* producer, CMessage* msg, const char* shardingKey, CSendResult* result) { - if (producer == NULL || msg == NULL || shardingKey == NULL || result == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - MQMessage* message = (MQMessage*)msg; - - string sKey(shardingKey); - message->setProperty("__SHARDINGKEY", sKey); - try { - // Constructing SelectMessageQueue objects through function pointer callback - int retryTimes = 3; - SelectMessageQueueInner selectMessageQueue; - SendResult sendResult = - defaultMQProducer->innerProducer->send(*message, &selectMessageQueue, (void*)shardingKey, retryTimes); - // Convert SendStatus to CSendStatus - result->sendStatus = CSendStatus((int)sendResult.getSendStatus()); - result->offset = sendResult.getQueueOffset(); - strncpy(result->msgId, sendResult.getMsgId().c_str(), MAX_MESSAGE_ID_LENGTH - 1); - result->msgId[MAX_MESSAGE_ID_LENGTH - 1] = 0; - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_SEND_ORDERLY_FAILED; - } - return OK; -} - -int SendMessageTransaction(CProducer* producer, - CMessage* msg, - CLocalTransactionExecutorCallback callback, - void* userData, - CSendResult* result) { - if (producer == NULL || msg == NULL || callback == NULL || result == NULL) { - return NULL_POINTER; - } - try { - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - MQMessage* message = (MQMessage*)msg; - MyLocalTransactionExecuterInner executerInner(callback, msg, userData); - // defaultMQProducer->listenerInner->setM_m_ExcutorCallback(callback); - SendResult sendResult = - defaultMQProducer->innerTransactionProducer->sendMessageInTransaction(*message, &executerInner); - result->sendStatus = CSendStatus((int)sendResult.getSendStatus()); - result->offset = sendResult.getQueueOffset(); - strncpy(result->msgId, sendResult.getMsgId().c_str(), MAX_MESSAGE_ID_LENGTH - 1); - result->msgId[MAX_MESSAGE_ID_LENGTH - 1] = 0; - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_SEND_TRANSACTION_FAILED; - } - return OK; -} -int SetProducerGroupName(CProducer* producer, const char* groupName) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->setGroupName(groupName); - } else { - defaultMQProducer->innerProducer->setGroupName(groupName); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} -int SetProducerInstanceName(CProducer* producer, const char* instanceName) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->setInstanceName(instanceName); - } else { - defaultMQProducer->innerProducer->setInstanceName(instanceName); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} -int SetProducerSessionCredentials(CProducer* producer, - const char* accessKey, - const char* secretKey, - const char* onsChannel) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->setSessionCredentials(accessKey, secretKey, onsChannel); - } else { - defaultMQProducer->innerProducer->setSessionCredentials(accessKey, secretKey, onsChannel); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} -int SetProducerLogPath(CProducer* producer, const char* logPath) { - if (producer == NULL) { - return NULL_POINTER; - } - setenv(ROCKETMQ_CLIENT_LOG_DIR.c_str(), logPath, 1); - return OK; -} - -int SetProducerLogFileNumAndSize(CProducer* producer, int fileNum, long fileSize) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->setLogFileSizeAndNum(fileNum, fileSize); - } else { - defaultMQProducer->innerProducer->setLogFileSizeAndNum(fileNum, fileSize); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} - -int SetProducerLogLevel(CProducer* producer, CLogLevel level) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->setLogLevel((elogLevel)level); - } else { - defaultMQProducer->innerProducer->setLogLevel((elogLevel)level); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} - -int SetProducerSendMsgTimeout(CProducer* producer, int timeout) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->setSendMsgTimeout(timeout); - } else { - defaultMQProducer->innerProducer->setSendMsgTimeout(timeout); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} - -int SetProducerCompressMsgBodyOverHowmuch(CProducer* producer, int howmuch) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->setCompressMsgBodyOverHowmuch(howmuch); - } else { - defaultMQProducer->innerProducer->setCompressMsgBodyOverHowmuch(howmuch); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} - -int SetProducerCompressLevel(CProducer* producer, int level) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->setCompressLevel(level); - } else { - defaultMQProducer->innerProducer->setCompressLevel(level); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} - -int SetProducerMaxMessageSize(CProducer* producer, int size) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->setMaxMessageSize(size); - } else { - defaultMQProducer->innerProducer->setMaxMessageSize(size); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} -int SetProducerMessageTrace(CProducer* producer, CTraceModel openTrace) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - bool messageTrace = openTrace == OPEN ? true : false; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->setMessageTrace(messageTrace); - } else { - defaultMQProducer->innerProducer->setMessageTrace(messageTrace); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} - -int SetProducerSsl(CProducer* producer, int enableSsl) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - bool ssl = enableSsl != 0; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->setEnableSsl(ssl); - } else { - defaultMQProducer->innerProducer->setEnableSsl(ssl); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} - -int SetProducerSslPropertyFile(CProducer* producer, const char* sslPropertyFile) { - if (producer == NULL) { - return NULL_POINTER; - } - DefaultProducer* defaultMQProducer = (DefaultProducer*)producer; - try { - if (CAPI_C_PRODUCER_TYPE_TRANSACTION == defaultMQProducer->producerType) { - defaultMQProducer->innerTransactionProducer->setSslPropertyFile(sslPropertyFile); - } else { - defaultMQProducer->innerProducer->setSslPropertyFile(sslPropertyFile); - } - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PRODUCER_START_FAILED; - } - return OK; -} - -#ifdef __cplusplus -}; -#endif diff --git a/src/extern/CPullConsumer.cpp b/src/extern/CPullConsumer.cpp deleted file mode 100644 index 9ea26710e..000000000 --- a/src/extern/CPullConsumer.cpp +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "CPullConsumer.h" -#include "CCommon.h" -#include "CMessageExt.h" -#include "DefaultMQPullConsumer.h" -#include "MQClientErrorContainer.h" -#include "Logging.h" - -using namespace rocketmq; -using namespace std; - -#ifdef __cplusplus -extern "C" { -#endif -char VERSION_FOR_PULL_CONSUMER[MAX_SDK_VERSION_LENGTH]; -CPullConsumer* CreatePullConsumer(const char* groupId) { - if (groupId == NULL) { - return NULL; - } - DefaultMQPullConsumer* defaultMQPullConsumer = new DefaultMQPullConsumer(groupId); - strncpy(VERSION_FOR_PULL_CONSUMER, defaultMQPullConsumer->version().c_str(), MAX_SDK_VERSION_LENGTH - 1); - VERSION_FOR_PULL_CONSUMER[MAX_SDK_VERSION_LENGTH - 1] = 0; - return (CPullConsumer*)defaultMQPullConsumer; -} -int DestroyPullConsumer(CPullConsumer* consumer) { - if (consumer == NULL) { - return NULL_POINTER; - } - delete reinterpret_cast(consumer); - return OK; -} -int StartPullConsumer(CPullConsumer* consumer) { - if (consumer == NULL) { - return NULL_POINTER; - } - try { - ((DefaultMQPullConsumer*)consumer)->start(); - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PULLCONSUMER_START_FAILED; - } - return OK; -} -int ShutdownPullConsumer(CPullConsumer* consumer) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPullConsumer*)consumer)->shutdown(); - return OK; -} -const char* ShowPullConsumerVersion(CPullConsumer* consumer) { - if (consumer == NULL) { - return NULL; - } - return VERSION_FOR_PULL_CONSUMER; -} - -int SetPullConsumerGroupID(CPullConsumer* consumer, const char* groupId) { - if (consumer == NULL || groupId == NULL) { - return NULL_POINTER; - } - ((DefaultMQPullConsumer*)consumer)->setGroupName(groupId); - return OK; -} -const char* GetPullConsumerGroupID(CPullConsumer* consumer) { - if (consumer == NULL) { - return NULL; - } - return ((DefaultMQPullConsumer*)consumer)->getGroupName().c_str(); -} -int SetPullConsumerNameServerAddress(CPullConsumer* consumer, const char* namesrv) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPullConsumer*)consumer)->setNamesrvAddr(namesrv); - return OK; -} -int SetPullConsumerNameServerDomain(CPullConsumer* consumer, const char* domain) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPullConsumer*)consumer)->setNamesrvDomain(domain); - return OK; -} -int SetPullConsumerSessionCredentials(CPullConsumer* consumer, - const char* accessKey, - const char* secretKey, - const char* channel) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPullConsumer*)consumer)->setSessionCredentials(accessKey, secretKey, channel); - return OK; -} - -int SetPullConsumerLogPath(CPullConsumer* consumer, const char* logPath) { - if (consumer == NULL) { - return NULL_POINTER; - } - // Todo, This api should be implemented by core api. - //((DefaultMQPullConsumer *) consumer)->setInstanceName(instanceName); - setenv(ROCKETMQ_CLIENT_LOG_DIR.c_str(), logPath, 1); - return OK; -} - -int SetPullConsumerLogFileNumAndSize(CPullConsumer* consumer, int fileNum, long fileSize) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPullConsumer*)consumer)->setLogFileSizeAndNum(fileNum, fileSize); - return OK; -} - -int SetPullConsumerLogLevel(CPullConsumer* consumer, CLogLevel level) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPullConsumer*)consumer)->setLogLevel((elogLevel)level); - return OK; -} - -int SetPullConsumerSsl(CPullConsumer* consumer, int enableSsl) { - if (consumer == NULL) { - return NULL_POINTER; - } - bool ssl = enableSsl != 0; - ((DefaultMQPullConsumer*)consumer)->setEnableSsl(ssl); - return OK; -} - -int SetPullConsumerSslPropertyFile(CPullConsumer* consumer, const char* sslPropertyFile) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPullConsumer*)consumer)->setSslPropertyFile(sslPropertyFile); - return OK; -} - -int FetchSubscriptionMessageQueues(CPullConsumer* consumer, const char* topic, CMessageQueue** mqs, int* size) { - if (consumer == NULL) { - return NULL_POINTER; - } - unsigned int index = 0; - CMessageQueue* temMQ = NULL; - std::vector fullMQ; - try { - ((DefaultMQPullConsumer*)consumer)->fetchSubscribeMessageQueues(topic, fullMQ); - *size = fullMQ.size(); - // Alloc memory to save the pointer to CPP MessageQueue, and the MessageQueues may be changed. - // Thus, this memory should be released by users using @ReleaseSubscribeMessageQueue every time. - temMQ = (CMessageQueue*)malloc(*size * sizeof(CMessageQueue)); - if (temMQ == NULL) { - *size = 0; - *mqs = NULL; - return MALLOC_FAILED; - } - auto iter = fullMQ.begin(); - for (index = 0; iter != fullMQ.end() && index <= fullMQ.size(); ++iter, index++) { - strncpy(temMQ[index].topic, iter->getTopic().c_str(), MAX_TOPIC_LENGTH - 1); - strncpy(temMQ[index].brokerName, iter->getBrokerName().c_str(), MAX_BROKER_NAME_ID_LENGTH - 1); - temMQ[index].queueId = iter->getQueueId(); - } - *mqs = temMQ; - } catch (MQException& e) { - *size = 0; - *mqs = NULL; - MQClientErrorContainer::setErr(string(e.what())); - return PULLCONSUMER_FETCH_MQ_FAILED; - } - return OK; -} -int ReleaseSubscriptionMessageQueue(CMessageQueue* mqs) { - if (mqs == NULL) { - return NULL_POINTER; - } - free((void*)mqs); - mqs = NULL; - return OK; -} -CPullResult Pull(CPullConsumer* consumer, - const CMessageQueue* mq, - const char* subExpression, - long long offset, - int maxNums) { - CPullResult pullResult; - memset(&pullResult, 0, sizeof(CPullResult)); - if (consumer == NULL || subExpression == NULL) { - pullResult.pullStatus = E_BROKER_TIMEOUT; - return pullResult; - } - MQMessageQueue messageQueue(mq->topic, mq->brokerName, mq->queueId); - PullResult cppPullResult; - try { - cppPullResult = ((DefaultMQPullConsumer*)consumer)->pull(messageQueue, subExpression, offset, maxNums); - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - cppPullResult.pullStatus = BROKER_TIMEOUT; - } - - if (cppPullResult.pullStatus != BROKER_TIMEOUT) { - pullResult.maxOffset = cppPullResult.maxOffset; - pullResult.minOffset = cppPullResult.minOffset; - pullResult.nextBeginOffset = cppPullResult.nextBeginOffset; - } - - switch (cppPullResult.pullStatus) { - case FOUND: { - pullResult.pullStatus = E_FOUND; - pullResult.size = cppPullResult.msgFoundList.size(); - PullResult* tmpPullResult = new PullResult(cppPullResult); - pullResult.pData = tmpPullResult; - // Alloc memory to save the pointer to CPP MQMessageExt, which will be release by the CPP SDK core. - // Thus, this memory should be released by users using @ReleasePullResult - pullResult.msgFoundList = (CMessageExt**)malloc(pullResult.size * sizeof(CMessageExt*)); - for (size_t i = 0; i < cppPullResult.msgFoundList.size(); i++) { - MQMessageExt* msg = const_cast(&tmpPullResult->msgFoundList[i]); - pullResult.msgFoundList[i] = (CMessageExt*)(msg); - } - break; - } - case NO_NEW_MSG: { - pullResult.pullStatus = E_NO_NEW_MSG; - break; - } - case NO_MATCHED_MSG: { - pullResult.pullStatus = E_NO_MATCHED_MSG; - break; - } - case OFFSET_ILLEGAL: { - pullResult.pullStatus = E_OFFSET_ILLEGAL; - break; - } - case BROKER_TIMEOUT: { - pullResult.pullStatus = E_BROKER_TIMEOUT; - break; - } - default: - pullResult.pullStatus = E_NO_NEW_MSG; - break; - } - return pullResult; -} -int ReleasePullResult(CPullResult pullResult) { - if (pullResult.size == 0 || pullResult.msgFoundList == NULL || pullResult.pData == NULL) { - return NULL_POINTER; - } - if (pullResult.pData != NULL) { - try { - delete ((PullResult*)pullResult.pData); - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return NULL_POINTER; - } - } - free((void*)pullResult.msgFoundList); - pullResult.msgFoundList = NULL; - return OK; -} - -#ifdef __cplusplus -}; -#endif diff --git a/src/extern/CPushConsumer.cpp b/src/extern/CPushConsumer.cpp deleted file mode 100644 index 431a5671b..000000000 --- a/src/extern/CPushConsumer.cpp +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "CPushConsumer.h" -#include -#include "CCommon.h" -#include "CMessageExt.h" -#include "DefaultMQPushConsumer.h" -#include "MQClientErrorContainer.h" -#include "Logging.h" - -using namespace rocketmq; -using namespace std; - -class MessageListenerInner : public MessageListenerConcurrently { - public: - MessageListenerInner() {} - - MessageListenerInner(CPushConsumer* consumer, MessageCallBack pCallback) { - m_pconsumer = consumer; - m_pMsgReceiveCallback = pCallback; - } - - ~MessageListenerInner() {} - - ConsumeStatus consumeMessage(const std::vector& msgs) { - // to do user call back - if (m_pMsgReceiveCallback == NULL) { - return RECONSUME_LATER; - } - for (size_t i = 0; i < msgs.size(); ++i) { - MQMessageExt* msg = const_cast(&msgs[i]); - CMessageExt* message = (CMessageExt*)(msg); - if (m_pMsgReceiveCallback(m_pconsumer, message) != E_CONSUME_SUCCESS) - return RECONSUME_LATER; - } - return CONSUME_SUCCESS; - } - - private: - MessageCallBack m_pMsgReceiveCallback; - CPushConsumer* m_pconsumer; -}; - -class MessageListenerOrderlyInner : public MessageListenerOrderly { - public: - MessageListenerOrderlyInner(CPushConsumer* consumer, MessageCallBack pCallback) { - m_pconsumer = consumer; - m_pMsgReceiveCallback = pCallback; - } - - ConsumeStatus consumeMessage(const std::vector& msgs) { - if (m_pMsgReceiveCallback == NULL) { - return RECONSUME_LATER; - } - for (size_t i = 0; i < msgs.size(); ++i) { - MQMessageExt* msg = const_cast(&msgs[i]); - CMessageExt* message = (CMessageExt*)(msg); - if (m_pMsgReceiveCallback(m_pconsumer, message) != E_CONSUME_SUCCESS) - return RECONSUME_LATER; - } - return CONSUME_SUCCESS; - } - - private: - MessageCallBack m_pMsgReceiveCallback; - CPushConsumer* m_pconsumer; -}; - -map g_ListenerMap; -map g_OrderListenerMap; -#ifdef __cplusplus -extern "C" { -#endif -char VERSION_FOR_PUSH_CONSUMER[MAX_SDK_VERSION_LENGTH]; -CPushConsumer* CreatePushConsumer(const char* groupId) { - if (groupId == NULL) { - return NULL; - } - DefaultMQPushConsumer* defaultMQPushConsumer = new DefaultMQPushConsumer(groupId); - defaultMQPushConsumer->setConsumeFromWhere(CONSUME_FROM_LAST_OFFSET); - - strncpy(VERSION_FOR_PUSH_CONSUMER, defaultMQPushConsumer->version().c_str(), MAX_SDK_VERSION_LENGTH - 1); - VERSION_FOR_PUSH_CONSUMER[MAX_SDK_VERSION_LENGTH - 1] = 0; - return (CPushConsumer*)defaultMQPushConsumer; -} -int DestroyPushConsumer(CPushConsumer* consumer) { - if (consumer == NULL) { - return NULL_POINTER; - } - delete reinterpret_cast(consumer); - return OK; -} -int StartPushConsumer(CPushConsumer* consumer) { - if (consumer == NULL) { - return NULL_POINTER; - } - try { - ((DefaultMQPushConsumer*)consumer)->start(); - } catch (exception& e) { - MQClientErrorContainer::setErr(string(e.what())); - return PUSHCONSUMER_START_FAILED; - } - return OK; -} -int ShutdownPushConsumer(CPushConsumer* consumer) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPushConsumer*)consumer)->shutdown(); - return OK; -} - -const char* ShowPushConsumerVersion(CPushConsumer* consumer) { - if (consumer == NULL) { - return NULL; - } - return VERSION_FOR_PUSH_CONSUMER; -} -int SetPushConsumerGroupID(CPushConsumer* consumer, const char* groupId) { - if (consumer == NULL || groupId == NULL) { - return NULL_POINTER; - } - ((DefaultMQPushConsumer*)consumer)->setGroupName(groupId); - return OK; -} -const char* GetPushConsumerGroupID(CPushConsumer* consumer) { - if (consumer == NULL) { - return NULL; - } - return ((DefaultMQPushConsumer*)consumer)->getGroupName().c_str(); -} -int SetPushConsumerNameServerAddress(CPushConsumer* consumer, const char* namesrv) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPushConsumer*)consumer)->setNamesrvAddr(namesrv); - return OK; -} -int SetPushConsumerNameServerDomain(CPushConsumer* consumer, const char* domain) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPushConsumer*)consumer)->setNamesrvDomain(domain); - return OK; -} -int Subscribe(CPushConsumer* consumer, const char* topic, const char* expression) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPushConsumer*)consumer)->subscribe(topic, expression); - return OK; -} - -int RegisterMessageCallback(CPushConsumer* consumer, MessageCallBack pCallback) { - if (consumer == NULL || pCallback == NULL) { - return NULL_POINTER; - } - MessageListenerInner* listenerInner = new MessageListenerInner(consumer, pCallback); - ((DefaultMQPushConsumer*)consumer)->registerMessageListener(listenerInner); - g_ListenerMap[consumer] = listenerInner; - return OK; -} - -int RegisterMessageCallbackOrderly(CPushConsumer* consumer, MessageCallBack pCallback) { - if (consumer == NULL || pCallback == NULL) { - return NULL_POINTER; - } - MessageListenerOrderlyInner* messageListenerOrderlyInner = new MessageListenerOrderlyInner(consumer, pCallback); - ((DefaultMQPushConsumer*)consumer)->registerMessageListener(messageListenerOrderlyInner); - g_OrderListenerMap[consumer] = messageListenerOrderlyInner; - return OK; -} - -int UnregisterMessageCallbackOrderly(CPushConsumer* consumer) { - if (consumer == NULL) { - return NULL_POINTER; - } - map::iterator iter; - iter = g_OrderListenerMap.find(consumer); - if (iter != g_OrderListenerMap.end()) { - MessageListenerOrderlyInner* listenerInner = iter->second; - if (listenerInner != NULL) { - delete listenerInner; - } - g_OrderListenerMap.erase(iter); - } - return OK; -} - -int UnregisterMessageCallback(CPushConsumer* consumer) { - if (consumer == NULL) { - return NULL_POINTER; - } - map::iterator iter; - iter = g_ListenerMap.find(consumer); - - if (iter != g_ListenerMap.end()) { - MessageListenerInner* listenerInner = iter->second; - if (listenerInner != NULL) { - delete listenerInner; - } - g_ListenerMap.erase(iter); - } - return OK; -} - -int SetPushConsumerMessageModel(CPushConsumer* consumer, CMessageModel messageModel) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPushConsumer*)consumer)->setMessageModel(MessageModel((int)messageModel)); - return OK; -} -int SetPushConsumerThreadCount(CPushConsumer* consumer, int threadCount) { - if (consumer == NULL || threadCount == 0) { - return NULL_POINTER; - } - ((DefaultMQPushConsumer*)consumer)->setConsumeThreadCount(threadCount); - return OK; -} -int SetPushConsumerMessageBatchMaxSize(CPushConsumer* consumer, int batchSize) { - if (consumer == NULL || batchSize == 0) { - return NULL_POINTER; - } - ((DefaultMQPushConsumer*)consumer)->setConsumeMessageBatchMaxSize(batchSize); - return OK; -} -int SetPushConsumerMaxCacheMessageSize(CPushConsumer* consumer, int maxCacheSize) { - if (consumer == NULL || maxCacheSize <= 0) { - return NULL_POINTER; - } - ((DefaultMQPushConsumer*)consumer)->setMaxCacheMsgSizePerQueue(maxCacheSize); - return OK; -} - -int SetPushConsumerMaxCacheMessageSizeInMb(CPushConsumer* consumer, int maxCacheSizeInMb) { - if (consumer == NULL || maxCacheSizeInMb <= 0) { - return NULL_POINTER; - } - return Not_Support; -} -int SetPushConsumerInstanceName(CPushConsumer* consumer, const char* instanceName) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPushConsumer*)consumer)->setInstanceName(instanceName); - return OK; -} - -int SetPushConsumerSessionCredentials(CPushConsumer* consumer, - const char* accessKey, - const char* secretKey, - const char* channel) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPushConsumer*)consumer)->setSessionCredentials(accessKey, secretKey, channel); - return OK; -} - -int SetPushConsumerLogPath(CPushConsumer* consumer, const char* logPath) { - if (consumer == NULL) { - return NULL_POINTER; - } - // Todo, This api should be implemented by core api. - //((DefaultMQPushConsumer *) consumer)->setInstanceName(instanceName); - setenv(ROCKETMQ_CLIENT_LOG_DIR.c_str(), logPath, 1); - return OK; -} - -int SetPushConsumerLogFileNumAndSize(CPushConsumer* consumer, int fileNum, long fileSize) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPushConsumer*)consumer)->setLogFileSizeAndNum(fileNum, fileSize); - return OK; -} - -int SetPushConsumerLogLevel(CPushConsumer* consumer, CLogLevel level) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPushConsumer*)consumer)->setLogLevel((elogLevel)level); - return OK; -} -int SetPushConsumerMessageTrace(CPushConsumer* consumer, CTraceModel openTrace) { - if (consumer == NULL) { - return NULL_POINTER; - } - bool messageTrace = openTrace == OPEN ? true : false; - ((DefaultMQPushConsumer*)consumer)->setMessageTrace(messageTrace); - return OK; -} - -int SetPushConsumerSsl(CPushConsumer* consumer, int enableSsl) { - if (consumer == NULL) { - return NULL_POINTER; - } - bool ssl = enableSsl != 0; - ((DefaultMQPushConsumer*)consumer)->setEnableSsl(ssl); - return OK; -} - -int SetPushConsumerSslPropertyFile(CPushConsumer* consumer, const char* sslPropertyFile) { - if (consumer == NULL) { - return NULL_POINTER; - } - ((DefaultMQPushConsumer*)consumer)->setSslPropertyFile(sslPropertyFile); - return OK; -} - -#ifdef __cplusplus -}; -#endif diff --git a/src/include/DefaultMQClient.h b/src/include/DefaultMQClient.h deleted file mode 100644 index 10399c517..000000000 --- a/src/include/DefaultMQClient.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __DEFAULTMQADMIN_H__ -#define __DEFAULTMQADMIN_H__ -#include -#include -#include -#include -#include -#include -#include "MQClient.h" -#include "MQMessageExt.h" -#include "MQMessageQueue.h" -#include "QueryResult.h" -#include "RocketMQClient.h" -#include "SessionCredentials.h" -#include "UtilAll.h" - -namespace rocketmq { -class MQClientFactory; -// getTopicMessageQueueInfo(const std::string& topic); - - // log configuration interface, default LOG_LEVEL is LOG_LEVEL_INFO, default - // log file num is 3, each log size is 100M - void setLogLevel(elogLevel inputLevel); - elogLevel getLogLevel(); - void setLogFileSizeAndNum(int fileNum, long perFileSize); // perFileSize is MB unit - - /** set TcpTransport pull thread num, which dermine the num of threads to - distribute network data, - 1. its default value is CPU num, it must be setted before producer/consumer - start, minimum value is CPU num; - 2. this pullThread num must be tested on your environment to find the best - value for RT of sendMsg or delay time of consume msg before you change it; - 3. producer and consumer need different pullThread num, if set this num, - producer and consumer must set different instanceName. - 4. configuration suggestion: - 1>. minimum RT of sendMsg: - pullThreadNum = brokerNum*2 - **/ - void setTcpTransportPullThreadNum(int num); - int getTcpTransportPullThreadNum() const; - - /** timeout of tcp connect, it is same meaning for both producer and consumer; - 1. default value is 3000ms - 2. input parameter could only be milliSecond, suggestion value is - 1000-3000ms; - **/ - void setTcpTransportConnectTimeout(uint64_t timeout); // ms - uint64_t getTcpTransportConnectTimeout() const; - - /** timeout of tryLock tcpTransport before sendMsg/pullMsg, if timeout, - returns NULL - 1. paremeter unit is ms, default value is 3000ms, the minimun value is - 1000ms - suggestion value is 3000ms; - 2. if configured with value smaller than 1000ms, the tryLockTimeout value - will be setted to 1000ms - **/ - void setTcpTransportTryLockTimeout(uint64_t timeout); // ms - uint64_t getTcpTransportTryLockTimeout() const; - - void setUnitName(const std::string& unitName); - const std::string& getUnitName() const; - - void setSessionCredentials(const std::string& input_accessKey, - const std::string& input_secretKey, - const std::string& input_onsChannel); - const SessionCredentials& getSessionCredentials() const; - - virtual void setFactory(MQClientFactory*); - - void setEnableSsl(bool enableSsl); - bool getEnableSsl() const; - - void setSslPropertyFile(const std::string& sslPropertyFile); - const std::string& getSslPropertyFile() const; - bool getMessageTrace() const; - void setMessageTrace(bool mMessageTrace); - - protected: - virtual void start(); - virtual void shutdown(); - MQClientFactory* getFactory() const; - virtual bool isServiceStateOk(); - void showClientConfigs(); - - protected: - std::string m_namesrvAddr; - std::string m_namesrvDomain; - std::string m_instanceName; - std::string m_nameSpace; - std::string m_GroupName; - std::string m_sslPropertyFile{DEFAULT_SSL_PROPERTY_FILE}; - bool m_enableSsl{false}; - MQClientFactory* m_clientFactory; - int m_serviceState; - int m_pullThreadNum; - uint64_t m_tcpConnectTimeout; // ms - uint64_t m_tcpTransportTryLockTimeout; // s - - std::string m_unitName; - SessionCredentials m_SessionCredentials; - bool m_messageTrace; -}; -// -#include "AsyncCallback.h" -#include "ConsumeType.h" -#include "DefaultMQClient.h" -#include "RocketMQClient.h" - -namespace rocketmq { -class SubscriptionData; -class PullRequest; -class Rebalance; -class ConsumerRunningInfo; -//& mqs) = 0; - virtual void doRebalance() = 0; - virtual void persistConsumerOffset() = 0; - virtual void persistConsumerOffsetByResetOffset() = 0; - virtual void updateTopicSubscribeInfo(const std::string& topic, std::vector& info) = 0; - virtual void updateConsumeOffset(const MQMessageQueue& mq, int64 offset) = 0; - virtual void removeConsumeOffset(const MQMessageQueue& mq) = 0; - virtual ConsumeType getConsumeType() = 0; - virtual ConsumeFromWhere getConsumeFromWhere() = 0; - virtual void getSubscriptions(std::vector&) = 0; - virtual bool producePullMsgTask(boost::weak_ptr) = 0; - virtual Rebalance* getRebalance() const = 0; - virtual PullResult pull(const MQMessageQueue& mq, const std::string& subExpression, int64 offset, int maxNums) = 0; - virtual void pull(const MQMessageQueue& mq, - const std::string& subExpression, - int64 offset, - int maxNums, - PullCallback* pPullCallback) = 0; - virtual ConsumerRunningInfo* getConsumerRunningInfo() = 0; - - public: - MessageModel getMessageModel() const { return m_messageModel; } - void setMessageModel(MessageModel messageModel) { m_messageModel = messageModel; } - bool isUseNameSpaceMode() const { return m_useNameSpaceMode; } - - protected: - MessageModel m_messageModel; - bool m_useNameSpaceMode = false; -}; - -//& msgs) = 0; - virtual SendResult send(std::vector& msgs, const MQMessageQueue& mq) = 0; - virtual void sendOneway(MQMessage& msg, bool bSelectActiveBroker = false) = 0; - virtual void sendOneway(MQMessage& msg, const MQMessageQueue& mq) = 0; - virtual void sendOneway(MQMessage& msg, MessageQueueSelector* selector, void* arg) = 0; -}; -//& messageList) { - m_indexLastUpdateTimestamp = indexLastUpdateTimestamp; - m_messageList = messageList; - } - - uint64 getIndexLastUpdateTimestamp() { return m_indexLastUpdateTimestamp; } - - std::vector& getMessageList() { return m_messageList; } - - private: - uint64 m_indexLastUpdateTimestamp; - std::vector m_messageList; -}; -// -#include "UtilAll.h" -#define BOOST_DATE_TIME_SOURCE - -namespace rocketmq { -logAdapter* logAdapter::alogInstance; -boost::mutex logAdapter::m_imtx; - -logAdapter::~logAdapter() { - logging::core::get()->remove_all_sinks(); -} - -logAdapter* logAdapter::getLogInstance() { - if (alogInstance == NULL) { - boost::mutex::scoped_lock guard(m_imtx); - if (alogInstance == NULL) { - alogInstance = new logAdapter(); - } - } - return alogInstance; -} - -logAdapter::logAdapter() : m_logLevel(eLOG_LEVEL_INFO) { - setLogDir(); - string homeDir(UtilAll::getHomeDirectory()); - homeDir.append(m_log_dir); - m_logFile += homeDir; - std::string fileName = "rocketmq_client.log"; - m_logFile += fileName; - - // boost::log::expressions::attr< - // boost::log::attributes::current_thread_id::value_type>("ThreadID"); - boost::log::register_simple_formatter_factory("Severity"); - m_logSink = logging::add_file_log(keywords::file_name = m_logFile, - keywords::target_file_name = "rocketmq_client_%Y%m%d-%N.log", - keywords::rotation_size = 100 * 1024 * 1024, - keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0), - keywords::format = "[%TimeStamp%](%Severity%):%Message%", - keywords::min_free_space = 300 * 1024 * 1024, keywords::target = homeDir, - keywords::max_size = 200 * 1024 * 1024, // max keep 3 log file defaultly - keywords::auto_flush = true); - // logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::info); - setLogLevelInner(m_logLevel); - - logging::add_common_attributes(); -} - -void logAdapter::setLogLevelInner(elogLevel logLevel) { - switch (logLevel) { - case eLOG_LEVEL_FATAL: - logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::fatal); - break; - case eLOG_LEVEL_ERROR: - logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::error); - - break; - case eLOG_LEVEL_WARN: - logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::warning); - - break; - case eLOG_LEVEL_INFO: - logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::info); - - break; - case eLOG_LEVEL_DEBUG: - logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::debug); - - break; - case eLOG_LEVEL_TRACE: - logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::trace); - - break; - default: - logging::core::get()->set_filter(logging::trivial::severity >= logging::trivial::info); - - break; - } -} -void logAdapter::setLogLevel(elogLevel logLevel) { - m_logLevel = logLevel; - setLogLevelInner(logLevel); -} - -elogLevel logAdapter::getLogLevel() { - return m_logLevel; -} - -void logAdapter::setLogDir() { - char* p = nullptr; - if ((p = getenv(ROCKETMQ_CLIENT_LOG_DIR.c_str()))) { - m_log_dir = p; - } - if (!m_log_dir.empty()) { - if (m_log_dir[m_log_dir.length() - 1] != '/') { - m_log_dir += '/'; - } - } else { - m_log_dir = "/logs/rocketmq-client/"; - } -} - -void logAdapter::setLogFileNumAndSize(int logNum, int sizeOfPerFile) { - string homeDir(UtilAll::getHomeDirectory()); - homeDir.append(m_log_dir); - m_logSink->locked_backend()->set_rotation_size(sizeOfPerFile * 1024 * 1024); - m_logSink->locked_backend()->set_file_collector(sinks::file::make_collector( - keywords::target = homeDir, keywords::max_size = logNum * sizeOfPerFile * 1024 * 1024)); -} -} // namespace rocketmq diff --git a/src/log/Logging.h b/src/log/Logging.h deleted file mode 100644 index 3917328d1..000000000 --- a/src/log/Logging.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _ALOG_ADAPTER_H_ -#define _ALOG_ADAPTER_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "include/DefaultMQClient.h" - -namespace logging = boost::log; -namespace src = boost::log::sources; -namespace sinks = boost::log::sinks; -namespace expr = boost::log::expressions; -namespace keywords = boost::log::keywords; -using namespace boost::log::trivial; -namespace rocketmq { - -class logAdapter { - public: - ~logAdapter(); - static logAdapter* getLogInstance(); - void setLogDir(); - void setLogLevel(elogLevel logLevel); - elogLevel getLogLevel(); - void setLogFileNumAndSize(int logNum, int sizeOfPerFile); - src::severity_logger& getSeverityLogger() { return m_severityLogger; } - - private: - logAdapter(); - void setLogLevelInner(elogLevel logLevel); - elogLevel m_logLevel; - std::string m_logFile; - src::severity_logger m_severityLogger; - typedef sinks::synchronous_sink logSink_t; - boost::shared_ptr m_logSink; - static logAdapter* alogInstance; - static boost::mutex m_imtx; - std::string m_log_dir; -}; - -#define ALOG_ADAPTER logAdapter::getLogInstance() - -#define AGENT_LOGGER ALOG_ADAPTER->getSeverityLogger() - -class LogUtil { - public: - static void LogMessage(boost::log::trivial::severity_level level, int line, const char* format, ...) { - va_list arg_ptr; - va_start(arg_ptr, format); - boost::scoped_array formattedString(new char[1024]); - vsnprintf(formattedString.get(), 1024, format, arg_ptr); - BOOST_LOG_SEV(AGENT_LOGGER, level) << formattedString.get(); - va_end(arg_ptr); - } - static void LogMessageFull(boost::log::trivial::severity_level level, - const char* file, - const char* func, - int line, - const char* format, - ...) { - va_list arg_ptr; - va_start(arg_ptr, format); - boost::scoped_array formattedString(new char[1024]); - vsnprintf(formattedString.get(), 1024, format, arg_ptr); - // BOOST_LOG_SEV(AGENT_LOGGER, level) << formattedString.get() << "[" << file << ":" << func << ":"<< line << "]"; - BOOST_LOG_SEV(AGENT_LOGGER, level) << formattedString.get() << "[" << func << ":" << line << "]"; - va_end(arg_ptr); - } -}; - -#define LOG_FATAL(...) \ - LogUtil::LogMessageFull(boost::log::trivial::fatal, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) -#define LOG_ERROR(...) \ - LogUtil::LogMessageFull(boost::log::trivial::error, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) -#define LOG_WARN(...) \ - LogUtil::LogMessageFull(boost::log::trivial::warning, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) -//#define LOG_INFO(...) LogUtil::LogMessage(boost::log::trivial::info, __LINE__, __VA_ARGS__) -#define LOG_INFO(...) LogUtil::LogMessageFull(boost::log::trivial::info, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) -#define LOG_DEBUG(...) \ - LogUtil::LogMessageFull(boost::log::trivial::debug, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) -} // namespace rocketmq -#endif diff --git a/src/main/cpp/admin/AdminClient.cpp b/src/main/cpp/admin/AdminClient.cpp new file mode 100644 index 000000000..8a20d649a --- /dev/null +++ b/src/main/cpp/admin/AdminClient.cpp @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "AdminClient.h" +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +namespace admin { + +Status AdminClient::changeLogLevel(const rmq::ChangeLogLevelRequest& request, rmq::ChangeLogLevelResponse& response) { + grpc::ClientContext context; + auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(3); + context.set_deadline(deadline); + Status status = stub_->ChangeLogLevel(&context, request, &response); + return status; +} + +} // namespace admin + +ROCKETMQ_NAMESPACE_END + +void wrapChangeLogLevelRequest(rmq::ChangeLogLevelRequest& request, const std::string& level) { + if (level.empty()) { + return; + } + + if ("trace" == level) { + request.set_level(rmq::ChangeLogLevelRequest_Level_TRACE); + return; + } + + if ("debug" == level) { + request.set_level(rmq::ChangeLogLevelRequest_Level_DEBUG); + return; + } + + if ("info" == level) { + request.set_level(rmq::ChangeLogLevelRequest_Level_INFO); + return; + } + + if ("warn" == level) { + request.set_level(rmq::ChangeLogLevelRequest_Level_WARN); + return; + } + + if ("error" == level) { + request.set_level(rmq::ChangeLogLevelRequest_Level_ERROR); + return; + } +} + +int main(int argc, char* argv[]) { + if (argc <= 1) { + std::cerr << "Usage: 'admin_client level [port]' where level is among trace/debug/info/warn/error.\n"; + return EXIT_SUCCESS; + } + + int port = 9877; + + char* env_port = getenv("ROCKETMQ_ADMIN_PORT"); + if (nullptr != env_port) { + try { + port = std::stoi(env_port); + } catch (...) { + std::cerr << "Failed to parse port from environment variable ROCKETMQ_ADMIN_PORT" << env_port << "\n"; + } + } + + if (argc > 2) { + try { + port = std::stoi(argv[2]); + } catch (...) { + std::cerr << "Failed to parse port from command line:" << argv[2] << "\n"; + } + } + + std::string target("127.0.0.1:"); + target.append(std::to_string(port)); + + std::cout << "Target address: " << target << "\n"; + auto channel = grpc::CreateChannel(target, grpc::InsecureChannelCredentials()); + rocketmq::admin::AdminClient client(channel); + + rmq::ChangeLogLevelRequest request; + wrapChangeLogLevelRequest(request, argv[1]); + rmq::ChangeLogLevelResponse response; + auto status = client.changeLogLevel(request, response); + if (status.ok()) { + std::cout << "Log level changed OK" << std::endl; + } else { + std::cerr << "Failed to change log level. GRPC error code: " << status.error_code() + << ", GRPC error message: " << status.error_message() << "\n"; + std::cerr << "Server remark: " << response.remark() << std::endl; + } + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/src/main/cpp/admin/AdminFacade.cpp b/src/main/cpp/admin/AdminFacade.cpp new file mode 100644 index 000000000..a224abe75 --- /dev/null +++ b/src/main/cpp/admin/AdminFacade.cpp @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "AdminServerImpl.h" + +using namespace ROCKETMQ_NAMESPACE::admin; + +AdminServer& AdminFacade::getServer() { + static AdminServerImpl admin_server; + return admin_server; +} \ No newline at end of file diff --git a/src/main/cpp/admin/AdminServerImpl.cpp b/src/main/cpp/admin/AdminServerImpl.cpp new file mode 100644 index 000000000..ce16072cc --- /dev/null +++ b/src/main/cpp/admin/AdminServerImpl.cpp @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "AdminServerImpl.h" + +#include "AdminServiceImpl.h" +#include "ServerCall.h" +#include "spdlog/spdlog.h" +#include + +using grpc::ServerBuilder; + +ROCKETMQ_NAMESPACE_BEGIN + +namespace admin { +bool AdminServerImpl::start() { + if (State::CREATED != state_) { + return false; + } + State current = State::CREATED; + if (state_.compare_exchange_weak(current, State::STARTING, std::memory_order_relaxed)) { + std::string server_address("127.0.0.1:"); + server_address.append(std::to_string(port_)); + + grpc::EnableDefaultHealthCheckService(true); + + ServerBuilder server_builder; + server_builder.AddListeningPort(server_address, grpc::InsecureServerCredentials(), &port_); + server_builder.RegisterService(async_stub_.get()); + // A gRPC server may have multiple per-thread CompletionQueue + completion_queue_ = server_builder.AddCompletionQueue(); + server_ = server_builder.BuildAndStart(); + { + loop(); + std::unique_lock lk(loop_mtx_); + loop_cv_.wait(lk, [this]() { return State::STARTED == state_.load(); }); + } + SPDLOG_INFO("Admin server started and listening 127.0.0.1:{}", port_); + return true; + } + return false; +} + +void AdminServerImpl::loop() { + auto loop_lambda = [this] { + state_.store(State::STARTED); + { + std::unique_lock lk(loop_mtx_); + loop_cv_.notify_all(); + } + + SPDLOG_DEBUG("Prepare initial ServerCall"); + new ServerCall(async_stub_.get(), service_.get(), completion_queue_.get()); + void* tag; + bool ok; + + while (completion_queue_->Next(&tag, &ok)) { + if (!ok) { + delete static_cast(tag); + break; + } + static_cast(tag)->proceed(); + } + }; + loop_thread_ = std::thread(loop_lambda); +} + +bool AdminServerImpl::stop() { + if (State::STARTED != state_.load()) { + return false; + } + + if (server_) { + State expected = State::STARTED; + if (state_.compare_exchange_strong(expected, State::STOPPING, std::memory_order_relaxed)) { + SPDLOG_INFO("Stopping admin server"); + server_->Shutdown(); + + if (completion_queue_) { + completion_queue_->Shutdown(); + // Drain completion_queue_ + { + void* tag; + bool ignore_ok; + while (completion_queue_->Next(&tag, &ignore_ok)) { + } + } + } + + if (loop_thread_.joinable()) { + loop_thread_.join(); + } + + state_.store(State::STOPPED); + SPDLOG_INFO("Admin server stopped"); + return true; + } + return false; + } else { + SPDLOG_ERROR("Admin server is unexpected nullptr"); + } + return false; +} +} // namespace admin + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/admin/AdminServiceImpl.cpp b/src/main/cpp/admin/AdminServiceImpl.cpp new file mode 100644 index 000000000..3a4d0fa35 --- /dev/null +++ b/src/main/cpp/admin/AdminServiceImpl.cpp @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "AdminServiceImpl.h" +#include "spdlog/spdlog.h" + +ROCKETMQ_NAMESPACE_BEGIN + +namespace admin { + +Status applyChange(const rmq::ChangeLogLevelRequest* request) { + auto logger = spdlog::get("rocketmq_logger"); + if (!logger) { + return Status(grpc::StatusCode::INTERNAL, "rocketmq_logger is not registered"); + } + + auto level = request->level(); + switch (level) { + case rmq::ChangeLogLevelRequest_Level_TRACE: + logger->set_level(spdlog::level::trace); + break; + case rmq::ChangeLogLevelRequest_Level_DEBUG: + logger->set_level(spdlog::level::debug); + break; + case rmq::ChangeLogLevelRequest_Level_INFO: + logger->set_level(spdlog::level::info); + break; + case rmq::ChangeLogLevelRequest_Level_WARN: + logger->set_level(spdlog::level::warn); + break; + case rmq::ChangeLogLevelRequest_Level_ERROR: + logger->set_level(spdlog::level::err); + break; + default: + logger->set_level(spdlog::level::info); + break; + } + return grpc::Status::OK; +} + +Status AdminServiceImpl::ChangeLogLevel(ServerContext* context, const rmq::ChangeLogLevelRequest* request, + rmq::ChangeLogLevelResponse* reply) { + Status status = applyChange(request); + if (status.ok()) { + reply->set_remark("OK"); + } + return status; +} + +} // namespace admin + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/admin/BUILD.bazel b/src/main/cpp/admin/BUILD.bazel new file mode 100644 index 000000000..1e8efe9bb --- /dev/null +++ b/src/main/cpp/admin/BUILD.bazel @@ -0,0 +1,59 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_binary") +cc_library( + name = "admin_server_library", + hdrs = [ + "include/AdminServiceImpl.h", + "include/AdminServerImpl.h", + "include/ServerCall.h", + ], + srcs = [ + "AdminFacade.cpp", + "AdminServerImpl.cpp", + "AdminServiceImpl.cpp", + ], + strip_include_prefix = "//src/main/cpp/admin/include", + deps = [ + "//api:rocketmq_interface", + "//proto:rocketmq_grpc_library", + "@com_github_gabime_spdlog//:spdlog", + ], + visibility = ["//visibility:public"], +) + +cc_library( + name = "admin_client_interface", + hdrs = [ + "include/AdminClient.h", + ], + strip_include_prefix = "//src/main/cpp/admin/include", + deps = [ + "//api:rocketmq_interface", + ], +) + +cc_binary( + name = "admin_client", + srcs = [ + "AdminClient.cpp", + ], + deps = [ + ":admin_client_interface", + "//proto:rocketmq_grpc_library", + ], +) \ No newline at end of file diff --git a/src/main/cpp/admin/include/AdminClient.h b/src/main/cpp/admin/include/AdminClient.h new file mode 100644 index 000000000..9e6e7c7b7 --- /dev/null +++ b/src/main/cpp/admin/include/AdminClient.h @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once +#include "apache/rocketmq/v2/admin.grpc.pb.h" +#include "rocketmq/RocketMQ.h" +#include +#include + +namespace rmq = apache::rocketmq::v2; + +ROCKETMQ_NAMESPACE_BEGIN + +using grpc::Channel; +using grpc::Status; + +namespace admin { + +class AdminClient { +public: + explicit AdminClient(std::shared_ptr& channel) : stub_(rmq::Admin::NewStub(channel)) { + } + + Status changeLogLevel(const rmq::ChangeLogLevelRequest& request, rmq::ChangeLogLevelResponse& response); + +private: + std::unique_ptr stub_; +}; + +} // namespace admin + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/admin/include/AdminServerImpl.h b/src/main/cpp/admin/include/AdminServerImpl.h new file mode 100644 index 000000000..5ef88ab2d --- /dev/null +++ b/src/main/cpp/admin/include/AdminServerImpl.h @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include +#include + +#include "AdminServiceImpl.h" +#include "rocketmq/AdminServer.h" + +#include "grpcpp/grpcpp.h" + +using grpc::Server; + +ROCKETMQ_NAMESPACE_BEGIN + +namespace admin { +class AdminServerImpl : public AdminServer { +public: + AdminServerImpl() + : port_(0), state_(State::CREATED), async_stub_(new rmq::Admin::AsyncService), service_(new AdminServiceImpl) { + } + + bool start() override; + + bool stop() override; + + int port() const override { + return port_; + } + +private: + int port_; + std::unique_ptr server_; + std::atomic state_; + std::unique_ptr async_stub_; + std::unique_ptr service_; + std::unique_ptr completion_queue_; + std::thread loop_thread_; + + std::mutex loop_mtx_; + std::condition_variable loop_cv_; + void loop(); +}; +} // namespace admin + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/admin/include/AdminServiceImpl.h b/src/main/cpp/admin/include/AdminServiceImpl.h new file mode 100644 index 000000000..e2d750cbc --- /dev/null +++ b/src/main/cpp/admin/include/AdminServiceImpl.h @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once +#include "apache/rocketmq/v2/admin.grpc.pb.h" +#include "grpcpp/grpcpp.h" +#include "rocketmq/RocketMQ.h" + +using grpc::ServerContext; +using grpc::Status; + +namespace rmq = apache::rocketmq::v2; + +ROCKETMQ_NAMESPACE_BEGIN + +namespace admin { +class AdminServiceImpl final : public rmq::Admin::Service { +public: + Status ChangeLogLevel(ServerContext* context, const rmq::ChangeLogLevelRequest* request, + rmq::ChangeLogLevelResponse* reply) override; +}; +} // namespace admin + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/admin/include/ServerCall.h b/src/main/cpp/admin/include/ServerCall.h new file mode 100644 index 000000000..66f3246a0 --- /dev/null +++ b/src/main/cpp/admin/include/ServerCall.h @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "apache/rocketmq/v2/admin.grpc.pb.h" + +#include "rocketmq/RocketMQ.h" + +namespace rmq = apache::rocketmq::v2; + +ROCKETMQ_NAMESPACE_BEGIN + +enum ServerCallStatus : int8_t +{ + CREATE = 0, + PROCESS = 1, + FINISH = 2 +}; + +class ServerCall { +public: + ServerCall(rmq::Admin::AsyncService* async_service, rmq::Admin::Service* service, + grpc::ServerCompletionQueue* completion_queue) + : async_stub_(async_service), service_(service), completion_queue_(completion_queue), + response_observer_(&context_), status_(ServerCallStatus::CREATE) { + proceed(); + } + + void proceed() { + switch (status_) { + case CREATE: { + status_ = PROCESS; + async_stub_->RequestChangeLogLevel(&context_, &request_, &response_observer_, completion_queue_, + completion_queue_, this); + break; + } + case PROCESS: { + // Create a new ServerCall to serve the next incoming request. + new ServerCall(async_stub_, service_, completion_queue_); + + // Now that request_ is already filled with actual data from clients, invoke the actual process function + const grpc::Status rpc_status = service_->ChangeLogLevel(&context_, &request_, &response_); + + status_ = FINISH; + response_observer_.Finish(response_, rpc_status, this); + break; + } + default: { + assert(FINISH == status_); + delete this; + } + } + } + +private: + rmq::Admin::AsyncService* async_stub_; + rmq::Admin::Service* service_; + grpc::ServerCompletionQueue* completion_queue_; + grpc::ServerContext context_; + rmq::ChangeLogLevelRequest request_; + rmq::ChangeLogLevelResponse response_; + grpc::ServerAsyncResponseWriter response_observer_; + ServerCallStatus status_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/BUILD.bazel b/src/main/cpp/base/BUILD.bazel new file mode 100644 index 000000000..959bba5e7 --- /dev/null +++ b/src/main/cpp/base/BUILD.bazel @@ -0,0 +1,46 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_library") + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "base_library", + hdrs = glob(["include/*.h"]), + srcs = glob(["*.cpp"]), + strip_include_prefix = "//src/main/cpp/base/include", + deps = [ + "//src/main/cpp/log:log_library", + "//proto:rocketmq_grpc_library", + "@com_github_fmtlib_fmt//:fmtlib", + "@com_google_absl//absl/base", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/random", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/time", + "@com_github_gabime_spdlog//:spdlog", + "@com_github_grpc_grpc//:grpc", + "@com_googlesource_code_re2//:re2", + "@boringssl//:crypto", + "@boringssl//:ssl", + "//external:madler_zlib", + "@com_github_yhirose_cpp_httplib//:cpp_httplib", + "@asio//:asio", + ], +) \ No newline at end of file diff --git a/libs/signature/include/param_list.h b/src/main/cpp/base/Configuration.cpp similarity index 51% rename from libs/signature/include/param_list.h rename to src/main/cpp/base/Configuration.cpp index afe87b05e..cf0f4bd3d 100644 --- a/libs/signature/include/param_list.h +++ b/src/main/cpp/base/Configuration.cpp @@ -15,40 +15,31 @@ * limitations under the License. */ -#ifndef PARAM_LIST_H -#define PARAM_LIST_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -namespace rocketmqSignature { -#endif - -typedef struct _spas_param_node { - char* name; - char* value; - struct _spas_param_node* pnext; -} SPAS_PARAM_NODE; - -typedef struct _spas_param_list { - SPAS_PARAM_NODE* phead; - unsigned int length; /* count of nodes */ - unsigned int size; /* total size of string presentation */ -} SPAS_PARAM_LIST; - -extern SPAS_PARAM_LIST* create_param_list(void); -extern int add_param_to_list(SPAS_PARAM_LIST* list, const char* name, const char* value); -extern void free_param_list(SPAS_PARAM_LIST* list); -extern char* param_list_to_str(const SPAS_PARAM_LIST* list); - -#ifdef __cplusplus +#include "rocketmq/Configuration.h" + +ROCKETMQ_NAMESPACE_BEGIN + +ConfigurationBuilder Configuration::newBuilder() { + return {}; +} + +ConfigurationBuilder& ConfigurationBuilder::withEndpoints(std::string endpoints) { + configuration_.endpoints_ = std::move(endpoints); + return *this; +} + +ConfigurationBuilder& ConfigurationBuilder::withCredentialsProvider(std::shared_ptr provider) { + configuration_.credentials_provider_ = std::move(provider); + return *this; +} + +ConfigurationBuilder& ConfigurationBuilder::withRequestTimeout(std::chrono::milliseconds request_timeout) { + configuration_.request_timeout_ = request_timeout; + return *this; } -#endif -#ifdef __cplusplus +Configuration ConfigurationBuilder::build() { + return std::move(configuration_); } -#endif -#endif +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/ConfigurationDefaults.cpp b/src/main/cpp/base/ConfigurationDefaults.cpp new file mode 100644 index 000000000..b11a6e6b0 --- /dev/null +++ b/src/main/cpp/base/ConfigurationDefaults.cpp @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +#include "rocketmq/ConfigurationDefaults.h" + +ROCKETMQ_NAMESPACE_BEGIN + +const std::chrono::milliseconds ConfigurationDefaults::RequestTimeout = std::chrono::seconds(3); + +ROCKETMQ_NAMESPACE_END diff --git a/src/main/cpp/base/CredentialsProvider.cpp b/src/main/cpp/base/CredentialsProvider.cpp new file mode 100644 index 000000000..548e9d810 --- /dev/null +++ b/src/main/cpp/base/CredentialsProvider.cpp @@ -0,0 +1,210 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include + +#include "absl/memory/memory.h" +#include "absl/strings/match.h" +#include "fmt/format.h" +#include "ghc/filesystem.hpp" +#include "google/protobuf/struct.pb.h" +#include "google/protobuf/util/json_util.h" +#include "spdlog/spdlog.h" + +#include "MixAll.h" +#include "StsCredentialsProviderImpl.h" +#include "rocketmq/Logger.h" + +ROCKETMQ_NAMESPACE_BEGIN + +StaticCredentialsProvider::StaticCredentialsProvider(std::string access_key, std::string access_secret) + : access_key_(std::move(access_key)), access_secret_(std::move(access_secret)) { +} + +Credentials StaticCredentialsProvider::getCredentials() { + return Credentials(access_key_, access_secret_); +} + +const char* EnvironmentVariablesCredentialsProvider::ENVIRONMENT_ACCESS_KEY = "ROCKETMQ_ACCESS_KEY"; +const char* EnvironmentVariablesCredentialsProvider::ENVIRONMENT_ACCESS_SECRET = "ROCKETMQ_ACCESS_SECRET"; + +EnvironmentVariablesCredentialsProvider::EnvironmentVariablesCredentialsProvider() { + char* key = getenv(ENVIRONMENT_ACCESS_KEY); + if (key) { + access_key_ = std::string(key); + } + + char* secret = getenv(ENVIRONMENT_ACCESS_SECRET); + if (secret) { + access_secret_ = std::string(secret); + } +} + +Credentials EnvironmentVariablesCredentialsProvider::getCredentials() { + return Credentials(access_key_, access_secret_); +} + +const char* ConfigFileCredentialsProvider::CREDENTIAL_FILE_ = "rocketmq/credentials"; + +const char* ConfigFileCredentialsProvider::ACCESS_KEY_FIELD_NAME = "AccessKey"; +const char* ConfigFileCredentialsProvider::ACCESS_SECRET_FIELD_NAME = "AccessSecret"; + +ConfigFileCredentialsProvider::ConfigFileCredentialsProvider() { + std::string config_file; + if (MixAll::homeDirectory(config_file)) { + std::string path_separator(1, ghc::filesystem::path::preferred_separator); + if (!absl::EndsWith(config_file, path_separator)) { + config_file.append(1, ghc::filesystem::path::preferred_separator); + } + config_file.append(CREDENTIAL_FILE_); + ghc::filesystem::path config_file_path(config_file); + std::error_code ec; + if (!ghc::filesystem::exists(config_file_path, ec) || ec) { + SPDLOG_WARN("Config file[{}] does not exist.", config_file); + return; + } + std::ifstream config_file_stream; + config_file_stream.open(config_file.c_str(), std::ios::in | std::ios::ate | std::ios::binary); + if (config_file_stream.good()) { + auto size = config_file_stream.tellg(); + std::string content(size, '\0'); + config_file_stream.seekg(0); + config_file_stream.read(&content[0], size); + config_file_stream.close(); + google::protobuf::Struct root; + google::protobuf::util::Status status = google::protobuf::util::JsonStringToMessage(content, &root); + if (status.ok()) { + auto&& fields = root.fields(); + if (fields.contains(ACCESS_KEY_FIELD_NAME)) { + access_key_ = fields.at(ACCESS_KEY_FIELD_NAME).string_value(); + } + + if (fields.contains(ACCESS_SECRET_FIELD_NAME)) { + access_secret_ = fields.at(ACCESS_SECRET_FIELD_NAME).string_value(); + } + SPDLOG_DEBUG("Credentials for access_key={} loaded", access_key_); + } else { + SPDLOG_WARN("Failed to parse credential JSON config file. Message: {}", status.message().data()); + } + } else { + SPDLOG_WARN("Failed to open file: {}", config_file); + return; + } + } +} + +ConfigFileCredentialsProvider::ConfigFileCredentialsProvider(std::string config_file, + std::chrono::milliseconds refresh_interval) { +} + +Credentials ConfigFileCredentialsProvider::getCredentials() { + return Credentials(access_key_, access_secret_); +} + +StsCredentialsProvider::StsCredentialsProvider(std::string ram_role_name) + : impl_(absl::make_unique(std::move(ram_role_name))) { +} + +Credentials StsCredentialsProvider::getCredentials() { + return impl_->getCredentials(); +} + +StsCredentialsProviderImpl::StsCredentialsProviderImpl(std::string ram_role_name) + : ram_role_name_(std::move(ram_role_name)) { +} + +StsCredentialsProviderImpl::~StsCredentialsProviderImpl() { + http_client_->shutdown(); +} + +Credentials StsCredentialsProviderImpl::getCredentials() { + if (std::chrono::system_clock::now() >= expiration_) { + refresh(); + } + + { + absl::MutexLock lk(&mtx_); + return Credentials(access_key_, access_secret_, session_token_, expiration_); + } +} + +void StsCredentialsProviderImpl::refresh() { + std::string path = fmt::format("{}{}", RAM_ROLE_URL_PREFIX, ram_role_name_); + absl::Mutex sync_mtx; + absl::CondVar sync_cv; + bool completed = false; + auto callback = [&, this](int code, const std::multimap& headers, const std::string& body) { + SPDLOG_DEBUG("Received STS response. Code: {}", code); + if (static_cast(HttpStatus::OK) == code) { + google::protobuf::Struct doc; + google::protobuf::util::Status status = google::protobuf::util::JsonStringToMessage(body, &doc); + if (status.ok()) { + const auto& fields = doc.fields(); + assert(fields.contains(FIELD_ACCESS_KEY)); + std::string access_key = fields.at(FIELD_ACCESS_KEY).string_value(); + assert(fields.contains(FIELD_ACCESS_SECRET)); + std::string access_secret = fields.at(FIELD_ACCESS_SECRET).string_value(); + assert(fields.contains(FIELD_SESSION_TOKEN)); + std::string session_token = fields.at(FIELD_SESSION_TOKEN).string_value(); + assert(fields.contains(FIELD_EXPIRATION)); + std::string expiration_string = fields.at(FIELD_EXPIRATION).string_value(); + absl::Time expiration_instant; + std::string parse_error; + if (absl::ParseTime(EXPIRATION_DATE_TIME_FORMAT, expiration_string, absl::UTCTimeZone(), &expiration_instant, + &parse_error)) { + absl::MutexLock lk(&mtx_); + access_key_ = std::move(access_key); + access_secret_ = std::move(access_secret); + session_token_ = std::move(session_token); + expiration_ = absl::ToChronoTime(expiration_instant); + } else { + SPDLOG_WARN("Failed to parse expiration time. Message: {}", parse_error); + } + + } else { + SPDLOG_WARN("Failed to parse STS response. Message: {}", status.message().as_string()); + } + } else { + SPDLOG_WARN("STS response code is not OK. Code: {}", code); + } + + { + absl::MutexLock lk(&sync_mtx); + completed = true; + sync_cv.Signal(); + } + }; + + http_client_->get(HttpProtocol::HTTP, RAM_ROLE_HOST, 80, path, callback); + + while (!completed) { + absl::MutexLock lk(&sync_mtx); + sync_cv.Wait(&sync_mtx); + } +} + +const char* StsCredentialsProviderImpl::RAM_ROLE_HOST = "100.100.100.200"; +const char* StsCredentialsProviderImpl::RAM_ROLE_URL_PREFIX = "/latest/meta-data/Ram/security-credentials/"; +const char* StsCredentialsProviderImpl::FIELD_ACCESS_KEY = "AccessKeyId"; +const char* StsCredentialsProviderImpl::FIELD_ACCESS_SECRET = "AccessKeySecret"; +const char* StsCredentialsProviderImpl::FIELD_SESSION_TOKEN = "SecurityToken"; +const char* StsCredentialsProviderImpl::FIELD_EXPIRATION = "Expiration"; +const char* StsCredentialsProviderImpl::EXPIRATION_DATE_TIME_FORMAT = "%Y-%m-%d%ET%H:%H:%S%Ez"; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/ErrorCategory.cpp b/src/main/cpp/base/ErrorCategory.cpp new file mode 100644 index 000000000..4fe2ea0fd --- /dev/null +++ b/src/main/cpp/base/ErrorCategory.cpp @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "rocketmq/ErrorCategory.h" + +ROCKETMQ_NAMESPACE_BEGIN + +std::string ErrorCategory::message(int code) const { + ErrorCode ec = static_cast(code); + switch (ec) { + case ErrorCode::Success: + return "Success"; + + case ErrorCode::NoContent: + return "Broker has processed the request but is not going to return any content."; + + case ErrorCode::IllegalState: + return "Client state illegal. Forgot to call start()?"; + + case ErrorCode::BadConfiguration: + return "Bad configuration."; + + case ErrorCode::BadRequest: + return "Message is ill-formed. Check validity of your topic, tag, " + "etc"; + + case ErrorCode::BadRequestAsyncPubFifoMessage: + return "Publishing of FIFO messages is only allowed synchronously"; + + case ErrorCode::Unauthorized: + return "Authentication failed. Possibly caused by invalid credentials."; + + case ErrorCode::Forbidden: + return "Authenticated user does not have privilege to perform the " + "requested action"; + + case ErrorCode::NotFound: + return "Request resource not found, which should be created through console or " + "administration API before hand."; + case ErrorCode::TopicNotFound: + return "Topic is not found. Verify the request topic has already been created through console or management API"; + + case ErrorCode::GroupNotFound: + return "Group is not found. Verify the request group has already been created through console or management API"; + + case ErrorCode::RequestTimeout: + return "Timeout when connecting, reading from or writing to brokers."; + + case ErrorCode::PayloadTooLarge: + return "Message body is too large."; + + case ErrorCode::PreconditionRequired: + return "State of dependent procedure is not right"; + + case ErrorCode::TooManyRequest: + return "Quota exchausted. The user has sent too many requests in a given " + "amount of time."; + + case ErrorCode::UnavailableForLegalReasons: + return "A server operator has received a legal demand to deny access to " + "a resource or to a set of resources that " + "includes the requested resource."; + + case ErrorCode::HeaderFieldsTooLarge: + return "The server is unwilling to process the request because either an " + "individual header field, or all the header fields collectively, " + "are too large"; + + case ErrorCode::InternalServerError: + return "Server side interval error"; + + case ErrorCode::NotImplemented: + return "The server either does not recognize the request method, or it " + "lacks the ability to fulfil the request."; + + case ErrorCode::BadGateway: + return "The server was acting as a gateway or proxy and received an " + "invalid response from the upstream server."; + + case ErrorCode::ServiceUnavailable: + return "The server cannot handle the request (because it is overloaded " + "or down for maintenance). Generally, this " + "is a temporary state."; + + case ErrorCode::GatewayTimeout: + return "The server was acting as a gateway or proxy and did not receive " + "a timely response from the upstream " + "server."; + + case ErrorCode::ProtocolVersionNotSupported: + return "The server does not support the protocol version used in the " + "request."; + + case ErrorCode::InsufficientStorage: + return "The server is unable to store the representation needed to " + "complete the request."; + + default: + return "Not-Implemented"; + } +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/ErrorCode.cpp b/src/main/cpp/base/ErrorCode.cpp new file mode 100644 index 000000000..59c1aec41 --- /dev/null +++ b/src/main/cpp/base/ErrorCode.cpp @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "rocketmq/ErrorCategory.h" + +ROCKETMQ_NAMESPACE_BEGIN + +std::error_code make_error_code(ErrorCode code) { + const ErrorCategory& instance = ErrorCategory::instance(); + return {static_cast(code), instance}; +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/dllmain.cpp b/src/main/cpp/base/FilterExpression.cpp similarity index 61% rename from src/dllmain.cpp rename to src/main/cpp/base/FilterExpression.cpp index a9be1e020..b187994d1 100644 --- a/src/dllmain.cpp +++ b/src/main/cpp/base/FilterExpression.cpp @@ -14,20 +14,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "rocketmq/FilterExpression.h" -#include -#include "windows.h" +ROCKETMQ_NAMESPACE_BEGIN -BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { - switch (ul_reason_for_call) { - case DLL_PROCESS_ATTACH: - break; - case DLL_THREAD_ATTACH: - break; - case DLL_THREAD_DETACH: - break; - case DLL_PROCESS_DETACH: - break; +bool FilterExpression::accept(const Message& message) const { + switch (type_) { + case ExpressionType::TAG: { + if (WILD_CARD_TAG == content_) { + return true; + } else { + return message.tag() == content_; + } + } + + case ExpressionType::SQL92: { + // Server should have strictly filtered. + return true; + } } - return TRUE; + return true; } + +const char* FilterExpression::WILD_CARD_TAG = "*"; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/HostInfo.cpp b/src/main/cpp/base/HostInfo.cpp new file mode 100644 index 000000000..8b57247b3 --- /dev/null +++ b/src/main/cpp/base/HostInfo.cpp @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "HostInfo.h" +#include "absl/strings/match.h" +#include "rocketmq/RocketMQ.h" +#include +#include + +ROCKETMQ_NAMESPACE_BEGIN + +const char* HostInfo::ENV_LABEL_SITE = "SIGMA_APP_SITE"; +const char* HostInfo::ENV_LABEL_UNIT = "SIGMA_APP_UNIT"; +const char* HostInfo::ENV_LABEL_APP = "SIGMA_APP_NAME"; +const char* HostInfo::ENV_LABEL_STAGE = "SIGMA_APP_STAGE"; + +HostInfo::HostInfo() { + getEnv(ENV_LABEL_SITE, site_); + getEnv(ENV_LABEL_UNIT, unit_); + getEnv(ENV_LABEL_APP, app_); + getEnv(ENV_LABEL_STAGE, stage_); +} + +void HostInfo::getEnv(const char* env, std::string& holder) { + if (!strlen(env)) { + return; + } + + char* value = getenv(env); + if (nullptr != value) { + holder.clear(); + holder.append(value); + } +} + +bool HostInfo::hasHostInfo() const { + return !unit_.empty() && !stage_.empty(); +} + +std::string HostInfo::queryString() const { + if (!hasHostInfo()) { + return std::string(); + } + + std::string query_string("labels="); + appendLabel(query_string, "site", site_); + appendLabel(query_string, "unit", unit_); + appendLabel(query_string, "app", app_); + appendLabel(query_string, "stage", stage_); + return query_string; +} + +void HostInfo::appendLabel(std::string& query_string, const char* key, const std::string& value) { + if (value.empty()) { + return; + } + + if (absl::EndsWith(query_string, "=")) { + query_string.append(key).append(":").append(value); + } else { + query_string.append(",").append(key).append(":").append(value); + } +} +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/HttpClientImpl.cpp b/src/main/cpp/base/HttpClientImpl.cpp new file mode 100644 index 000000000..cb25ae96f --- /dev/null +++ b/src/main/cpp/base/HttpClientImpl.cpp @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "HttpClientImpl.h" + +#include +#include + +#include "fmt/format.h" +#include "spdlog/spdlog.h" + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +void HttpClientImpl::start() { +} + +void HttpClientImpl::shutdown() { +} + +/** + * @brief We current implement this function in sync mode since async http request in CURL is sort of unnecessarily + * complex. + * + * @param protocol + * @param host + * @param port + * @param path + * @param cb + */ +void HttpClientImpl::get( + HttpProtocol protocol, const std::string& host, std::uint16_t port, const std::string& path, + const std::function&, const std::string&)>& cb) { + + std::string key; + switch (protocol) { + case HttpProtocol::HTTP: + key = fmt::format("http://{}:{}", host, port); + break; + case HttpProtocol::HTTPS: + key = fmt::format("https://{}:{}", host, port); + break; + } + + std::shared_ptr client; + { + absl::MutexLock lk(&clients_mtx_); + if (clients_.contains(key)) { + client = clients_[key]; + } + + if (!client || !client->is_valid()) { + client = std::make_shared(key); + clients_.insert_or_assign(key, client); + } + } + + if (!client || !client->is_valid()) { + int code = 400; + std::multimap headers; + std::string response; + cb(code, headers, response); + return; + } + + auto res = client->Get(path.c_str()); + + std::multimap headers; + for (auto& header : headers) { + headers.insert({header.first, header.second}); + } + + cb(res->status, headers, res->body); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/Message.cpp b/src/main/cpp/base/Message.cpp new file mode 100644 index 000000000..f20b4cd68 --- /dev/null +++ b/src/main/cpp/base/Message.cpp @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "rocketmq/Message.h" + +#include "UniqueIdGenerator.h" +#include "absl/memory/memory.h" + +ROCKETMQ_NAMESPACE_BEGIN + +Message::Message() { + id_ = UniqueIdGenerator::instance().next(); +} + +MessageBuilder Message::newBuilder() { + return {}; +} + +MessageBuilder::MessageBuilder() : message_(absl::make_unique()) { +} + +MessageBuilder& MessageBuilder::withTopic(std::string topic) { + message_->topic_.swap(topic); + return *this; +} + +MessageBuilder& MessageBuilder::withTag(std::string tag) { + message_->tag_.swap(tag); + return *this; +} + +MessageBuilder& MessageBuilder::withKeys(std::vector keys) { + message_->keys_.swap(keys); + return *this; +} + +MessageBuilder& MessageBuilder::withTraceContext(std::string trace_context) { + message_->trace_context_.swap(trace_context); + return *this; +} + +MessageBuilder& MessageBuilder::withBody(std::string body) { + message_->body_.swap(body); + return *this; +} + +MessageBuilder& MessageBuilder::withGroup(std::string group) { + message_->group_.swap(group); + return *this; +} + +MessageBuilder& MessageBuilder::withProperties(std::unordered_map properties) { + message_->properties_ = std::move(properties); + return *this; +} + +MessageConstPtr MessageBuilder::build() { + return std::move(message_); +} + +MessageBuilder& MessageBuilder::withId(std::string id) { + message_->id_ = std::move(id); + return *this; +} + +MessageBuilder& MessageBuilder::withBornTime(std::chrono::system_clock::time_point born_time) { + message_->born_time_ = born_time; + return *this; +} + +MessageBuilder& MessageBuilder::withBornHost(std::string born_host) { + message_->born_host_ = std::move(born_host); + return *this; +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/include/CMessageQueue.h b/src/main/cpp/base/MessageExt.cpp similarity index 71% rename from include/CMessageQueue.h rename to src/main/cpp/base/MessageExt.cpp index 859f71fd2..5477df764 100644 --- a/include/CMessageQueue.h +++ b/src/main/cpp/base/MessageExt.cpp @@ -14,23 +14,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "MessageExt.h" -#ifndef __C_MESSAGE_QUEUE_H__ -#define __C_MESSAGE_QUEUE_H__ +ROCKETMQ_NAMESPACE_BEGIN -#include "CCommon.h" +rmq::MessageType typeOf(const Message& message) { + if (message.group().has_value()) { + return rmq::MessageType::FIFO; + } -#ifdef __cplusplus -extern "C" { -#endif + if (message.deliveryTimestamp().has_value()) { + return rmq::MessageType::DELAY; + } -typedef struct _CMessageQueue_ { - char topic[MAX_TOPIC_LENGTH]; - char brokerName[MAX_BROKER_NAME_ID_LENGTH]; - int queueId; -} CMessageQueue; - -#ifdef __cplusplus + return rmq::MessageType::NORMAL; } -#endif -#endif //__C_MESSAGE_H__ + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/MetadataConstants.cpp b/src/main/cpp/base/MetadataConstants.cpp new file mode 100644 index 000000000..71e3da98f --- /dev/null +++ b/src/main/cpp/base/MetadataConstants.cpp @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "MetadataConstants.h" + +ROCKETMQ_NAMESPACE_BEGIN + +#ifndef CLIENT_VERSION_MAJOR +#define CLIENT_VERSION_MAJOR "5" +#endif + +#ifndef CLIENT_VERSION_MINOR +#define CLIENT_VERSION_MINOR "0" +#endif + +#ifndef CLIENT_VERSION_PATCH +#define CLIENT_VERSION_PATCH "0" +#endif + +const char* MetadataConstants::CLIENT_VERSION = CLIENT_VERSION_MAJOR "." CLIENT_VERSION_MINOR "." CLIENT_VERSION_PATCH; + +const char* MetadataConstants::TENANT_ID_KEY = "x-mq-tenant-id"; +const char* MetadataConstants::CLIENT_ID_KEY = "x-mq-client-id"; +const char* MetadataConstants::NAMESPACE_KEY = "x-mq-namespace"; +const char* MetadataConstants::AUTHORIZATION = "authorization"; +const char* MetadataConstants::STS_SESSION_TOKEN = "x-mq-session-token"; +const char* MetadataConstants::DATE_TIME_KEY = "x-mq-date-time"; +const char* MetadataConstants::ALGORITHM_KEY = "MQv2-HMAC-SHA1"; +const char* MetadataConstants::CREDENTIAL_KEY = "Credential"; +const char* MetadataConstants::SIGNED_HEADERS_KEY = "SignedHeaders"; +const char* MetadataConstants::SIGNATURE_KEY = "Signature"; +const char* MetadataConstants::DATE_TIME_FORMAT = "%Y%m%dT%H%M%SZ"; +const char* MetadataConstants::LANGUAGE_KEY = "x-mq-language"; +const char* MetadataConstants::CLIENT_VERSION_KEY = "x-mq-client-version"; +const char* MetadataConstants::PROTOCOL_VERSION_KEY = "x-mq-protocol-version"; +const char* MetadataConstants::REQUEST_ID_KEY = "x-mq-request-id"; +const char* MetadataConstants::SERVICE_NAME = "RocketMQ"; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/MixAll.cpp b/src/main/cpp/base/MixAll.cpp new file mode 100644 index 000000000..4d244cec8 --- /dev/null +++ b/src/main/cpp/base/MixAll.cpp @@ -0,0 +1,325 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "MixAll.h" + +#include +#include +#include + +#include "absl/random/random.h" +#include "absl/strings/str_split.h" +#include "fmt/format.h" +#include "openssl/md5.h" +#include "openssl/sha.h" +#include "zlib.h" + +#ifdef _WIN32 +#include +#else +#include +#include +#include +#endif + +ROCKETMQ_NAMESPACE_BEGIN + +const int32_t MixAll::MASTER_BROKER_ID = 0; + +const int32_t MixAll::DEFAULT_RECEIVE_MESSAGE_BATCH_SIZE = 32; + +const uint32_t MixAll::MAX_MESSAGE_BODY_SIZE = 1024 * 1024 * 4; +const uint32_t MixAll::MAX_CACHED_MESSAGE_COUNT = 65535; +const uint32_t MixAll::DEFAULT_CACHED_MESSAGE_COUNT = 1024; +const uint64_t MixAll::DEFAULT_CACHED_MESSAGE_MEMORY = 128L * 1024 * 1024; +const uint32_t MixAll::DEFAULT_CONSUME_THREAD_POOL_SIZE = 20; +const uint32_t MixAll::DEFAULT_CONSUME_MESSAGE_BATCH_SIZE = 1; +const int32_t MixAll::DEFAULT_MAX_DELIVERY_ATTEMPTS = 16; + +const RE2 MixAll::TOPIC_REGEX("[a-zA-Z0-9\\-_]{3,64}"); +const RE2 MixAll::IP_REGEX("\\d+\\.\\d+\\.\\d+\\.\\d+"); + +const std::chrono::duration MixAll::DEFAULT_INVISIBLE_TIME_ = std::chrono::seconds(30); + +const std::chrono::duration MixAll::PROCESS_QUEUE_EXPIRATION_THRESHOLD_ = std::chrono::seconds(120); + +const std::size_t MixAll::MAX_SEND_MESSAGE_ATTEMPT_TIMES_ = 3; + +const std::string MixAll::PROPERTY_TRANSACTION_PREPARED_ = "TRAN_MSG"; + +const std::string MixAll::DEFAULT_LOAD_BALANCER_STRATEGY_NAME_ = "AVG"; + +const uint32_t MixAll::DEFAULT_COMPRESS_BODY_THRESHOLD_ = 1024 * 1024 * 4; + +const std::chrono::milliseconds MixAll::DefaultReceiveMessageTimeout = std::chrono::seconds(30); + +const char* MixAll::HOME_PROFILE_ENV_ = "HOME"; +const char* MixAll::MESSAGE_KEY_SEPARATOR = " "; + +const char* MixAll::OTLP_NAME_VALUE = "org.apache.rocketmq.message"; + +const char* MixAll::TRACE_RESOURCE_ATTRIBUTE_KEY_TELEMETRY_SDK_LANGUAGE = "telemetry.sdk.language"; +const char* MixAll::TRACE_RESOURCE_ATTRIBUTE_VALUE_TELEMETRY_SDK_LANGUAGE = "cpp"; + +const char* MixAll::TRACE_RESOURCE_ATTRIBUTE_KEY_HOST_NAME = "host.name"; +const char* MixAll::TRACE_RESOURCE_ATTRIBUTE_KEY_SERVICE_NAME = "service.name"; +const char* MixAll::TRACE_RESOURCE_ATTRIBUTE_VALUE_SERVICE_NAME = "rocketmq-client"; + +// Span attributes follows to the opentelemetry specification, refers to: +// https://github.com/open-telemetry/opentelemetry-specification + +// RocketMQ span attribute name list +const char* MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_OPERATION = "messaging.rocketmq.operation"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_NAMESPACE = "messaging.rocketmq.namespace"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_TAG = "messaging.rocketmq.message_tag"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_KEYS = "messaging.rocketmq.message_keys"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_CLIENT_ID = "messaging.rocketmq.client_id"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_MESSAGE_TYPE = "messaging.rocketmq.message_type"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_CLIENT_GROUP = "messaging.rocketmq.client_group"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_ATTEMPT = "messaging.rocketmq.attempt"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_BATCH_SIZE = "messaging.rocketmq.batch_size"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_DELIVERY_TIMESTAMP = "messaging.rocketmq.delivery_timestamp"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_AVAILABLE_TIMESTAMP = "messaging.rocketmq.available_timestamp"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_ACCESS_KEY = "messaging.rocketmq.access_key"; + +const char* MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_MESSAGING_SYSTEM = "rocketmq"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_DESTINATION_KIND = "topic"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_MESSAGING_PROTOCOL = "RMQ-gRPC"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_MESSAGING_PROTOCOL_VERSION = "v1"; + +const char* MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_NORMAL_MESSAGE = "normal"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_FIFO_MESSAGE = "fifo"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_DELAY_MESSAGE = "delay"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_TRANSACTION_MESSAGE = "transaction"; + +const char* MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_SEND_OPERATION = "send"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_RECEIVE_OPERATION = "receive"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_PULL_OPERATION = "pull"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_AWAIT_OPERATION = "await"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_PROCESS_OPERATION = "process"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_ACK_OPERATION = "ack"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_NACK_OPERATION = "nack"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_COMMIT_OPERATION = "commit"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_ROLLBACK_OPERATION = "rollback"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_DLQ_OPERATION = "dlq"; + +// Messaging span attribute name list +const char* MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_SYSTEM = "messaging.system"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_DESTINATION = "messaging.destination"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_DESTINATION_KIND = "messaging.destination_kind"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_PROTOCOL = "messaging.protocol"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_PROTOCOL_VERSION = "messaging.protocol_version"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_URL = "messaging.url"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_ID = "messaging.message_id"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_PAYLOAD_SIZE_BYTES = "messaging.message_payload_size_bytes"; +const char* MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_OPERATION = "messaging.operation"; + +const char* MixAll::SPAN_ATTRIBUTE_VALUE_MESSAGING_SEND_OPERATION = "send"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_MESSAGING_RECEIVE_OPERATION = "receive"; +const char* MixAll::SPAN_ATTRIBUTE_VALUE_MESSAGING_PROCESS_OPERATION = "process"; + +const char* MixAll::SPAN_ATTRIBUTE_KEY_TRANSACTION_RESOLUTION = "commitAction"; + +// Span annotation +const char* MixAll::SPAN_ANNOTATION_AWAIT_CONSUMPTION = "__await_consumption"; +const char* MixAll::SPAN_ANNOTATION_MESSAGE_KEYS = "__message_keys"; +const char* MixAll::SPAN_ANNOTATION_ATTR_START_TIME = "__start_time"; + +bool MixAll::validate(const Message& message) { + if (message.topic().empty()) { + return false; + } + const std::string& topic = message.topic(); + // Topic should not start with "CID" or "GID" which are reserved prefix + if (absl::StartsWith(topic, "CID") || absl::StartsWith(topic, "GID")) { + return false; + } + + // Legal topic characters are a-z, A-Z, 0-9, hyphen('-') and underline('_') + if (!RE2::FullMatch(topic, TOPIC_REGEX)) { + return false; + } + + uint32_t body_length = message.body().length(); + if (!body_length || body_length > MAX_MESSAGE_BODY_SIZE) { + return false; + } + return true; +} + +uint32_t MixAll::random(uint32_t left, uint32_t right) { + static absl::BitGen gen; + return absl::Uniform(gen, left, right); +} + +bool MixAll::crc32(const std::string& data, std::string& digest) { + uLong crc = ::crc32(0L, reinterpret_cast(data.c_str()), data.length()); + uint32_t network_byte_order = htonl(crc); + digest = hex(&network_byte_order, sizeof(network_byte_order)); + return true; +} + +bool MixAll::md5(const std::string& data, std::string& digest) { + MD5_CTX ctx; + MD5_Init(&ctx); + MD5_Update(&ctx, data.data(), data.length()); + unsigned char md[MD5_DIGEST_LENGTH + 1]; + int success = MD5_Final(md, &ctx); + if (!success) { + return false; + } + digest.clear(); + digest.append(hex(md, MD5_DIGEST_LENGTH)); + return true; +} + +bool MixAll::sha1(const std::string& data, std::string& digest) { + unsigned char out[SHA_DIGEST_LENGTH]; + SHA_CTX ctx; + SHA1_Init(&ctx); + SHA1_Update(&ctx, data.data(), data.length()); + SHA1_Final(out, &ctx); + digest.clear(); + digest.append(hex(reinterpret_cast(out), SHA_DIGEST_LENGTH)); + return true; +} + +std::string MixAll::format(std::chrono::system_clock::time_point time_point) { + std::time_t creation_time_t = std::chrono::system_clock::to_time_t(time_point); + auto fraction = std::chrono::duration_cast(time_point.time_since_epoch()).count() % 1000; + char fmt_date_time[128]; + + /** + * TODO: std::localtime is not thread-safe, output, as a result, may be less reliable in highly contending + * scenario + */ + std::strftime(fmt_date_time, sizeof(fmt_date_time), "%Y-%m-%d %H:%M:%S", std::localtime(&creation_time_t)); + return fmt::format("{}.{}", fmt_date_time, fraction); +} + +std::string MixAll::hex(const void* data, std::size_t len) { + const char dict[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + std::string s; + const uint8_t* ptr = reinterpret_cast(data); + for (std::size_t i = 0; i < len; i++) { + unsigned char c = *(ptr + i); + s.append(&dict[(0xF0 & c) >> 4], 1); + s.append(&dict[(0x0F & c)], 1); + } + return s; +} + +bool MixAll::hexToBinary(const std::string& hex, std::vector& bin) { + // Length of valid Hex string should always be even. + if (hex.length() % 2) { + return false; + } + for (std::string::size_type i = 0; i < hex.length(); i += 2) { + char c1 = hex.at(i); + char c2 = hex.at(i + 1); + + uint8_t value = 0; + uint8_t tmp; + if (hexCharValue(c1, tmp)) { + value = tmp << 4; + } else { + return false; + } + + if (hexCharValue(c2, tmp)) { + value |= tmp; + bin.push_back(value); + } else { + return false; + } + } + return true; +} + +bool MixAll::hexCharValue(char c, uint8_t& value) { + if ('0' <= c && c <= '9') { + value = c - '0'; + return true; + } + + if ('a' <= c && c <= 'f') { + value = c - 'a' + 10; + return true; + } + + if ('A' <= c && c <= 'F') { + value = c - 'A' + 10; + return true; + } + + return false; +} + +bool MixAll::homeDirectory(std::string& home_dir) { +#ifndef _WIN32 + char* home = getenv(HOME_PROFILE_ENV_); + if (home) { + home_dir.append(home, strlen(home)); + return true; + } else { + struct passwd* pwd = getpwuid(getuid()); + if (pwd) { + home_dir.clear(); + home_dir.append(pwd->pw_dir, strlen(pwd->pw_dir)); + return true; + } + } + return false; +#else + char* home = getenv("USERPROFILE"); + if (home) { + home_dir.clear(); + home_dir.append(home, strlen(home)); + return true; + } + return false; +#endif +} + +bool MixAll::isIPv4(absl::string_view host) { + return RE2::FullMatch(re2::StringPiece(host.data(), host.length()), IP_REGEX); +} + +const char* MixAll::osName() { +#if INTPTR_MAX == INT32_MAX +#define BITS " 32-bit" +#elif INTPTR_MAX == INT64_MAX +#define BITS " 64-bit" +#else +#define BITS "" +#endif + +#if defined(_WIN32) || defined(_WIN64) + return "Windows" BITS; +#elif __APPLE__ || __MACH__ + return "Mac OSX" BITS; +#elif __linux__ + return "Linux" BITS; +#elif __FreeBSD__ + return "FreeBSD" BITS; +#elif __unix || __unix__ + return "Unix" BITS; +#else + return "Other" BITS; +#endif +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/Protocol.cpp b/src/main/cpp/base/Protocol.cpp new file mode 100644 index 000000000..91a643b3d --- /dev/null +++ b/src/main/cpp/base/Protocol.cpp @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Protocol.h" + +ROCKETMQ_NAMESPACE_BEGIN + +const char* protocolVersion() { + static const char* protocol_version = "v2"; + return protocol_version; +} + +bool writable(rmq::Permission p) { + switch (p) { + case rmq::Permission::WRITE: + case rmq::Permission::READ_WRITE: + return true; + default: { + return false; + } + } +} + +bool readable(rmq::Permission p) { + switch (p) { + case rmq::Permission::READ: + case rmq::Permission::READ_WRITE: + return true; + default: + return false; + } +} + +bool operator<(const rmq::Resource& lhs, const rmq::Resource& rhs) { + return lhs.resource_namespace() < rhs.resource_namespace() || lhs.name() < rhs.name(); +} + +bool operator==(const rmq::Resource& lhs, const rmq::Resource& rhs) { + return lhs.resource_namespace() == rhs.resource_namespace() && lhs.name() == rhs.name(); +} + +bool operator<(const rmq::Broker& lhs, const rmq::Broker& rhs) { + return lhs.name() < rhs.name() || lhs.id() < rhs.id(); +} + +bool operator==(const rmq::Broker& lhs, const rmq::Broker& rhs) { + return lhs.name() == rhs.name() && lhs.id() == rhs.id(); +} + +bool operator<(const rmq::MessageQueue& lhs, const rmq::MessageQueue& rhs) { + return lhs.topic() < rhs.topic() || lhs.id() < rhs.id() || lhs.broker() < rhs.broker() || + lhs.permission() < rhs.permission(); +} + +bool operator==(const rmq::MessageQueue& lhs, const rmq::MessageQueue& rhs) { + return lhs.topic() == rhs.topic() && lhs.id() == rhs.id() && lhs.broker() == rhs.broker() && + lhs.permission() == rhs.permission(); +} + +std::string simpleNameOf(const rmq::MessageQueue& m) { + return fmt::format("{}{}-{}-{}", m.topic().resource_namespace(), m.topic().name(), m.id(), m.broker().name()); +} + +bool operator==(const std::vector& lhs, const std::vector& rhs) { + if (lhs.size() != rhs.size()) { + return false; + } + + for (std::size_t i = 0; i < lhs.size(); i++) { + if (lhs[i] == rhs[i]) { + continue; + } + return false; + } + + return true; +} + +bool operator!=(const std::vector& lhs, const std::vector& rhs) { + return !(lhs == rhs); +} + +std::string urlOf(const rmq::MessageQueue& message_queue) { + const auto& endpoints = message_queue.broker().endpoints(); + const auto& addresses = endpoints.addresses(); + switch (endpoints.scheme()) { + case rmq::AddressScheme::DOMAIN_NAME: { + assert(addresses.size() == 1); + auto first = addresses.begin(); + return fmt::format("dns:{}:{}", first->host(), first->port()); + } + case rmq::AddressScheme::IPv4: { + assert(!addresses.empty()); + auto it = addresses.cbegin(); + std::string result = fmt::format("ipv4:{}:{}", it->host(), it->port()); + for (++it; it != addresses.cend(); ++it) { + result.append(fmt::format(",{}:{}", it->host(), it->port())); + } + return result; + } + case rmq::AddressScheme::IPv6: { + assert(!addresses.empty()); + auto it = addresses.cbegin(); + std::string result = fmt::format("ipv6:{}:{}", it->host(), it->port()); + for (++it; it != addresses.cend(); ++it) { + result.append(fmt::format(",{}:{}", it->host(), it->port())); + } + return result; + } + default: { + break; + } + } + return {}; +} + +bool operator<(const rmq::Assignment& lhs, const rmq::Assignment& rhs) { + return lhs.message_queue() < rhs.message_queue(); +} + +bool operator==(const rmq::Assignment& lhs, const rmq::Assignment& rhs) { + return lhs.message_queue() == rhs.message_queue(); +} + +bool operator==(const std::vector& lhs, const std::vector& rhs) { + if (lhs.size() != rhs.size()) { + return false; + } + + for (std::size_t i = 0; i < lhs.size(); i++) { + if (lhs[i] == rhs[i]) { + continue; + } + return false; + } + return true; +} + +ROCKETMQ_NAMESPACE_END diff --git a/src/main/cpp/base/RateLimiter.cpp b/src/main/cpp/base/RateLimiter.cpp new file mode 100644 index 000000000..1a8247ec3 --- /dev/null +++ b/src/main/cpp/base/RateLimiter.cpp @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "RateLimiter.h" + +ROCKETMQ_NAMESPACE_BEGIN + +RateLimiterObserver::RateLimiterObserver() : stopped_(false) { + tick_thread_ = std::thread([this] { + while (!stopped_.load(std::memory_order_relaxed)) { + { + std::lock_guard lk(members_mtx_); + for (auto it = members_.begin(); it != members_.end();) { + std::shared_ptr tick = it->lock(); + if (!tick) { + it = members_.erase(it); + continue; + } else { + ++it; + } + tick->tick(); + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + }); +} + +void RateLimiterObserver::subscribe(const std::shared_ptr& tick) { + std::lock_guard lk(members_mtx_); + members_.emplace_back(tick); +} + +void RateLimiterObserver::stop() { + stopped_.store(true, std::memory_order_relaxed); + if (tick_thread_.joinable()) { + tick_thread_.join(); + } +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/ThreadPoolImpl.cpp b/src/main/cpp/base/ThreadPoolImpl.cpp new file mode 100644 index 000000000..3befa9c35 --- /dev/null +++ b/src/main/cpp/base/ThreadPoolImpl.cpp @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ThreadPoolImpl.h" +#include "absl/memory/memory.h" +#include "asio/executor_work_guard.hpp" +#include "asio/io_context.hpp" +#include "asio/post.hpp" +#include "rocketmq/RocketMQ.h" +#include "rocketmq/State.h" +#include "spdlog/spdlog.h" +#include +#include +#include +#include + +ROCKETMQ_NAMESPACE_BEGIN + +ThreadPoolImpl::ThreadPoolImpl(std::uint16_t workers) + : work_guard_( + absl::make_unique>(context_.get_executor())), + workers_(workers) { +} + +void ThreadPoolImpl::start() { + for (std::uint16_t i = 0; i < workers_; i++) { + std::thread worker([this]() { + State expected = State::CREATED; + if (state_.compare_exchange_strong(expected, State::STARTED, std::memory_order_relaxed)) { + absl::MutexLock lk(&start_mtx_); + start_cv_.SignalAll(); + } + + while (true) { +#ifdef __EXCEPTIONS + try { +#endif + std::error_code ec; + context_.run(ec); + if (ec) { + SPDLOG_WARN("Error raised from ThreadPool: {}", ec.message()); + } +#ifdef __EXCEPTIONS + } catch (std::exception& e) { + SPDLOG_WARN("Exception raised from ThreadPool: {}", e.what()); + } +#endif + if (State::STARTED != state_.load(std::memory_order_relaxed)) { + SPDLOG_INFO("A thread-pool worker quit"); + break; + } + } + }); + threads_.emplace_back(std::move(worker)); + } + + { + absl::MutexLock lk(&start_mtx_); + if (State::CREATED == state_.load(std::memory_order_relaxed)) { + start_cv_.Wait(&start_mtx_); + } + } +} + +void ThreadPoolImpl::shutdown() { + State expected = State::STARTED; + if (state_.compare_exchange_strong(expected, State::STOPPING, std::memory_order_relaxed)) { + work_guard_->reset(); + context_.stop(); + for (auto& thread : threads_) { + if (thread.joinable()) { + thread.join(); + } + } + state_.store(State::STOPPED, std::memory_order_relaxed); + } +} + +void ThreadPoolImpl::submit(std::function task) { + if (State::STARTED == state_.load(std::memory_order_relaxed)) { + asio::post(context_, task); + } else { + SPDLOG_WARN("State of ThreadPool is not STARTED"); + } +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/TopAddressing.cpp b/src/main/cpp/base/TopAddressing.cpp new file mode 100644 index 000000000..dd45e67fa --- /dev/null +++ b/src/main/cpp/base/TopAddressing.cpp @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "TopAddressing.h" + +#include "HttpClientImpl.h" +#include "absl/memory/memory.h" +#include "absl/strings/match.h" +#include "absl/strings/str_split.h" +#include "spdlog/spdlog.h" +#include + +ROCKETMQ_NAMESPACE_BEGIN + +TopAddressing::TopAddressing() : TopAddressing("jmenv.tbsite.net", 8080, "/rocketmq/nsaddr") { +} + +TopAddressing::TopAddressing(std::string host, int port, std::string path) + : host_(std::move(host)), port_(port), path_(std::move(path)), http_client_(absl::make_unique()) { + http_client_->start(); +} + +TopAddressing::~TopAddressing() { + http_client_->shutdown(); +} + +void TopAddressing::fetchNameServerAddresses(const std::function&)>& cb) { + SPDLOG_DEBUG("Prepare to send HTTP request, timeout=3s"); + std::string base(fmt::format("http://{}:{}", host_, port_)); + // Append host info if necessary. + std::string query_string(path_); + + if (absl::StrContains(query_string, "?")) { + query_string.append("&"); + } else { + query_string.append("?"); + } + + if (host_info_.hasHostInfo()) { + query_string.append(host_info_.queryString()); + } else { + query_string.append("nofix=1"); + } + + auto callback = [cb](int code, const std::multimap& metadata, const std::string& body) { + SPDLOG_DEBUG("Receive HTTP response. Code: {}, body: {}", code, body); + if (static_cast(HttpStatus::OK) == code) { + cb(true, absl::StrSplit(body, ';')); + } else { + std::vector name_server_list; + cb(false, name_server_list); + } + }; + + http_client_->get(HttpProtocol::HTTP, host_, port_, query_string, callback); +} + +void TopAddressing::injectHttpClient(std::unique_ptr http_client) { + http_client_->shutdown(); + http_client_.swap(http_client); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/Tracing.cpp b/src/main/cpp/base/Tracing.cpp new file mode 100644 index 000000000..9eb733577 --- /dev/null +++ b/src/main/cpp/base/Tracing.cpp @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "rocketmq/Tracing.h" + +ROCKETMQ_NAMESPACE_BEGIN + +opencensus::trace::Sampler* traceSampler() { + static opencensus::trace::NeverSampler sampler; + return &sampler; +} + +ROCKETMQ_NAMESPACE_END diff --git a/src/main/cpp/base/UniqueIdGenerator.cpp b/src/main/cpp/base/UniqueIdGenerator.cpp new file mode 100644 index 000000000..aab5b146d --- /dev/null +++ b/src/main/cpp/base/UniqueIdGenerator.cpp @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "UniqueIdGenerator.h" +#include "LoggerImpl.h" +#include "MixAll.h" +#include "UtilAll.h" +#include "absl/base/internal/endian.h" +#include + +#ifdef _WIN32 +#include +#endif + +ROCKETMQ_NAMESPACE_BEGIN + +const uint8_t UniqueIdGenerator::VERSION = 1; + +UniqueIdGenerator::UniqueIdGenerator() + : prefix_(), since_custom_epoch_(std::chrono::system_clock::now() - customEpoch()), + start_time_point_(std::chrono::steady_clock::now()), seconds_(deltaSeconds()), sequence_(0) { + std::vector mac_address; + if (UtilAll::macAddress(mac_address)) { + memcpy(prefix_.data(), mac_address.data(), mac_address.size()); + } else { + SPDLOG_WARN("Failed to get network interface MAC address"); + } + +#ifdef _WIN32 + int pid = _getpid(); +#else + pid_t pid = getpid(); +#endif + + uint32_t big_endian_pid = absl::big_endian::FromHost32(pid); + // Copy the lower 2 bytes + memcpy(prefix_.data() + 6, reinterpret_cast(&big_endian_pid) + 2, sizeof(uint16_t)); +} + +UniqueIdGenerator& UniqueIdGenerator::instance() { + static UniqueIdGenerator generator; + return generator; +} + +std::string UniqueIdGenerator::next() { + Slot slot = {}; + { + absl::MutexLock lk(&mtx_); + uint32_t delta = deltaSeconds(); + if (seconds_ != delta) { + seconds_ = delta; + sequence_ = 0; + SPDLOG_DEBUG("Second: {} and sequence: {}", seconds_, sequence_); + } else { + sequence_++; + } + slot.seconds = seconds_; + slot.sequence = sequence_; + } + std::array raw{}; + raw[0] = VERSION; + memcpy(raw.data() + sizeof(VERSION), prefix_.data(), prefix_.size()); + memcpy(raw.data() + sizeof(VERSION) + prefix_.size(), &slot, sizeof(slot)); + return MixAll::hex(raw.data(), raw.size()); +} + +std::chrono::system_clock::time_point UniqueIdGenerator::customEpoch() { + return absl::ToChronoTime(absl::FromDateTime(2021, 1, 1, 0, 0, 0, absl::UTCTimeZone())); +} + +uint32_t UniqueIdGenerator::deltaSeconds() { + return std::chrono::duration_cast((std::chrono::steady_clock::now() - start_time_point_) + + since_custom_epoch_) + .count(); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/UtilAll.cpp b/src/main/cpp/base/UtilAll.cpp new file mode 100644 index 000000000..892dc87c2 --- /dev/null +++ b/src/main/cpp/base/UtilAll.cpp @@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "UtilAll.h" + +#include "LoggerImpl.h" +#include "zlib.h" +#include + +#if defined(__APPLE__) +#include +#define AF_FAMILY AF_LINK +#elif defined(__linux__) +#include +#include +#include +#define AF_FAMILY AF_PACKET +#elif defined(_WIN32) +#include +#include +#pragma comment(lib, "iphlpapi.lib") +#endif + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#endif + +#include "asio.hpp" + +ROCKETMQ_NAMESPACE_BEGIN + +std::string UtilAll::hostname() { + return asio::ip::host_name(); +} + +bool UtilAll::macAddress(std::vector& mac) { + static std::vector cache; + static bool mac_cached = false; + + if (mac_cached) { + mac = cache; + return true; + } + +#ifndef _WIN32 + struct ifaddrs *head = nullptr, *node; + if (getifaddrs(&head)) { + return false; + } + + for (node = head; node; node = node->ifa_next) { + if (node->ifa_addr->sa_family == AF_FAMILY) { +#if defined(__APPLE__) + auto* ptr = reinterpret_cast(LLADDR(reinterpret_cast(node->ifa_addr))); +#elif defined(__linux__) + auto* ptr = reinterpret_cast(reinterpret_cast(node->ifa_addr)->sll_addr); +#endif + bool all_zero = true; + for (int i = 0; i < 6; i++) { + if (*(ptr + i) != 0) { + all_zero = false; + break; + } + } + if (all_zero) { + SPDLOG_TRACE("Skip MAC address of network interface {}", node->ifa_name); + continue; + } + SPDLOG_DEBUG("Use MAC address of network interface {}", node->ifa_name); + // MAC address has 48 bits + cache.resize(6); + memcpy(cache.data(), ptr, 6); + mac_cached = true; + mac = cache; + break; + } + } + freeifaddrs(head); + return true; +#else + PIP_ADAPTER_INFO adaptor_info; + DWORD buf_len = sizeof(IP_ADAPTER_INFO); + char mac_address[18]; + adaptor_info = (IP_ADAPTER_INFO*)malloc(buf_len); + if (!adaptor_info) { + // TODO: running out of memroy + } + + if (GetAdaptersInfo(adaptor_info, &buf_len) == NO_ERROR) { + PIP_ADAPTER_INFO item = adaptor_info; + do { + bool all_zero = true; + for (auto& b : item->Address) { + if (b != 0) { + all_zero = false; + break; + } + } + if (!all_zero) { + cache.resize(6); + memcpy(cache.data(), item->Address, 6); + mac_cached = true; + mac = cache; + break; + } + item = item->Next; + } while (item); + } else { + free(adaptor_info); + } +#endif +} + +bool UtilAll::compress(const std::string& src, std::string& dst) { + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + stream.next_in = reinterpret_cast(const_cast(src.c_str())); + stream.avail_in = src.length(); + + deflateInit(&stream, Z_DEFAULT_COMPRESSION); + uint32_t bound = deflateBound(&stream, src.length()); + std::vector buffer(bound); + stream.next_out = buffer.data(); + stream.avail_out = bound; + + int status = deflate(&stream, Z_FINISH); + + // zlib is unexpected wrong. + if (Z_STREAM_END != status) { + deflateEnd(&stream); + return false; + } + + dst.reserve(stream.total_out); + assert(stream.total_out == bound - stream.avail_out); + std::copy(buffer.data(), buffer.data() + stream.total_out, std::back_inserter(dst)); + deflateEnd(&stream); + return true; +} + +bool UtilAll::uncompress(const std::string& src, std::string& dst) { + int status; + uint32_t buffer_length = 4096; + std::vector buffer(buffer_length); + z_stream stream; + + // Use default malloc / free allocator. + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + stream.next_in = reinterpret_cast(const_cast(src.c_str())); + stream.avail_in = src.length(); + + inflateInit(&stream); + stream.next_out = buffer.data(); + stream.avail_out = buffer_length; + + while (true) { + status = inflate(&stream, Z_SYNC_FLUSH); + + if (Z_STREAM_ERROR == status) { + return false; + } + std::copy(buffer.data(), buffer.data() + buffer_length - stream.avail_out, std::back_inserter(dst)); + stream.avail_out = buffer_length; + stream.next_out = buffer.data(); + + // inflation completed OK + if (Z_STREAM_END == status) { + inflateEnd(&stream); + return true; + } + + // inflation made some progress + if (Z_OK == status) { + continue; + } + + // Something is wrong + inflateEnd(&stream); + return false; + } +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/include/Histogram.h b/src/main/cpp/base/include/Histogram.h new file mode 100644 index 000000000..89b7f3fcc --- /dev/null +++ b/src/main/cpp/base/include/Histogram.h @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include +#include + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class Histogram { +public: + Histogram(std::string title, int32_t capacity) : title_(std::move(title)), capacity_(capacity) { + data_.reserve(capacity); + for (int i = 0; i < capacity_; ++i) { + data_.push_back(std::unique_ptr>(new std::atomic(0))); + } + } + + void countIn(int grade) { + if (grade < 0) { + return; + } + + if (grade >= capacity_) { + data_[capacity_ - 1]->fetch_add(1, std::memory_order_relaxed); + return; + } + + data_[grade]->fetch_add(1, std::memory_order_relaxed); + } + + /** + * Change labels of histogram duration the initialization phase only. + * @return + */ + std::vector& labels() { + return labels_; + } + + void reportAndReset(std::string& result) { + assert(labels_.size() == static_cast::size_type>(capacity_)); + std::vector values; + values.reserve(capacity_); + for (auto& item : data_) { + int value = item->load(std::memory_order_relaxed); + values.push_back(value); + item->fetch_sub(value, std::memory_order_relaxed); + } + result.clear(); + result.append(title_).append(":"); + for (std::vector::size_type i = 0; i < labels_.size(); ++i) { + if (i) { + result.append(", "); + } + result.append(labels_[i]).append(std::to_string(values[i])); + } + } + +private: + std::string title_; + std::vector>> data_; + int32_t capacity_; + std::vector labels_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/include/HostInfo.h b/src/main/cpp/base/include/HostInfo.h new file mode 100644 index 000000000..1b2a543c9 --- /dev/null +++ b/src/main/cpp/base/include/HostInfo.h @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN +struct HostInfo { + std::string site_; + std::string unit_; + std::string app_; + std::string stage_; + + explicit HostInfo(); + + bool hasHostInfo() const; + + std::string queryString() const; + + static const char* ENV_LABEL_SITE; + static const char* ENV_LABEL_UNIT; + static const char* ENV_LABEL_APP; + static const char* ENV_LABEL_STAGE; + +private: + static void getEnv(const char* env, std::string& holder); + + static void appendLabel(std::string& query_string, const char* key, const std::string& value); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/test/src/protocol/KVTableTest.cpp b/src/main/cpp/base/include/HttpClient.h similarity index 57% rename from test/src/protocol/KVTableTest.cpp rename to src/main/cpp/base/include/HttpClient.h index b6fd50493..77f695516 100644 --- a/test/src/protocol/KVTableTest.cpp +++ b/src/main/cpp/base/include/HttpClient.h @@ -14,38 +14,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once + +#include +#include #include #include -#include "gmock/gmock.h" -#include "gtest/gtest.h" +#include "rocketmq/RocketMQ.h" -#include "KVTable.h" +ROCKETMQ_NAMESPACE_BEGIN -using std::map; -using std::string; +enum class HttpProtocol : int8_t +{ + HTTP = 1, + HTTPS = 2, +}; -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; +enum class HttpStatus : int +{ + OK = 200, + INTERNAL = 500, +}; -using rocketmq::KVTable; +class HttpClient { +public: + virtual ~HttpClient() = default; -TEST(KVTable, init) { - KVTable table; + virtual void start() = 0; - EXPECT_EQ(table.getTable().size(), 0); + virtual void shutdown() = 0; - map maps; - maps["string"] = "string"; - table.setTable(maps); - EXPECT_EQ(table.getTable().size(), 1); -} + virtual void + get(HttpProtocol protocol, const std::string& host, std::uint16_t port, const std::string& path, + const std::function&, const std::string&)>& cb) = 0; +}; -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "KVTable.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/libs/signature/include/base64.h b/src/main/cpp/base/include/HttpClientImpl.h similarity index 51% rename from libs/signature/include/base64.h rename to src/main/cpp/base/include/HttpClientImpl.h index 9e2d1331a..e54bb4372 100644 --- a/libs/signature/include/base64.h +++ b/src/main/cpp/base/include/HttpClientImpl.h @@ -14,36 +14,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once -#ifndef BASE64_H -#define BASE64_H +#include "absl/base/thread_annotations.h" +#include "absl/container/flat_hash_map.h" +#include "absl/synchronization/mutex.h" +#include "httplib.h" -/* Get size_t. */ -#include +#include "HttpClient.h" +#include "rocketmq/RocketMQ.h" -/* Get bool. */ -#include +ROCKETMQ_NAMESPACE_BEGIN -#ifdef __cplusplus -namespace rocketmqSignature { -#endif +class HttpClientImpl : public HttpClient { +public: + ~HttpClientImpl() override = default; -/* This uses that the expression (n+(k-1))/k means the smallest - integer >= n/k, i.e., the ceiling of n/k. */ -#define BASE64_LENGTH(inlen) ((((inlen) + 2) / 3) * 4) + void start() override; -extern bool isbase64(char ch); + void shutdown() override; -extern void base64_encode(const char* in, size_t inlen, char* out, size_t outlen); + void + get(HttpProtocol protocol, const std::string& host, std::uint16_t port, const std::string& path, + const std::function&, const std::string&)>& cb) override; -extern size_t base64_encode_alloc(const char* in, size_t inlen, char** out); +private: + absl::flat_hash_map> clients_ GUARDED_BY(clients_mtx_); + absl::Mutex clients_mtx_; +}; -extern bool base64_decode(const char* in, size_t inlen, char* out, size_t* outlen); - -extern bool base64_decode_alloc(const char* in, size_t inlen, char** out, size_t* outlen); - -#ifdef __cplusplus -} -#endif - -#endif /* BASE64_H */ +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/include/InvocationContext.h b/src/main/cpp/base/include/InvocationContext.h new file mode 100644 index 000000000..910a65dcf --- /dev/null +++ b/src/main/cpp/base/include/InvocationContext.h @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include + +#include "absl/synchronization/mutex.h" +#include "absl/time/time.h" +#include "grpcpp/client_context.h" +#include "grpcpp/grpcpp.h" +#include "grpcpp/impl/codegen/async_stream.h" +#include "grpcpp/impl/codegen/async_unary_call.h" + +#include "LoggerImpl.h" +#include "MetadataConstants.h" +#include "UniqueIdGenerator.h" + +ROCKETMQ_NAMESPACE_BEGIN + +/** + * Note: + * Before modifying anything in this file, ensure you have read all comments in completion_queue_impl.h and + * async_stream.h + */ +struct BaseInvocationContext { + BaseInvocationContext() : request_id_(UniqueIdGenerator::instance().next()) { + context.AddMetadata(MetadataConstants::REQUEST_ID_KEY, request_id_); + } + + virtual ~BaseInvocationContext() = default; + virtual void onCompletion(bool ok) = 0; + std::string request_id_; + std::string remote_address; + grpc::ClientContext context; + grpc::Status status; + std::string task_name; + absl::Time created_time{absl::Now()}; + std::chrono::steady_clock::time_point start_time{std::chrono::steady_clock::now()}; +}; + +template +struct InvocationContext : public BaseInvocationContext { + + void onCompletion(bool ok) override { + auto elapsed = + std::chrono::duration_cast(std::chrono::steady_clock::now() - start_time).count(); + SPDLOG_DEBUG("RPC[{}] costs {}ms", task_name, elapsed); + /// Client-side Read, Server-side Read, Client-side + /// RecvInitialMetadata (which is typically included in Read if not + /// done explicitly): ok indicates whether there is a valid message + /// that got read. If not, you know that there are certainly no more + /// messages that can ever be read from this stream. For the client-side + /// operations, this only happens because the call is dead. For the + /// server-side operation, though, this could happen because the client + /// has done a WritesDone already. + if (!ok) { + SPDLOG_WARN("One async call is already dead"); + if (callback) { + callback(this); + } + delete this; + return; + } + + if (!status.ok() && grpc::StatusCode::DEADLINE_EXCEEDED == status.error_code()) { + auto diff = + std::chrono::duration_cast(std::chrono::system_clock::now() - context.deadline()) + .count(); + SPDLOG_WARN("Asynchronous RPC[{}.{}] timed out, elapsing {}ms, deadline-over-due: {}ms", + absl::FormatTime(created_time, absl::UTCTimeZone()), elapsed, diff); + } + + try { + if (callback) { + callback(this); + } + } catch (const std::exception& e) { + SPDLOG_WARN("Unexpected error while invoking user-defined callback. Reason: {}", e.what()); + } catch (...) { + SPDLOG_WARN("Unexpected error while invoking user-defined callback"); + } + delete this; + } + + T response; + std::function*)> callback; + std::unique_ptr> response_reader; +}; +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/common/sync_http_client.h b/src/main/cpp/base/include/MessageExt.h similarity index 75% rename from src/common/sync_http_client.h rename to src/main/cpp/base/include/MessageExt.h index 1bf55fa18..31106bba5 100644 --- a/src/common/sync_http_client.h +++ b/src/main/cpp/base/include/MessageExt.h @@ -14,16 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef ROCKETMQ_CLIENT4CPP__SYNC_HTTP_CLIENT_H_ -#define ROCKETMQ_CLIENT4CPP__SYNC_HTTP_CLIENT_H_ +#pragma once +#include +#include +#include #include -namespace rocketmq { -class Url; +#include "Protocol.h" +#include "rocketmq/Message.h" -extern bool SyncfetchNsAddr(const Url& url_s, std::string& body); +ROCKETMQ_NAMESPACE_BEGIN -} // namespace rocketmq +rmq::MessageType typeOf(const Message& message); -#endif // ROCKETMQ_CLIENT4CPP__SYNC_HTTP_CLIENT_H_ +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/include/MetadataConstants.h b/src/main/cpp/base/include/MetadataConstants.h new file mode 100644 index 000000000..a02fc1919 --- /dev/null +++ b/src/main/cpp/base/include/MetadataConstants.h @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class MetadataConstants { +public: + static const char* REQUEST_ID_KEY; + static const char* TENANT_ID_KEY; + static const char* CLIENT_ID_KEY; + static const char* NAMESPACE_KEY; + static const char* AUTHORIZATION; + static const char* STS_SESSION_TOKEN; + static const char* DATE_TIME_KEY; + static const char* ALGORITHM_KEY; + static const char* CREDENTIAL_KEY; + static const char* SIGNED_HEADERS_KEY; + static const char* SIGNATURE_KEY; + static const char* DATE_TIME_FORMAT; + static const char* LANGUAGE_KEY; + static const char* CLIENT_VERSION_KEY; + static const char* PROTOCOL_VERSION_KEY; + static const char* CLIENT_VERSION; + static const char* SERVICE_NAME; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/include/MixAll.h b/src/main/cpp/base/include/MixAll.h new file mode 100644 index 000000000..148373708 --- /dev/null +++ b/src/main/cpp/base/include/MixAll.h @@ -0,0 +1,173 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "re2/re2.h" + +#include "rocketmq/Message.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class MixAll { +public: + static const int32_t MASTER_BROKER_ID; + static const int32_t DEFAULT_RECEIVE_MESSAGE_BATCH_SIZE; + static const uint32_t MAX_MESSAGE_BODY_SIZE; + static const uint32_t MAX_CACHED_MESSAGE_COUNT; + static const uint32_t DEFAULT_CACHED_MESSAGE_COUNT; + static const uint64_t DEFAULT_CACHED_MESSAGE_MEMORY; + static const uint32_t DEFAULT_CONSUME_THREAD_POOL_SIZE; + static const uint32_t DEFAULT_CONSUME_MESSAGE_BATCH_SIZE; + static const int32_t DEFAULT_MAX_DELIVERY_ATTEMPTS; + + static const RE2 TOPIC_REGEX; + static const RE2 IP_REGEX; + + /** + * The amount of time required before a popped message is eligible to be consumed again. By default, 30s. + */ + static const std::chrono::duration DEFAULT_INVISIBLE_TIME_; + + static const std::chrono::duration PROCESS_QUEUE_EXPIRATION_THRESHOLD_; + + static const std::chrono::milliseconds DefaultReceiveMessageTimeout; + + static const std::size_t MAX_SEND_MESSAGE_ATTEMPT_TIMES_; + + static const std::string PROPERTY_TRANSACTION_PREPARED_; + + static const std::string DEFAULT_LOAD_BALANCER_STRATEGY_NAME_; + + static const uint32_t DEFAULT_COMPRESS_BODY_THRESHOLD_; + + static const char* HOME_PROFILE_ENV_; + + static const char* MESSAGE_KEY_SEPARATOR; + + static const char* OTLP_NAME_VALUE; + + static const char* TRACE_RESOURCE_ATTRIBUTE_KEY_TELEMETRY_SDK_LANGUAGE; + static const char* TRACE_RESOURCE_ATTRIBUTE_VALUE_TELEMETRY_SDK_LANGUAGE; + + static const char* TRACE_RESOURCE_ATTRIBUTE_KEY_HOST_NAME; + static const char* TRACE_RESOURCE_ATTRIBUTE_KEY_SERVICE_NAME; + static const char* TRACE_RESOURCE_ATTRIBUTE_VALUE_SERVICE_NAME; + + // RocketMQ span attribute name list + static const char* SPAN_ATTRIBUTE_KEY_ROCKETMQ_OPERATION; + static const char* SPAN_ATTRIBUTE_KEY_ROCKETMQ_NAMESPACE; + static const char* SPAN_ATTRIBUTE_KEY_ROCKETMQ_TAG; + static const char* SPAN_ATTRIBUTE_KEY_ROCKETMQ_KEYS; + static const char* SPAN_ATTRIBUTE_KEY_ROCKETMQ_CLIENT_ID; + static const char* SPAN_ATTRIBUTE_KEY_ROCKETMQ_MESSAGE_TYPE; + static const char* SPAN_ATTRIBUTE_KEY_ROCKETMQ_CLIENT_GROUP; + static const char* SPAN_ATTRIBUTE_KEY_ROCKETMQ_ATTEMPT; + static const char* SPAN_ATTRIBUTE_KEY_ROCKETMQ_BATCH_SIZE; + static const char* SPAN_ATTRIBUTE_KEY_ROCKETMQ_DELIVERY_TIMESTAMP; + static const char* SPAN_ATTRIBUTE_KEY_ROCKETMQ_AVAILABLE_TIMESTAMP; + static const char* SPAN_ATTRIBUTE_KEY_ROCKETMQ_ACCESS_KEY; + + static const char* SPAN_ATTRIBUTE_VALUE_ROCKETMQ_MESSAGING_SYSTEM; + static const char* SPAN_ATTRIBUTE_VALUE_DESTINATION_KIND; + static const char* SPAN_ATTRIBUTE_VALUE_MESSAGING_PROTOCOL; + static const char* SPAN_ATTRIBUTE_VALUE_MESSAGING_PROTOCOL_VERSION; + + static const char* SPAN_ATTRIBUTE_VALUE_ROCKETMQ_NORMAL_MESSAGE; + static const char* SPAN_ATTRIBUTE_VALUE_ROCKETMQ_FIFO_MESSAGE; + static const char* SPAN_ATTRIBUTE_VALUE_ROCKETMQ_DELAY_MESSAGE; + static const char* SPAN_ATTRIBUTE_VALUE_ROCKETMQ_TRANSACTION_MESSAGE; + + static const char* SPAN_ATTRIBUTE_VALUE_ROCKETMQ_SEND_OPERATION; + static const char* SPAN_ATTRIBUTE_VALUE_ROCKETMQ_RECEIVE_OPERATION; + static const char* SPAN_ATTRIBUTE_VALUE_ROCKETMQ_PULL_OPERATION; + static const char* SPAN_ATTRIBUTE_VALUE_ROCKETMQ_AWAIT_OPERATION; + static const char* SPAN_ATTRIBUTE_VALUE_ROCKETMQ_PROCESS_OPERATION; + static const char* SPAN_ATTRIBUTE_VALUE_ROCKETMQ_ACK_OPERATION; + static const char* SPAN_ATTRIBUTE_VALUE_ROCKETMQ_NACK_OPERATION; + static const char* SPAN_ATTRIBUTE_VALUE_ROCKETMQ_COMMIT_OPERATION; + static const char* SPAN_ATTRIBUTE_VALUE_ROCKETMQ_ROLLBACK_OPERATION; + static const char* SPAN_ATTRIBUTE_VALUE_ROCKETMQ_DLQ_OPERATION; + + // Messaging attribute name list + static const char* SPAN_ATTRIBUTE_KEY_MESSAGING_SYSTEM; + static const char* SPAN_ATTRIBUTE_KEY_MESSAGING_DESTINATION; + static const char* SPAN_ATTRIBUTE_KEY_MESSAGING_DESTINATION_KIND; + static const char* SPAN_ATTRIBUTE_KEY_MESSAGING_PROTOCOL; + static const char* SPAN_ATTRIBUTE_KEY_MESSAGING_PROTOCOL_VERSION; + static const char* SPAN_ATTRIBUTE_KEY_MESSAGING_URL; + static const char* SPAN_ATTRIBUTE_KEY_MESSAGING_ID; + static const char* SPAN_ATTRIBUTE_KEY_MESSAGING_PAYLOAD_SIZE_BYTES; + static const char* SPAN_ATTRIBUTE_KEY_MESSAGING_OPERATION; + + static const char* SPAN_ATTRIBUTE_VALUE_MESSAGING_SEND_OPERATION; + static const char* SPAN_ATTRIBUTE_VALUE_MESSAGING_RECEIVE_OPERATION; + static const char* SPAN_ATTRIBUTE_VALUE_MESSAGING_PROCESS_OPERATION; + + static const char* SPAN_ATTRIBUTE_KEY_TRANSACTION_RESOLUTION; + + // Tracing annotation + static const char* SPAN_ANNOTATION_AWAIT_CONSUMPTION; + static const char* SPAN_ANNOTATION_MESSAGE_KEYS; + static const char* SPAN_ANNOTATION_ATTR_START_TIME; + + template + static int64_t millisecondsOf(std::chrono::duration duration) { + return std::chrono::duration_cast(duration).count(); + } + + template + static int64_t microsecondsOf(std::chrono::duration duration) { + return std::chrono::duration_cast(duration).count(); + } + + /** + * Validate message is legal. Aka, topic + * @param message + * @return + */ + static bool validate(const Message& message); + + static uint32_t random(uint32_t left, uint32_t right); + + static bool crc32(const std::string& data, std::string& digest); + + static bool md5(const std::string& data, std::string& digest); + + static bool sha1(const std::string& data, std::string& digest); + + static std::string format(std::chrono::system_clock::time_point time_point); + + static std::string hex(const void* data, std::size_t len); + + static bool hexToBinary(const std::string& hex, std::vector& bin); + + static bool homeDirectory(std::string& home); + + static bool isIPv4(absl::string_view host); + + static const char* osName(); + +private: + static bool hexCharValue(char c, uint8_t& value); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/include/Protocol.h b/src/main/cpp/base/include/Protocol.h new file mode 100644 index 000000000..5a8e671f6 --- /dev/null +++ b/src/main/cpp/base/include/Protocol.h @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "absl/hash/hash.h" +#include "fmt/format.h" + +#include "apache/rocketmq/v2/definition.grpc.pb.h" +#include "apache/rocketmq/v2/definition.pb.h" +#include "apache/rocketmq/v2/service.grpc.pb.h" +#include "apache/rocketmq/v2/service.pb.h" + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +namespace rmq = apache::rocketmq::v2; + +using ChangeInvisibleDurationRequest = rmq::ChangeInvisibleDurationRequest; +using ChangeInvisibleDurationResponse = rmq::ChangeInvisibleDurationResponse; +using QueryRouteRequest = rmq::QueryRouteRequest; +using QueryRouteResponse = rmq::QueryRouteResponse; +using SendMessageRequest = rmq::SendMessageRequest; +using SendMessageResponse = rmq::SendMessageResponse; +using QueryAssignmentRequest = rmq::QueryAssignmentRequest; +using QueryAssignmentResponse = rmq::QueryAssignmentResponse; +using ReceiveMessageRequest = rmq::ReceiveMessageRequest; +using ReceiveMessageResponse = rmq::ReceiveMessageResponse; +using AckMessageRequest = rmq::AckMessageRequest; +using AckMessageResponse = rmq::AckMessageResponse; +using HeartbeatRequest = rmq::HeartbeatRequest; +using HeartbeatResponse = rmq::HeartbeatResponse; +using EndTransactionRequest = rmq::EndTransactionRequest; +using EndTransactionResponse = rmq::EndTransactionResponse; +using RecoverOrphanedTransactionCommand = rmq::RecoverOrphanedTransactionCommand; +using PrintThreadStackTraceCommand = rmq::PrintThreadStackTraceCommand; +using ThreadStackTrace = rmq::ThreadStackTrace; +using VerifyMessageCommand = rmq::VerifyMessageCommand; +using VerifyMessageResult = rmq::VerifyMessageResult; +using TelemetryCommand = rmq::TelemetryCommand; +using ForwardMessageToDeadLetterQueueRequest = rmq::ForwardMessageToDeadLetterQueueRequest; +using ForwardMessageToDeadLetterQueueResponse = rmq::ForwardMessageToDeadLetterQueueResponse; +using NotifyClientTerminationRequest = rmq::NotifyClientTerminationRequest; +using NotifyClientTerminationResponse = rmq::NotifyClientTerminationResponse; + +const char* protocolVersion(); + +bool writable(rmq::Permission p); + +bool readable(rmq::Permission p); + +bool operator<(const rmq::Resource& lhs, const rmq::Resource& rhs); + +bool operator==(const rmq::Resource& lhs, const rmq::Resource& rhs); + +bool operator<(const rmq::Broker& lhs, const rmq::Broker& rhs); + +bool operator==(const rmq::Broker& lhs, const rmq::Broker& rhs); + +bool operator<(const rmq::MessageQueue& lhs, const rmq::MessageQueue& rhs); + +bool operator==(const rmq::MessageQueue& lhs, const rmq::MessageQueue& rhs); + +std::string simpleNameOf(const rmq::MessageQueue& m); + +bool operator==(const std::vector& lhs, const std::vector& rhs); + +bool operator!=(const std::vector& lhs, const std::vector& rhs); + +std::string urlOf(const rmq::MessageQueue& message_queue); + +bool operator<(const rmq::Assignment& lhs, const rmq::Assignment& rhs); + +bool operator==(const rmq::Assignment& lhs, const rmq::Assignment& rhs); + +bool operator==(const std::vector& lhs, const std::vector& rhs); + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/include/RateLimiter.h b/src/main/cpp/base/include/RateLimiter.h new file mode 100644 index 000000000..76982a34d --- /dev/null +++ b/src/main/cpp/base/include/RateLimiter.h @@ -0,0 +1,184 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class Tick { +public: + virtual ~Tick() = default; + + virtual void tick() = 0; +}; + +class RateLimiterObserver { +public: + RateLimiterObserver(); + + void subscribe(const std::shared_ptr& tick); + + void stop(); + +private: + std::vector> members_; + std::mutex members_mtx_; + + std::atomic_bool stopped_; + + std::thread tick_thread_; +}; + +template +class RateLimiter : public Tick { +public: + explicit RateLimiter(uint32_t permit) : permits_{0}, interval_(1000 / PARTITION) { + uint32_t avg = permit / PARTITION; + for (auto& i : partition_) { + i = avg; + } + + uint32_t r = permit % PARTITION; + + if (r) { + uint32_t step = PARTITION / r; + for (uint32_t i = 0; i < r; ++i) { + partition_[i * step]++; + } + } + } + + ~RateLimiter() override = default; + + std::array& partition() { + return permits_; + } + + int slot() { + auto current = std::chrono::steady_clock::now(); + long ms = std::chrono::duration_cast(current.time_since_epoch()).count(); + return ms / interval_ % PARTITION; + } + + uint32_t available() { + uint32_t available_permit = 0; + int idx = slot(); + // Reuse quota of the past half of the cycle + for (int j = 0; j <= PARTITION / 2; ++j) { + int index = idx - j; + if (index < 0) { + index += PARTITION; + } + if (permits_[index] > 0) { + available_permit += permits_[index]; + } + } + + return available_permit; + } + + uint32_t acquire(uint32_t permit) { + int idx = slot(); + { + std::unique_lock lk(mtx_); + if (permits_[idx] >= permit) { + permits_[idx] -= permit; + return permit; + } + + uint32_t acquired = 0; + if (permits_[idx] > 0) { + acquired += permits_[idx]; + permits_[idx] = 0; + } + + // Reuse quota of the past half of the cycle + for (int j = 1; j <= PARTITION / 2; ++j) { + int index = idx - j; + if (index < 0) { + index += PARTITION; + } + while (permits_[index] > 0) { + --permits_[index]; + if (++acquired >= permit) { + break; + } + } + } + return acquired; + } + } + + void acquire() { + int idx = slot(); + { + std::unique_lock lk(mtx_); + if (permits_[idx] > 0) { + --permits_[idx]; + return; + } + + // Reuse quota of the past half of the cycle + for (int j = 1; j <= PARTITION / 2; ++j) { + int index = idx - j; + if (index < 0) { + index += PARTITION; + } + if (permits_[index] > 0) { + --permits_[index]; + return; + } + } + + cv_.wait(lk, [this]() { + int idx = slot(); + return permits_[idx] > 0; + }); + idx = slot(); + --permits_[idx]; + } + } + + void tick() override { + std::this_thread::sleep_for(std::chrono::milliseconds(1000 / PARTITION)); + int idx = slot(); + { + std::unique_lock lk(mtx_); + permits_[idx] = partition_[idx]; + cv_.notify_all(); + } + } + +private: + std::array partition_; + std::array permits_; + int interval_; + std::mutex mtx_; + std::condition_variable cv_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/include/RetryPolicy.h b/src/main/cpp/base/include/RetryPolicy.h new file mode 100644 index 000000000..5cc413863 --- /dev/null +++ b/src/main/cpp/base/include/RetryPolicy.h @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include + +#include "absl/time/time.h" +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +enum class BackoffStrategy : std::uint8_t +{ + Customized = 0, + Exponential = 1, +}; + +struct RetryPolicy { + std::uint32_t max_attempt; + + BackoffStrategy strategy; + + // Exponential back-off + absl::Duration initial; + absl::Duration max; + float multiplier; + + // User defined back-off intervals. + std::vector next; + + std::int64_t backoff(std::size_t attempt) { + static std::int64_t default_backoff = 1000; + if (!attempt) { + attempt = 1; + } + + switch (strategy) { + case BackoffStrategy::Customized: { + if (next.empty()) { + return default_backoff; + } + if (attempt >= next.size()) { + return absl::ToInt64Milliseconds(next[next.size() - 1]); + } + return absl::ToInt64Milliseconds(next[attempt - 1]); + } + + case BackoffStrategy::Exponential: { + if (!absl::ToInt64Milliseconds(max)) { + return default_backoff; + } + + auto result = initial * pow(2, attempt); + if (result > max) { + return absl::ToInt64Milliseconds(max); + } + return absl::ToInt64Milliseconds(result); + } + default: + return default_backoff; + } + } +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/include/StsCredentialsProviderImpl.h b/src/main/cpp/base/include/StsCredentialsProviderImpl.h new file mode 100644 index 000000000..0789e4ae6 --- /dev/null +++ b/src/main/cpp/base/include/StsCredentialsProviderImpl.h @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "absl/base/thread_annotations.h" +#include "absl/synchronization/mutex.h" + +#include "HttpClient.h" +#include "rocketmq/CredentialsProvider.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class StsCredentialsProviderImpl : public CredentialsProvider { +public: + explicit StsCredentialsProviderImpl(std::string ram_role_name); + + ~StsCredentialsProviderImpl() override; + + Credentials getCredentials() override; + + void withHttpClient(std::unique_ptr http_client) { + http_client_ = std::move(http_client); + } + +private: + static const char* RAM_ROLE_HOST; + static const char* RAM_ROLE_URL_PREFIX; + static const char* FIELD_ACCESS_KEY; + static const char* FIELD_ACCESS_SECRET; + static const char* FIELD_SESSION_TOKEN; + static const char* FIELD_EXPIRATION; + static const char* EXPIRATION_DATE_TIME_FORMAT; + + std::string ram_role_name_; + + std::string access_key_ GUARDED_BY(mtx_); + std::string access_secret_ GUARDED_BY(mtx_); + std::string session_token_ GUARDED_BY(mtx_); + std::chrono::system_clock::time_point expiration_; + + absl::Mutex mtx_; + void refresh() LOCKS_EXCLUDED(mtx_); + + std::unique_ptr http_client_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/include/SubscriptionEntry.h b/src/main/cpp/base/include/SubscriptionEntry.h new file mode 100644 index 000000000..9256242ae --- /dev/null +++ b/src/main/cpp/base/include/SubscriptionEntry.h @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include + +#include "FilterExpression.h" +#include "Resource.h" +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +struct SubscriptionEntry { + Resource topic; + FilterExpression expression; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/common/MQClientErrorContainer.cpp b/src/main/cpp/base/include/ThreadPool.h similarity index 72% rename from src/common/MQClientErrorContainer.cpp rename to src/main/cpp/base/include/ThreadPool.h index a9e0e5d31..d4582252a 100644 --- a/src/common/MQClientErrorContainer.cpp +++ b/src/main/cpp/base/include/ThreadPool.h @@ -14,18 +14,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "MQClientErrorContainer.h" +#pragma once -namespace rocketmq { +#include -thread_local std::string MQClientErrorContainer::t_err; +#include "rocketmq/RocketMQ.h" -void MQClientErrorContainer::setErr(const std::string& str) { - t_err = str; -} +ROCKETMQ_NAMESPACE_BEGIN -const std::string& MQClientErrorContainer::getErr() { - return t_err; -} +class ThreadPool { +public: + virtual ~ThreadPool() = default; -} // namespace rocketmq + virtual void start() = 0; + + virtual void shutdown() = 0; + + virtual void submit(std::function task) = 0; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/include/ThreadPoolImpl.h b/src/main/cpp/base/include/ThreadPoolImpl.h new file mode 100644 index 000000000..b5d754cf8 --- /dev/null +++ b/src/main/cpp/base/include/ThreadPoolImpl.h @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "absl/synchronization/mutex.h" +#include "asio.hpp" +#include "asio/io_context.hpp" + +#include "ThreadPool.h" +#include "rocketmq/State.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ThreadPoolImpl : public ThreadPool { +public: + explicit ThreadPoolImpl(std::uint16_t workers); + + ~ThreadPoolImpl() override = default; + + void start() override; + + void shutdown() override; + + void submit(std::function task) override; + +private: + asio::io_context context_; + std::unique_ptr> work_guard_; + std::uint16_t workers_; + std::vector threads_; + std::atomic state_{State::CREATED}; + absl::Mutex start_mtx_; + absl::CondVar start_cv_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/common/TopAddressing.h b/src/main/cpp/base/include/TopAddressing.h similarity index 59% rename from src/common/TopAddressing.h rename to src/main/cpp/base/include/TopAddressing.h index 07297dbad..02602598f 100644 --- a/src/common/TopAddressing.h +++ b/src/main/cpp/base/include/TopAddressing.h @@ -14,34 +14,39 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef __TOPADDRESSING_H__ -#define __TOPADDRESSING_H__ +#pragma once -#include -#include -#include +#include +#include +#include +#include #include -#include "Logging.h" -#include "UtilAll.h" +#include + +#include "HostInfo.h" +#include "HttpClient.h" + +ROCKETMQ_NAMESPACE_BEGIN -namespace rocketmq { class TopAddressing { - public: - TopAddressing(const std::string& unitName); +public: + TopAddressing(); + + TopAddressing(std::string host, int port, std::string path); + virtual ~TopAddressing(); - public: - virtual string fetchNSAddr(const string& NSDomain); + void fetchNameServerAddresses(const std::function&)>& cb); + + void injectHttpClient(std::unique_ptr http_client); - private: - string clearNewLine(const string& str); - void updateNameServerAddressList(const string& adds); - int IsIPAddr(const char* sValue); +private: + std::string host_; + int port_{8080}; + std::string path_; + HostInfo host_info_; - private: - boost::mutex m_addrLock; - list m_addrs; - string m_unitName; + std::unique_ptr http_client_; }; -} // namespace rocketmq -#endif + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/include/UniqueIdGenerator.h b/src/main/cpp/base/include/UniqueIdGenerator.h new file mode 100644 index 000000000..e44c5e64c --- /dev/null +++ b/src/main/cpp/base/include/UniqueIdGenerator.h @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include + +#include "absl/base/thread_annotations.h" +#include "absl/synchronization/mutex.h" + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class UniqueIdGenerator { +public: + static UniqueIdGenerator& instance(); + + std::string next() LOCKS_EXCLUDED(mtx_); + + UniqueIdGenerator(const UniqueIdGenerator&) = delete; + + UniqueIdGenerator(UniqueIdGenerator&&) = delete; + + UniqueIdGenerator& operator=(const UniqueIdGenerator&) = delete; + + UniqueIdGenerator& operator=(UniqueIdGenerator&&) = delete; + +private: + UniqueIdGenerator(); + + struct Slot { + uint32_t seconds; + uint32_t sequence; + }; + + static std::chrono::system_clock::time_point customEpoch(); + + /** + * Seconds since 2021-01-01 00:00:00.0 +0000 + * @return + */ + uint32_t deltaSeconds(); + + std::array prefix_; + absl::Mutex mtx_; + + /** + * Duration since 2021-01-01 00:00:00.0(UTC) + */ + std::chrono::system_clock::duration since_custom_epoch_; + + /** + * @brief Generator created time point using steady clock. Such that when system time are adjusted backward using NTP + * service, generated message identifiers remain unique. + * + * Note: when program restarts, duplicated message-id may still get generated. However, if program run in + * containerized environment, say Kubernetes, this will NOT be a problem since MAC address would change on restart. + */ + std::chrono::steady_clock::time_point start_time_point_; + + uint32_t seconds_; + uint32_t sequence_; + static const uint8_t VERSION; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/trace/TraceTransferBean.h b/src/main/cpp/base/include/UtilAll.h similarity index 66% rename from src/trace/TraceTransferBean.h rename to src/main/cpp/base/include/UtilAll.h index 5ca054a11..d4cb2eac4 100644 --- a/src/trace/TraceTransferBean.h +++ b/src/main/cpp/base/include/UtilAll.h @@ -14,27 +14,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -#ifndef __ROCKETMQ_TRACE_TRANSFER_BEAN_H__ -#define __ROCKETMQ_TRACE_TRANSFER_BEAN_H__ +#pragma once #include #include -namespace rocketmq { -class TraceTransferBean { - public: - std::string getTransData(); +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN - void setTransData(const std::string& transData); +class UtilAll { +public: + static std::string hostname(); - std::vector getTransKey(); + static bool macAddress(std::vector& mac); - void setTransKey(const std::string& transkey); + /** + * Compress + * @param src + * @param dst + * @return + */ + static bool compress(const std::string& src, std::string& dst); - private: - std::string m_transData; - std::vector m_transKey; + static bool uncompress(const std::string& src, std::string& dst); + +private: }; -} // namespace rocketmq -#endif \ No newline at end of file + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/mocks/BUILD.bazel b/src/main/cpp/base/mocks/BUILD.bazel new file mode 100644 index 000000000..be924e72f --- /dev/null +++ b/src/main/cpp/base/mocks/BUILD.bazel @@ -0,0 +1,28 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_library") +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "base_mocks", + hdrs = glob(["include/*h"]), + strip_include_prefix = "//src/main/cpp/base/mocks/include", + deps = [ + "//api:rocketmq_interface", + "//external:gtest", + ], +) \ No newline at end of file diff --git a/src/main/cpp/base/mocks/include/HttpClientMock.h b/src/main/cpp/base/mocks/include/HttpClientMock.h new file mode 100644 index 000000000..c2e946470 --- /dev/null +++ b/src/main/cpp/base/mocks/include/HttpClientMock.h @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "HttpClient.h" +#include "rocketmq/RocketMQ.h" +#include "gmock/gmock.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class HttpClientMock : public HttpClient { +public: + ~HttpClientMock() override = default; + + MOCK_METHOD(void, start, (), (override)); + MOCK_METHOD(void, shutdown, (), (override)); + MOCK_METHOD(void, get, + (HttpProtocol, const std::string&, std::uint16_t, const std::string&, + const std::function&, const std::string&)>&), + (override)); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/common/AsyncArg.h b/src/main/cpp/base/mocks/include/MessageListenerMock.h similarity index 63% rename from src/common/AsyncArg.h rename to src/main/cpp/base/mocks/include/MessageListenerMock.h index a683e6d5e..431d1bb79 100644 --- a/src/common/AsyncArg.h +++ b/src/main/cpp/base/mocks/include/MessageListenerMock.h @@ -14,23 +14,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once -#ifndef _AsyncArg_H_ -#define _AsyncArg_H_ +#include "rocketmq/MessageListener.h" +#include "gmock/gmock.h" -#include "MQMessageQueue.h" -#include "PullAPIWrapper.h" -#include "SubscriptionData.h" +ROCKETMQ_NAMESPACE_BEGIN -namespace rocketmq { -//&), (override)); +}; -struct AsyncArg { - MQMessageQueue mq; - SubscriptionData subData; - PullAPIWrapper* pPullWrapper; +class FifoMessageListenerMock : public FifoMessageListener { +public: + MOCK_METHOD(ConsumeMessageResult, consumeMessage, (const MQMessageExt&), (override)); }; -// + +#include "Protocol.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class AssignmentTest : public testing::Test { +public: + void SetUp() override { + } + + void TearDown() override { + } +}; + +TEST_F(AssignmentTest, testSort) { + std::vector assignments; + std::sort(assignments.begin(), assignments.end(), + [](const rmq::Assignment& lhs, const rmq::Assignment& rhs) { return lhs < rhs; }); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/tests/BUILD.bazel b/src/main/cpp/base/tests/BUILD.bazel new file mode 100644 index 000000000..054dfb5fb --- /dev/null +++ b/src/main/cpp/base/tests/BUILD.bazel @@ -0,0 +1,54 @@ +load("@rules_cc//cc:defs.bzl", "cc_test") + +base_deps = [ + "//src/main/cpp/base:base_library", + "@com_google_googletest//:gtest_main", +] + +cc_test( + name = "message_builder_test", + srcs = [ + "MessageBuilderTest.cpp", + ], + deps = base_deps, +) + +cc_test( + name = "assignment_test", + srcs = [ + "AssignmentTest.cpp", + ], + deps = base_deps, +) + +cc_test( + name = "message_queue_test", + srcs = [ + "MessageQueueTest.cpp", + ], + deps = base_deps, +) + +cc_test( + name = "configuration_test", + srcs = [ + "ConfigurationTest.cpp", + ], + deps = base_deps, +) + +cc_test( + name = "mix_all_test", + srcs = [ + "MixAllTest.cpp", + ], + deps = base_deps, +) + +cc_test( + name = "retry_policy_test", + srcs = [ + "RetryPolicyTest.cpp", + ], + deps = base_deps, +) \ No newline at end of file diff --git a/src/main/cpp/base/tests/ConfigurationTest.cpp b/src/main/cpp/base/tests/ConfigurationTest.cpp new file mode 100644 index 000000000..9174e395d --- /dev/null +++ b/src/main/cpp/base/tests/ConfigurationTest.cpp @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "gtest/gtest.h" +#include "rocketmq/Configuration.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ConfigurationTest : public testing::Test { +public: +protected: + std::string endpoints_{"8.8.8.8:80;8.8.4.4:80"}; + std::chrono::milliseconds request_timeout_{std::chrono::seconds(1)}; +}; + +TEST_F(ConfigurationTest, testEndpoints) { + auto configuration = Configuration::newBuilder().withEndpoints(endpoints_).build(); + ASSERT_EQ(endpoints_, configuration.endpoints()); +} + +TEST_F(ConfigurationTest, testCredentialsProvider) { + std::string access_key = "ak"; + std::string access_secret = "as"; + auto credentials_provider = std::make_shared(access_key, access_secret); + auto configuration = Configuration::newBuilder().withCredentialsProvider(credentials_provider).build(); + auto credentials = configuration.credentialsProvider()->getCredentials(); + + ASSERT_EQ(access_key, credentials.accessKey()); + ASSERT_EQ(access_secret, credentials.accessSecret()); +} + +TEST_F(ConfigurationTest, testRequestTimeout) { + auto configuration = Configuration::newBuilder().withRequestTimeout(request_timeout_).build(); + ASSERT_EQ(request_timeout_, configuration.requestTimeout()); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/tests/MessageBuilderTest.cpp b/src/main/cpp/base/tests/MessageBuilderTest.cpp new file mode 100644 index 000000000..9ad4d58e2 --- /dev/null +++ b/src/main/cpp/base/tests/MessageBuilderTest.cpp @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +#include "MessageExt.h" +#include "gtest/gtest.h" +#include "rocketmq/Message.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class MessageBuilderTest : public testing::Test { +protected: + std::string topic_{"TestTopic"}; + std::string tag_{"TagA"}; + std::vector keys_{"k1", "k2"}; + std::string body_{"sample body content"}; + std::string group_{"message-group"}; +}; + +TEST_F(MessageBuilderTest, testBuilder) { + MessageConstPtr message = + Message::newBuilder().withTopic(topic_).withTag(tag_).withKeys(keys_).withBody(body_).build(); + ASSERT_EQ(topic_, message->topic()); + ASSERT_EQ(tag_, message->tag()); + ASSERT_TRUE(keys_ == message->keys()); + ASSERT_EQ(body_, message->body()); + ASSERT_EQ(false, message->traceContext().has_value()); +} + +TEST_F(MessageBuilderTest, testBuilder2) { + for (std::size_t i = 0; i < 128; i++) { + MessageConstPtr message = + Message::newBuilder().withTopic(topic_).withTag(tag_).withKeys(keys_).withBody(body_).build(); + ASSERT_EQ(topic_, message->topic()); + ASSERT_EQ(tag_, message->tag()); + ASSERT_TRUE(keys_ == message->keys()); + ASSERT_EQ(body_, message->body()); + ASSERT_EQ(false, message->traceContext().has_value()); + } +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/base/tests/MessageQueueTest.cpp b/src/main/cpp/base/tests/MessageQueueTest.cpp new file mode 100644 index 000000000..2db2c83cb --- /dev/null +++ b/src/main/cpp/base/tests/MessageQueueTest.cpp @@ -0,0 +1,21 @@ +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "google/protobuf/map.h" +#include "gtest/gtest.h" + +#include "Protocol.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class MessageQueueTest : public testing::Test { +public: + void SetUp() override { + } + + void TearDown() override { + } +}; + +ROCKETMQ_NAMESPACE_END diff --git a/src/main/cpp/base/tests/MixAllTest.cpp b/src/main/cpp/base/tests/MixAllTest.cpp new file mode 100644 index 000000000..e66030e39 --- /dev/null +++ b/src/main/cpp/base/tests/MixAllTest.cpp @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "MixAll.h" +#include "gtest/gtest.h" + +ROCKETMQ_NAMESPACE_BEGIN + +TEST(MixAllTest, testOsName) { + const char* os_name = MixAll::osName(); + std::cout << os_name << std::endl; +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/test/src/producer/StringIdMakerTest.cpp b/src/main/cpp/base/tests/RetryPolicyTest.cpp similarity index 62% rename from test/src/producer/StringIdMakerTest.cpp rename to src/main/cpp/base/tests/RetryPolicyTest.cpp index ebe5897f2..4a49bccec 100644 --- a/test/src/producer/StringIdMakerTest.cpp +++ b/src/main/cpp/base/tests/RetryPolicyTest.cpp @@ -14,27 +14,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include -#include - -#include "gmock/gmock.h" +#include "RetryPolicy.h" #include "gtest/gtest.h" -#include "StringIdMaker.h" - -using namespace std; -using namespace rocketmq; -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; +ROCKETMQ_NAMESPACE_BEGIN -TEST(StringIdMakerTest, get_unique_id) { - string unique_id = StringIdMaker::getInstance().createUniqID(); - cout << "unique_id: " << unique_id << endl; - EXPECT_EQ(unique_id.size(), 32); +TEST(RetryPolicyTest, testBackoff) { + RetryPolicy policy{.max_attempt = 3, + .strategy = BackoffStrategy::Customized, + .next = {absl::Milliseconds(10), absl::Milliseconds(100), absl::Milliseconds(500)}}; + ASSERT_EQ(policy.backoff(1), 10); + ASSERT_EQ(policy.backoff(2), 100); + ASSERT_EQ(policy.backoff(3), 500); + ASSERT_EQ(policy.backoff(4), 500); + ASSERT_EQ(policy.backoff(10000), 500); } -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - return RUN_ALL_TESTS(); -} +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/BUILD.bazel b/src/main/cpp/client/BUILD.bazel new file mode 100644 index 000000000..c56f27931 --- /dev/null +++ b/src/main/cpp/client/BUILD.bazel @@ -0,0 +1,41 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_library") +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "client_library", + hdrs = glob(["include/*.h"]), + srcs = glob(["*.cpp"]), + strip_include_prefix = "//src/main/cpp/client/include", + deps = [ + "//api:rocketmq_interface", + "//proto:rocketmq_grpc_library", + "//src/main/cpp/admin:admin_server_library", + "//src/main/cpp/base:base_library", + "//src/main/cpp/scheduler:scheduler_library", + "//src/main/cpp/concurrent:countdown_latch_library", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", + "@com_github_grpc_grpc//:grpc_secure", + "@com_github_grpc_grpc//:grpc++", + "@boringssl//:ssl", + "//external:gtest", + ], + defines = [ + ], +) \ No newline at end of file diff --git a/src/main/cpp/client/ClientManagerFactory.cpp b/src/main/cpp/client/ClientManagerFactory.cpp new file mode 100644 index 000000000..3cacaae0a --- /dev/null +++ b/src/main/cpp/client/ClientManagerFactory.cpp @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ClientManagerFactory.h" +#include "ClientManagerImpl.h" + +ROCKETMQ_NAMESPACE_BEGIN + +ClientManagerFactory& ClientManagerFactory::getInstance() { + static ClientManagerFactory instance; + return instance; +} + +ClientManagerPtr ClientManagerFactory::getClientManager(const ClientConfig& client_config) { + { + absl::MutexLock lock(&client_manager_table_mtx_); + auto search = client_manager_table_.find(client_config.resource_namespace); + if (search != client_manager_table_.end()) { + ClientManagerPtr client_manager = search->second.lock(); + if (client_manager) { + SPDLOG_DEBUG("Re-use existing client_manager[resource_namespace={}]", client_config.resource_namespace); + return client_manager; + } else { + client_manager_table_.erase(client_config.resource_namespace); + } + } + ClientManagerPtr client_manager = std::make_shared(client_config.resource_namespace); + std::weak_ptr client_instance_weak_ptr(client_manager); + client_manager_table_.insert_or_assign(client_config.resource_namespace, client_instance_weak_ptr); + SPDLOG_INFO("Created a new client manager[resource_namespace={}]", client_config.resource_namespace); + return client_manager; + } +} + +void ClientManagerFactory::addClientManager(const std::string& resource_namespace, + const ClientManagerPtr& client_manager) { + absl::MutexLock lk(&client_manager_table_mtx_); + client_manager_table_.insert_or_assign(resource_namespace, std::weak_ptr(client_manager)); +} + +ClientManagerFactory::ClientManagerFactory() : admin_server_(admin::AdminFacade::getServer()) { + admin_server_.start(); +} + +ClientManagerFactory::~ClientManagerFactory() { + admin_server_.stop(); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/ClientManagerImpl.cpp b/src/main/cpp/client/ClientManagerImpl.cpp new file mode 100644 index 000000000..0c6e155f7 --- /dev/null +++ b/src/main/cpp/client/ClientManagerImpl.cpp @@ -0,0 +1,1088 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ClientManagerImpl.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "InvocationContext.h" +#include "LogInterceptor.h" +#include "LogInterceptorFactory.h" +#include "LoggerImpl.h" +#include "MessageExt.h" +#include "MetadataConstants.h" +#include "MixAll.h" +#include "Protocol.h" +#include "ReceiveMessageContext.h" +#include "RpcClient.h" +#include "RpcClientImpl.h" +#include "Scheduler.h" +#include "TlsHelper.h" +#include "UtilAll.h" +#include "google/protobuf/util/time_util.h" +#include "grpcpp/create_channel.h" +#include "rocketmq/ErrorCode.h" +#include "rocketmq/SendReceipt.h" + +ROCKETMQ_NAMESPACE_BEGIN + +ClientManagerImpl::ClientManagerImpl(std::string resource_namespace) + : scheduler_(std::make_shared()), resource_namespace_(std::move(resource_namespace)), + state_(State::CREATED), + callback_thread_pool_(absl::make_unique(std::thread::hardware_concurrency())), + latency_histogram_("Message-Latency", 11) { + spdlog::set_level(spdlog::level::trace); + assignLabels(latency_histogram_); + + certificate_verifier_ = grpc::experimental::ExternalCertificateVerifier::Create(); + tls_channel_credential_options_.set_verify_server_certs(false); + tls_channel_credential_options_.set_check_call_host(false); + channel_credential_ = grpc::experimental::TlsCredentials(tls_channel_credential_options_); + + // Use unlimited receive message size. + channel_arguments_.SetMaxReceiveMessageSize(-1); + + int max_send_message_size = 1024 * 1024 * 16; + channel_arguments_.SetMaxSendMessageSize(max_send_message_size); + + /* + * Keep-alive settings: + * https://github.com/grpc/grpc/blob/master/doc/keepalive.md + * Keep-alive ping timeout duration: 3s + * Keep-alive ping interval, 30s + */ + channel_arguments_.SetInt(GRPC_ARG_KEEPALIVE_TIME_MS, 60000); + channel_arguments_.SetInt(GRPC_ARG_KEEPALIVE_TIMEOUT_MS, 3000); + channel_arguments_.SetInt(GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS, 1); + channel_arguments_.SetInt(GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA, 0); + + /* + * If set to zero, disables retry behavior. Otherwise, transparent retries + * are enabled for all RPCs, and configurable retries are enabled when they + * are configured via the service config. For details, see: + * https://github.com/grpc/proposal/blob/master/A6-client-retries.md + */ + channel_arguments_.SetInt(GRPC_ARG_ENABLE_RETRIES, 0); + + channel_arguments_.SetSslTargetNameOverride("localhost"); + + SPDLOG_INFO("ClientManager[ResourceNamespace={}] created", resource_namespace_); +} + +ClientManagerImpl::~ClientManagerImpl() { + shutdown(); + SPDLOG_INFO("ClientManager[ResourceNamespace={}] destructed", resource_namespace_); +} + +void ClientManagerImpl::start() { + if (State::CREATED != state_.load(std::memory_order_relaxed)) { + SPDLOG_WARN("Unexpected client instance state: {}", state_.load(std::memory_order_relaxed)); + return; + } + state_.store(State::STARTING, std::memory_order_relaxed); + + callback_thread_pool_->start(); + + scheduler_->start(); + + std::weak_ptr client_instance_weak_ptr = shared_from_this(); + + auto heartbeat_functor = [client_instance_weak_ptr]() { + auto client_instance = client_instance_weak_ptr.lock(); + if (client_instance) { + client_instance->doHeartbeat(); + } + }; + heartbeat_task_id_ = + scheduler_->schedule(heartbeat_functor, HEARTBEAT_TASK_NAME, std::chrono::seconds(1), std::chrono::seconds(10)); + SPDLOG_DEBUG("Heartbeat task-id={}", heartbeat_task_id_); + + auto stats_functor_ = [client_instance_weak_ptr]() { + auto client_instance = client_instance_weak_ptr.lock(); + if (client_instance) { + client_instance->logStats(); + } + }; + stats_task_id_ = + scheduler_->schedule(stats_functor_, STATS_TASK_NAME, std::chrono::seconds(0), std::chrono::seconds(10)); + state_.store(State::STARTED, std::memory_order_relaxed); +} + +void ClientManagerImpl::shutdown() { + SPDLOG_INFO("Client manager shutdown"); + if (State::STARTED != state_.load(std::memory_order_relaxed)) { + SPDLOG_WARN("Unexpected client instance state: {}", state_.load(std::memory_order_relaxed)); + return; + } + state_.store(STOPPING, std::memory_order_relaxed); + + callback_thread_pool_->shutdown(); + + if (heartbeat_task_id_) { + scheduler_->cancel(heartbeat_task_id_); + } + + if (stats_task_id_) { + scheduler_->cancel(stats_task_id_); + } + + scheduler_->shutdown(); + + { + absl::MutexLock lk(&rpc_clients_mtx_); + rpc_clients_.clear(); + SPDLOG_DEBUG("rpc_clients_ is clear"); + } + + state_.store(State::STOPPED, std::memory_order_relaxed); + SPDLOG_DEBUG("ClientManager stopped"); +} + +void ClientManagerImpl::assignLabels(Histogram& histogram) { + histogram.labels().emplace_back("[000ms~020ms): "); + histogram.labels().emplace_back("[020ms~040ms): "); + histogram.labels().emplace_back("[040ms~060ms): "); + histogram.labels().emplace_back("[060ms~080ms): "); + histogram.labels().emplace_back("[080ms~100ms): "); + histogram.labels().emplace_back("[100ms~120ms): "); + histogram.labels().emplace_back("[120ms~140ms): "); + histogram.labels().emplace_back("[140ms~160ms): "); + histogram.labels().emplace_back("[160ms~180ms): "); + histogram.labels().emplace_back("[180ms~200ms): "); + histogram.labels().emplace_back("[200ms~inf): "); +} + +std::vector ClientManagerImpl::cleanOfflineRpcClients() { + absl::flat_hash_set hosts; + { + absl::MutexLock lk(&clients_mtx_); + for (const auto& item : clients_) { + std::shared_ptr client = item.lock(); + if (!client) { + continue; + } + client->endpointsInUse(hosts); + } + } + + std::vector removed; + { + absl::MutexLock lk(&rpc_clients_mtx_); + for (auto it = rpc_clients_.begin(); it != rpc_clients_.end();) { + std::string host = it->first; + if (it->second->needHeartbeat() && !hosts.contains(host)) { + SPDLOG_INFO("Removed RPC client whose peer is offline. RemoteHost={}", host); + removed.push_back(host); + rpc_clients_.erase(it++); + } else { + it++; + } + } + } + + return removed; +} + +void ClientManagerImpl::heartbeat(const std::string& target_host, const Metadata& metadata, + const HeartbeatRequest& request, std::chrono::milliseconds timeout, + const std::function& cb) { + SPDLOG_DEBUG("Prepare to send heartbeat to {}. Request: {}", target_host, request.DebugString()); + auto client = getRpcClient(target_host, true); + auto invocation_context = new InvocationContext(); + invocation_context->task_name = fmt::format("Heartbeat to {}", target_host); + invocation_context->remote_address = target_host; + for (const auto& item : metadata) { + invocation_context->context.AddMetadata(item.first, item.second); + } + + auto callback = [cb](const InvocationContext* invocation_context) { + if (!invocation_context->status.ok()) { + SPDLOG_WARN("Failed to send heartbeat to target_host={}. gRPC code: {}, message: {}", + invocation_context->remote_address, invocation_context->status.error_code(), + invocation_context->status.error_message()); + std::error_code ec = ErrorCode::RequestTimeout; + cb(ec, invocation_context->response); + return; + } + + auto&& status = invocation_context->response.status(); + std::error_code ec; + switch (status.code()) { + case rmq::Code::OK: { + cb(ec, invocation_context->response); + } break; + case rmq::Code::UNAUTHORIZED: { + SPDLOG_WARN("Unauthorized: {}, host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::Unauthorized; + cb(ec, invocation_context->response); + } break; + case rmq::Code::FORBIDDEN: { + SPDLOG_WARN("Forbidden: {}, host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::Forbidden; + cb(ec, invocation_context->response); + } break; + case rmq::Code::INTERNAL_SERVER_ERROR: { + SPDLOG_WARN("InternalServerError: {}, host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::InternalServerError; + cb(ec, invocation_context->response); + } break; + default: { + SPDLOG_WARN("NotImplemented: Please upgrade SDK to latest release. Message={}, host={}", status.message(), + invocation_context->remote_address); + } break; + } + }; + + invocation_context->callback = callback; + invocation_context->context.set_deadline(std::chrono::system_clock::now() + timeout); + client->asyncHeartbeat(request, invocation_context); +} + +void ClientManagerImpl::doHeartbeat() { + if (State::STARTED != state_.load(std::memory_order_relaxed) && + State::STARTING != state_.load(std::memory_order_relaxed)) { + SPDLOG_WARN("Unexpected client manager state={}.", state_.load(std::memory_order_relaxed)); + return; + } + + { + absl::MutexLock lk(&clients_mtx_); + for (const auto& item : clients_) { + auto client = item.lock(); + if (client && client->active()) { + client->heartbeat(); + } + } + } +} + +bool ClientManagerImpl::send(const std::string& target_host, const Metadata& metadata, SendMessageRequest& request, + SendCallback cb) { + assert(cb); + SPDLOG_DEBUG("Prepare to send message to {} asynchronously", target_host); + RpcClientSharedPtr client = getRpcClient(target_host); + // Invocation context will be deleted in its onComplete() method. + auto invocation_context = new InvocationContext(); + invocation_context->task_name = fmt::format("Send message to {}", target_host); + invocation_context->remote_address = target_host; + for (const auto& entry : metadata) { + invocation_context->context.AddMetadata(entry.first, entry.second); + } + + const std::string& topic = request.messages().begin()->topic().name(); + std::weak_ptr client_manager(shared_from_this()); + auto completion_callback = [topic, cb, + client_manager](const InvocationContext* invocation_context) { + ClientManagerPtr client_manager_ptr = client_manager.lock(); + if (!client_manager_ptr) { + return; + } + + if (State::STARTED != client_manager_ptr->state()) { + // TODO: Would this leak some memroy? + return; + } + + SendReceipt send_receipt; + std::error_code ec; + if (!invocation_context->status.ok()) { + SPDLOG_WARN("Failed to send message to {} due to gRPC error. gRPC code: {}, gRPC error message: {}", + invocation_context->remote_address, invocation_context->status.error_code(), + invocation_context->status.error_message()); + ec = ErrorCode::RequestTimeout; + cb(ec, send_receipt); + return; + } + + auto&& status = invocation_context->response.status(); + switch (invocation_context->response.status().code()) { + case rmq::Code::OK: { + send_receipt.message_id = invocation_context->response.entries().begin()->message_id(); + break; + } + case rmq::Code::TOPIC_NOT_FOUND: { + SPDLOG_WARN("TopicNotFound: {}", status.message()); + ec = ErrorCode::NotFound; + break; + } + case rmq::Code::UNAUTHORIZED: { + SPDLOG_WARN("Unauthenticated: {}", status.message()); + ec = ErrorCode::Unauthorized; + break; + } + case rmq::Code::FORBIDDEN: { + SPDLOG_WARN("Forbidden: {}", status.message()); + ec = ErrorCode::Forbidden; + cb(ec, send_receipt); + break; + } + case rmq::Code::INTERNAL_SERVER_ERROR: { + SPDLOG_WARN("InternalServerError: {}", status.message()); + ec = ErrorCode::InternalServerError; + break; + } + default: { + SPDLOG_WARN("Unsupported status code. Check and upgrade SDK to the latest"); + ec = ErrorCode::NotImplemented; + break; + } + } + cb(ec, send_receipt); + }; + + invocation_context->callback = completion_callback; + client->asyncSend(request, invocation_context); + return true; +} + +/** + * @brief Create a gRPC channel to target host. + * + * @param target_host + * @return std::shared_ptr + */ +std::shared_ptr ClientManagerImpl::createChannel(const std::string& target_host) { + std::vector> interceptor_factories; + interceptor_factories.emplace_back(absl::make_unique()); + auto channel = grpc::experimental::CreateCustomChannelWithInterceptors( + target_host, channel_credential_, channel_arguments_, std::move(interceptor_factories)); + return channel; +} + +RpcClientSharedPtr ClientManagerImpl::getRpcClient(const std::string& target_host, bool need_heartbeat) { + std::shared_ptr client; + { + absl::MutexLock lock(&rpc_clients_mtx_); + auto search = rpc_clients_.find(target_host); + if (search == rpc_clients_.end() || !search->second->ok()) { + if (search == rpc_clients_.end()) { + SPDLOG_INFO("Create a RPC client to {}", target_host.data()); + } else if (!search->second->ok()) { + SPDLOG_INFO("Prior RPC client to {} is not OK. Re-create one", target_host); + } + std::vector> interceptor_factories; + interceptor_factories.emplace_back(absl::make_unique()); + auto channel = grpc::experimental::CreateCustomChannelWithInterceptors( + target_host, channel_credential_, channel_arguments_, std::move(interceptor_factories)); + std::weak_ptr client_manager(shared_from_this()); + client = std::make_shared(client_manager, channel, target_host, need_heartbeat); + rpc_clients_.insert_or_assign(target_host, client); + } else { + client = search->second; + } + } + + if (need_heartbeat && !client->needHeartbeat()) { + client->needHeartbeat(need_heartbeat); + } + + return client; +} + +void ClientManagerImpl::addRpcClient(const std::string& target_host, const RpcClientSharedPtr& client) { + { + absl::MutexLock lock(&rpc_clients_mtx_); + rpc_clients_.insert_or_assign(target_host, client); + } +} + +void ClientManagerImpl::cleanRpcClients() { + absl::MutexLock lk(&rpc_clients_mtx_); + rpc_clients_.clear(); +} + +SendReceipt ClientManagerImpl::processSendResponse(const rmq::MessageQueue& message_queue, + const SendMessageResponse& response, std::error_code& ec) { + SendReceipt send_receipt; + + switch (response.status().code()) { + case rmq::Code::OK: { + assert(response.entries_size() > 0); + send_receipt.message_id = response.entries().begin()->message_id(); + send_receipt.transaction_id = response.entries().begin()->transaction_id(); + return send_receipt; + } + case rmq::Code::ILLEGAL_TOPIC: { + ec = ErrorCode::BadRequest; + return send_receipt; + } + default: { + // TODO: handle other cases. + break; + } + } + return send_receipt; +} + +void ClientManagerImpl::addClientObserver(std::weak_ptr client) { + absl::MutexLock lk(&clients_mtx_); + clients_.emplace_back(std::move(client)); +} + +void ClientManagerImpl::resolveRoute(const std::string& target_host, const Metadata& metadata, + const QueryRouteRequest& request, std::chrono::milliseconds timeout, + const std::function& cb) { + SPDLOG_DEBUG("Name server connection URL: {}", target_host); + SPDLOG_DEBUG("Query route request: {}", request.DebugString()); + RpcClientSharedPtr client = getRpcClient(target_host, false); + if (!client) { + SPDLOG_WARN("Failed to create RPC client for name server[host={}]", target_host); + std::error_code ec = ErrorCode::RequestTimeout; + cb(ec, nullptr); + return; + } + + auto invocation_context = new InvocationContext(); + invocation_context->task_name = fmt::format("Query route of topic={} from {}", request.topic().name(), target_host); + invocation_context->remote_address = target_host; + invocation_context->context.set_deadline(std::chrono::system_clock::now() + timeout); + for (const auto& item : metadata) { + invocation_context->context.AddMetadata(item.first, item.second); + } + + auto callback = [cb](const InvocationContext* invocation_context) { + if (!invocation_context->status.ok()) { + SPDLOG_WARN("Failed to send query route request to server[host={}]. Reason: {}", + invocation_context->remote_address, invocation_context->status.error_message()); + std::error_code ec = ErrorCode::RequestTimeout; + cb(ec, nullptr); + return; + } + + std::error_code ec; + auto&& status = invocation_context->response.status(); + switch (status.code()) { + case rmq::Code::OK: { + std::vector message_queues; + for (const auto& item : invocation_context->response.message_queues()) { + message_queues.push_back(item); + } + auto ptr = std::make_shared(std::move(message_queues)); + cb(ec, ptr); + } break; + case rmq::Code::UNAUTHORIZED: { + SPDLOG_WARN("Unauthorized: {}. Host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::Unauthorized; + cb(ec, nullptr); + } break; + case rmq::Code::FORBIDDEN: { + SPDLOG_WARN("Forbidden: {}. Host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::Forbidden; + cb(ec, nullptr); + } break; + case rmq::Code::TOPIC_NOT_FOUND: { + SPDLOG_WARN("TopicNotFound: {}. Host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::NotFound; + cb(ec, nullptr); + } break; + case rmq::Code::INTERNAL_SERVER_ERROR: { + SPDLOG_WARN("InternalServerError: {}. Host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::InternalServerError; + cb(ec, nullptr); + } break; + default: { + SPDLOG_WARN("NotImplement: Please upgrade to latest SDK release. Host={}", invocation_context->remote_address); + ec = ErrorCode::NotImplemented; + cb(ec, nullptr); + } break; + } + }; + invocation_context->callback = callback; + client->asyncQueryRoute(request, invocation_context); +} + +void ClientManagerImpl::queryAssignment( + const std::string& target, const Metadata& metadata, const QueryAssignmentRequest& request, + std::chrono::milliseconds timeout, + const std::function& cb) { + SPDLOG_DEBUG("Prepare to send query assignment request to broker[address={}]", target); + std::shared_ptr client = getRpcClient(target); + + auto callback = [&, cb](const InvocationContext* invocation_context) { + if (!invocation_context->status.ok()) { + SPDLOG_WARN("Failed to query assignment. Reason: {}", invocation_context->status.error_message()); + std::error_code ec = ErrorCode::RequestTimeout; + cb(ec, invocation_context->response); + return; + } + + auto&& status = invocation_context->response.status(); + std::error_code ec; + switch (status.code()) { + case rmq::Code::OK: { + SPDLOG_DEBUG("Query assignment OK"); + } break; + case rmq::Code::UNAUTHORIZED: { + SPDLOG_WARN("Unauthorized: {}, host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::Unauthorized; + } break; + case rmq::Code::FORBIDDEN: { + SPDLOG_WARN("Forbidden: {}, host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::Forbidden; + } break; + case rmq::Code::INTERNAL_SERVER_ERROR: { + SPDLOG_WARN("InternalServerError: {}, host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::InternalServerError; + } break; + default: { + SPDLOG_WARN("NotImplemented: please upgrade SDK to latest release. Host={}", + invocation_context->remote_address); + ec = ErrorCode::NotImplemented; + } break; + } + cb(ec, invocation_context->response); + }; + + auto invocation_context = new InvocationContext(); + invocation_context->task_name = fmt::format("QueryAssignment from {}", target); + invocation_context->remote_address = target; + for (const auto& item : metadata) { + invocation_context->context.AddMetadata(item.first, item.second); + } + invocation_context->context.set_deadline(std::chrono::system_clock::now() + timeout); + invocation_context->callback = callback; + client->asyncQueryAssignment(request, invocation_context); +} + +void ClientManagerImpl::receiveMessage(const std::string& target_host, const Metadata& metadata, + const ReceiveMessageRequest& request, std::chrono::milliseconds timeout, + ReceiveMessageCallback cb) { + SPDLOG_DEBUG("Prepare to receive message from {} asynchronously. Request: {}", target_host, request.DebugString()); + RpcClientSharedPtr client = getRpcClient(target_host); + auto context = absl::make_unique(); + context->callback = std::move(cb); + context->metadata = metadata; + context->timeout = timeout; + client->asyncReceive(request, std::move(context)); +} + +State ClientManagerImpl::state() const { + return state_.load(std::memory_order_relaxed); +} + +MessageConstSharedPtr ClientManagerImpl::wrapMessage(const rmq::Message& item) { + assert(item.topic().resource_namespace() == resource_namespace_); + auto builder = Message::newBuilder(); + + // base + builder.withTopic(item.topic().name()); + + const auto& system_properties = item.system_properties(); + + // Tag + if (system_properties.has_tag()) { + builder.withTag(system_properties.tag()); + } + + // Keys + std::vector keys; + for (const auto& key : system_properties.keys()) { + keys.push_back(key); + } + if (!keys.empty()) { + builder.withKeys(std::move(keys)); + } + + // Message-Id + const auto& message_id = system_properties.message_id(); + builder.withId(message_id); + + // Validate body digest + const rmq::Digest& digest = system_properties.body_digest(); + bool body_digest_match = false; + if (item.body().empty()) { + SPDLOG_WARN("Body of message[topic={}, msgId={}] is empty", item.topic().name(), + item.system_properties().message_id()); + body_digest_match = true; + } else { + switch (digest.type()) { + case rmq::DigestType::CRC32: { + std::string checksum; + bool success = MixAll::crc32(item.body(), checksum); + if (success) { + body_digest_match = (digest.checksum() == checksum); + if (body_digest_match) { + SPDLOG_DEBUG("Message body CRC32 checksum validation passed."); + } else { + SPDLOG_WARN("Body CRC32 checksum validation failed. Actual: {}, expect: {}", checksum, digest.checksum()); + } + } else { + SPDLOG_WARN("Failed to calculate CRC32 checksum. Skip."); + } + break; + } + case rmq::DigestType::MD5: { + std::string checksum; + bool success = MixAll::md5(item.body(), checksum); + if (success) { + body_digest_match = (digest.checksum() == checksum); + if (body_digest_match) { + SPDLOG_DEBUG("Body of message[{}] MD5 checksum validation passed.", message_id); + } else { + SPDLOG_WARN("Body of message[{}] MD5 checksum validation failed. Expect: {}, Actual: {}", message_id, + digest.checksum(), checksum); + } + } else { + SPDLOG_WARN("Failed to calculate MD5 digest. Skip."); + body_digest_match = true; + } + break; + } + case rmq::DigestType::SHA1: { + std::string checksum; + bool success = MixAll::sha1(item.body(), checksum); + if (success) { + body_digest_match = (checksum == digest.checksum()); + if (body_digest_match) { + SPDLOG_DEBUG("Body of message[{}] SHA1 checksum validation passed", message_id); + } else { + SPDLOG_WARN("Body of message[{}] SHA1 checksum validation failed. Expect: {}, Actual: {}", message_id, + digest.checksum(), checksum); + } + } else { + SPDLOG_WARN("Failed to calculate SHA1 digest for message[{}]. Skip.", message_id); + } + break; + } + default: { + SPDLOG_WARN("Unsupported message body digest algorithm"); + body_digest_match = true; + break; + } + } + } + + if (!body_digest_match) { + SPDLOG_WARN("Message body checksum failed. MsgId={}", system_properties.message_id()); + // TODO: NACK it immediately + return nullptr; + } + + // Body encoding + switch (system_properties.body_encoding()) { + case rmq::Encoding::GZIP: { + std::string uncompressed; + UtilAll::uncompress(item.body(), uncompressed); + builder.withBody(uncompressed); + break; + } + case rmq::Encoding::IDENTITY: { + builder.withBody(item.body()); + break; + } + default: { + SPDLOG_WARN("Unsupported encoding algorithm"); + break; + } + } + + // User-properties + std::unordered_map properties; + for (const auto& it : item.user_properties()) { + properties.insert(std::make_pair(it.first, it.second)); + } + if (!properties.empty()) { + builder.withProperties(properties); + } + + // Born-timestamp + if (system_properties.has_born_timestamp()) { + auto born_timestamp = google::protobuf::util::TimeUtil::TimestampToMilliseconds(system_properties.born_timestamp()); + builder.withBornTime(absl::ToChronoTime(absl::FromUnixMillis(born_timestamp))); + } + + // Born-host + builder.withBornHost(system_properties.born_host()); + + // Trace-context + if (system_properties.has_trace_context()) { + builder.withTraceContext(system_properties.trace_context()); + } + + auto message = builder.build(); + + const Message* raw = message.release(); + Message* msg = const_cast(raw); + Extension& extension = msg->mutableExtension(); + + // Receipt-handle + extension.receipt_handle = system_properties.receipt_handle(); + + // Store-timestamp + if (system_properties.has_store_timestamp()) { + auto store_timestamp = + google::protobuf::util::TimeUtil::TimestampToMilliseconds(system_properties.store_timestamp()); + extension.store_time = absl::ToChronoTime(absl::FromUnixMillis(store_timestamp)); + } + + // Store-host + extension.store_host = system_properties.store_host(); + + // Process one-of: delivery-timestamp and delay-level. + if (system_properties.has_delivery_timestamp()) { + auto delivery_timestamp_ms = + google::protobuf::util::TimeUtil::TimestampToMilliseconds(system_properties.delivery_timestamp()); + extension.delivery_timepoint = absl::ToChronoTime(absl::FromUnixMillis(delivery_timestamp_ms)); + } + + // Queue-id + extension.queue_id = system_properties.queue_id(); + + // Queue-offset + extension.offset = system_properties.queue_offset(); + + // Invisible-period + if (system_properties.has_invisible_duration()) { + auto invisible_period = std::chrono::seconds(system_properties.invisible_duration().seconds()) + + std::chrono::nanoseconds(system_properties.invisible_duration().nanos()); + extension.invisible_period = invisible_period; + } + + // Delivery attempt + extension.delivery_attempt = system_properties.delivery_attempt(); + + // Decoded Time-Point + extension.decode_time = std::chrono::system_clock::now(); + + // Extension + { + auto elapsed = MixAll::millisecondsOf(std::chrono::system_clock::now() - extension.store_time); + if (elapsed >= 0) { + latency_histogram_.countIn(elapsed / 20); + } + } + return MessageConstSharedPtr(raw); +} + +SchedulerSharedPtr ClientManagerImpl::getScheduler() { + return scheduler_; +} + +void ClientManagerImpl::ack(const std::string& target, const Metadata& metadata, const AckMessageRequest& request, + std::chrono::milliseconds timeout, const std::function& cb) { + std::string target_host(target.data(), target.length()); + SPDLOG_DEBUG("Prepare to ack message against {} asynchronously. AckMessageRequest: {}", target_host, + request.DebugString()); + RpcClientSharedPtr client = getRpcClient(target_host); + + auto invocation_context = new InvocationContext(); + invocation_context->task_name = fmt::format("Ack messages against {}", target); + invocation_context->remote_address = target_host; + invocation_context->context.set_deadline(std::chrono::system_clock::now() + timeout); + + for (const auto& item : metadata) { + invocation_context->context.AddMetadata(item.first, item.second); + } + + // TODO: Use capture by move and pass-by-value paradigm when C++ 14 is available. + auto callback = [request, cb](const InvocationContext* invocation_context) { + std::error_code ec; + if (!invocation_context->status.ok()) { + ec = ErrorCode::RequestTimeout; + cb(ec); + return; + } + + auto&& status = invocation_context->response.status(); + switch (status.code()) { + case rmq::Code::OK: { + SPDLOG_DEBUG("Ack OK. host={}", invocation_context->remote_address); + } break; + case rmq::Code::UNAUTHORIZED: { + SPDLOG_WARN("Unauthorized: {}, host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::Unauthorized; + } break; + case rmq::Code::FORBIDDEN: { + SPDLOG_WARN("PermissionDenied: {}, host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::Forbidden; + } break; + case rmq::Code::INTERNAL_SERVER_ERROR: { + SPDLOG_WARN("InternalServerError: {}, host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::InternalServerError; + } break; + default: { + SPDLOG_WARN("NotImplement: please upgrade SDK to latest release. host={}", invocation_context->remote_address); + ec = ErrorCode::NotImplemented; + } break; + } + cb(ec); + }; + invocation_context->callback = callback; + client->asyncAck(request, invocation_context); +} + +void ClientManagerImpl::changeInvisibleDuration( + const std::string& target_host, const Metadata& metadata, const ChangeInvisibleDurationRequest& request, + std::chrono::milliseconds timeout, const std::function& completion_callback) { + RpcClientSharedPtr client = getRpcClient(target_host); + assert(client); + auto invocation_context = new InvocationContext(); + invocation_context->task_name = fmt::format("ChangeInvisibleDuration Message[receipt-handle={}] against {}", + request.receipt_handle(), target_host); + invocation_context->remote_address = target_host; + invocation_context->context.set_deadline(std::chrono::system_clock::now() + timeout); + + for (const auto& item : metadata) { + invocation_context->context.AddMetadata(item.first, item.second); + } + + auto callback = [completion_callback](const InvocationContext* invocation_context) { + if (!invocation_context->status.ok()) { + SPDLOG_WARN("Failed to write Nack request to wire. gRPC-code: {}, gRPC-message: {}", + invocation_context->status.error_code(), invocation_context->status.error_message()); + std::error_code ec = ErrorCode::RequestTimeout; + completion_callback(ec); + return; + } + + std::error_code ec; + auto&& status = invocation_context->response.status(); + switch (status.code()) { + case rmq::Code::OK: { + SPDLOG_DEBUG("Nack to {} OK", invocation_context->remote_address); + break; + }; + case rmq::Code::UNAUTHORIZED: { + SPDLOG_WARN("Unauthorized: {}, host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::Unauthorized; + break; + } + case rmq::Code::FORBIDDEN: { + SPDLOG_WARN("Forbidden: {}, host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::Forbidden; + break; + } + case rmq::Code::INTERNAL_SERVER_ERROR: { + SPDLOG_WARN("InternalServerError: {}, host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::InternalServerError; + break; + } + default: { + SPDLOG_WARN("NotImplemented: Please upgrade to latest SDK, host={}", invocation_context->remote_address); + ec = ErrorCode::NotImplemented; + break; + } + } + completion_callback(ec); + }; + invocation_context->callback = callback; + client->asyncChangeInvisibleDuration(request, invocation_context); +} + +void ClientManagerImpl::endTransaction( + const std::string& target_host, const Metadata& metadata, const EndTransactionRequest& request, + std::chrono::milliseconds timeout, + const std::function& cb) { + RpcClientSharedPtr client = getRpcClient(target_host); + if (!client) { + SPDLOG_WARN("No RPC client for {}", target_host); + EndTransactionResponse response; + std::error_code ec = ErrorCode::BadRequest; + cb(ec, response); + return; + } + + SPDLOG_DEBUG("Prepare to endTransaction. TargetHost={}, Request: {}", target_host.data(), request.DebugString()); + + auto invocation_context = new InvocationContext(); + invocation_context->task_name = fmt::format("End transaction[{}] of message[] against {}", request.transaction_id(), + request.message_id(), target_host); + invocation_context->remote_address = target_host; + for (const auto& item : metadata) { + invocation_context->context.AddMetadata(item.first, item.second); + } + + // Set RPC deadline. + auto deadline = std::chrono::system_clock::now() + timeout; + invocation_context->context.set_deadline(deadline); + + auto callback = [target_host, cb](const InvocationContext* invocation_context) { + std::error_code ec; + if (!invocation_context->status.ok()) { + SPDLOG_WARN("Failed to write EndTransaction to wire. gRPC-code: {}, gRPC-message: {}, host={}", + invocation_context->status.error_code(), invocation_context->status.error_message(), + invocation_context->remote_address); + ec = ErrorCode::BadRequest; + cb(ec, invocation_context->response); + return; + } + + auto&& status = invocation_context->response.status(); + switch (status.code()) { + case rmq::Code::OK: { + SPDLOG_DEBUG("endTransaction completed OK. Response: {}, host={}", invocation_context->response.DebugString(), + invocation_context->remote_address); + } break; + case rmq::Code::UNAUTHORIZED: { + SPDLOG_WARN("Unauthorized: {}, host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::Unauthorized; + } break; + case rmq::Code::FORBIDDEN: { + SPDLOG_WARN("Forbidden: {}, host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::Forbidden; + } break; + case rmq::Code::INTERNAL_SERVER_ERROR: { + SPDLOG_WARN("InternalServerError: {}, host={}", status.message(), invocation_context->remote_address); + ec = ErrorCode::InternalServerError; + } break; + default: { + SPDLOG_WARN("NotImplemented: please upgrade SDK to latest release. {}, host={}", status.message(), + invocation_context->remote_address); + ec = ErrorCode::NotImplemented; + } + } + cb(ec, invocation_context->response); + }; + + invocation_context->callback = callback; + client->asyncEndTransaction(request, invocation_context); +} + +void ClientManagerImpl::forwardMessageToDeadLetterQueue(const std::string& target_host, + const Metadata& metadata, + const ForwardMessageToDeadLetterQueueRequest& request, + std::chrono::milliseconds timeout, + const std::function& cb) { + SPDLOG_DEBUG("ForwardMessageToDeadLetterQueue Request: {}", request.DebugString()); + auto client = getRpcClient(target_host); + auto invocation_context = new InvocationContext(); + invocation_context->task_name = + fmt::format("Forward message[{}] to DLQ against {}", request.message_id(), target_host); + invocation_context->remote_address = target_host; + invocation_context->context.set_deadline(std::chrono::system_clock::now() + timeout); + + for (const auto& item : metadata) { + invocation_context->context.AddMetadata(item.first, item.second); + } + + auto callback = [cb](const InvocationContext* invocation_context) { + if (!invocation_context->status.ok()) { + SPDLOG_WARN("Failed to transmit SendMessageToDeadLetterQueueRequest to host={}", + invocation_context->remote_address); + std::error_code ec = ErrorCode::BadRequest; + cb(ec); + return; + } + + SPDLOG_DEBUG("Received forwardToDeadLetterQueue response from server[host={}]", invocation_context->remote_address); + std::error_code ec; + switch (invocation_context->response.status().code()) { + case rmq::Code::OK: { + break; + } + case rmq::Code::INTERNAL_SERVER_ERROR: { + ec = ErrorCode::ServiceUnavailable; + } + case rmq::Code::TOO_MANY_REQUESTS: { + ec = ErrorCode::TooManyRequest; + } + default: { + ec = ErrorCode::NotImplemented; + } + } + cb(ec); + }; + invocation_context->callback = callback; + client->asyncForwardMessageToDeadLetterQueue(request, invocation_context); +} + +std::error_code ClientManagerImpl::notifyClientTermination(const std::string& target_host, const Metadata& metadata, + const NotifyClientTerminationRequest& request, + std::chrono::milliseconds timeout) { + std::error_code ec; + auto client = getRpcClient(target_host); + if (!client) { + SPDLOG_WARN("Failed to create RpcClient for host={}", target_host); + ec = ErrorCode::RequestTimeout; + return ec; + } + + grpc::ClientContext context; + context.set_deadline(std::chrono::system_clock::now() + timeout); + for (const auto& item : metadata) { + context.AddMetadata(item.first, item.second); + } + + SPDLOG_DEBUG("NotifyClientTermination request: {}", request.DebugString()); + + NotifyClientTerminationResponse response; + { + grpc::Status status = client->notifyClientTermination(&context, request, &response); + if (!status.ok()) { + SPDLOG_WARN("NotifyClientTermination failed. gRPC-code={}, gRPC-message={}, host={}", status.error_code(), + status.error_message(), target_host); + ec = ErrorCode::RequestTimeout; + return ec; + } + } + + auto&& status = response.status(); + + switch (status.code()) { + case rmq::Code::OK: { + SPDLOG_DEBUG("NotifyClientTermination OK. host={}", target_host); + break; + } + case rmq::Code::INTERNAL_SERVER_ERROR: { + SPDLOG_WARN("InternalServerError: Cause={}, host={}", status.message(), target_host); + ec = ErrorCode::InternalServerError; + break; + } + case rmq::Code::UNAUTHORIZED: { + SPDLOG_WARN("Unauthorized due to lack of valid authentication credentials: Cause={}, host={}", status.message(), + target_host); + ec = ErrorCode::Unauthorized; + break; + } + case rmq::Code::FORBIDDEN: { + SPDLOG_WARN("Forbidden due to insufficient permission to the resource: Cause={}, host={}", status.message(), + target_host); + ec = ErrorCode::Forbidden; + break; + } + default: { + SPDLOG_WARN("NotImplemented. Please upgrade to latest SDK release. host={}", target_host); + ec = ErrorCode::NotImplemented; + break; + } + } + return ec; +} + +void ClientManagerImpl::logStats() { + std::string stats; + latency_histogram_.reportAndReset(stats); + SPDLOG_INFO("{}", stats); +} + +void ClientManagerImpl::submit(std::function task) { + State current_state = state(); + if (current_state == State::STOPPING || current_state == State::STOPPED) { + return; + } + callback_thread_pool_->submit(task); +} + +const char* ClientManagerImpl::HEARTBEAT_TASK_NAME = "heartbeat-task"; +const char* ClientManagerImpl::STATS_TASK_NAME = "stats-task"; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/LogInterceptor.cpp b/src/main/cpp/client/LogInterceptor.cpp new file mode 100644 index 000000000..09dbc9fff --- /dev/null +++ b/src/main/cpp/client/LogInterceptor.cpp @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "LogInterceptor.h" +#include "InterceptorContinuation.h" +#include "absl/container/flat_hash_map.h" +#include "absl/strings/str_join.h" +#include "google/protobuf/message.h" +#include "rocketmq/Logger.h" +#include "spdlog/spdlog.h" +#include + +ROCKETMQ_NAMESPACE_BEGIN + +void LogInterceptor::Intercept(grpc::experimental::InterceptorBatchMethods* methods) { + InterceptorContinuation continuation(methods); + + auto level = spdlog::default_logger()->level(); + switch (level) { + case spdlog::level::trace: + // fall-through on purpose. + case spdlog::level::debug: { + break; + } + case spdlog::level::info: + // fall-through on purpose. + case spdlog::level::warn: + // fall-through on purpose. + case spdlog::level::err: { + return; + } + default: { + return; + } + } + + if (methods->QueryInterceptionHookPoint(grpc::experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA)) { + std::multimap* metadata = methods->GetSendInitialMetadata(); + if (metadata) { + SPDLOG_DEBUG("[Outbound]Headers of {}: \n{}", client_rpc_info_->method(), + absl::StrJoin(*metadata, "\n", absl::PairFormatter(" --> "))); + } + } + + if (methods->QueryInterceptionHookPoint(grpc::experimental::InterceptionHookPoints::PRE_SEND_MESSAGE)) { + grpc::ByteBuffer* buffer = methods->GetSerializedSendMessage(); + if (buffer) { + SPDLOG_DEBUG("[Outbound] {}: Buffer: {}bytes", client_rpc_info_->method(), buffer->Length()); + } + } + + if (methods->QueryInterceptionHookPoint(grpc::experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA)) { + std::multimap* metadata = methods->GetRecvInitialMetadata(); + if (metadata) { + absl::flat_hash_map response_headers; + for (const auto& it : *metadata) { + response_headers.insert({absl::string_view(it.first.data(), it.first.length()), + absl::string_view(it.second.data(), it.second.length())}); + } + if (!response_headers.empty()) { + SPDLOG_DEBUG("[Inbound]Response Headers of {}:\n{}", client_rpc_info_->method(), + absl::StrJoin(response_headers, "\n", absl::PairFormatter(" --> "))); + } else { + SPDLOG_DEBUG("[Inbound]Response metadata of {} is empty", client_rpc_info_->method()); + } + } + } + + if (methods->QueryInterceptionHookPoint(grpc::experimental::InterceptionHookPoints::POST_RECV_MESSAGE)) { + void* message = methods->GetRecvMessage(); + if (message) { + auto* response = reinterpret_cast(message); + std::string&& response_text = response->DebugString(); + std::size_t limit = 1024; + if (response_text.size() <= limit) { + SPDLOG_DEBUG("[Inbound] {}\n{}", client_rpc_info_->method(), response_text); + } else { + SPDLOG_DEBUG("[Inbound] {}\n{}...", client_rpc_info_->method(), response_text.substr(0, limit)); + } + } + } +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/LogInterceptorFactory.cpp b/src/main/cpp/client/LogInterceptorFactory.cpp new file mode 100644 index 000000000..16247e0ef --- /dev/null +++ b/src/main/cpp/client/LogInterceptorFactory.cpp @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "LogInterceptorFactory.h" +#include "LogInterceptor.h" + +ROCKETMQ_NAMESPACE_BEGIN + +grpc::experimental::Interceptor* +LogInterceptorFactory::CreateClientInterceptor(grpc::experimental::ClientRpcInfo* info) { + return new LogInterceptor(info); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/ReceiveMessageStreamReader.cpp b/src/main/cpp/client/ReceiveMessageStreamReader.cpp new file mode 100644 index 000000000..223c8797f --- /dev/null +++ b/src/main/cpp/client/ReceiveMessageStreamReader.cpp @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ReceiveMessageStreamReader.h" + +#include "LoggerImpl.h" + +ROCKETMQ_NAMESPACE_BEGIN + +ReceiveMessageStreamReader::ReceiveMessageStreamReader(std::weak_ptr client_manager, + rmq::MessagingService::Stub* stub, + std::string peer_address, + rmq::ReceiveMessageRequest request, + std::unique_ptr context) + : client_manager_(client_manager), + stub_(stub), + peer_address_(std::move(peer_address)), + request_(std::move(request)), + context_(std::move(context)) { + for (const auto& entry : context_->metadata) { + client_context_.AddMetadata(entry.first, entry.second); + } + client_context_.set_deadline(std::chrono::system_clock::now() + context_->timeout); + + stub_->async()->ReceiveMessage(&client_context_, &request_, this); + result_.source_host = peer_address_; + StartCall(); + StartRead(&response_); +} + +void ReceiveMessageStreamReader::OnReadDone(bool ok) { + if (ok) { + SPDLOG_DEBUG("ReceiveMessageStreamReader#OnReadDone: ok={}", ok); + } else { + if (result_.messages.empty() && !ec_) { + SPDLOG_WARN("ReceiveMessageStreamReader#OnReadDone: ok={}", ok); + ec_ = ErrorCode::BadGateway; + } else { + SPDLOG_DEBUG("ReceiveMessageStreamReader#OnReadDone reached end-of-stream"); + } + return; + } + + SPDLOG_DEBUG("ReceiveMessageStreamReader#OnReadDone: response={}", response_.DebugString()); + switch (response_.content_case()) { + case rmq::ReceiveMessageResponse::ContentCase::kStatus: { + SPDLOG_DEBUG("ReceiveMessageResponse.status.message={}", response_.status().message()); + switch (response_.status().code()) { + case rmq::Code::OK: { + break; + } + case rmq::Code::TOPIC_NOT_FOUND: { + ec_ = ErrorCode::TopicNotFound; + break; + } + + case rmq::Code::CONSUMER_GROUP_NOT_FOUND: { + ec_ = ErrorCode::GroupNotFound; + break; + } + case rmq::Code::TOO_MANY_REQUESTS: { + ec_ = ErrorCode::TooManyRequest; + break; + } + case rmq::Code::MESSAGE_NOT_FOUND: { + ec_ = ErrorCode::NoContent; + break; + } + default: + SPDLOG_WARN("Unsupported code={}", response_.status().code()); + break; + } + break; + } + case rmq::ReceiveMessageResponse::ContentCase::kMessage: { + auto client_manager = client_manager_.lock(); + auto message = client_manager->wrapMessage(response_.message()); + auto raw = const_cast(message.get()); + raw->mutableExtension().target_endpoint = peer_address_; + if (message) { + result_.messages.push_back(message); + } + break; + } + default: + break; + } + + StartRead(&response_); +} + +void ReceiveMessageStreamReader::OnDone(const grpc::Status& s) { + if (!s.ok()) { + SPDLOG_WARN("ReceiveMessageStreamReader#OnDone: status.ok={}, status.error_message={}", s.ok(), s.error_message()); + } else { + SPDLOG_DEBUG("ReceiveMessageStreamReader#OnDone: status.ok={}", s.ok()); + } + + status_ = s; + context_->callback(ec_, result_); + delete this; +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/RpcClientImpl.cpp b/src/main/cpp/client/RpcClientImpl.cpp new file mode 100644 index 000000000..623547e6b --- /dev/null +++ b/src/main/cpp/client/RpcClientImpl.cpp @@ -0,0 +1,173 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "RpcClientImpl.h" + +#include +#include +#include +#include + +#include "absl/time/time.h" + +#include "ClientManager.h" +#include "ReceiveMessageStreamReader.h" +#include "RpcClient.h" +#include "TelemetryBidiReactor.h" +#include "TlsHelper.h" +#include "include/ReceiveMessageContext.h" + +ROCKETMQ_NAMESPACE_BEGIN + +using ClientContext = grpc::ClientContext; + +void RpcClientImpl::asyncCallback(std::weak_ptr client, BaseInvocationContext* invocation_context, + grpc::Status status) { + + invocation_context->status = std::move(status); + std::shared_ptr stub = client.lock(); + if (!stub) { + SPDLOG_WARN("RpcClient has destructed. Response Ignored"); + // TODO: execute orphan callback in event-loop thread? + // invocation_context->onCompletion(false); + // or + delete invocation_context; + return; + } + + std::weak_ptr client_manager = stub->clientManager(); + std::shared_ptr manager = client_manager.lock(); + if (!manager) { + SPDLOG_WARN("ClientManager has destructed. Response ignored"); + // TODO: execute orphan callback in event-loop thread? + // invocation_context->onCompletion(false); + // or + delete invocation_context; + } + + auto task = [invocation_context, client] { + auto ptr = client.lock(); + if (!ptr) { + // RPC client should have destructed. + return; + } + invocation_context->onCompletion(invocation_context->status.ok()); + }; + + // Execute business post-processing in callback thread pool. + manager->submit(task); +} + +void RpcClientImpl::asyncQueryRoute(const QueryRouteRequest& request, + InvocationContext* invocation_context) { + std::weak_ptr rpc_client(shared_from_this()); + auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1); + stub_->async()->QueryRoute(&invocation_context->context, &request, &invocation_context->response, callback); +} + +void RpcClientImpl::asyncSend(const SendMessageRequest& request, + InvocationContext* invocation_context) { + std::weak_ptr rpc_client(shared_from_this()); + auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1); + stub_->async()->SendMessage(&invocation_context->context, &request, &invocation_context->response, callback); +} + +void RpcClientImpl::asyncQueryAssignment(const QueryAssignmentRequest& request, + InvocationContext* invocation_context) { + std::weak_ptr rpc_client(shared_from_this()); + auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1); + stub_->async()->QueryAssignment(&invocation_context->context, &request, &invocation_context->response, callback); +} + +void RpcClientImpl::asyncReceive(const ReceiveMessageRequest& request, std::unique_ptr context) { + new ReceiveMessageStreamReader(client_manager_, stub_.get(), peer_address_, request, std::move(context)); +} + +void RpcClientImpl::asyncAck(const AckMessageRequest& request, + InvocationContext* invocation_context) { + std::weak_ptr rpc_client(shared_from_this()); + auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1); + stub_->async()->AckMessage(&invocation_context->context, &request, &invocation_context->response, callback); +} + +void RpcClientImpl::asyncChangeInvisibleDuration( + const ChangeInvisibleDurationRequest& request, + InvocationContext* invocation_context) { + + std::weak_ptr rpc_client(shared_from_this()); + auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1); + + stub_->async()->ChangeInvisibleDuration(&invocation_context->context, &request, &invocation_context->response, + callback); +} + +void RpcClientImpl::asyncHeartbeat(const HeartbeatRequest& request, + InvocationContext* invocation_context) { + std::weak_ptr rpc_client(shared_from_this()); + auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1); + stub_->async()->Heartbeat(&invocation_context->context, &request, &invocation_context->response, callback); +} + +void RpcClientImpl::asyncEndTransaction(const EndTransactionRequest& request, + InvocationContext* invocation_context) { + std::weak_ptr rpc_client(shared_from_this()); + auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1); + stub_->async()->EndTransaction(&invocation_context->context, &request, &invocation_context->response, callback); +} + +bool RpcClientImpl::ok() const { + return channel_ && grpc_connectivity_state::GRPC_CHANNEL_SHUTDOWN != channel_->GetState(false); +} + +void RpcClientImpl::addMetadata(grpc::ClientContext& context, + const absl::flat_hash_map& metadata) { + for (const auto& entry : metadata) { + context.AddMetadata(entry.first, entry.second); + } +} + +bool RpcClientImpl::needHeartbeat() { + return need_heartbeat_; +} + +void RpcClientImpl::needHeartbeat(bool need_heartbeat) { + need_heartbeat_ = need_heartbeat; +} + +std::shared_ptr RpcClientImpl::asyncTelemetry(std::weak_ptr client) { + return std::make_shared(client, stub_.get(), peer_address_); +} + +grpc::Status RpcClientImpl::notifyClientTermination(grpc::ClientContext* context, + const NotifyClientTerminationRequest& request, + NotifyClientTerminationResponse* response) { + return stub_->NotifyClientTermination(context, request, response); +} + +void RpcClientImpl::asyncForwardMessageToDeadLetterQueue( + const ForwardMessageToDeadLetterQueueRequest& request, + InvocationContext* invocation_context) { + std::weak_ptr rpc_client(shared_from_this()); + auto callback = std::bind(&RpcClientImpl::asyncCallback, rpc_client, invocation_context, std::placeholders::_1); + stub_->async()->ForwardMessageToDeadLetterQueue(&invocation_context->context, &request, &invocation_context->response, + callback); +} + +std::weak_ptr RpcClientImpl::clientManager() { + return client_manager_; +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/common/MessageSysFlag.cpp b/src/main/cpp/client/SessionImpl.cpp similarity index 54% rename from src/common/MessageSysFlag.cpp rename to src/main/cpp/client/SessionImpl.cpp index 732f1d5c6..5b7c08569 100644 --- a/src/common/MessageSysFlag.cpp +++ b/src/main/cpp/client/SessionImpl.cpp @@ -14,24 +14,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "MessageSysFlag.h" -namespace rocketmq { -int MessageSysFlag::CompressedFlag = (0x1 << 0); -int MessageSysFlag::MultiTagsFlag = (0x1 << 1); +#include "SessionImpl.h" +#include "LoggerImpl.h" -int MessageSysFlag::TransactionNotType = (0x0 << 2); -int MessageSysFlag::TransactionPreparedType = (0x1 << 2); -int MessageSysFlag::TransactionCommitType = (0x2 << 2); -int MessageSysFlag::TransactionRollbackType = (0x3 << 2); +ROCKETMQ_NAMESPACE_BEGIN -int MessageSysFlag::getTransactionValue(int flag) { - return flag & TransactionRollbackType; +SessionImpl::SessionImpl(std::weak_ptr client, std::shared_ptr rpc_client) : client_(client), rpc_client_(rpc_client) { + telemetry_ = rpc_client->asyncTelemetry(client_); + syncSettings(); } -int MessageSysFlag::resetTransactionValue(int flag, int type) { - return (flag & (~TransactionRollbackType)) | type; +bool SessionImpl::await() { + return telemetry_->await(); } -//CopyFrom(ptr->clientSettings()); + telemetry_->write(command); +} + +SessionImpl::~SessionImpl() { + SPDLOG_DEBUG("Session for {} destructed", rpc_client_->remoteAddress()); + telemetry_->fireClose(); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/Signature.cpp b/src/main/cpp/client/Signature.cpp new file mode 100644 index 000000000..e25dbb54b --- /dev/null +++ b/src/main/cpp/client/Signature.cpp @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "Signature.h" +#include "ClientConfig.h" +#include "MetadataConstants.h" +#include "Protocol.h" +#include "TlsHelper.h" +#include "spdlog/spdlog.h" + +ROCKETMQ_NAMESPACE_BEGIN + +void Signature::sign(const ClientConfig& client, absl::flat_hash_map& metadata) { + + metadata.insert({MetadataConstants::LANGUAGE_KEY, "CPP"}); + // Add common headers + metadata.insert({MetadataConstants::CLIENT_ID_KEY, client.client_id}); + metadata.insert({MetadataConstants::CLIENT_VERSION_KEY, MetadataConstants::CLIENT_VERSION}); + metadata.insert({MetadataConstants::PROTOCOL_VERSION_KEY, protocolVersion()}); + + absl::Time now = absl::Now(); + absl::TimeZone utc_time_zone = absl::UTCTimeZone(); + const std::string request_date_time = absl::FormatTime(MetadataConstants::DATE_TIME_FORMAT, now, utc_time_zone); + metadata.insert({MetadataConstants::DATE_TIME_KEY, request_date_time}); + + if (client.credentials_provider) { + Credentials&& credentials = client.credentials_provider->getCredentials(); + if (credentials.accessKey().empty() || credentials.accessSecret().empty()) { + SPDLOG_WARN("Access credential is incomplete. Check your access key/secret."); + return; + } + + std::string authorization; + authorization.append(MetadataConstants::ALGORITHM_KEY) + .append(" ") + .append(MetadataConstants::CREDENTIAL_KEY) + .append("=") + .append(credentials.accessKey()) + .append("/") + .append(client.region) + .append("/") + .append(MetadataConstants::SERVICE_NAME) + .append(", ") + .append(MetadataConstants::SIGNED_HEADERS_KEY) + .append("=") + .append(MetadataConstants::DATE_TIME_KEY) + .append(", ") + .append(MetadataConstants::SIGNATURE_KEY) + .append("=") + .append(TlsHelper::sign(credentials.accessSecret(), request_date_time)); + SPDLOG_DEBUG("Add authorization header: {}", authorization); + metadata.insert({MetadataConstants::AUTHORIZATION, authorization}); + + if (!credentials.sessionToken().empty()) { + metadata.insert({MetadataConstants::STS_SESSION_TOKEN, credentials.sessionToken()}); + } + } +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/TelemetryBidiReactor.cpp b/src/main/cpp/client/TelemetryBidiReactor.cpp new file mode 100644 index 000000000..cf251e49f --- /dev/null +++ b/src/main/cpp/client/TelemetryBidiReactor.cpp @@ -0,0 +1,347 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "TelemetryBidiReactor.h" + +#include +#include +#include + +#include "ClientManager.h" +#include "LoggerImpl.h" +#include "MessageExt.h" +#include "Metadata.h" +#include "RpcClient.h" +#include "Signature.h" +#include "google/protobuf/util/time_util.h" + +ROCKETMQ_NAMESPACE_BEGIN + +TelemetryBidiReactor::TelemetryBidiReactor(std::weak_ptr client, + rmq::MessagingService::Stub* stub, + std::string peer_address) + : client_(client), peer_address_(std::move(peer_address)), stream_state_(StreamState::Created) { + auto ptr = client.lock(); + auto deadline = std::chrono::system_clock::now() + std::chrono::hours(1); + context_.set_deadline(deadline); + Metadata metadata; + Signature::sign(ptr->config(), metadata); + for (const auto& entry : metadata) { + context_.AddMetadata(entry.first, entry.second); + } + stub->async()->Telemetry(&context_, this); + StartCall(); +} + +TelemetryBidiReactor::~TelemetryBidiReactor() { + SPDLOG_INFO("Telemetry stream for {} destructed. StreamState={}", peer_address_, stream_state_); +} + +bool TelemetryBidiReactor::await() { + absl::MutexLock lk(&server_setting_received_mtx_); + if (server_setting_received_) { + return true; + } + + server_setting_received_cv_.Wait(&server_setting_received_mtx_); + return server_setting_received_; +} + +void TelemetryBidiReactor::OnWriteDone(bool ok) { + SPDLOG_DEBUG("OnWriteDone: {}", ok); + + { + bool expect = true; + if (!command_inflight_.compare_exchange_strong(expect, false, std::memory_order_relaxed)) { + SPDLOG_WARN("Illegal command-inflight state"); + } + } + + if (!ok) { + SPDLOG_WARN("Failed to write telemetry command {} to {}", write_.DebugString(), peer_address_); + { + absl::MutexLock lk(&stream_state_mtx_); + stream_state_ = StreamState::WriteDone; + } + + fireClose(); + return; + } + + { + absl::MutexLock lk(&stream_state_mtx_); + if (StreamState::Created == stream_state_) { + stream_state_ = StreamState::Active; + fireRead(); + } + } + + fireWrite(); +} + +void TelemetryBidiReactor::OnReadDone(bool ok) { + SPDLOG_DEBUG("OnReadDone: ok={}", ok); + if (!ok) { + SPDLOG_WARN("Failed to read telemetry command from {}", peer_address_); + { + absl::MutexLock lk(&stream_state_mtx_); + stream_state_ = StreamState::ReadDone; + } + fireClose(); + return; + } + + SPDLOG_DEBUG("Read a telemetry command from {}: {}", peer_address_, read_.DebugString()); + auto ptr = client_.lock(); + if (!ptr) { + SPDLOG_INFO("Client for {} has destructed", peer_address_); + return; + } + + switch (read_.command_case()) { + case rmq::TelemetryCommand::kSettings: { + auto settings = read_.settings(); + SPDLOG_INFO("Received settings from {}: {}", peer_address_, settings.DebugString()); + applySettings(settings); + { + absl::MutexLock lk(&server_setting_received_mtx_); + if (!server_setting_received_) { + server_setting_received_ = true; + server_setting_received_cv_.SignalAll(); + } + } + break; + } + case rmq::TelemetryCommand::kRecoverOrphanedTransactionCommand: { + auto client = client_.lock(); + if (!client) { + fireClose(); + return; + } + + auto message = client->manager()->wrapMessage(read_.release_verify_message_command()->message()); + auto raw = const_cast(message.get()); + raw->mutableExtension().target_endpoint = peer_address_; + raw->mutableExtension().transaction_id = read_.recover_orphaned_transaction_command().transaction_id(); + client->recoverOrphanedTransaction(message); + + break; + } + + case rmq::TelemetryCommand::kPrintThreadStackTraceCommand: { + TelemetryCommand response; + response.mutable_thread_stack_trace()->set_nonce(read_.print_thread_stack_trace_command().nonce()); + response.mutable_thread_stack_trace()->set_thread_stack_trace("PrintStackTrace is not supported"); + { + absl::MutexLock lk(&writes_mtx_); + writes_.push_back(response); + } + fireWrite(); + StartRead(&read_); + break; + } + + case rmq::TelemetryCommand::kVerifyMessageCommand: { + auto client = client_.lock(); + if (!client) { + fireClose(); + return; + } + + std::weak_ptr ptr(shared_from_this()); + auto cb = [ptr](TelemetryCommand command) { + auto reactor = ptr.lock(); + if (!reactor) { + return; + } + reactor->onVerifyMessageResult(std::move(command)); + }; + auto message = client->manager()->wrapMessage(read_.verify_message_command().message()); + auto raw = const_cast(message.get()); + raw->mutableExtension().target_endpoint = peer_address_; + raw->mutableExtension().nonce = read_.verify_message_command().nonce(); + client->verify(message, cb); + StartRead(&read_); + break; + } + + default: { + SPDLOG_WARN("Unsupported command"); + break; + } + } +} + +void TelemetryBidiReactor::applySettings(const rmq::Settings& settings) { + auto ptr = client_.lock(); + if (!ptr) { + SPDLOG_INFO("Client for {} has destructed", peer_address_); + return; + } + + applyBackoffPolicy(settings, ptr); + + // Sync metrics collector configuration + if (settings.has_metric()) { + const auto& metric = settings.metric(); + ptr->config().metric.on = metric.on(); + ptr->config().metric.endpoints.set_scheme(metric.endpoints().scheme()); + ptr->config().metric.endpoints.mutable_addresses()->CopyFrom(metric.endpoints().addresses()); + } + + switch (settings.pub_sub_case()) { + case rmq::Settings::PubSubCase::kPublishing: { + applyPublishingConfig(settings, ptr); + break; + } + case rmq::Settings::PubSubCase::kSubscription: { + applySubscriptionConfig(settings, ptr); + break; + } + default: { + break; + } + } +} + +void TelemetryBidiReactor::applyBackoffPolicy(const rmq::Settings& settings, std::shared_ptr& ptr) { + // Apply backoff policy on throttling + if (settings.has_backoff_policy()) { + const auto& backoff_policy = settings.backoff_policy(); + ptr->config().backoff_policy.max_attempt = backoff_policy.max_attempts(); + if (backoff_policy.has_customized_backoff()) { + for (const auto& item : backoff_policy.customized_backoff().next()) { + auto backoff = std::chrono::seconds(item.seconds()) + std::chrono::nanoseconds(item.nanos()); + ptr->config().backoff_policy.next.push_back(absl::FromChrono(backoff)); + } + } + + if (backoff_policy.has_exponential_backoff()) { + const auto& exp_backoff = backoff_policy.exponential_backoff(); + ptr->config().backoff_policy.initial = absl::FromChrono(std::chrono::seconds(exp_backoff.initial().seconds()) + + std::chrono::nanoseconds(exp_backoff.initial().nanos())); + ptr->config().backoff_policy.multiplier = exp_backoff.multiplier(); + ptr->config().backoff_policy.max = absl::FromChrono(std::chrono::seconds(exp_backoff.max().seconds()) + + std::chrono::nanoseconds(exp_backoff.max().nanos())); + } + } +} + +void TelemetryBidiReactor::applyPublishingConfig(const rmq::Settings& settings, std::shared_ptr client) { + client->config().publisher.max_body_size = settings.publishing().max_body_size(); + client->config().publisher.compress_body_threshold = settings.publishing().compress_body_threshold(); +} + +void TelemetryBidiReactor::applySubscriptionConfig(const rmq::Settings& settings, std::shared_ptr client) { + client->config().subscriber.fifo = settings.subscription().fifo(); + auto polling_timeout = + google::protobuf::util::TimeUtil::DurationToMilliseconds(settings.subscription().long_polling_timeout()); + client->config().subscriber.polling_timeout = absl::Milliseconds(polling_timeout); + client->config().subscriber.receive_batch_size = settings.subscription().receive_batch_size(); +} + +void TelemetryBidiReactor::fireRead() { + SPDLOG_DEBUG("{}#fireRead", peer_address_); + StartRead(&read_); +} + +void TelemetryBidiReactor::write(TelemetryCommand command) { + { + absl::MutexLock lk(&writes_mtx_); + writes_.push_back(command); + } + fireWrite(); +} + +void TelemetryBidiReactor::fireWrite() { + SPDLOG_DEBUG("{}#fireWrite", peer_address_); + { + absl::MutexLock lk(&writes_mtx_); + if (writes_.empty()) { + SPDLOG_DEBUG("No TelemtryCommand to write. Peer={}", peer_address_); + return; + } + + bool expect = false; + if (command_inflight_.compare_exchange_strong(expect, true, std::memory_order_relaxed)) { + write_ = std::move(*writes_.begin()); + writes_.erase(writes_.begin()); + } else { + SPDLOG_DEBUG("Another command is already on the wire. Peer={}", peer_address_); + return; + } + } + SPDLOG_DEBUG("Writing telemetry command to {}: {}", peer_address_, write_.DebugString()); + StartWrite(&write_); +} + +void TelemetryBidiReactor::fireClose() { + SPDLOG_INFO("{}#fireClose", peer_address_); + if (StreamState::Active == stream_state_) { + StartWritesDone(); + { + absl::MutexLock lk(&stream_state_mtx_); + if (StreamState::Active == stream_state_) { + stream_state_cv_.Wait(&stream_state_mtx_); + } + } + } +} + +void TelemetryBidiReactor::OnWritesDoneDone(bool ok) { + SPDLOG_DEBUG("{}#OnWritesDoneDone", peer_address_); +} + +void TelemetryBidiReactor::onVerifyMessageResult(TelemetryCommand command) { + { + absl::MutexLock lk(&writes_mtx_); + writes_.emplace_back(command); + } + fireWrite(); +} + +/// Notifies the application that all operations associated with this RPC +/// have completed and all Holds have been removed. OnDone provides the RPC +/// status outcome for both successful and failed RPCs and will be called in +/// all cases. If it is not called, it indicates an application-level problem +/// (like failure to remove a hold). +/// +/// \param[in] status The status outcome of this RPC +void TelemetryBidiReactor::OnDone(const grpc::Status& status) { + SPDLOG_DEBUG("{}#OnDone, status.ok={}", peer_address_, status.ok()); + if (!status.ok()) { + SPDLOG_WARN("{}#OnDone, status.error_code={}, status.error_message={}, status.error_details={}", peer_address_, + status.error_code(), status.error_message(), status.error_details()); + } + + { + SPDLOG_DEBUG("{} notifies awaiting close call", peer_address_); + absl::MutexLock lk(&stream_state_mtx_); + stream_state_ = StreamState::Closed; + stream_state_cv_.SignalAll(); + } + + auto client = client_.lock(); + if (!client) { + return; + } + + if (client->active()) { + client->createSession(peer_address_, true); + } +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/include/CBatchMessage.h b/src/main/cpp/client/TlsHelper.cpp similarity index 53% rename from include/CBatchMessage.h rename to src/main/cpp/client/TlsHelper.cpp index b9a0e9daa..aa4970a54 100644 --- a/include/CBatchMessage.h +++ b/src/main/cpp/client/TlsHelper.cpp @@ -14,23 +14,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "TlsHelper.h" -#ifndef __C_BATCHMESSAGE_H__ -#define __C_BATCHMESSAGE_H__ -#include "CCommon.h" -#include "CMessage.h" +#include -#ifdef __cplusplus -extern "C" { -#endif +#include "MixAll.h" +#include "OpenSSLCompatible.h" +#include "openssl/hmac.h" -typedef struct CBatchMessage CBatchMessage; +ROCKETMQ_NAMESPACE_BEGIN -ROCKETMQCLIENT_API CBatchMessage* CreateBatchMessage(); -ROCKETMQCLIENT_API int AddMessage(CBatchMessage* batchMsg, CMessage* msg); -ROCKETMQCLIENT_API int DestroyBatchMessage(CBatchMessage* batchMsg); +std::string TlsHelper::sign(const std::string& access_secret, const std::string& content) { + HMAC_CTX* ctx = HMAC_CTX_new(); + HMAC_Init_ex(ctx, access_secret.c_str(), access_secret.length(), EVP_sha1(), nullptr); + HMAC_Update(ctx, reinterpret_cast(content.c_str()), content.length()); + auto result = new unsigned char[EVP_MD_size(EVP_sha1())]; + unsigned int len; + HMAC_Final(ctx, result, &len); + HMAC_CTX_free(ctx); -#ifdef __cplusplus + std::string hex_str = MixAll::hex(result, len); + delete[] result; + return hex_str; } -#endif -#endif //__C_BATCHMESSAGE_H__ + +ROCKETMQ_NAMESPACE_END diff --git a/src/main/cpp/client/TopicAssignmentInfo.cpp b/src/main/cpp/client/TopicAssignmentInfo.cpp new file mode 100644 index 000000000..9ebd8e1fc --- /dev/null +++ b/src/main/cpp/client/TopicAssignmentInfo.cpp @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TopicAssignmentInfo.h" +#include "LoggerImpl.h" + +ROCKETMQ_NAMESPACE_BEGIN + +thread_local uint32_t TopicAssignment::query_which_broker_ = 0; + +TopicAssignment::TopicAssignment(const QueryAssignmentResponse& response) { + if (response.status().code() != rmq::Code::OK) { + SPDLOG_WARN("QueryAssignmentResponse#code is not SUCCESS. Keep assignment info intact. QueryAssignmentResponse: {}", + response.DebugString()); + return; + } + + for (const auto& item : response.assignments()) { + const rmq::MessageQueue& queue = item.message_queue(); + if (!readable(queue.permission())) { + continue; + } + + assert(queue.has_broker()); + const auto& broker = queue.broker(); + + if (broker.endpoints().addresses().empty()) { + SPDLOG_WARN("Broker[{}] is not addressable", broker.DebugString()); + continue; + } + + rmq::Assignment assignment; + assignment.mutable_message_queue()->CopyFrom(queue); + assignment_list_.emplace_back(std::move(assignment)); + } + + std::sort(assignment_list_.begin(), assignment_list_.end(), + [](const rmq::Assignment& lhs, const rmq::Assignment& rhs) { return lhs < rhs; }); +} + +bool operator==(const TopicAssignment& lhs, const TopicAssignment& rhs) { + return lhs.assignmentList() == rhs.assignmentList(); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/Client.h b/src/main/cpp/client/include/Client.h new file mode 100644 index 000000000..db4eb09f3 --- /dev/null +++ b/src/main/cpp/client/include/Client.h @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "ClientConfig.h" +#include "RpcClient.h" +#include "absl/container/flat_hash_set.h" +#include "rocketmq/CredentialsProvider.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class Client { +public: + virtual ~Client() = default; + + virtual rmq::Settings clientSettings() = 0; + + virtual ClientConfig& config() = 0; + + virtual void endpointsInUse(absl::flat_hash_set& endpoints) = 0; + + virtual void heartbeat() = 0; + + virtual bool active() = 0; + + virtual void onRemoteEndpointRemoval(const std::vector&) = 0; + + virtual void schedule(const std::string& task_name, const std::function& task, + std::chrono::milliseconds delay) = 0; + + /** + * @brief Create a Session object + * + * @param target Remote endpoint address in form of gRPC naming convention. + * @param verify Verify presence of target in route table before creating session. + */ + virtual void createSession(const std::string& target, bool verify) = 0; + + virtual void verify(MessageConstSharedPtr message, std::function) = 0; + + virtual void recoverOrphanedTransaction(MessageConstSharedPtr message) = 0; + + virtual void notifyClientTermination() = 0; + + virtual void withCredentialsProvider(std::shared_ptr credentials_provider) = 0; + + virtual std::shared_ptr manager() const = 0; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/ClientConfig.h b/src/main/cpp/client/include/ClientConfig.h new file mode 100644 index 000000000..66ca230b2 --- /dev/null +++ b/src/main/cpp/client/include/ClientConfig.h @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/time/time.h" + +#include "Protocol.h" +#include "RetryPolicy.h" +#include "rocketmq/CredentialsProvider.h" + +ROCKETMQ_NAMESPACE_BEGIN + +struct PublisherConfig { + std::vector topics; + std::uint32_t compress_body_threshold{4096}; + std::uint32_t max_body_size{4194304}; +}; + +struct SubscriberConfig { + rmq::Resource group; + absl::flat_hash_map subscriptions; + bool fifo{false}; + std::uint32_t receive_batch_size{32}; + absl::Duration polling_timeout{absl::Seconds(30)}; +}; + +struct Metric { + bool on{false}; + rmq::Endpoints endpoints; +}; + +struct ClientConfig { + std::string client_id; + rmq::ClientType client_type{rmq::ClientType::CLIENT_TYPE_UNSPECIFIED}; + RetryPolicy backoff_policy; + // TODO: use std::chrono::milliseconds + absl::Duration request_timeout; + std::string region{"cn-hangzhou"}; + std::string resource_namespace; + std::shared_ptr credentials_provider; + PublisherConfig publisher; + SubscriberConfig subscriber; + Metric metric; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/ClientManager.h b/src/main/cpp/client/include/ClientManager.h new file mode 100644 index 000000000..99ec6adeb --- /dev/null +++ b/src/main/cpp/client/include/ClientManager.h @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include + +#include "Client.h" +#include "MessageExt.h" +#include "Metadata.h" +#include "ReceiveMessageCallback.h" +#include "RpcClient.h" +#include "Scheduler.h" +#include "TelemetryBidiReactor.h" +#include "TopAddressing.h" +#include "TopicRouteData.h" +#include "rocketmq/SendCallback.h" +#include "rocketmq/State.h" + +ROCKETMQ_NAMESPACE_BEGIN + +/** + * @brief SessionManager + */ +class ClientManager { +public: + virtual ~ClientManager() = default; + + virtual void start() = 0; + + virtual void shutdown() = 0; + + virtual SchedulerSharedPtr getScheduler() = 0; + + virtual std::shared_ptr getRpcClient(const std::string& target_host, bool need_heartbeat) = 0; + + virtual std::shared_ptr createChannel(const std::string& target_host) = 0; + + virtual void resolveRoute(const std::string& target_host, const Metadata& metadata, const QueryRouteRequest& request, + std::chrono::milliseconds timeout, + const std::function& cb) = 0; + + virtual void heartbeat(const std::string& target_host, const Metadata& metadata, const HeartbeatRequest& request, + std::chrono::milliseconds timeout, + const std::function& cb) = 0; + + virtual MessageConstSharedPtr wrapMessage(const rmq::Message&) = 0; + + virtual void ack(const std::string& target_host, const Metadata& metadata, const AckMessageRequest& request, + std::chrono::milliseconds timeout, const std::function& cb) = 0; + + virtual void changeInvisibleDuration(const std::string& target_host, const Metadata& metadata, + const ChangeInvisibleDurationRequest&, std::chrono::milliseconds timeout, + const std::function&) = 0; + + virtual void forwardMessageToDeadLetterQueue( + const std::string& target_host, const Metadata& metadata, const ForwardMessageToDeadLetterQueueRequest& request, + std::chrono::milliseconds timeout, + const std::function& cb) = 0; + + virtual void endTransaction(const std::string& target_host, const Metadata& metadata, + const EndTransactionRequest& request, std::chrono::milliseconds timeout, + const std::function& cb) = 0; + + virtual void addClientObserver(std::weak_ptr client) = 0; + + virtual void + queryAssignment(const std::string& target, const Metadata& metadata, const QueryAssignmentRequest& request, + std::chrono::milliseconds timeout, + const std::function& cb) = 0; + + virtual void receiveMessage(const std::string& target, const Metadata& metadata, const ReceiveMessageRequest& request, + std::chrono::milliseconds timeout, ReceiveMessageCallback callback) = 0; + + virtual bool send(const std::string& target_host, const Metadata& metadata, SendMessageRequest& request, + SendCallback cb) = 0; + + virtual std::error_code notifyClientTermination(const std::string& target_host, const Metadata& metadata, + const NotifyClientTerminationRequest& request, + std::chrono::milliseconds timeout) = 0; + + virtual State state() const = 0; + + virtual void submit(std::function task) = 0; +}; + +using ClientManagerPtr = std::shared_ptr; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/ClientManagerFactory.h b/src/main/cpp/client/include/ClientManagerFactory.h new file mode 100644 index 000000000..ec6488de7 --- /dev/null +++ b/src/main/cpp/client/include/ClientManagerFactory.h @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include + +#include "absl/base/thread_annotations.h" +#include "absl/container/flat_hash_map.h" +#include "absl/synchronization/mutex.h" + +#include "ClientConfig.h" +#include "ClientManager.h" +#include "rocketmq/AdminServer.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ClientManagerFactory { +public: + static ClientManagerFactory& getInstance(); + + ClientManagerPtr getClientManager(const ClientConfig& client_config) LOCKS_EXCLUDED(client_manager_table_mtx_); + + // For test purpose only + void addClientManager(const std::string& resource_namespace, const ClientManagerPtr& client_manager) + LOCKS_EXCLUDED(client_manager_table_mtx_); + +private: + ClientManagerFactory(); + + virtual ~ClientManagerFactory(); + + /** + * Client Id --> Client Instance + */ + absl::flat_hash_map> + client_manager_table_ GUARDED_BY(client_manager_table_mtx_); + absl::Mutex client_manager_table_mtx_; // protects client_manager_table_ + + rocketmq::admin::AdminServer& admin_server_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/ClientManagerImpl.h b/src/main/cpp/client/include/ClientManagerImpl.h new file mode 100644 index 000000000..63b07137d --- /dev/null +++ b/src/main/cpp/client/include/ClientManagerImpl.h @@ -0,0 +1,241 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Client.h" +#include "ClientManager.h" +#include "HeartbeatDataCallback.h" +#include "Histogram.h" +#include "InsecureCertificateVerifier.h" +#include "InvocationContext.h" +#include "ReceiveMessageCallback.h" +#include "RpcClient.h" +#include "RpcClientImpl.h" +#include "Scheduler.h" +#include "SchedulerImpl.h" +#include "SendMessageContext.h" +#include "TelemetryBidiReactor.h" +#include "ThreadPoolImpl.h" +#include "TopAddressing.h" +#include "TopicRouteChangeCallback.h" +#include "TopicRouteData.h" +#include "absl/base/thread_annotations.h" +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" +#include "rocketmq/State.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ClientManagerImpl : virtual public ClientManager, public std::enable_shared_from_this { +public: + /** + * @brief Construct a new Client Manager Impl object + * TODO: Make it protected such that instantiating it through ClientManagerFactory only, achieving Singleton + * effectively. + * @param resource_namespace Abstract resource namespace, in which this client manager lives. + */ + explicit ClientManagerImpl(std::string resource_namespace); + + ~ClientManagerImpl() override; + + void start() override; + + void shutdown() override LOCKS_EXCLUDED(rpc_clients_mtx_); + + static void assignLabels(Histogram& histogram); + + std::shared_ptr createChannel(const std::string& target_host) override; + + /** + * Resolve route data from name server for the given topic. + * + * @param target_host Name server host address; + * @param metadata Request headers; + * @param request Query route entries request. + * @param timeout RPC timeout. + * @param cb Callback to execute once the request/response completes. + */ + void resolveRoute(const std::string& target_host, const Metadata& metadata, const QueryRouteRequest& request, + std::chrono::milliseconds timeout, + const std::function& cb) override + LOCKS_EXCLUDED(rpc_clients_mtx_); + + /** + * If inactive RPC clients refer to remote hosts that are absent from topic_route_table_, we need to purge them + * immediately. + */ + std::vector cleanOfflineRpcClients() LOCKS_EXCLUDED(clients_mtx_, rpc_clients_mtx_); + + bool send(const std::string& target_host, const Metadata& metadata, SendMessageRequest& request, + SendCallback cb) override LOCKS_EXCLUDED(rpc_clients_mtx_); + + /** + * Get a RpcClient according to the given target hosts, which follows scheme specified + * https://github.com/grpc/grpc/blob/master/doc/naming.md + * + * Note that a channel in gRPC is composted of one or more sub-channels. Every sub-channel represents a solid TCP + * connection. gRPC supports a number of configurable load-balancing policy with "pick-first" as the default option. + * Requests are distributed + * @param target_host + * @param need_heartbeat + * @return + */ + RpcClientSharedPtr getRpcClient(const std::string& target_host, bool need_heartbeat = true) override + LOCKS_EXCLUDED(rpc_clients_mtx_); + + static SendReceipt processSendResponse(const rmq::MessageQueue& message_queue, const SendMessageResponse& response, + std::error_code& ec); + + // only for test + void addRpcClient(const std::string& target_host, const RpcClientSharedPtr& client) LOCKS_EXCLUDED(rpc_clients_mtx_); + + // Test purpose only + void cleanRpcClients() LOCKS_EXCLUDED(rpc_clients_mtx_); + + void addClientObserver(std::weak_ptr client) override; + + void queryAssignment(const std::string& target, const Metadata& metadata, const QueryAssignmentRequest& request, + std::chrono::milliseconds timeout, + const std::function& cb) override; + + void receiveMessage(const std::string& target, const Metadata& metadata, const ReceiveMessageRequest& request, + std::chrono::milliseconds timeout, ReceiveMessageCallback cb) override + LOCKS_EXCLUDED(rpc_clients_mtx_); + + /** + * Translate protobuf message struct to domain model. + * + * @param item + * @return true if the translation succeeded; false if something wrong happens, including checksum verification, etc. + */ + MessageConstSharedPtr wrapMessage(const rmq::Message& item) override; + + SchedulerSharedPtr getScheduler() override; + + /** + * Ack message asynchronously. + * @param target_host Target broker host address. + * @param request Ack message request. + */ + void ack(const std::string& target_host, const Metadata& metadata, const AckMessageRequest& request, + std::chrono::milliseconds timeout, const std::function& cb) override; + + void changeInvisibleDuration(const std::string& target_host, const Metadata& metadata, + const ChangeInvisibleDurationRequest&, std::chrono::milliseconds timeout, + const std::function&) override; + + void forwardMessageToDeadLetterQueue(const std::string& target_host, + const Metadata& metadata, + const ForwardMessageToDeadLetterQueueRequest& request, + std::chrono::milliseconds timeout, + const std::function& cb) override; + + /** + * End a transaction asynchronously. + * + * Callback conforms the following method signature: + * void callable(bool rpc_ok, const EndTransactionResponse& response) + * + * if rpc_ok is false, the end transaction request may never reach the server and consequently no need to inspect the + * response. If rpc_ok is true, response should be further inspected to determine business tier code and logic. + * @param target_host + * @param metadata + * @param request + * @param timeout + * @param cb + */ + void endTransaction(const std::string& target_host, const Metadata& metadata, const EndTransactionRequest& request, + std::chrono::milliseconds timeout, + const std::function& cb) override; + + std::error_code notifyClientTermination(const std::string& target_host, const Metadata& metadata, + const NotifyClientTerminationRequest& request, + std::chrono::milliseconds timeout) override; + + void trace(bool trace) { + trace_ = trace; + } + + void heartbeat(const std::string& target_host, const Metadata& metadata, const HeartbeatRequest& request, + std::chrono::milliseconds timeout, + const std::function& cb) override; + + State state() const override; + + void submit(std::function task) override; + +private: + void doHeartbeat(); + + void logStats(); + + SchedulerSharedPtr scheduler_; + + static const char* HEARTBEAT_TASK_NAME; + static const char* STATS_TASK_NAME; + + std::string resource_namespace_; + + std::atomic state_; + + std::vector> clients_ GUARDED_BY(clients_mtx_); + absl::Mutex clients_mtx_; + + absl::flat_hash_map> rpc_clients_ GUARDED_BY(rpc_clients_mtx_); + absl::Mutex rpc_clients_mtx_; // protects rpc_clients_ + + std::uint32_t heartbeat_task_id_{0}; + std::uint32_t stats_task_id_{0}; + + std::unique_ptr callback_thread_pool_; + + Histogram latency_histogram_; + + absl::flat_hash_set exporter_endpoint_set_ GUARDED_BY(exporter_endpoint_set_mtx_); + absl::Mutex exporter_endpoint_set_mtx_; + + /** + * Tenant-id. Each user shall have one unique identifier. + */ + std::string tenant_id_; + + std::string service_name_{"RocketMQ"}; + + /** + * TLS configuration + */ + std::shared_ptr certificate_verifier_; + grpc::experimental::TlsChannelCredentialsOptions tls_channel_credential_options_; + std::shared_ptr channel_credential_; + grpc::ChannelArguments channel_arguments_; + + bool trace_{false}; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/ConsumeMessageType.h b/src/main/cpp/client/include/ConsumeMessageType.h new file mode 100644 index 000000000..9af69ba8f --- /dev/null +++ b/src/main/cpp/client/include/ConsumeMessageType.h @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +enum class ConsumeMessageType : int8_t +{ + ACTIVE = 0, + PASSIVE = 1, +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/HeartbeatDataCallback.h b/src/main/cpp/client/include/HeartbeatDataCallback.h new file mode 100644 index 000000000..f4466e2b0 --- /dev/null +++ b/src/main/cpp/client/include/HeartbeatDataCallback.h @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "RpcClient.h" + +ROCKETMQ_NAMESPACE_BEGIN + +/** + * This callback will be invoked to collect and prepare heartbeat data, which will be sent to brokers. + */ +class HeartbeatDataCallback { +public: + virtual void onHeartbeatDataCallback(HeartbeatRequest& request) = 0; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/InsecureCertificateVerifier.h b/src/main/cpp/client/include/InsecureCertificateVerifier.h new file mode 100644 index 000000000..a673ddd5d --- /dev/null +++ b/src/main/cpp/client/include/InsecureCertificateVerifier.h @@ -0,0 +1,42 @@ +#include "grpcpp/security/tls_certificate_verifier.h" +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class InsecureCertificateVerifier : public grpc::experimental::ExternalCertificateVerifier { +public: + // The verification logic that will be performed after the TLS handshake + // completes. Implementers can choose to do their checks synchronously or + // asynchronously. + // + // request: the verification information associated with this request + // callback: This should only be used if your check is done asynchronously. + // When the asynchronous work is done, invoke this callback function + // with the proper status, indicating the success or the failure of + // the check. The implementer MUST NOT invoke this |callback| in the + // same thread before Verify() returns, otherwise it can lead to + // deadlocks. + // sync_status: This should only be used if your check is done synchronously. + // Modifies this value to indicate the success or the failure of + // the check. + // return: return true if your check is done synchronously, otherwise return + // false + bool Verify(grpc::experimental::TlsCustomVerificationCheckRequest* request, + std::function callback, + grpc::Status* sync_status) override { + *sync_status = grpc::Status(grpc::StatusCode::OK, ""); + return true; + } + + // Cancels a verification request previously started via Verify(). + // Used when the connection attempt times out or is cancelled while an async + // verification request is pending. The implementation should abort whatever + // async operation it is waiting for and quickly invoke the callback that was + // passed to Verify() with a status indicating the cancellation. + // + // request: the verification information associated with this request + void Cancel(grpc::experimental::TlsCustomVerificationCheckRequest* request) override { + } +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/InterceptorContinuation.h b/src/main/cpp/client/include/InterceptorContinuation.h new file mode 100644 index 000000000..07c64335f --- /dev/null +++ b/src/main/cpp/client/include/InterceptorContinuation.h @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "grpcpp/impl/codegen/interceptor.h" + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class InterceptorContinuation { +public: + explicit InterceptorContinuation(grpc::experimental::InterceptorBatchMethods* methods) : methods_(methods) { + } + + ~InterceptorContinuation() { + if (!hijacked_) { + methods_->Proceed(); + } + } + + void hijack() { + hijacked_ = true; + } + +private: + grpc::experimental::InterceptorBatchMethods* methods_; + bool hijacked_{false}; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/LogInterceptor.h b/src/main/cpp/client/include/LogInterceptor.h new file mode 100644 index 000000000..0bec16162 --- /dev/null +++ b/src/main/cpp/client/include/LogInterceptor.h @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "grpcpp/impl/codegen/client_interceptor.h" + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class LogInterceptor : public grpc::experimental::Interceptor { +public: + explicit LogInterceptor(grpc::experimental::ClientRpcInfo* client_rpc_info) : client_rpc_info_(client_rpc_info) { + } + + void Intercept(grpc::experimental::InterceptorBatchMethods* methods) override; + +private: + grpc::experimental::ClientRpcInfo* client_rpc_info_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/LogInterceptorFactory.h b/src/main/cpp/client/include/LogInterceptorFactory.h new file mode 100644 index 000000000..b18ab10e5 --- /dev/null +++ b/src/main/cpp/client/include/LogInterceptorFactory.h @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "grpcpp/impl/codegen/client_interceptor.h" + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class LogInterceptorFactory : public grpc::experimental::ClientInterceptorFactoryInterface { +public: + grpc::experimental::Interceptor* CreateClientInterceptor(grpc::experimental::ClientRpcInfo* info) override; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/Metadata.h b/src/main/cpp/client/include/Metadata.h new file mode 100644 index 000000000..c831629b3 --- /dev/null +++ b/src/main/cpp/client/include/Metadata.h @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "rocketmq/RocketMQ.h" + +#include "absl/container/flat_hash_map.h" + +ROCKETMQ_NAMESPACE_BEGIN + +using Metadata = absl::flat_hash_map; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/OpenSSLCompatible.h b/src/main/cpp/client/include/OpenSSLCompatible.h new file mode 100644 index 000000000..cca778726 --- /dev/null +++ b/src/main/cpp/client/include/OpenSSLCompatible.h @@ -0,0 +1,390 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +/** + * This is to make our code work with openssl both 1.0.x and 1.1.y + * https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes#Compatibility_Layer + */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#include +#include + +static void* OPENSSL_zalloc(size_t num) { + void* ret = OPENSSL_malloc(num); + + if (ret != NULL) + memset(ret, 0, num); + return ret; +} + +int RSA_set0_key(RSA* r, BIGNUM* n, BIGNUM* e, BIGNUM* d) { + /* If the fields n and e in r are NULL, the corresponding input + * parameters MUST be non-NULL for n and e. d may be + * left NULL (in case only the public key is used). + */ + if ((r->n == NULL && n == NULL) || (r->e == NULL && e == NULL)) + return 0; + + if (n != NULL) { + BN_free(r->n); + r->n = n; + } + if (e != NULL) { + BN_free(r->e); + r->e = e; + } + if (d != NULL) { + BN_free(r->d); + r->d = d; + } + + return 1; +} + +int RSA_set0_factors(RSA* r, BIGNUM* p, BIGNUM* q) { + /* If the fields p and q in r are NULL, the corresponding input + * parameters MUST be non-NULL. + */ + if ((r->p == NULL && p == NULL) || (r->q == NULL && q == NULL)) + return 0; + + if (p != NULL) { + BN_free(r->p); + r->p = p; + } + if (q != NULL) { + BN_free(r->q); + r->q = q; + } + + return 1; +} + +int RSA_set0_crt_params(RSA* r, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp) { + /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input + * parameters MUST be non-NULL. + */ + if ((r->dmp1 == NULL && dmp1 == NULL) || (r->dmq1 == NULL && dmq1 == NULL) || (r->iqmp == NULL && iqmp == NULL)) + return 0; + + if (dmp1 != NULL) { + BN_free(r->dmp1); + r->dmp1 = dmp1; + } + if (dmq1 != NULL) { + BN_free(r->dmq1); + r->dmq1 = dmq1; + } + if (iqmp != NULL) { + BN_free(r->iqmp); + r->iqmp = iqmp; + } + + return 1; +} + +void RSA_get0_key(const RSA* r, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d) { + if (n != NULL) + *n = r->n; + if (e != NULL) + *e = r->e; + if (d != NULL) + *d = r->d; +} + +void RSA_get0_factors(const RSA* r, const BIGNUM** p, const BIGNUM** q) { + if (p != NULL) + *p = r->p; + if (q != NULL) + *q = r->q; +} + +void RSA_get0_crt_params(const RSA* r, const BIGNUM** dmp1, const BIGNUM** dmq1, const BIGNUM** iqmp) { + if (dmp1 != NULL) + *dmp1 = r->dmp1; + if (dmq1 != NULL) + *dmq1 = r->dmq1; + if (iqmp != NULL) + *iqmp = r->iqmp; +} + +void DSA_get0_pqg(const DSA* d, const BIGNUM** p, const BIGNUM** q, const BIGNUM** g) { + if (p != NULL) + *p = d->p; + if (q != NULL) + *q = d->q; + if (g != NULL) + *g = d->g; +} + +int DSA_set0_pqg(DSA* d, BIGNUM* p, BIGNUM* q, BIGNUM* g) { + /* If the fields p, q and g in d are NULL, the corresponding input + * parameters MUST be non-NULL. + */ + if ((d->p == NULL && p == NULL) || (d->q == NULL && q == NULL) || (d->g == NULL && g == NULL)) + return 0; + + if (p != NULL) { + BN_free(d->p); + d->p = p; + } + if (q != NULL) { + BN_free(d->q); + d->q = q; + } + if (g != NULL) { + BN_free(d->g); + d->g = g; + } + + return 1; +} + +void DSA_get0_key(const DSA* d, const BIGNUM** pub_key, const BIGNUM** priv_key) { + if (pub_key != NULL) + *pub_key = d->pub_key; + if (priv_key != NULL) + *priv_key = d->priv_key; +} + +int DSA_set0_key(DSA* d, BIGNUM* pub_key, BIGNUM* priv_key) { + /* If the field pub_key in d is NULL, the corresponding input + * parameters MUST be non-NULL. The priv_key field may + * be left NULL. + */ + if (d->pub_key == NULL && pub_key == NULL) + return 0; + + if (pub_key != NULL) { + BN_free(d->pub_key); + d->pub_key = pub_key; + } + if (priv_key != NULL) { + BN_free(d->priv_key); + d->priv_key = priv_key; + } + + return 1; +} + +void DSA_SIG_get0(const DSA_SIG* sig, const BIGNUM** pr, const BIGNUM** ps) { + if (pr != NULL) + *pr = sig->r; + if (ps != NULL) + *ps = sig->s; +} + +int DSA_SIG_set0(DSA_SIG* sig, BIGNUM* r, BIGNUM* s) { + if (r == NULL || s == NULL) + return 0; + BN_clear_free(sig->r); + BN_clear_free(sig->s); + sig->r = r; + sig->s = s; + return 1; +} + +void ECDSA_SIG_get0(const ECDSA_SIG* sig, const BIGNUM** pr, const BIGNUM** ps) { + if (pr != NULL) + *pr = sig->r; + if (ps != NULL) + *ps = sig->s; +} + +int ECDSA_SIG_set0(ECDSA_SIG* sig, BIGNUM* r, BIGNUM* s) { + if (r == NULL || s == NULL) + return 0; + BN_clear_free(sig->r); + BN_clear_free(sig->s); + sig->r = r; + sig->s = s; + return 1; +} + +void DH_get0_pqg(const DH* dh, const BIGNUM** p, const BIGNUM** q, const BIGNUM** g) { + if (p != NULL) + *p = dh->p; + if (q != NULL) + *q = dh->q; + if (g != NULL) + *g = dh->g; +} + +int DH_set0_pqg(DH* dh, BIGNUM* p, BIGNUM* q, BIGNUM* g) { + /* If the fields p and g in d are NULL, the corresponding input + * parameters MUST be non-NULL. q may remain NULL. + */ + if ((dh->p == NULL && p == NULL) || (dh->g == NULL && g == NULL)) + return 0; + + if (p != NULL) { + BN_free(dh->p); + dh->p = p; + } + if (q != NULL) { + BN_free(dh->q); + dh->q = q; + } + if (g != NULL) { + BN_free(dh->g); + dh->g = g; + } + + if (q != NULL) { + dh->length = BN_num_bits(q); + } + + return 1; +} + +void DH_get0_key(const DH* dh, const BIGNUM** pub_key, const BIGNUM** priv_key) { + if (pub_key != NULL) + *pub_key = dh->pub_key; + if (priv_key != NULL) + *priv_key = dh->priv_key; +} + +int DH_set0_key(DH* dh, BIGNUM* pub_key, BIGNUM* priv_key) { + /* If the field pub_key in dh is NULL, the corresponding input + * parameters MUST be non-NULL. The priv_key field may + * be left NULL. + */ + if (dh->pub_key == NULL && pub_key == NULL) + return 0; + + if (pub_key != NULL) { + BN_free(dh->pub_key); + dh->pub_key = pub_key; + } + if (priv_key != NULL) { + BN_free(dh->priv_key); + dh->priv_key = priv_key; + } + + return 1; +} + +int DH_set_length(DH* dh, long length) { + dh->length = length; + return 1; +} + +const unsigned char* EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX* ctx) { + return ctx->iv; +} + +unsigned char* EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX* ctx) { + return ctx->iv; +} + +EVP_MD_CTX* EVP_MD_CTX_new(void) { + return OPENSSL_zalloc(sizeof(EVP_MD_CTX)); +} + +void EVP_MD_CTX_free(EVP_MD_CTX* ctx) { + EVP_MD_CTX_cleanup(ctx); + OPENSSL_free(ctx); +} + +RSA_METHOD* RSA_meth_dup(const RSA_METHOD* meth) { + RSA_METHOD* ret; + + ret = OPENSSL_malloc(sizeof(RSA_METHOD)); + + if (ret != NULL) { + memcpy(ret, meth, sizeof(*meth)); + ret->name = OPENSSL_strdup(meth->name); + if (ret->name == NULL) { + OPENSSL_free(ret); + return NULL; + } + } + + return ret; +} + +int RSA_meth_set1_name(RSA_METHOD* meth, const char* name) { + char* tmpname; + + tmpname = OPENSSL_strdup(name); + if (tmpname == NULL) { + return 0; + } + + OPENSSL_free((char*)meth->name); + meth->name = tmpname; + + return 1; +} + +int RSA_meth_set_priv_enc(RSA_METHOD* meth, int (*priv_enc)(int flen, const unsigned char* from, unsigned char* to, + RSA* rsa, int padding)) { + meth->rsa_priv_enc = priv_enc; + return 1; +} + +int RSA_meth_set_priv_dec(RSA_METHOD* meth, int (*priv_dec)(int flen, const unsigned char* from, unsigned char* to, + RSA* rsa, int padding)) { + meth->rsa_priv_dec = priv_dec; + return 1; +} + +int RSA_meth_set_finish(RSA_METHOD* meth, int (*finish)(RSA* rsa)) { + meth->finish = finish; + return 1; +} + +void RSA_meth_free(RSA_METHOD* meth) { + if (meth != NULL) { + OPENSSL_free((char*)meth->name); + OPENSSL_free(meth); + } +} + +int RSA_bits(const RSA* r) { + return (BN_num_bits(r->n)); +} + +RSA* EVP_PKEY_get0_RSA(EVP_PKEY* pkey) { + if (pkey->type != EVP_PKEY_RSA) { + return NULL; + } + return pkey->pkey.rsa; +} + +HMAC_CTX* HMAC_CTX_new(void) { + HMAC_CTX* ctx = OPENSSL_malloc(sizeof(*ctx)); + if (ctx != NULL) { + if (!HMAC_CTX_reset(ctx)) { + HMAC_CTX_free(ctx); + return NULL; + } + } + return ctx; +} + +void HMAC_CTX_free(HMAC_CTX* ctx) { + if (ctx != NULL) { + hmac_ctx_cleanup(ctx); + EVP_MD_CTX_free(ctx->i_ctx); + EVP_MD_CTX_free(ctx->o_ctx); + EVP_MD_CTX_free(ctx->md_ctx); + OPENSSL_free(ctx); + } +} +#endif \ No newline at end of file diff --git a/src/main/cpp/client/include/ReceiveMessageCallback.h b/src/main/cpp/client/include/ReceiveMessageCallback.h new file mode 100644 index 000000000..6a9db7cf2 --- /dev/null +++ b/src/main/cpp/client/include/ReceiveMessageCallback.h @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include + +#include "ReceiveMessageResult.h" + +ROCKETMQ_NAMESPACE_BEGIN + +using ReceiveMessageCallback = std::function; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/ReceiveMessageContext.h b/src/main/cpp/client/include/ReceiveMessageContext.h new file mode 100644 index 000000000..190f1bbb9 --- /dev/null +++ b/src/main/cpp/client/include/ReceiveMessageContext.h @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "InvocationContext.h" +#include "Metadata.h" +#include "ReceiveMessageCallback.h" + +ROCKETMQ_NAMESPACE_BEGIN + +struct ReceiveMessageContext : public BaseInvocationContext { + ReceiveMessageCallback callback; + Metadata metadata; + std::chrono::milliseconds timeout; + + void onCompletion(bool ok) override {} + +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/ReceiveMessageResult.h b/src/main/cpp/client/include/ReceiveMessageResult.h new file mode 100644 index 000000000..d084cbf23 --- /dev/null +++ b/src/main/cpp/client/include/ReceiveMessageResult.h @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include + +#include "MessageExt.h" +#include "MixAll.h" +#include "absl/time/time.h" + +ROCKETMQ_NAMESPACE_BEGIN + +struct ReceiveMessageResult { + absl::Time pop_time; + absl::Duration invisible_time; + + std::vector messages; + + std::string source_host; + + std::int64_t min_offset{0}; + std::int64_t next_offset{0}; + std::int64_t max_offset{0}; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/ReceiveMessageStreamReader.h b/src/main/cpp/client/include/ReceiveMessageStreamReader.h new file mode 100644 index 000000000..f0a767e26 --- /dev/null +++ b/src/main/cpp/client/include/ReceiveMessageStreamReader.h @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include + +#include "MessageExt.h" +#include "ReceiveMessageCallback.h" +#include "ReceiveMessageContext.h" +#include "grpcpp/client_context.h" + +#include "Client.h" +#include "ClientManager.h" +#include "Protocol.h" +#include "ReceiveMessageContext.h" +#include "ReceiveMessageResult.h" +#include "rocketmq/ErrorCode.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ReceiveMessageStreamReader : public grpc::ClientReadReactor { +public: + ReceiveMessageStreamReader(std::weak_ptr client_manager, + rmq::MessagingService::Stub* stub, + std::string peer_address, + rmq::ReceiveMessageRequest request, + std::unique_ptr context); + + void OnReadDone(bool ok) override; + + void OnDone(const grpc::Status& s) override; + +private: + std::weak_ptr client_manager_; + rmq::MessagingService::Stub* stub_; + std::string peer_address_; + rmq::ReceiveMessageRequest request_; + std::unique_ptr context_; + rmq::ReceiveMessageResponse response_; + grpc::ClientContext client_context_; + grpc::Status status_; + std::error_code ec_; + ReceiveMessageResult result_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/RpcClient.h b/src/main/cpp/client/include/RpcClient.h new file mode 100644 index 000000000..2fc8448ae --- /dev/null +++ b/src/main/cpp/client/include/RpcClient.h @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include + +#include "ReceiveMessageResult.h" +#include "absl/container/flat_hash_map.h" +#include "absl/strings/string_view.h" +#include "grpcpp/grpcpp.h" + +#include "InvocationContext.h" +#include "Protocol.h" +#include "ReceiveMessageContext.h" + +ROCKETMQ_NAMESPACE_BEGIN + +using Channel = grpc::Channel; +using Status = grpc::Status; +using CompletionQueue = grpc::CompletionQueue; + +class Client; +class ClientManager; +class TelemetryBidiReactor; + +/** + * @brief A RpcClient represents a session between client and a remote broker. + * + */ +class RpcClient { +public: + RpcClient() = default; + + virtual ~RpcClient() = default; + + virtual const std::string& remoteAddress() const = 0; + + virtual void asyncQueryRoute(const QueryRouteRequest& request, + InvocationContext* invocation_context) = 0; + + virtual void asyncSend(const SendMessageRequest& request, + InvocationContext* invocation_context) = 0; + + virtual void asyncQueryAssignment(const QueryAssignmentRequest& request, + InvocationContext* invocation_context) = 0; + + virtual void asyncReceive(const ReceiveMessageRequest& request, std::unique_ptr context) = 0; + + virtual void asyncAck(const AckMessageRequest& request, + InvocationContext* invocation_context) = 0; + + virtual void asyncChangeInvisibleDuration(const ChangeInvisibleDurationRequest& request, + InvocationContext*) = 0; + + virtual void asyncHeartbeat(const HeartbeatRequest& request, + InvocationContext* invocation_context) = 0; + + virtual void asyncEndTransaction(const EndTransactionRequest& request, + InvocationContext* invocation_context) = 0; + + virtual std::shared_ptr asyncTelemetry(std::weak_ptr client) = 0; + + virtual void asyncForwardMessageToDeadLetterQueue( + const ForwardMessageToDeadLetterQueueRequest& request, + InvocationContext* invocation_context) = 0; + + virtual grpc::Status notifyClientTermination(grpc::ClientContext* context, + const NotifyClientTerminationRequest& request, + NotifyClientTerminationResponse* response) = 0; + + virtual std::weak_ptr clientManager() = 0; + + /** + * Indicate if heartbeat is required. + * @return true if periodic heartbeat is required; false otherwise. + */ + virtual bool needHeartbeat() = 0; + + virtual void needHeartbeat(bool need_heartbeat) = 0; + + /** + * Indicate if current client connection state is OK or recoverable. + * + * @return true if underlying connection is OK or recoverable; false otherwise. + */ + virtual bool ok() const = 0; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/RpcClientImpl.h b/src/main/cpp/client/include/RpcClientImpl.h new file mode 100644 index 000000000..6406c746e --- /dev/null +++ b/src/main/cpp/client/include/RpcClientImpl.h @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "InvocationContext.h" +#include "ReceiveMessageCallback.h" +#include "ReceiveMessageContext.h" +#include "absl/container/flat_hash_map.h" + +#include "Client.h" +#include "ClientManager.h" +#include "RpcClient.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class RpcClientImpl : public RpcClient, public std::enable_shared_from_this { +public: + RpcClientImpl(std::weak_ptr client_manager, std::shared_ptr channel, std::string peer_address, + bool need_heartbeat = true) + : client_manager_(client_manager), channel_(std::move(channel)), peer_address_(std::move(peer_address)), + stub_(rmq::MessagingService::NewStub(channel_)), need_heartbeat_(need_heartbeat) { + } + + RpcClientImpl(const RpcClientImpl&) = delete; + + RpcClientImpl& operator=(const RpcClientImpl&) = delete; + + ~RpcClientImpl() override = default; + + const std::string& remoteAddress() const override { + return peer_address_; + } + + void asyncQueryRoute(const QueryRouteRequest& request, + InvocationContext* invocation_context) override; + + void asyncSend(const SendMessageRequest& request, + InvocationContext* invocation_context) override; + + void asyncQueryAssignment(const QueryAssignmentRequest& request, + InvocationContext* invocation_context) override; + + void asyncReceive(const ReceiveMessageRequest& request, std::unique_ptr context) override; + + void asyncAck(const AckMessageRequest& request, InvocationContext* invocation_context) override; + + void asyncChangeInvisibleDuration(const ChangeInvisibleDurationRequest& request, + InvocationContext*) override; + + void asyncHeartbeat(const HeartbeatRequest& request, + InvocationContext* invocation_context) override; + + void asyncEndTransaction(const EndTransactionRequest& request, + InvocationContext* invocation_context) override; + + std::shared_ptr asyncTelemetry(std::weak_ptr client) override; + + void asyncForwardMessageToDeadLetterQueue( + const ForwardMessageToDeadLetterQueueRequest& request, + InvocationContext* invocation_context) override; + + grpc::Status notifyClientTermination(grpc::ClientContext* context, const NotifyClientTerminationRequest& request, + NotifyClientTerminationResponse* response) override; + + std::weak_ptr clientManager() override; + + bool needHeartbeat() override; + + void needHeartbeat(bool need_heartbeat) override; + + bool ok() const override; + +private: + static void addMetadata(grpc::ClientContext& context, const absl::flat_hash_map& metadata); + + static void asyncCallback(std::weak_ptr client, BaseInvocationContext* invocation_context, + grpc::Status status); + + std::weak_ptr client_manager_; + std::shared_ptr channel_; + std::string peer_address_; + std::unique_ptr stub_; + std::chrono::milliseconds connect_timeout_{3000}; + bool need_heartbeat_{true}; +}; + +using RpcClientSharedPtr = std::shared_ptr; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/SendMessageContext.h b/src/main/cpp/client/include/SendMessageContext.h new file mode 100644 index 000000000..12ee91b79 --- /dev/null +++ b/src/main/cpp/client/include/SendMessageContext.h @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "Protocol.h" +#include "rocketmq/Message.h" + +ROCKETMQ_NAMESPACE_BEGIN +class SendMessageContext { +public: + const std::string& getProducerGroup() const { + return producer_group_; + }; + void setProducerGroup(const std::string& producer_group) { + this->producer_group_ = producer_group; + }; + const Message& getMessage() const { + return message_; + } + void setMessage(const Message& message) { + this->message_ = message; + } + const rmq::MessageQueue& getMessageQueue() const { + return message_queue_; + } + void setMessageQueue(const rmq::MessageQueue& message_queue) { + this->message_queue_ = message_queue; + } + const std::string& getBornHost() const { + return born_host_; + } + void setBornHost(const std::string& born_host) { + this->born_host_ = born_host; + } + const std::string& getMessageId() const { + return message_id_; + } + void setMessageId(const std::string& message_id) { + this->message_id_ = message_id; + } + long long int getQueueOffset() const { + return queue_offset_; + } + void setQueueOffset(long long queue_offset) { + this->queue_offset_ = queue_offset; + } + +private: + std::string producer_group_; + Message message_; + rmq::MessageQueue message_queue_; + std::string born_host_; + std::string message_id_; + long long queue_offset_{-1}; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/Session.h b/src/main/cpp/client/include/Session.h new file mode 100644 index 000000000..3c32ca58a --- /dev/null +++ b/src/main/cpp/client/include/Session.h @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class Session { +public: + virtual ~Session() = default; + + virtual bool await() = 0; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/SessionImpl.h b/src/main/cpp/client/include/SessionImpl.h new file mode 100644 index 000000000..3ab381d16 --- /dev/null +++ b/src/main/cpp/client/include/SessionImpl.h @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "Client.h" +#include "RpcClient.h" +#include "Session.h" +#include "TelemetryBidiReactor.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class SessionImpl : public Session { +public: + SessionImpl(std::weak_ptr client, std::shared_ptr rpc_client); + + ~SessionImpl() override; + + bool await() override; + +private: + std::weak_ptr client_; + std::shared_ptr rpc_client_; + // TODO: use unique_ptr + std::shared_ptr telemetry_; + + void syncSettings(); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/Signature.h b/src/main/cpp/client/include/Signature.h new file mode 100644 index 000000000..29d5f331c --- /dev/null +++ b/src/main/cpp/client/include/Signature.h @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "absl/container/flat_hash_map.h" + +#include "ClientConfig.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class Signature { +public: + static void sign(const ClientConfig& client, absl::flat_hash_map& metadata); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/TelemetryBidiReactor.h b/src/main/cpp/client/include/TelemetryBidiReactor.h new file mode 100644 index 000000000..9fe65f31e --- /dev/null +++ b/src/main/cpp/client/include/TelemetryBidiReactor.h @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "Client.h" +#include "RpcClient.h" +#include "absl/base/thread_annotations.h" +#include "absl/synchronization/mutex.h" +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +enum class StreamState : std::uint8_t +{ + Created = 0, + Active = 1, + ReadDone = 2, + WriteDone = 3, + Closed = 4, +}; + +class TelemetryBidiReactor : public grpc::ClientBidiReactor, + public std::enable_shared_from_this { +public: + TelemetryBidiReactor(std::weak_ptr client, rmq::MessagingService::Stub* stub, std::string peer_address); + + ~TelemetryBidiReactor(); + + void OnWriteDone(bool ok) override; + + void OnWritesDoneDone(bool ok) override; + + void OnReadDone(bool ok) override; + + void OnDone(const grpc::Status& status) override; + + void fireRead(); + + void fireWrite(); + + void fireClose(); + + void write(TelemetryCommand command); + + bool await(); + +private: + grpc::ClientContext context_; + + /** + * @brief Command to read from server. + */ + TelemetryCommand read_; + + /** + * @brief Buffered commands to write to server + */ + std::vector writes_ GUARDED_BY(writes_mtx_); + absl::Mutex writes_mtx_; + + /** + * @brief The command that is currently being written back to server. + */ + TelemetryCommand write_; + + /** + * @brief Each TelemetryBidiReactor belongs to a specific client as its owner. + */ + std::weak_ptr client_; + + /** + * @brief Address of remote peer. + */ + std::string peer_address_; + + /** + * @brief Indicate if there is a command being written to network. + */ + std::atomic_bool command_inflight_{false}; + + StreamState stream_state_ GUARDED_BY(stream_state_mtx_); + absl::Mutex stream_state_mtx_; + absl::CondVar stream_state_cv_; + + bool server_setting_received_ GUARDED_BY(server_setting_received_mtx_){false}; + absl::Mutex server_setting_received_mtx_; + absl::CondVar server_setting_received_cv_; + + void onVerifyMessageResult(TelemetryCommand command); + + void applySettings(const rmq::Settings& settings); + + void applyBackoffPolicy(const rmq::Settings& settings, std::shared_ptr& client); + + void applyPublishingConfig(const rmq::Settings& settings, std::shared_ptr client); + + void applySubscriptionConfig(const rmq::Settings& settings, std::shared_ptr client); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/TlsHelper.h b/src/main/cpp/client/include/TlsHelper.h new file mode 100644 index 000000000..b906ce97e --- /dev/null +++ b/src/main/cpp/client/include/TlsHelper.h @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "openssl/x509.h" +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class TlsHelper { + +public: + static std::string sign(const std::string& access_secret, const std::string& content); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/Topic.h b/src/main/cpp/client/include/Topic.h new file mode 100644 index 000000000..258abab55 --- /dev/null +++ b/src/main/cpp/client/include/Topic.h @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class Topic { +public: + Topic(std::string resource_namespace, std::string name) + : resource_namespace_(std::move(resource_namespace)), name_(std::move(name)) { + } + + const std::string& resourceNamespace() const { + return resource_namespace_; + } + + const std::string& name() const { + return name_; + } + + bool operator==(const Topic& other) const { + return resource_namespace_ == other.resource_namespace_ && name_ == other.name_; + } + + bool operator<(const Topic& other) const { + if (resource_namespace_ < other.resource_namespace_) { + return true; + } else if (resource_namespace_ > other.resource_namespace_) { + return false; + } + + if (name_ < other.name_) { + return true; + } else if (name_ > other.name_) { + return false; + } + return false; + } + +private: + std::string resource_namespace_; + std::string name_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/TopicAssignmentInfo.h b/src/main/cpp/client/include/TopicAssignmentInfo.h new file mode 100644 index 000000000..76777a950 --- /dev/null +++ b/src/main/cpp/client/include/TopicAssignmentInfo.h @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include + +#include "Protocol.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class TopicAssignment { +public: + explicit TopicAssignment(std::vector&& assignments) : assignment_list_(std::move(assignments)) { + std::sort(assignment_list_.begin(), assignment_list_.end(), + [](const rmq::Assignment& lhs, const rmq::Assignment& rhs) { return lhs < rhs; }); + } + + explicit TopicAssignment(const QueryAssignmentResponse& response); + + ~TopicAssignment() = default; + + const std::vector& assignmentList() const { + return assignment_list_; + } + + static unsigned int getAndIncreaseQueryWhichBroker() { + return ++query_which_broker_; + } + +private: + /** + * Once it is set, it will be immutable. + */ + std::vector assignment_list_; + + thread_local static uint32_t query_which_broker_; +}; + +bool operator==(const TopicAssignment& lhs, const TopicAssignment& rhs); + +using TopicAssignmentPtr = std::shared_ptr; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/TopicRouteChangeCallback.h b/src/main/cpp/client/include/TopicRouteChangeCallback.h new file mode 100644 index 000000000..0490808f7 --- /dev/null +++ b/src/main/cpp/client/include/TopicRouteChangeCallback.h @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "absl/strings/string_view.h" + +#include "TopicRouteData.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class TopicRouteChangeCallback { +public: + virtual void onTopicRouteChange(absl::string_view topic, const TopicRouteDataPtr& topic_route_data) = 0; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/include/TopicRouteData.h b/src/main/cpp/client/include/TopicRouteData.h new file mode 100644 index 000000000..807ac811b --- /dev/null +++ b/src/main/cpp/client/include/TopicRouteData.h @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include + +#include "absl/strings/str_join.h" + +#include "Protocol.h" + +ROCKETMQ_NAMESPACE_BEGIN + +/** + * Thread Safety: This class is immutable and thus effectively thread safe. + */ +class TopicRouteData { +public: + TopicRouteData(std::vector message_queues) : message_queues_(message_queues) { + std::sort(message_queues_.begin(), message_queues_.end(), + [](const rmq::MessageQueue& lhs, const rmq::MessageQueue& rhs) { return lhs < rhs; }); + } + + const std::vector& messageQueues() const { + return message_queues_; + } + + std::string debugString() const { + return absl::StrJoin(message_queues_.begin(), message_queues_.end(), ",", + [](std::string* out, const rmq::MessageQueue& m) { out->append(m.DebugString()); }); + }; + +private: + std::vector message_queues_; + + friend bool operator==(const TopicRouteData&, const TopicRouteData&); + + friend bool operator!=(const TopicRouteData&, const TopicRouteData&); +}; + +inline bool operator==(const TopicRouteData& lhs, const TopicRouteData& rhs) { + return lhs.message_queues_ == rhs.message_queues_; +} + +inline bool operator!=(const TopicRouteData& lhs, const TopicRouteData& rhs) { + return lhs.message_queues_ != rhs.message_queues_; +} + +using TopicRouteDataPtr = std::shared_ptr; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/mocks/BUILD.bazel b/src/main/cpp/client/mocks/BUILD.bazel new file mode 100644 index 000000000..6da613f6f --- /dev/null +++ b/src/main/cpp/client/mocks/BUILD.bazel @@ -0,0 +1,29 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_library") +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "client_mocks", + hdrs = glob(["include/*.h"]), + srcs = glob(["*.cpp"]), + strip_include_prefix = "//src/main/cpp/client/mocks/include", + deps = [ + "//src/main/cpp/client:client_library", + "//external:gtest", + ], +) \ No newline at end of file diff --git a/src/main/cpp/client/mocks/include/ClientManagerMock.h b/src/main/cpp/client/mocks/include/ClientManagerMock.h new file mode 100644 index 000000000..d255b901b --- /dev/null +++ b/src/main/cpp/client/mocks/include/ClientManagerMock.h @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include + +#include "gmock/gmock.h" + +#include "ClientManager.h" +#include "RpcClient.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ClientManagerMock : public ClientManager { +public: + MOCK_METHOD(void, start, (), (override)); + + MOCK_METHOD(void, shutdown, (), (override)); + + MOCK_METHOD(SchedulerSharedPtr, getScheduler, (), (override)); + + MOCK_METHOD((std::shared_ptr), createChannel, (const std::string&), (override)); + + MOCK_METHOD(void, resolveRoute, + (const std::string&, const Metadata&, const QueryRouteRequest&, std::chrono::milliseconds, + (const std::function&)), + (override)); + + MOCK_METHOD(void, heartbeat, + (const std::string&, const Metadata&, const HeartbeatRequest&, std::chrono::milliseconds, + (const std::function&)), + (override)); + + MOCK_METHOD(std::shared_ptr, telemetry, (const std::string&, std::weak_ptr), + (override)); + + MOCK_METHOD(bool, wrapMessage, (const rmq::Message&, MessageExt&), (override)); + + MOCK_METHOD(void, ack, + (const std::string&, const Metadata&, const AckMessageRequest&, std::chrono::milliseconds, + (const std::function&)), + (override)); + + MOCK_METHOD(void, changeInvisibleDuration, + (const std::string&, const Metadata&, const ChangeInvisibleDurationRequest&, std::chrono::milliseconds, + (const std::function&)), + (override)); + + MOCK_METHOD(void, forwardMessageToDeadLetterQueue, + (const std::string&, const Metadata&, const ForwardMessageToDeadLetterQueueRequest&, + std::chrono::milliseconds, + (const std::function*)>&)), + (override)); + + MOCK_METHOD(void, endTransaction, + (const std::string&, const Metadata&, const EndTransactionRequest&, std::chrono::milliseconds, + (const std::function&)), + (override)); + + MOCK_METHOD(void, addClientObserver, (std::weak_ptr), (override)); + + MOCK_METHOD(void, queryAssignment, + (const std::string& target, const Metadata&, const QueryAssignmentRequest&, std::chrono::milliseconds, + (const std::function&)), + (override)); + + MOCK_METHOD(void, receiveMessage, + (const std::string&, const Metadata&, const ReceiveMessageRequest&, std::chrono::milliseconds, + ReceiveMessageCallback), + (override)); + + MOCK_METHOD(bool, send, (const std::string&, const Metadata&, SendMessageRequest&, SendCallback), (override)); + + MOCK_METHOD(std::error_code, notifyClientTermination, + (const std::string&, const Metadata&, const NotifyClientTerminationRequest&, std::chrono::milliseconds), + (override)); + + MOCK_METHOD(State, state, (), (const override)); + + MOCK_METHOD(void, submit, (std::function), (override)); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/mocks/include/ClientMock.h b/src/main/cpp/client/mocks/include/ClientMock.h new file mode 100644 index 000000000..b88e3c819 --- /dev/null +++ b/src/main/cpp/client/mocks/include/ClientMock.h @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "Client.h" +#include "RpcClient.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ClientMock : virtual public Client { +public: + MOCK_METHOD(void, endpointsInUse, (absl::flat_hash_set&), (override)); + + MOCK_METHOD(void, heartbeat, (), (override)); + + MOCK_METHOD(bool, active, (), (override)); + + MOCK_METHOD(void, onRemoteEndpointRemoval, (const std::vector&), (override)); + + MOCK_METHOD(void, schedule, (const std::string&, const std::function&, std::chrono::milliseconds), + (override)); + + MOCK_METHOD(void, createSession, (const std::string&), (override)); + + MOCK_METHOD(void, notifyClientTermination, (), (override)); + + MOCK_METHOD(void, verify, (VerifyMessageCommand, (std::function)), (override)); + + MOCK_METHOD(void, recoverOrphanedTransaction, (const RecoverOrphanedTransactionCommand&), (override)); +}; + +ROCKETMQ_NAMESPACE_END diff --git a/src/main/cpp/client/mocks/include/ReceiveMessageCallbackMock.h b/src/main/cpp/client/mocks/include/ReceiveMessageCallbackMock.h new file mode 100644 index 000000000..02c958838 --- /dev/null +++ b/src/main/cpp/client/mocks/include/ReceiveMessageCallbackMock.h @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "gmock/gmock.h" + +#include "ReceiveMessageCallback.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ReceiveMessageCallbackMock : public ReceiveMessageCallback { +public: + MOCK_METHOD(void, onCompletion, (const std::error_code&, const ReceiveMessageResult&), (override)); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/client/mocks/include/RpcClientMock.h b/src/main/cpp/client/mocks/include/RpcClientMock.h new file mode 100644 index 000000000..a84759763 --- /dev/null +++ b/src/main/cpp/client/mocks/include/RpcClientMock.h @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include + +#include "gmock/gmock.h" + +#include "Client.h" +#include "InvocationContext.h" +#include "RpcClient.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class RpcClientMock : public RpcClient { +public: + RpcClientMock() = default; + + ~RpcClientMock() override { + std::cout << "~RpcClientMock()" << std::endl; + } + + MOCK_METHOD(const std::string&, remoteAddress, (), (const override)); + + MOCK_METHOD(void, asyncQueryRoute, (const QueryRouteRequest&, InvocationContext*), (override)); + + MOCK_METHOD(void, asyncSend, (const SendMessageRequest&, InvocationContext*), (override)); + + MOCK_METHOD(void, asyncQueryAssignment, (const QueryAssignmentRequest&, InvocationContext*), + (override)); + + MOCK_METHOD(void, asyncReceive, (const ReceiveMessageRequest&, (std::unique_ptr)), (override)); + + MOCK_METHOD(void, asyncAck, (const AckMessageRequest&, InvocationContext*), (override)); + + MOCK_METHOD(void, asyncChangeInvisibleDuration, + (const ChangeInvisibleDurationRequest&, InvocationContext*), (override)); + + MOCK_METHOD(void, asyncHeartbeat, (const HeartbeatRequest&, InvocationContext*), (override)); + + MOCK_METHOD(void, asyncEndTransaction, (const EndTransactionRequest&, InvocationContext*), + (override)); + + MOCK_METHOD(void, asyncForwardMessageToDeadLetterQueue, + (const ForwardMessageToDeadLetterQueueRequest&, + InvocationContext*), + (override)); + + MOCK_METHOD(std::shared_ptr, asyncTelemetry, (std::weak_ptr), (override)); + + MOCK_METHOD(grpc::Status, notifyClientTermination, + (grpc::ClientContext*, const NotifyClientTerminationRequest&, NotifyClientTerminationResponse* response), + (override)); + + MOCK_METHOD(std::weak_ptr, clientManager, (), (override)); + + MOCK_METHOD(bool, needHeartbeat, (), (override)); + + MOCK_METHOD(void, needHeartbeat, (bool), (override)); + + MOCK_METHOD(bool, ok, (), (const override)); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/concurrent/BUILD.bazel b/src/main/cpp/concurrent/BUILD.bazel new file mode 100644 index 000000000..0501d2005 --- /dev/null +++ b/src/main/cpp/concurrent/BUILD.bazel @@ -0,0 +1,37 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_library") +cc_library( + name = "countdown_latch_library", + hdrs = [ + "include/CountdownLatch.h", + ], + srcs = [ + "CountdownLatch.cpp" + ], + strip_include_prefix = "//src/main/cpp/concurrent/include", + deps = [ + "//src/main/cpp/base:base_library", + "//src/main/cpp/log:log_library", + "@com_google_absl//absl/base", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/synchronization", + ], + visibility = [ + "//visibility:public", + ], +) \ No newline at end of file diff --git a/src/common/MQVersion.cpp b/src/main/cpp/concurrent/CountdownLatch.cpp similarity index 54% rename from src/common/MQVersion.cpp rename to src/main/cpp/concurrent/CountdownLatch.cpp index 5c0c78963..363494e06 100644 --- a/src/common/MQVersion.cpp +++ b/src/main/cpp/concurrent/CountdownLatch.cpp @@ -14,22 +14,39 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "MQVersion.h" +#include "CountdownLatch.h" +#include "LoggerImpl.h" -namespace rocketmq { -int MQVersion::s_CurrentVersion = MQVersion::V4_6_0; -std::string MQVersion::s_CurrentLanguage = "CPP"; +ROCKETMQ_NAMESPACE_BEGIN -//= HIGHER_VERSION) { - currentVersion = HIGHER_VERSION; + while (count_ > 0) { + cv_.Wait(&mtx_); } - return RocketMQCPPClientVersion[currentVersion]; } -//= 0) { + SPDLOG_TRACE("After countdown(), latch[{}]={}", name_, count_); + } + } +} + +void CountdownLatch::increaseCount() { + absl::MutexLock lock(&mtx_); + ++count_; + if (!name_.empty()) { + SPDLOG_TRACE("After increaseCount(), latch[{}]={}", name_, count_); + } +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/concurrent/include/CountdownLatch.h b/src/main/cpp/concurrent/include/CountdownLatch.h new file mode 100644 index 000000000..966b5e291 --- /dev/null +++ b/src/main/cpp/concurrent/include/CountdownLatch.h @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "absl/base/thread_annotations.h" +#include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class CountdownLatch { +public: + explicit CountdownLatch(int32_t count) : CountdownLatch(count, "anonymous") { + } + CountdownLatch(int32_t count, absl::string_view name) : count_(count), name_(name.data(), name.length()) { + } + + void await() LOCKS_EXCLUDED(mtx_); + + void countdown() LOCKS_EXCLUDED(mtx_); + + void increaseCount() LOCKS_EXCLUDED(mtx_); + +private: + int32_t count_ GUARDED_BY(mtx_); + + absl::Mutex mtx_; // protects count_ + absl::CondVar cv_; + + std::string name_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/log/BUILD.bazel b/src/main/cpp/log/BUILD.bazel new file mode 100644 index 000000000..4b7670607 --- /dev/null +++ b/src/main/cpp/log/BUILD.bazel @@ -0,0 +1,29 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_library") +cc_library( + name = "log_library", + hdrs = glob(["include/*.h"]), + srcs = glob(["*.cpp"]), + strip_include_prefix = "//src/main/cpp/log/include", + deps = [ + "//api:rocketmq_interface", + "@com_github_gabime_spdlog//:spdlog", + "@com_github_gulrak_filesystem//:filesystem", + ], + visibility = ["//visibility:public"], +) \ No newline at end of file diff --git a/src/main/cpp/log/LoggerImpl.cpp b/src/main/cpp/log/LoggerImpl.cpp new file mode 100644 index 000000000..6ff39f105 --- /dev/null +++ b/src/main/cpp/log/LoggerImpl.cpp @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "LoggerImpl.h" +#include +#include +#include +#include + +// Check C++17 is used +#if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include) +#if __has_include() +#define GHC_USE_STD_FS +#include +namespace fs = std::filesystem; +#endif +#endif + +#ifndef GHC_USE_STD_FS +#include "ghc/filesystem.hpp" +namespace fs = ghc::filesystem; +#endif + +ROCKETMQ_NAMESPACE_BEGIN + +const char* LoggerImpl::LOG_FILE = "/logs/rocketmq/client.log"; +const char* LoggerImpl::LOGGER_NAME = "rocketmq_logger"; + +void LoggerImpl::setLevel(Level level) { + level_ = level; + auto logger = spdlog::get(LOGGER_NAME); + if (logger) { + setLevel(logger, level_); + } +} + +void LoggerImpl::setConsoleLevel(Level level) { + console_level_ = level; + setLevel(console_sink_, console_level_); +} + +void LoggerImpl::init() { + std::call_once(init_once_, [this] { init0(); }); +} + +void LoggerImpl::init0() { + if (log_home_.empty()) { + char* home = getenv(USER_HOME_ENV); + if (home) { + log_home_.append(home); + } else { + log_home_.append(fs::temp_directory_path().string()); + } + log_home_.append(LOG_FILE); + } + + // Create directories if necessary + fs::path log_file(log_home_); + fs::path log_dir = log_file.parent_path(); + if (!fs::exists(log_dir)) { + if (!fs::create_directories(log_dir)) { + std::cerr << "Failed to mkdir " << log_dir << std::endl; + abort(); + } + } + std::cout << "RocketMQ log files path: " << log_dir.c_str() << std::endl; + + if (pattern_.empty()) { + pattern_ = DEFAULT_PATTERN; + } + + console_sink_ = std::make_shared(); + setLevel(console_sink_, console_level_); + console_sink_->set_pattern(pattern_); + + file_sink_ = std::make_shared(log_home_, file_size_, file_count_, + /*rotate_on_open=*/false); + file_sink_->set_pattern(pattern_); + setLevel(file_sink_, level_); + + // std::make_shared does not with initializer_list. + auto default_logger = + std::make_shared(LOGGER_NAME, spdlog::sinks_init_list{console_sink_, file_sink_}); + default_logger->flush_on(spdlog::level::warn); + Level logger_level = + static_cast(std::min(static_cast(level_), static_cast(console_level_))); + switch (logger_level) { + case Level::Trace: { + default_logger->set_level(spdlog::level::trace); + break; + } + case Level::Debug: { + default_logger->set_level(spdlog::level::debug); + break; + } + case Level::Info: { + default_logger->set_level(spdlog::level::info); + break; + } + case Level::Warn: { + default_logger->set_level(spdlog::level::warn); + break; + } + default: { + default_logger->set_level(spdlog::level::info); + break; + } + } + spdlog::flush_every(std::chrono::seconds(1)); + spdlog::set_default_logger(default_logger); +} + +Logger& getLogger() { + static LoggerImpl logger; + return logger; +} + +const std::size_t LoggerImpl::DEFAULT_MAX_LOG_FILE_QUANTITY = 16; +const std::size_t LoggerImpl::DEFAULT_FILE_SIZE = 1048576 * 256; +const char* LoggerImpl::USER_HOME_ENV = "HOME"; +const char* LoggerImpl::DEFAULT_PATTERN = "[%Y/%m/%d-%H:%M:%S.%e %z] [%n] [%^---%L---%$] [thread %t] %v %@"; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/log/include/LoggerImpl.h b/src/main/cpp/log/include/LoggerImpl.h new file mode 100644 index 000000000..338b7e2e7 --- /dev/null +++ b/src/main/cpp/log/include/LoggerImpl.h @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once +#include "rocketmq/Logger.h" +#include "spdlog/sinks/rotating_file_sink.h" +#include "spdlog/sinks/stdout_color_sinks.h" +#include "spdlog/spdlog.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class LoggerImpl : public Logger { + +public: + ~LoggerImpl() override = default; + + void setLevel(Level level) override; + + void setConsoleLevel(Level level) override; + + void setFileSize(std::size_t file_size) override { + file_size_ = file_size; + } + + void setFileCount(std::size_t file_count) override { + file_count_ = file_count; + } + + void setPattern(std::string pattern) override { + pattern_ = std::move(pattern); + auto logger = spdlog::get(LOGGER_NAME); + if (logger) { + logger->set_pattern(pattern_); + } + } + + void init() override; + + static const char* LOGGER_NAME; + +private: + void init0(); + + template + void setLevel(std::shared_ptr& target, Level level) { + if (!target) { + return; + } + + switch (level) { + case Level::Trace: + target->set_level(spdlog::level::trace); + break; + case Level::Debug: + target->set_level(spdlog::level::debug); + break; + case Level::Info: + target->set_level(spdlog::level::info); + break; + case Level::Warn: + target->set_level(spdlog::level::warn); + break; + case Level::Error: + target->set_level(spdlog::level::err); + break; + } + } + + static const char* LOG_FILE; + + Level level_{Level::Info}; + Level console_level_{Level::Warn}; + std::string log_home_; + std::size_t file_size_{DEFAULT_FILE_SIZE}; + std::size_t file_count_{DEFAULT_MAX_LOG_FILE_QUANTITY}; + std::string pattern_; + + std::once_flag init_once_; + + std::shared_ptr file_sink_; + std::shared_ptr console_sink_; + + static const std::size_t DEFAULT_MAX_LOG_FILE_QUANTITY; + static const std::size_t DEFAULT_FILE_SIZE; + static const char* DEFAULT_PATTERN; + static const char* USER_HOME_ENV; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/remoting/BUILD.bazel b/src/main/cpp/remoting/BUILD.bazel new file mode 100644 index 000000000..155672b06 --- /dev/null +++ b/src/main/cpp/remoting/BUILD.bazel @@ -0,0 +1,32 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_library") +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "remoting", + hdrs = glob(["include/*.h"]), + srcs = glob(["*.cpp"]), + strip_include_prefix = "//src/main/cpp/remoting/include", + deps = [ + "//api:rocketmq_interface", + "@asio//:asio", + "@com_google_protobuf//:protobuf", + "@com_google_absl//absl/memory", + "@com_google_absl//absl/container:flat_hash_map", + ] +) \ No newline at end of file diff --git a/src/main/cpp/remoting/BrokerData.cpp b/src/main/cpp/remoting/BrokerData.cpp new file mode 100644 index 000000000..51650aeae --- /dev/null +++ b/src/main/cpp/remoting/BrokerData.cpp @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "BrokerData.h" +#include + +ROCKETMQ_NAMESPACE_BEGIN + +BrokerData BrokerData::decode(const google::protobuf::Struct& root) { + BrokerData broker_data; + auto fields = root.fields(); + if (fields.contains("cluster")) { + broker_data.cluster_ = fields["cluster"].string_value(); + } + + if (fields.contains("brokerName")) { + broker_data.broker_name_ = fields["brokerName"].string_value(); + } + + if (fields.contains("brokerAddrs")) { + auto items = fields["brokerAddrs"].struct_value().fields(); + for (const auto& item : items) { + auto k = std::stoll(item.first); + broker_data.broker_addresses_.insert({k, item.second.string_value()}); + } + } + return broker_data; +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/include/CTransactionStatus.h b/src/main/cpp/remoting/QueryRouteRequestHeader.cpp similarity index 69% rename from include/CTransactionStatus.h rename to src/main/cpp/remoting/QueryRouteRequestHeader.cpp index 435b841b8..551f3a2c5 100644 --- a/include/CTransactionStatus.h +++ b/src/main/cpp/remoting/QueryRouteRequestHeader.cpp @@ -14,20 +14,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "QueryRouteRequestHeader.h" +#include "rocketmq/RocketMQ.h" -#ifndef __C_TRANSACTION_STATUS_H__ -#define __C_TRANSACTION_STATUS_H__ +ROCKETMQ_NAMESPACE_BEGIN -#ifdef __cplusplus -extern "C" { -#endif -typedef enum E_CTransactionStatus { - E_COMMIT_TRANSACTION = 0, - E_ROLLBACK_TRANSACTION = 1, - E_UNKNOWN_TRANSACTION = 2, -} CTransactionStatus; - -#ifdef __cplusplus +void QueryRouteRequestHeader::encode(google::protobuf::Value& root) const { + auto fields = root.mutable_struct_value()->mutable_fields(); + google::protobuf::Value topic; + topic.set_string_value(topic_); + fields->insert({"topic", topic}); } -#endif -#endif //__C_TRANSACTION_STATUS_H__ \ No newline at end of file + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/test/src/common/NamesrvConfigTest.cpp b/src/main/cpp/remoting/QueueData.cpp similarity index 51% rename from test/src/common/NamesrvConfigTest.cpp rename to src/main/cpp/remoting/QueueData.cpp index e4e1206ae..1a0796eaf 100644 --- a/test/src/common/NamesrvConfigTest.cpp +++ b/src/main/cpp/remoting/QueueData.cpp @@ -14,37 +14,36 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "QueueData.h" -#include +ROCKETMQ_NAMESPACE_BEGIN -#include "gmock/gmock.h" -#include "gtest/gtest.h" +QueueData QueueData::decode(const google::protobuf::Struct& root) { + auto fields = root.fields(); -#include "NamesrvConfig.h" + QueueData queue_data; -using std::string; + if (fields.contains("brokerName")) { + queue_data.broker_name_ = fields["brokerName"].string_value(); + } -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; + if (fields.contains("readQueueNums")) { + queue_data.read_queue_number_ = fields["readQueueNums"].number_value(); + } -using rocketmq::NamesrvConfig; + if (fields.contains("writeQueueNums")) { + queue_data.write_queue_number_ = fields["writeQueueNums"].number_value(); + } -TEST(namesrvConfig, init) { - NamesrvConfig namesrvConfig; + if (fields.contains("perm")) { + queue_data.perm_ = fields["perm"].number_value(); + } - const string home = "/home/rocketmq"; - namesrvConfig.setRocketmqHome(home); - EXPECT_EQ(namesrvConfig.getRocketmqHome(), "/home/rocketmq"); + if (fields.contains("topicSynFlag")) { + queue_data.topic_system_flag_ = fields["topicSynFlag"].number_value(); + } - namesrvConfig.setKvConfigPath("/home/rocketmq"); - EXPECT_EQ(namesrvConfig.getKvConfigPath(), "/home/rocketmq"); + return queue_data; } -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "namesrvConfig.init"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/remoting/RemotingCommand.cpp b/src/main/cpp/remoting/RemotingCommand.cpp new file mode 100644 index 000000000..743096aab --- /dev/null +++ b/src/main/cpp/remoting/RemotingCommand.cpp @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "RemotingCommand.h" + +#include +#include +#include + +#include "LanguageCode.h" +#include "absl/memory/memory.h" + +#include "QueryRouteRequestHeader.h" + +ROCKETMQ_NAMESPACE_BEGIN + +std::int32_t RemotingCommand::nextRequestId() { + static std::atomic_int32_t request_id{0}; + return request_id.fetch_add(1, std::memory_order_relaxed); +} + +RemotingCommand RemotingCommand::createRequest(RequestCode code, CommandCustomHeader* ext_fields) { + RemotingCommand command; + command.code_ = static_cast(code); + command.ext_fields_ = ext_fields; + return command; +} + +RemotingCommand RemotingCommand::createResponse(ResponseCode code, CommandCustomHeader* ext_fields) { + RemotingCommand response; + response.code_ = static_cast(code); + response.ext_fields_ = ext_fields; + response.flag_ |= (1 << RPC_TYPE_RESPONSE); + return response; +} + +void RemotingCommand::encodeHeader(google::protobuf::Value& root) { + auto fields = root.mutable_struct_value()->mutable_fields(); + + google::protobuf::Value code; + code.set_number_value(code_); + fields->insert({"code", code}); + + google::protobuf::Value language; + switch (language_) { + case LanguageCode::CPP: { + language.set_string_value("CPP"); + break; + } + case LanguageCode::JAVA: { + language.set_string_value("JAVA"); + break; + } + case LanguageCode::GO: { + language.set_string_value("GO"); + break; + } + case LanguageCode::DOTNET: { + language.set_string_value("DOTNET"); + break; + } + default: { + language.set_string_value("OTHER"); + break; + } + } + fields->insert({"language", language}); + + if (version_) { + google::protobuf::Value version; + version.set_number_value(version_); + fields->insert({"version", version}); + } + + google::protobuf::Value opaque; + opaque.set_number_value(opaque_); + fields->insert({"opaque", opaque}); + + google::protobuf::Value flag; + flag.set_number_value(flag_); + fields->insert({"flag", flag}); + + if (!remark_.empty()) { + google::protobuf::Value remark; + remark.set_string_value(remark_); + fields->insert({"remark", remark}); + } + + if (ext_fields_) { + google::protobuf::Value ext_fields; + ext_fields_->encode(ext_fields); + fields->insert({"extFields", ext_fields}); + } +} + +const std::uint8_t RemotingCommand::RPC_TYPE_RESPONSE = 0; + +const std::uint8_t RemotingCommand::RPC_TYPE_ONE_WAY = 1; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/message/MQMessageId.h b/src/main/cpp/remoting/TopicRouteData.cpp similarity index 50% rename from src/message/MQMessageId.h rename to src/main/cpp/remoting/TopicRouteData.cpp index fbe937bad..71a9f3c00 100644 --- a/src/message/MQMessageId.h +++ b/src/main/cpp/remoting/TopicRouteData.cpp @@ -14,40 +14,33 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef __MESSAGEID_H__ -#define __MESSAGEID_H__ - -#include "SocketUtil.h" -#include "UtilAll.h" - -namespace rocketmq { -//m_address = id.m_address; - this->m_offset = id.m_offset; - return *this; - } +#include "TopicRouteData.h" +#include "BrokerData.h" +#include "rocketmq/RocketMQ.h" - sockaddr getAddress() const { return m_address; } +ROCKETMQ_NAMESPACE_BEGIN - void setAddress(sockaddr address) { m_address = address; } +TopicRouteData TopicRouteData::decode(const google::protobuf::Struct& root) { + auto fields = root.fields(); - int64 getOffset() const { return m_offset; } + TopicRouteData topic_route_data; - void setOffset(int64 offset) { m_offset = offset; } + if (fields.contains("queueDatas")) { + auto queue_data_list = fields.at("queueDatas"); - private: - sockaddr m_address; - int64 m_offset; -}; + for (auto& item : queue_data_list.list_value().values()) { + topic_route_data.queue_data_.push_back(QueueData::decode(item.struct_value())); + } + } + + if (fields.contains("brokerDatas")) { + auto broker_data_list = fields.at("brokerDatas"); + for (auto& item : broker_data_list.list_value().values()) { + topic_route_data.broker_data_.push_back(BrokerData::decode(item.struct_value())); + } + } -} // namespace rocketmq + return topic_route_data; +} -#endif +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/common/url.h b/src/main/cpp/remoting/include/BrokerData.h similarity index 65% rename from src/common/url.h rename to src/main/cpp/remoting/include/BrokerData.h index 62d86a232..83ef5fd81 100644 --- a/src/common/url.h +++ b/src/main/cpp/remoting/include/BrokerData.h @@ -14,25 +14,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef ROCKETMQ_CLIENT4CPP_URL_HH_ -#define ROCKETMQ_CLIENT4CPP_URL_HH_ +#pragma once +#include #include -namespace rocketmq { -class Url { - public: - Url(const std::string& url_s); // omitted copy, ==, accessors, ... +#include "absl/container/flat_hash_map.h" +#include "google/protobuf/struct.pb.h" +#include "google/protobuf/util/json_util.h" - private: - void parse(const std::string& url_s); +#include "rocketmq/RocketMQ.h" - public: - std::string protocol_; - std::string host_; - std::string port_; - std::string path_; - std::string query_; +ROCKETMQ_NAMESPACE_BEGIN + +struct BrokerData { + std::string cluster_; + std::string broker_name_; + absl::flat_hash_map broker_addresses_; + + static BrokerData decode(const google::protobuf::Struct& root); }; -} // namespace rocketmq -#endif // ROCKETMQ_CLIENT4CPP_URL_HH_ + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/common/noncopyable.h b/src/main/cpp/remoting/include/CommandCustomHeader.h similarity index 71% rename from src/common/noncopyable.h rename to src/main/cpp/remoting/include/CommandCustomHeader.h index f52f98806..a6afbc22e 100644 --- a/src/common/noncopyable.h +++ b/src/main/cpp/remoting/include/CommandCustomHeader.h @@ -14,20 +14,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef __NONCOPYABLE_H__ -#define __NONCOPYABLE_H__ +#pragma once -namespace rocketmq { +#include "google/protobuf/struct.pb.h" +#include "google/protobuf/util/json_util.h" -class noncopyable { - protected: - noncopyable() = default; - ~noncopyable() = default; +#include "rocketmq/RocketMQ.h" - noncopyable(const noncopyable&) = delete; - noncopyable& operator=(const noncopyable&) = delete; -}; +ROCKETMQ_NAMESPACE_BEGIN + +class CommandCustomHeader { +public: + virtual ~CommandCustomHeader() = default; -} // namespace rocketmq + virtual void encode(google::protobuf::Value& root) const = 0; +}; -#endif //__NONCOPYABLE_H__ +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/remoting/include/LanguageCode.h b/src/main/cpp/remoting/include/LanguageCode.h new file mode 100644 index 000000000..7151faf4d --- /dev/null +++ b/src/main/cpp/remoting/include/LanguageCode.h @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +enum class LanguageCode : std::uint8_t +{ + JAVA = 0, + CPP = 1, + DOTNET = 2, + PYTHON = 3, + DELPHI = 4, + ERLANG = 5, + RUBY = 6, + OTHER = 7, + HTTP = 8, + GO = 9, + PHP = 10, + OMS = 11, +}; + +ROCKETMQ_NAMESPACE_END diff --git a/src/main/cpp/remoting/include/QueryRouteRequestHeader.h b/src/main/cpp/remoting/include/QueryRouteRequestHeader.h new file mode 100644 index 000000000..b5669690e --- /dev/null +++ b/src/main/cpp/remoting/include/QueryRouteRequestHeader.h @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "absl/strings/string_view.h" + +#include "CommandCustomHeader.h" +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class QueryRouteRequestHeader : public CommandCustomHeader { +public: + ~QueryRouteRequestHeader() override = default; + + void topic(absl::string_view topic) { + topic_ = std::string(topic.data(), topic.length()); + } + + const std::string& topic() const { + return topic_; + } + + void encode(google::protobuf::Value& root) const override; + +private: + std::string topic_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/include/Arg_helper.h b/src/main/cpp/remoting/include/QueueData.h similarity index 61% rename from include/Arg_helper.h rename to src/main/cpp/remoting/include/QueueData.h index bc2896232..9530cfca8 100644 --- a/include/Arg_helper.h +++ b/src/main/cpp/remoting/include/QueueData.h @@ -14,27 +14,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once -#ifndef _ARG_HELPER_H_ -#define _ARG_HELPER_H_ - +#include #include -#include -#include "RocketMQClient.h" - -namespace rocketmq { -class ROCKETMQCLIENT_API Arg_helper { - public: - Arg_helper(int argc, char* argv[]); - Arg_helper(std::string arg_str_); - std::string get_option(int idx_) const; - bool is_enable_option(std::string opt_) const; - std::string get_option_value(std::string opt_) const; - - private: - std::vector m_args; -}; -} // namespace rocketmq +#include "google/protobuf/struct.pb.h" +#include "google/protobuf/util/json_util.h" + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +struct QueueData { + std::string broker_name_; + std::int32_t read_queue_number_{0}; + std::int32_t write_queue_number_{0}; + std::uint32_t perm_{0}; + + /** + * @brief in Java, it's named "topicSynFlag" + * + */ + std::uint32_t topic_system_flag_{0}; + + static QueueData decode(const google::protobuf::Struct& root); +}; -#endif // +#include +#include +#include + +#include "CommandCustomHeader.h" +#include "LanguageCode.h" +#include "RequestCode.h" +#include "ResponseCode.h" +#include "Version.h" + +ROCKETMQ_NAMESPACE_BEGIN + +/** + * RemotingCommand is non-copyable. It is movable. + */ +class RemotingCommand { +public: + RemotingCommand(const RemotingCommand&) = delete; + + RemotingCommand(RemotingCommand&& rhs) noexcept { + code_ = rhs.code_; + language_ = rhs.language_; + version_ = rhs.version_; + opaque_ = rhs.opaque_; + remark_ = std::move(rhs.remark_); + body_ = std::move(rhs.body_); + ext_fields_ = rhs.ext_fields_; + rhs.ext_fields_ = nullptr; + } + + RemotingCommand& operator=(const RemotingCommand&) = delete; + + RemotingCommand& operator=(RemotingCommand&& rhs) noexcept { + if (this == &rhs) { + return *this; + } + + code_ = rhs.code_; + language_ = rhs.language_; + version_ = rhs.version_; + opaque_ = rhs.opaque_; + remark_ = std::move(rhs.remark_); + body_ = std::move(rhs.body_); + ext_fields_ = rhs.ext_fields_; + rhs.ext_fields_ = nullptr; + return *this; + } + + virtual ~RemotingCommand() { + delete ext_fields_; + } + + static std::int32_t nextRequestId(); + + static RemotingCommand createRequest(RequestCode, CommandCustomHeader*); + + static RemotingCommand createResponse(ResponseCode, CommandCustomHeader*); + + virtual void encodeHeader(google::protobuf::Value& root); + +private: + RemotingCommand() = default; + + std::int32_t code_{static_cast(RequestCode::QueryRoute)}; + LanguageCode language_{LanguageCode::CPP}; + std::int32_t version_{static_cast(Version::V4_9_1)}; + std::int32_t opaque_{nextRequestId()}; + std::uint32_t flag_{0}; + std::string remark_; + + CommandCustomHeader* ext_fields_{nullptr}; + + std::vector body_; + + /** + * Bit-field shift amount for flag_ field, indicating the RPC is a response from broker or name-server. + */ + const static std::uint8_t RPC_TYPE_RESPONSE; + + /** + * Bit-field shift amount for flag_ field. Request marked one-way should NOT expect a respose from broker or + * name-server. + */ + const static std::uint8_t RPC_TYPE_ONE_WAY; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/remoting/include/RemotingCommandType.h b/src/main/cpp/remoting/include/RemotingCommandType.h new file mode 100644 index 000000000..9ca78d2c0 --- /dev/null +++ b/src/main/cpp/remoting/include/RemotingCommandType.h @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +enum class RemotingCommandType : std::uint8_t +{ + REQUEST = 0, + RESPONSE = 1, +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/remoting/include/RequestCode.h b/src/main/cpp/remoting/include/RequestCode.h new file mode 100644 index 000000000..cb28eaf2a --- /dev/null +++ b/src/main/cpp/remoting/include/RequestCode.h @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +enum class RequestCode : std::int32_t +{ + SendMessage = 10, + PullMessage = 11, + QueryRoute = 105, +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/remoting/include/ResponseCode.h b/src/main/cpp/remoting/include/ResponseCode.h new file mode 100644 index 000000000..4cfa924e4 --- /dev/null +++ b/src/main/cpp/remoting/include/ResponseCode.h @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +enum class ResponseCode : std::uint16_t +{ + Success = 0, + InternalSystemError = 1, + TooManyRequests = 2, +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/common/TopicFilterType.h b/src/main/cpp/remoting/include/TopicRouteData.h similarity index 65% rename from src/common/TopicFilterType.h rename to src/main/cpp/remoting/include/TopicRouteData.h index 055d112ec..2c044f8c9 100644 --- a/src/common/TopicFilterType.h +++ b/src/main/cpp/remoting/include/TopicRouteData.h @@ -14,21 +14,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef __TOPICFILTERTYPE_H__ -#define __TOPICFILTERTYPE_H__ +#pragma once + +#include + +#include "BrokerData.h" +#include "QueueData.h" +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +struct TopicRouteData { -namespace rocketmq { -// queue_data_; + /** - * not support now + * @brief In Java, it's named "brokerDatas" + * */ - MULTI_TAG + std::vector broker_data_; + + static TopicRouteData decode(const google::protobuf::Struct& root); }; -// + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +enum class Version : std::int32_t +{ + V4_9_1 = 396, + V4_9_2 = 398, +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/AsyncReceiveMessageCallback.cpp b/src/main/cpp/rocketmq/AsyncReceiveMessageCallback.cpp new file mode 100644 index 000000000..c1b57d455 --- /dev/null +++ b/src/main/cpp/rocketmq/AsyncReceiveMessageCallback.cpp @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "AsyncReceiveMessageCallback.h" + +#include + +#include "ClientManagerImpl.h" +#include "ConsumeMessageType.h" +#include "LoggerImpl.h" +#include "ProcessQueue.h" +#include "PushConsumerImpl.h" + +ROCKETMQ_NAMESPACE_BEGIN + +AsyncReceiveMessageCallback::AsyncReceiveMessageCallback(std::weak_ptr process_queue) + : process_queue_(std::move(process_queue)) { + receive_message_later_ = std::bind(&AsyncReceiveMessageCallback::checkThrottleThenReceive, this); +} + +void AsyncReceiveMessageCallback::onCompletion(const std::error_code& ec, const ReceiveMessageResult& result) { + std::shared_ptr process_queue = process_queue_.lock(); + if (!process_queue) { + SPDLOG_INFO("Process queue has been destructed."); + return; + } + + auto consumer = process_queue->getConsumer().lock(); + if (!consumer) { + return; + } + + if (ec) { + SPDLOG_WARN("Receive message from {} failed. Cause: {}. Attempt later.", process_queue->simpleName(), ec.message()); + receiveMessageLater(); + return; + } + + SPDLOG_DEBUG("Receive messages from broker[host={}] returns with status=FOUND, msgListSize={}, queue={}", + result.source_host, result.messages.size(), process_queue->simpleName()); + process_queue->cacheMessages(result.messages); + + consumer->getConsumeMessageService()->dispatch(process_queue, result.messages); + checkThrottleThenReceive(); +} + +const char* AsyncReceiveMessageCallback::RECEIVE_LATER_TASK_NAME = "receive-later-task"; + +void AsyncReceiveMessageCallback::checkThrottleThenReceive() { + auto process_queue = process_queue_.lock(); + if (!process_queue) { + SPDLOG_WARN("Process queue should have been destructed"); + return; + } + + if (process_queue->shouldThrottle()) { + SPDLOG_INFO("Number of messages in {} exceeds throttle threshold. Receive messages later.", + process_queue->simpleName()); + process_queue->syncIdleState(); + receiveMessageLater(); + } else { + // Receive message immediately + receiveMessageImmediately(); + } +} + +void AsyncReceiveMessageCallback::receiveMessageLater() { + auto process_queue = process_queue_.lock(); + if (!process_queue) { + return; + } + + auto client_instance = process_queue->getClientManager(); + std::weak_ptr receive_callback_weak_ptr(shared_from_this()); + + auto task = [receive_callback_weak_ptr]() { + auto async_receive_ptr = receive_callback_weak_ptr.lock(); + if (async_receive_ptr) { + async_receive_ptr->checkThrottleThenReceive(); + } + }; + + client_instance->getScheduler()->schedule(task, RECEIVE_LATER_TASK_NAME, std::chrono::seconds(1), + std::chrono::seconds(0)); +} + +void AsyncReceiveMessageCallback::receiveMessageImmediately() { + auto process_queue_shared_ptr = process_queue_.lock(); + if (!process_queue_shared_ptr) { + SPDLOG_INFO("ProcessQueue has been released. Ignore further receive message request-response cycles"); + return; + } + + std::shared_ptr impl = process_queue_shared_ptr->getConsumer().lock(); + if (!impl) { + SPDLOG_INFO("Owner of ProcessQueue[{}] has been released. Ignore further receive message request-response cycles", + process_queue_shared_ptr->simpleName()); + return; + } + impl->receiveMessage(process_queue_shared_ptr->messageQueue(), process_queue_shared_ptr->getFilterExpression()); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/BUILD.bazel b/src/main/cpp/rocketmq/BUILD.bazel new file mode 100644 index 000000000..b37957d3f --- /dev/null +++ b/src/main/cpp/rocketmq/BUILD.bazel @@ -0,0 +1,34 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_library") + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "rocketmq_library", + hdrs = glob(["include/*.h"]), + srcs = glob(["*.cpp"]), + strip_include_prefix = "//src/main/cpp/rocketmq/include", + deps = [ + "//src/main/cpp/client:client_library", + "//src/main/cpp/stats", + "//src/main/cpp/trace", + "//src/main/cpp/log:log_library", + "//src/main/cpp/admin:admin_server_library", + "@com_google_absl//absl/types:optional", + ], +) \ No newline at end of file diff --git a/src/main/cpp/rocketmq/ClientImpl.cpp b/src/main/cpp/rocketmq/ClientImpl.cpp new file mode 100644 index 000000000..8275922cd --- /dev/null +++ b/src/main/cpp/rocketmq/ClientImpl.cpp @@ -0,0 +1,539 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ClientImpl.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ClientManagerFactory.h" +#include "HttpClientImpl.h" +#include "InvocationContext.h" +#include "LoggerImpl.h" +#include "MessageExt.h" +#include "NamingScheme.h" +#include "SessionImpl.h" +#include "Signature.h" +#include "UtilAll.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_join.h" +#include "absl/strings/str_split.h" +#include "rocketmq/Message.h" +#include "rocketmq/MessageListener.h" + +ROCKETMQ_NAMESPACE_BEGIN + +ClientImpl::ClientImpl(absl::string_view group_name) : state_(State::CREATED) { + client_config_.subscriber.group.set_name(std::string(group_name.data(), group_name.length())); +} + +rmq::Endpoints ClientImpl::accessPoint() { + std::string endpoints = name_server_resolver_->resolve(); + rmq::Endpoints access_point; + + absl::string_view host_port; + if (absl::StartsWith(endpoints, NamingScheme::IPv4Prefix)) { + access_point.set_scheme(rmq::AddressScheme::IPv4); + host_port = absl::StripPrefix(endpoints, NamingScheme::IPv4Prefix); + } else if (absl::StartsWith(endpoints, NamingScheme::IPv6Prefix)) { + access_point.set_scheme(rmq::AddressScheme::IPv6); + host_port = absl::StripPrefix(endpoints, NamingScheme::IPv6Prefix); + } else { + access_point.set_scheme(rmq::AddressScheme::DOMAIN_NAME); + host_port = absl::StripPrefix(endpoints, NamingScheme::DnsPrefix); + } + + std::vector pairs = absl::StrSplit(host_port, ';', absl::SkipWhitespace()); + // Now endpoint is in form of host:port + for (auto& endpoint : pairs) { + std::reverse(endpoint.begin(), endpoint.end()); + std::vector segments = absl::StrSplit(endpoint, absl::MaxSplits(':', 1)); + for (auto& segment : segments) { + std::reverse(segment.begin(), segment.end()); + } + if (segments.size() != 2) { + continue; + } + + std::int32_t port; + if (!absl::SimpleAtoi(segments[0], &port)) { + // Failed to parse port + continue; + } + + auto addr = new rmq::Address(); + addr->set_host(segments[1]); + addr->set_port(port); + access_point.mutable_addresses()->AddAllocated(addr); + } + return access_point; +} + +void ClientImpl::start() { + State expected = CREATED; + if (!state_.compare_exchange_strong(expected, State::STARTING)) { + SPDLOG_ERROR("Attempt to start ClientImpl failed. Expecting: {} Actual: {}", State::CREATED, + state_.load(std::memory_order_relaxed)); + return; + } + + if (!name_server_resolver_) { + SPDLOG_ERROR("No name server resolver is configured."); + abort(); + } + name_server_resolver_->start(); + + client_config_.client_id = clientId(); + + client_manager_ = ClientManagerFactory::getInstance().getClientManager(client_config_); + client_manager_->start(); + + const auto& endpoint = name_server_resolver_->resolve(); + if (endpoint.empty()) { + SPDLOG_ERROR("Failed to resolve name server address"); + abort(); + } + + createSession(endpoint, false); + { + absl::MutexLock lk(&session_map_mtx_); + session_map_[endpoint]->await(); + } + + std::weak_ptr ptr(self()); + + { + // Query routes for topics of interest in synchronous + std::vector topics; + topicsOfInterest(topics); + + auto mtx = std::make_shared(); + auto cv = std::make_shared(); + bool completed = false; + for (const auto& topic : topics) { + completed = false; + auto callback = [&, mtx, cv](const std::error_code& ec, const TopicRouteDataPtr ptr) { + if (ec) { + SPDLOG_ERROR("Failed to query route for {} during starting. Cause: {}", topic, ec.message()); + } + + { + absl::MutexLock lk(mtx.get()); + completed = true; + } + cv->Signal(); + }; + getRouteFor(topic, callback); + { + absl::MutexLock lk(mtx.get()); + if (!completed) { + cv->Wait(mtx.get()); + } + } + } + } + + auto route_update_functor = [ptr]() { + std::shared_ptr base = ptr.lock(); + if (base) { + base->updateRouteInfo(); + } + }; + + route_update_handle_ = client_manager_->getScheduler()->schedule(route_update_functor, UPDATE_ROUTE_TASK_NAME, + std::chrono::seconds(10), std::chrono::seconds(30)); +} + +void ClientImpl::shutdown() { + State expected = State::STOPPING; + if (state_.compare_exchange_strong(expected, State::STOPPED)) { + name_server_resolver_->shutdown(); + if (route_update_handle_) { + client_manager_->getScheduler()->cancel(route_update_handle_); + } + client_manager_.reset(); + } else { + SPDLOG_ERROR("Try to shutdown ClientImpl, but its state is not as expected. Expecting: {}, Actual: {}", + State::STOPPING, state_.load(std::memory_order_relaxed)); + } +} + +const char* ClientImpl::UPDATE_ROUTE_TASK_NAME = "route_updater"; + +void ClientImpl::endpointsInUse(absl::flat_hash_set& endpoints) { + absl::MutexLock lk(&topic_route_table_mtx_); + for (const auto& item : topic_route_table_) { + for (const auto& queue : item.second->messageQueues()) { + std::string endpoint = urlOf(queue); + if (!endpoints.contains(endpoint)) { + endpoints.emplace(std::move(endpoint)); + } + } + } +} + +void ClientImpl::getRouteFor(const std::string& topic, + const std::function& cb) { + TopicRouteDataPtr route = nullptr; + { + absl::MutexLock lock(&topic_route_table_mtx_); + if (topic_route_table_.contains(topic)) { + route = topic_route_table_.at(topic); + } + } + + if (route) { + std::error_code ec; + cb(ec, route); + return; + } + + bool query_backend = true; + { + absl::MutexLock lk(&inflight_route_requests_mtx_); + { + absl::MutexLock route_table_lock(&topic_route_table_mtx_); + if (topic_route_table_.contains(topic)) { + route = topic_route_table_.at(topic); + query_backend = false; + } + } + + if (query_backend) { + if (inflight_route_requests_.contains(topic)) { + inflight_route_requests_.at(topic).emplace_back(cb); + SPDLOG_DEBUG("Would reuse prior route request for topic={}", topic); + return; + } else { + std::vector> inflight{cb}; + inflight_route_requests_.insert({topic, inflight}); + SPDLOG_INFO("Create inflight route query cache for topic={}", topic); + } + } + } + + if (!query_backend && route) { + std::error_code ec; + cb(ec, route); + } else { + fetchRouteFor(topic, + std::bind(&ClientImpl::onTopicRouteReady, this, topic, std::placeholders::_1, std::placeholders::_2)); + } +} + +void ClientImpl::fetchRouteFor(const std::string& topic, + const std::function& cb) { + std::string name_server = name_server_resolver_->resolve(); + if (name_server.empty()) { + SPDLOG_WARN("No name server available"); + return; + } + + auto callback = [this, topic, name_server, cb](const std::error_code& ec, const TopicRouteDataPtr& route) { + if (ec) { + SPDLOG_WARN("Failed to resolve route for topic={} from {}", topic, name_server); + std::string name_server_changed = name_server_resolver_->resolve(); + if (!name_server_changed.empty()) { + SPDLOG_INFO("Change current name server from {} to {}", name_server, name_server_changed); + } + cb(ec, nullptr); + return; + } + + SPDLOG_DEBUG("Apply callback of fetchRouteFor({}) since a valid route is fetched", topic); + cb(ec, route); + }; + + QueryRouteRequest request; + request.mutable_topic()->set_resource_namespace(client_config_.resource_namespace); + request.mutable_topic()->set_name(topic); + request.mutable_endpoints()->CopyFrom(accessPoint()); + absl::flat_hash_map metadata; + Signature::sign(client_config_, metadata); + client_manager_->resolveRoute(name_server, metadata, request, + absl::ToChronoMilliseconds(client_config_.request_timeout), callback); +} + +void ClientImpl::updateRouteInfo() { + if (State::STARTED != state_.load(std::memory_order_relaxed) && + State::STARTING != state_.load(std::memory_order_relaxed)) { + SPDLOG_WARN("Unexpected client instance state={}.", state_.load(std::memory_order_relaxed)); + return; + } + + std::vector topics; + { + absl::MutexLock lock(&topic_route_table_mtx_); + for (const auto& entry : topic_route_table_) { + topics.push_back(entry.first); + } + } + topicsOfInterest(topics); + + SPDLOG_DEBUG("Query route for {}", absl::StrJoin(topics, ",")); + + if (!topics.empty()) { + for (const auto& topic : topics) { + fetchRouteFor( + topic, std::bind(&ClientImpl::updateRouteCache, this, topic, std::placeholders::_1, std::placeholders::_2)); + } + } + SPDLOG_DEBUG("Topic route info updated"); +} + +void ClientImpl::heartbeat() { + absl::flat_hash_set hosts; + endpointsInUse(hosts); + if (hosts.empty()) { + SPDLOG_WARN("No hosts to send heartbeat to at present"); + return; + } + + HeartbeatRequest request; + prepareHeartbeatData(request); + + absl::flat_hash_map metadata; + Signature::sign(client_config_, metadata); + + for (const auto& target : hosts) { + auto callback = [target](const std::error_code& ec, const HeartbeatResponse& response) { + if (ec) { + SPDLOG_WARN("Failed to heartbeat against {}. Cause: {}", target, ec.message()); + return; + } + SPDLOG_DEBUG("Heartbeat to {} OK", target); + }; + client_manager_->heartbeat(target, metadata, request, absl::ToChronoMilliseconds(client_config_.request_timeout), + callback); + } +} + +void ClientImpl::onTopicRouteReady(const std::string& topic, const std::error_code& ec, + const TopicRouteDataPtr& route) { + if (route) { + SPDLOG_DEBUG("Received route data for topic={}", topic); + } + + updateRouteCache(topic, ec, route); + + // Take all pending callbacks + std::vector> pending_requests; + { + absl::MutexLock lk(&inflight_route_requests_mtx_); + assert(inflight_route_requests_.contains(topic)); + auto& inflight_requests = inflight_route_requests_.at(topic); + pending_requests.insert(pending_requests.end(), inflight_requests.begin(), inflight_requests.end()); + inflight_route_requests_.erase(topic); + } + + SPDLOG_DEBUG("Apply cached callbacks with acquired route data for topic={}", topic); + for (const auto& cb : pending_requests) { + cb(ec, route); + } +} + +void ClientImpl::updateRouteCache(const std::string& topic, const std::error_code& ec, const TopicRouteDataPtr& route) { + if (ec || !route || route->messageQueues().empty()) { + SPDLOG_WARN("Yuck! route for {} is invalid. Cause: {}", topic, ec.message()); + return; + } + + { + absl::MutexLock lk(&topic_route_table_mtx_); + if (!topic_route_table_.contains(topic)) { + topic_route_table_.insert({topic, route}); + SPDLOG_INFO("TopicRouteData for topic={} has changed. NONE --> {}", topic, route->debugString()); + } else { + TopicRouteDataPtr cached = topic_route_table_.at(topic); + if (*cached != *route) { + topic_route_table_.insert_or_assign(topic, route); + std::string previous = cached->debugString(); + SPDLOG_INFO("TopicRouteData for topic={} has changed. {} --> {}", topic, cached->debugString(), + route->debugString()); + } + } + } + + absl::flat_hash_set targets; + for (const auto& message_queue : route->messageQueues()) { + targets.insert(urlOf(message_queue)); + } + + { + absl::MutexLock lk(&session_map_mtx_); + for (auto it = targets.begin(); it != targets.end();) { + if (session_map_.contains(*it)) { + targets.erase(it++); + } else { + ++it; + } + } + } + + if (!targets.empty()) { + for (const auto& target : targets) { + createSession(target, true); + } + } +} + +rmq::Settings ClientImpl::clientSettings() { + rmq::Settings settings; + settings.mutable_access_point()->CopyFrom(accessPoint()); + + std::int64_t seconds = absl::ToInt64Seconds(client_config_.request_timeout); + settings.mutable_request_timeout()->set_seconds(seconds); + std::int64_t nanos = absl::ToInt64Nanoseconds(client_config_.request_timeout - absl::Seconds(seconds)); + settings.mutable_request_timeout()->set_nanos(nanos); + + // Fill User Agent + settings.mutable_user_agent()->set_hostname(UtilAll::hostname()); + settings.mutable_user_agent()->set_language(rmq::Language::CPP); + settings.mutable_user_agent()->set_version(MetadataConstants::CLIENT_VERSION); + settings.mutable_user_agent()->set_platform(MixAll::osName()); + + buildClientSettings(settings); + + return settings; +} + +void ClientImpl::createSession(const std::string& target, bool verify) { + if (verify) { + absl::flat_hash_set endpoints; + endpointsInUse(endpoints); + if (!endpoints.contains(target)) { + return; + } + } + + std::weak_ptr client = self(); + auto rpc_client = client_manager_->getRpcClient(target, true); + SPDLOG_DEBUG("Create a new session for {}", target); + auto session = absl::make_unique(client, rpc_client); + { + absl::MutexLock lk(&session_map_mtx_); + session_map_.insert_or_assign(target, std::move(session)); + } +} + +void ClientImpl::verify(MessageConstSharedPtr message, std::function cb) { + std::weak_ptr ptr(self()); + + // TODO: Use capture by move if C++14 is possible + auto task = [message, cb, ptr]() { + auto client = ptr.lock(); + if (!client) { + return; + } + + client->onVerifyMessage(message, cb); + }; + + // Verify message may take a long period of time, we need to execute it in dedicated thread pool + // such that network-IO thread will not get blocked. + client_manager_->submit(task); +} + +void ClientImpl::onVerifyMessage(MessageConstSharedPtr message, std::function cb) { + rmq::TelemetryCommand cmd; + cmd.mutable_verify_message_result()->set_nonce(message->extension().nonce); + cmd.mutable_status()->set_code(rmq::Code::NOT_IMPLEMENTED); + cmd.mutable_status()->set_message("Unsupported Operation"); + cb(std::move(cmd)); +} + +void ClientImpl::recoverOrphanedTransaction(MessageConstSharedPtr message) { + auto ptr = self(); + std::weak_ptr owner(ptr); + + auto do_recover = [message, owner]() { + auto client = owner.lock(); + if (!client) { + return; + } + client->doRecoverOrphanedTransaction(message); + }; + + // Execute orphaned transaction recovery in dedicated thread pool. + client_manager_->submit(do_recover); +} + +void ClientImpl::doRecoverOrphanedTransaction(MessageConstSharedPtr message) { + if (!message) { + SPDLOG_WARN("Failed to decode orphaned transaction message"); + return; + } + + onOrphanedTransactionalMessage(message); +} + +void ClientImpl::onRemoteEndpointRemoval(const std::vector& hosts) { + absl::MutexLock lk(&isolated_endpoints_mtx_); + for (auto it = isolated_endpoints_.begin(); it != isolated_endpoints_.end();) { + if (hosts.end() != std::find_if(hosts.begin(), hosts.end(), [&](const std::string& item) { return *it == item; })) { + SPDLOG_INFO("Drop isolated-endoint[{}] as it has been removed from route table", *it); + isolated_endpoints_.erase(it++); + } else { + it++; + } + } +} + +void ClientImpl::schedule(const std::string& task_name, const std::function& task, + std::chrono::milliseconds delay) { + client_manager_->getScheduler()->schedule(task, task_name, delay, std::chrono::milliseconds(0)); +} + +void ClientImpl::notifyClientTermination() { + SPDLOG_WARN("Should NOT reach here. Subclass should have overridden this function."); + std::abort(); +} + +void ClientImpl::notifyClientTermination(const NotifyClientTerminationRequest& request) { + absl::flat_hash_set endpoints; + endpointsInUse(endpoints); + + Metadata metadata; + Signature::sign(client_config_, metadata); + + for (const auto& endpoint : endpoints) { + client_manager_->notifyClientTermination(endpoint, metadata, request, + absl::ToChronoMilliseconds(client_config_.request_timeout)); + } +} + +std::string ClientImpl::clientId() { + static std::atomic_uint32_t sequence; + std::stringstream ss; + ss << UtilAll::hostname(); + ss << "@"; + std::string processID = std::to_string(getpid()); + ss << processID << "#"; + ss << sequence.fetch_add(1, std::memory_order_relaxed); + return ss.str(); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/ConsumeMessageServiceImpl.cpp b/src/main/cpp/rocketmq/ConsumeMessageServiceImpl.cpp new file mode 100644 index 000000000..74d8176c0 --- /dev/null +++ b/src/main/cpp/rocketmq/ConsumeMessageServiceImpl.cpp @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ConsumeMessageServiceImpl.h" + +#include "ConsumeStats.h" +#include "ConsumeTask.h" +#include "LoggerImpl.h" +#include "PushConsumerImpl.h" +#include "Tag.h" +#include "ThreadPoolImpl.h" + +ROCKETMQ_NAMESPACE_BEGIN + +ConsumeMessageServiceImpl::ConsumeMessageServiceImpl(std::weak_ptr consumer, + int thread_count, + MessageListener message_listener) + : state_(State::CREATED), + thread_count_(thread_count), + pool_(absl::make_unique(thread_count_)), + consumer_(std::move(consumer)), + message_listener_(message_listener) { +} + +void ConsumeMessageServiceImpl::start() { + State expected = State::CREATED; + if (state_.compare_exchange_strong(expected, State::STARTING, std::memory_order_relaxed)) { + pool_->start(); + } +} + +void ConsumeMessageServiceImpl::shutdown() { + State expected = State::STOPPING; + if (state_.compare_exchange_strong(expected, State::STOPPED, std::memory_order_relaxed)) { + pool_->shutdown(); + } +} + +void ConsumeMessageServiceImpl::dispatch(std::shared_ptr process_queue, + std::vector messages) { + auto consumer = consumer_.lock(); + if (!consumer) { + return; + } + + if (consumer->config().subscriber.fifo) { + auto consume_task = std::make_shared(shared_from_this(), process_queue, std::move(messages)); + pool_->submit([consume_task]() { consume_task->process(); }); + return; + } + + for (auto message : messages) { + auto consume_task = std::make_shared(shared_from_this(), process_queue, message); + pool_->submit([consume_task]() { consume_task->process(); }); + } +} + +void ConsumeMessageServiceImpl::submit(std::shared_ptr task) { + auto consumer = consumer_.lock(); + if (!consumer) { + return; + } + + pool_->submit([task]() { task->process(); }); +} + +void ConsumeMessageServiceImpl::ack(const Message& message, std::function cb) { + auto consumer = consumer_.lock(); + if (!consumer) { + return; + } + + std::weak_ptr client(consumer_); + const auto& topic = message.topic(); + // Collect metrics + opencensus::stats::Record({{consumer->stats().processSuccess(), 1}}, + {{Tag::topicTag(), topic}, {Tag::clientIdTag(), consumer->config().client_id}}); + auto callback = [cb, client, topic](const std::error_code& ec) { + auto consumer = client.lock(); + if (ec) { + opencensus::stats::Record({{consumer->stats().ackFailure(), 1}}, + {{Tag::topicTag(), topic}, {Tag::clientIdTag(), consumer->config().client_id}}); + } else { + opencensus::stats::Record({{consumer->stats().ackSuccess(), 1}}, + {{Tag::topicTag(), topic}, {Tag::clientIdTag(), consumer->config().client_id}}); + } + cb(ec); + }; + + consumer->ack(message, callback); +} + +void ConsumeMessageServiceImpl::nack(const Message& message, std::function cb) { + auto consumer = consumer_.lock(); + if (!consumer) { + return; + } + // Collect metrics + opencensus::stats::Record({{consumer->stats().processFailure(), 1}}, + {{Tag::topicTag(), message.topic()}, {Tag::clientIdTag(), consumer->config().client_id}}); + consumer->nack(message, cb); +} + +void ConsumeMessageServiceImpl::forward(const Message& message, std::function cb) { + auto consumer = consumer_.lock(); + if (!consumer) { + return; + } + consumer->forwardToDeadLetterQueue(message, cb); +} + +void ConsumeMessageServiceImpl::schedule(std::shared_ptr task, std::chrono::milliseconds delay) { +} + +std::size_t ConsumeMessageServiceImpl::maxDeliveryAttempt() { + std::shared_ptr consumer = consumer_.lock(); + if (!consumer) { + SPDLOG_WARN("The consumer has already destructed"); + return 0; + } + + return consumer->maxDeliveryAttempts(); +} + +std::weak_ptr ConsumeMessageServiceImpl::consumer() { + return consumer_; +} + +bool ConsumeMessageServiceImpl::preHandle(const Message& message) { + return true; +} + +bool ConsumeMessageServiceImpl::postHandle(const Message& message, ConsumeResult result) { + return true; +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/ConsumeTask.cpp b/src/main/cpp/rocketmq/ConsumeTask.cpp new file mode 100644 index 000000000..69d299a3e --- /dev/null +++ b/src/main/cpp/rocketmq/ConsumeTask.cpp @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ConsumeTask.h" + +#include "ConsumeStats.h" +#include "LoggerImpl.h" +#include "PushConsumerImpl.h" +#include "Tag.h" + +ROCKETMQ_NAMESPACE_BEGIN + +ConsumeTask::ConsumeTask(ConsumeMessageServiceWeakPtr service, + std::weak_ptr process_queue, + MessageConstSharedPtr message) + : service_(service), process_queue_(std::move(process_queue)) { + messages_.emplace_back(message); +} + +ConsumeTask::ConsumeTask(ConsumeMessageServiceWeakPtr service, + std::weak_ptr process_queue, + std::vector messages) + : service_(service), process_queue_(std::move(process_queue)), messages_(std::move(messages)) { + fifo_ = messages_.size() > 1; +} + +void ConsumeTask::pop() { + assert(!messages_.empty()); + auto process_queue = process_queue_.lock(); + if (!process_queue) { + return; + } + + process_queue->release(messages_[0]->body().size()); + + messages_.erase(messages_.begin()); +} + +void ConsumeTask::submit() { + auto svc = service_.lock(); + if (!svc) { + return; + } + svc->submit(shared_from_this()); +} + +void ConsumeTask::schedule() { + auto svc = service_.lock(); + if (!svc) { + return; + } + + svc->schedule(shared_from_this(), std::chrono::seconds(1)); +} + +void ConsumeTask::onAck(std::shared_ptr task, const std::error_code& ec) { + if (task->fifo_ && ec) { + auto service = task->service_.lock(); + task->next_step_ = NextStep::Ack; + task->schedule(); + } else { + // If it is not FIFO or ack operation succeeded + task->pop(); + task->next_step_ = NextStep::Consume; + } + task->submit(); +} + +void ConsumeTask::onNack(std::shared_ptr task, const std::error_code& ec) { + assert(!task->fifo_); + assert(!task->messages_.empty()); + if (ec) { + SPDLOG_WARN("Failed to nack message[message-id={}]. Cause: {}", task->messages_[0]->id(), ec.message()); + } + task->pop(); + task->next_step_ = NextStep::Consume; + task->submit(); +} + +void ConsumeTask::onForward(std::shared_ptr task, const std::error_code& ec) { + assert(task->fifo_); + assert(!task->messages_.empty()); + if (ec) { + SPDLOG_DEBUG("Failed to forward Message[message-id={}] to DLQ", task->messages_[0]->id()); + task->next_step_ = NextStep::Forward; + task->schedule(); + } else { + SPDLOG_DEBUG("Message[message-id={}] forwarded to DLQ", task->messages_[0]->id()); + task->pop(); + task->next_step_ = NextStep::Consume; + task->submit(); + } +} + +void ConsumeTask::process() { + auto svc = service_.lock(); + if (!svc) { + SPDLOG_DEBUG("ConsumeMessageService has destructed"); + return; + } + + if (messages_.empty()) { + SPDLOG_DEBUG("No more messages to process"); + return; + } + + std::shared_ptr consumer = svc->consumer().lock(); + + auto self = shared_from_this(); + + switch (next_step_) { + case NextStep::Consume: { + const auto& listener = svc->listener(); + auto it = messages_.begin(); + SPDLOG_DEBUG("Start to process message[message-id={}]", (*it)->id()); + svc->preHandle(**it); + auto await_time = std::chrono::system_clock::now() - (*it)->extension().decode_time; + opencensus::stats::Record( + {{consumer->stats().awaitTime(), MixAll::millisecondsOf(await_time)}}, + {{Tag::topicTag(), (*it)->topic()}, {Tag::clientIdTag(), consumer->config().client_id}}); + + std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); + auto result = listener(**it); + auto duration = std::chrono::steady_clock::now() - start; + opencensus::stats::Record( + {{consumer->stats().processTime(), MixAll::millisecondsOf(duration)}}, + {{Tag::topicTag(), (*it)->topic()}, {Tag::clientIdTag(), consumer->config().client_id}}); + svc->postHandle(**it, result); + switch (result) { + case ConsumeResult::SUCCESS: { + auto callback = std::bind(&ConsumeTask::onAck, self, std::placeholders::_1); + svc->ack(**it, callback); + break; + } + case ConsumeResult::FAILURE: { + if (fifo_) { + next_step_ = NextStep::Consume; + // Increase delivery attempts. + auto raw = const_cast((*it).get()); + raw->mutableExtension().delivery_attempt++; + schedule(); + } else { + // For standard way of processing, Nack to server. + auto callback = std::bind(&ConsumeTask::onNack, self, std::placeholders::_1); + svc->nack(**it, callback); + } + break; + } + } + break; + } + + case NextStep::Ack: { + assert(!messages_.empty()); + auto callback = std::bind(&ConsumeTask::onAck, self, std::placeholders::_1); + svc->ack(*messages_[0], callback); + break; + } + case NextStep::Forward: { + assert(!messages_.empty()); + auto callback = std::bind(&ConsumeTask::onForward, self, std::placeholders::_1); + svc->forward(*messages_[0], callback); + break; + } + } +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/DynamicNameServerResolver.cpp b/src/main/cpp/rocketmq/DynamicNameServerResolver.cpp new file mode 100644 index 000000000..f9981bc15 --- /dev/null +++ b/src/main/cpp/rocketmq/DynamicNameServerResolver.cpp @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "DynamicNameServerResolver.h" + +#include +#include +#include +#include +#include + +#include "absl/strings/str_join.h" + +#include "LoggerImpl.h" +#include "SchedulerImpl.h" + +ROCKETMQ_NAMESPACE_BEGIN + +DynamicNameServerResolver::DynamicNameServerResolver(absl::string_view endpoint, + std::chrono::milliseconds refresh_interval) + : endpoint_(endpoint.data(), endpoint.length()), scheduler_(std::make_shared(1)), + refresh_interval_(refresh_interval) { + absl::string_view remains; + if (absl::StartsWith(endpoint_, "https://")) { + ssl_ = true; + remains = absl::StripPrefix(endpoint_, "https://"); + } else { + remains = absl::StripPrefix(endpoint_, "http://"); + } + + std::int32_t port = 80; + if (ssl_) { + port = 443; + } + + absl::string_view host; + if (absl::StrContains(remains, ':')) { + std::vector segments = absl::StrSplit(remains, ':'); + host = segments[0]; + remains = absl::StripPrefix(remains, host); + remains = absl::StripPrefix(remains, ":"); + + segments = absl::StrSplit(remains, '/'); + if (!absl::SimpleAtoi(segments[0], &port)) { + SPDLOG_WARN("Failed to parse port of name-server-list discovery service endpoint"); + abort(); + } + remains = absl::StripPrefix(remains, segments[0]); + } else { + std::vector segments = absl::StrSplit(remains, '/'); + host = segments[0]; + remains = absl::StripPrefix(remains, host); + } + + top_addressing_ = absl::make_unique(std::string(host.data(), host.length()), port, + std::string(remains.data(), remains.length())); +} + +std::string DynamicNameServerResolver::resolve() { + bool fetch_immediately = false; + { + absl::MutexLock lk(&name_server_list_mtx_); + if (name_server_list_.empty()) { + fetch_immediately = true; + } + } + + if (fetch_immediately) { + fetch(); + } + + { + absl::MutexLock lk(&name_server_list_mtx_); + return naming_scheme_.buildAddress(name_server_list_); + } +} + +void DynamicNameServerResolver::fetch() { + std::weak_ptr ptr(shared_from_this()); + auto callback = [ptr](bool success, const std::vector& name_server_list) { + if (success && !name_server_list.empty()) { + std::shared_ptr resolver = ptr.lock(); + if (resolver) { + resolver->onNameServerListFetched(name_server_list); + } + } + }; + top_addressing_->fetchNameServerAddresses(callback); +} + +void DynamicNameServerResolver::onNameServerListFetched(const std::vector& name_server_list) { + if (!name_server_list.empty()) { + absl::MutexLock lk(&name_server_list_mtx_); + if (name_server_list_ != name_server_list) { + SPDLOG_INFO("Name server list changed. {} --> {}", absl::StrJoin(name_server_list_, ";"), + absl::StrJoin(name_server_list, ";")); + name_server_list_ = name_server_list; + } + } +} + +void DynamicNameServerResolver::injectHttpClient(std::unique_ptr http_client) { + top_addressing_->injectHttpClient(std::move(http_client)); +} + +void DynamicNameServerResolver::start() { + scheduler_->start(); + scheduler_->schedule(std::bind(&DynamicNameServerResolver::fetch, this), "DynamicNameServerResolver", + std::chrono::milliseconds(0), refresh_interval_); +} + +void DynamicNameServerResolver::shutdown() { + scheduler_->shutdown(); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/trace/TraceTransferBean.cpp b/src/main/cpp/rocketmq/MessageGroupQueueSelector.cpp similarity index 61% rename from src/trace/TraceTransferBean.cpp rename to src/main/cpp/rocketmq/MessageGroupQueueSelector.cpp index bd04c333e..b0825453e 100644 --- a/src/trace/TraceTransferBean.cpp +++ b/src/main/cpp/rocketmq/MessageGroupQueueSelector.cpp @@ -14,25 +14,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "MessageGroupQueueSelector.h" -#include "TraceTransferBean.h" -#include -#include +#include +#include -namespace rocketmq { -std::string TraceTransferBean::getTransData() { - return m_transData; -} +ROCKETMQ_NAMESPACE_BEGIN -void TraceTransferBean::setTransData(const std::string& transData) { - m_transData = transData; +MessageGroupQueueSelector::MessageGroupQueueSelector(std::string message_group) + : message_group_(std::move(message_group)) { } -std::vector TraceTransferBean::getTransKey() { - return m_transKey; +rmq::MessageQueue MessageGroupQueueSelector::select(const std::vector& mqs) { + std::size_t hash_code = std::hash{}(message_group_); + assert(!mqs.empty()); + std::size_t len = mqs.size(); + return mqs[hash_code % len]; } -void TraceTransferBean::setTransKey(const std::string& transkey) { - m_transKey.push_back(transkey); -} -} // namespace rocketmq \ No newline at end of file +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/NamingScheme.cpp b/src/main/cpp/rocketmq/NamingScheme.cpp new file mode 100644 index 000000000..467e295b0 --- /dev/null +++ b/src/main/cpp/rocketmq/NamingScheme.cpp @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "NamingScheme.h" + +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_join.h" +#include "absl/strings/str_split.h" + +ROCKETMQ_NAMESPACE_BEGIN + +const char* NamingScheme::DnsPrefix = "dns:"; +const char* NamingScheme::IPv4Prefix = "ipv4:"; +const char* NamingScheme::IPv6Prefix = "ipv6:"; + +const char* NamingScheme::IPv4Regex = + "(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"; + +const char* NamingScheme::IPv6Regex = "((([0-9a-fA-F]){1,4})\\:){7}([0-9a-fA-F]){1,4}"; + +NamingScheme::NamingScheme() : ipv4_pattern_(IPv4Regex), ipv6_pattern_(IPv6Regex) { +} + +bool NamingScheme::isIPv4(const std::string& host) { + return re2::RE2::FullMatch(host, ipv4_pattern_); +} + +bool NamingScheme::isIPv6(const std::string& host) { + return re2::RE2::FullMatch(host, ipv6_pattern_); +} + +std::string NamingScheme::buildAddress(const std::vector& list) { + absl::flat_hash_map ipv4; + absl::flat_hash_map ipv6; + + for (const auto& segment : list) { + std::vector host_port = absl::StrSplit(segment, ':'); + if (2 != host_port.size()) { + continue; + } + + if (isIPv4(host_port[0])) { + std::uint32_t port; + if (absl::SimpleAtoi(host_port[1], &port)) { + ipv4.insert_or_assign(host_port[0], port); + } + continue; + } + + if (isIPv6(host_port[0])) { + std::uint32_t port; + if (absl::SimpleAtoi(host_port[1], &port)) { + ipv6.insert_or_assign(host_port[0], port); + } + continue; + } + + // Once we find a domain name record, use it as the final result. + host_port.insert(host_port.begin(), "dns"); + return absl::StrJoin(host_port, ":"); + } + + if (!ipv4.empty()) { + return "ipv4:" + absl::StrJoin(ipv4, ",", absl::PairFormatter(":")); + } + + if (!ipv6.empty()) { + return "ipv6:" + absl::StrJoin(ipv4, ",", absl::PairFormatter(":")); + } + return std::string(); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/ProcessQueueImpl.cpp b/src/main/cpp/rocketmq/ProcessQueueImpl.cpp new file mode 100644 index 000000000..0eeb08eef --- /dev/null +++ b/src/main/cpp/rocketmq/ProcessQueueImpl.cpp @@ -0,0 +1,250 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ProcessQueueImpl.h" + +#include +#include +#include +#include +#include + +#include "ClientManagerImpl.h" +#include "MetadataConstants.h" +#include "Protocol.h" +#include "PushConsumerImpl.h" +#include "ReceiveMessageResult.h" +#include "Signature.h" +#include "include/AsyncReceiveMessageCallback.h" +#include "rocketmq/MessageListener.h" + +using namespace std::chrono; + +ROCKETMQ_NAMESPACE_BEGIN + +ProcessQueueImpl::ProcessQueueImpl(rmq::MessageQueue message_queue, FilterExpression filter_expression, + std::weak_ptr consumer, + std::shared_ptr client_instance) + : message_queue_(std::move(message_queue)), filter_expression_(std::move(filter_expression)), + invisible_time_(MixAll::millisecondsOf(MixAll::DEFAULT_INVISIBLE_TIME_)), + simple_name_(simpleNameOf(message_queue_)), consumer_(std::move(consumer)), + client_manager_(std::move(client_instance)), cached_message_quantity_(0), cached_message_memory_(0) { + SPDLOG_DEBUG("Created ProcessQueue={}", simpleName()); +} + +ProcessQueueImpl::~ProcessQueueImpl() { + SPDLOG_INFO("ProcessQueue={} should have been re-balanced away, thus, is destructed", simpleName()); +} + +void ProcessQueueImpl::callback(std::shared_ptr callback) { + receive_callback_ = callback; +} + +bool ProcessQueueImpl::expired() const { + auto duration = std::chrono::steady_clock::now() - idle_since_; + if (duration > MixAll::PROCESS_QUEUE_EXPIRATION_THRESHOLD_) { + SPDLOG_WARN("ProcessQueue={} is expired. It remains idle for {}ms", simpleName(), MixAll::millisecondsOf(duration)); + return true; + } + return false; +} + +bool ProcessQueueImpl::shouldThrottle() const { + auto consumer = consumer_.lock(); + if (!consumer) { + return false; + } + + std::size_t quantity = cached_message_quantity_.load(std::memory_order_relaxed); + uint32_t quantity_threshold = consumer->maxCachedMessageQuantity(); + uint64_t memory_threshold = consumer->maxCachedMessageMemory(); + bool need_throttle = quantity >= quantity_threshold; + if (need_throttle) { + SPDLOG_INFO("{}: Number of locally cached messages is {}, which exceeds threshold={}", simple_name_, quantity, + quantity_threshold); + return true; + } + + if (memory_threshold) { + uint64_t bytes = cached_message_memory_.load(std::memory_order_relaxed); + need_throttle = bytes >= memory_threshold; + if (need_throttle) { + SPDLOG_INFO("{}: Locally cached messages take {} bytes, which exceeds threshold={}", simple_name_, bytes, + memory_threshold); + return true; + } + } + return false; +} + +void ProcessQueueImpl::receiveMessage() { + auto consumer = consumer_.lock(); + if (!consumer) { + return; + } + + popMessage(); +} + +void ProcessQueueImpl::popMessage() { + rmq::ReceiveMessageRequest request; + absl::flat_hash_map metadata; + auto consumer_client = consumer_.lock(); + if (!consumer_client) { + return; + } + Signature::sign(consumer_client->config(), metadata); + wrapPopMessageRequest(metadata, request); + syncIdleState(); + SPDLOG_DEBUG("Try to pop message from {}", simpleNameOf(message_queue_)); + + std::weak_ptr cb{receive_callback_}; + auto callback = [cb](const std::error_code& ec, const ReceiveMessageResult& result) { + auto recv_cb = cb.lock(); + if (recv_cb) { + recv_cb->onCompletion(ec, result); + } + }; + + client_manager_->receiveMessage( + urlOf(message_queue_), metadata, request, + absl::ToChronoMilliseconds(consumer_client->config().subscriber.polling_timeout), callback); +} + +bool ProcessQueueImpl::hasPendingMessages() const { + absl::MutexLock lk(&messages_mtx_); + return !cached_messages_.empty(); +} + +void ProcessQueueImpl::cacheMessages(const std::vector& messages) { + auto consumer = consumer_.lock(); + if (!consumer) { + return; + } + + { + absl::MutexLock messages_lock_guard(&messages_mtx_); + for (const auto& message : messages) { + const std::string& msg_id = message->id(); + if (!filter_expression_.accept(*message)) { + const std::string& topic = message->topic(); + auto callback = [topic, msg_id](const std::error_code& ec) { + if (ec) { + SPDLOG_WARN( + "Failed to ack message[Topic={}, MsgId={}] directly as it fails to pass filter expression. Cause: {}", + topic, msg_id, ec.message()); + } else { + SPDLOG_DEBUG("Ack message[Topic={}, MsgId={}] directly as it fails to pass filter expression", topic, + msg_id); + } + }; + consumer->ack(*message, callback); + continue; + } + cached_messages_.emplace_back(message); + cached_message_quantity_.fetch_add(1, std::memory_order_relaxed); + cached_message_memory_.fetch_add(message->body().size(), std::memory_order_relaxed); + } + } +} + +bool ProcessQueueImpl::take(uint32_t batch_size, std::vector& messages) { + absl::MutexLock lock(&messages_mtx_); + if (cached_messages_.empty()) { + return false; + } + + for (auto it = cached_messages_.begin(); it != cached_messages_.end();) { + if (0 == batch_size--) { + break; + } + messages.push_back(*it); + it = cached_messages_.erase(it); + } + return !cached_messages_.empty(); +} + +void ProcessQueueImpl::release(uint64_t body_size) { + auto consumer = consumer_.lock(); + if (!consumer) { + return; + } + + cached_message_quantity_.fetch_sub(1); + cached_message_memory_.fetch_sub(body_size); +} + +void ProcessQueueImpl::wrapFilterExpression(rmq::FilterExpression* filter_expression) { + assert(filter_expression); + auto consumer = consumer_.lock(); + if (!consumer) { + return; + } + auto&& optional = consumer->getFilterExpression(message_queue_.topic().name()); + if (optional.has_value()) { + auto expression = optional.value(); + switch (expression.type_) { + case TAG: + filter_expression->set_type(rmq::FilterType::TAG); + filter_expression->set_expression(expression.content_); + break; + case SQL92: + filter_expression->set_type(rmq::FilterType::SQL); + filter_expression->set_expression(expression.content_); + break; + } + } else { + filter_expression->set_type(rmq::FilterType::TAG); + filter_expression->set_expression("*"); + } +} + +void ProcessQueueImpl::wrapPopMessageRequest(absl::flat_hash_map& metadata, + rmq::ReceiveMessageRequest& request) { + std::shared_ptr consumer = consumer_.lock(); + assert(consumer); + request.mutable_group()->CopyFrom(consumer->config().subscriber.group); + request.mutable_message_queue()->CopyFrom(message_queue_); + + wrapFilterExpression(request.mutable_filter_expression()); + + // Batch size + request.set_batch_size(consumer->receiveBatchSize()); + + // Let server to automatically extend invisible duration. + request.set_auto_renew(true); + + // Set invisible time + request.mutable_invisible_duration()->set_seconds( + std::chrono::duration_cast(invisible_time_).count()); + auto fraction = invisible_time_ - std::chrono::duration_cast(invisible_time_); + int32_t nano_seconds = static_cast(std::chrono::duration_cast(fraction).count()); + request.mutable_invisible_duration()->set_nanos(nano_seconds); +} + +std::weak_ptr ProcessQueueImpl::getConsumer() { + return consumer_; +} + +std::shared_ptr ProcessQueueImpl::getClientManager() { + return client_manager_; +} + +const FilterExpression& ProcessQueueImpl::getFilterExpression() const { + return filter_expression_; +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/Producer.cpp b/src/main/cpp/rocketmq/Producer.cpp new file mode 100644 index 000000000..b2bc5e014 --- /dev/null +++ b/src/main/cpp/rocketmq/Producer.cpp @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "rocketmq/Producer.h" + +#include +#include +#include +#include + +#include "DynamicNameServerResolver.h" +#include "LoggerImpl.h" +#include "MixAll.h" +#include "ProducerImpl.h" +#include "StaticNameServerResolver.h" +#include "absl/strings/str_split.h" +#include "rocketmq/ErrorCode.h" +#include "rocketmq/SendReceipt.h" +#include "rocketmq/Transaction.h" + +ROCKETMQ_NAMESPACE_BEGIN + +void Producer::start() { + impl_->start(); +} + +SendReceipt Producer::send(MessageConstPtr message, std::error_code& ec) noexcept { + if (!message) { + ec = ErrorCode::BadRequest; + return {}; + } + + return impl_->send(std::move(message), ec); +} + +void Producer::send(MessageConstPtr message, const SendCallback& callback) noexcept { + if (!message) { + std::error_code ec = ErrorCode::BadRequest; + SendReceipt send_receipt = {}; + callback(ec, send_receipt); + return; + } + + if (message->group().has_value()) { + SendReceipt empty; + std::error_code ec = ErrorCode::BadRequestAsyncPubFifoMessage; + callback(ec, empty); + return; + } + + impl_->send(std::move(message), callback); +} + +ProducerBuilder Producer::newBuilder() { + return {}; +} + +ProducerBuilder::ProducerBuilder() : impl_(std::make_shared()){}; + +ProducerBuilder& ProducerBuilder::withConfiguration(Configuration configuration) { + auto name_server_resolver = std::make_shared(configuration.endpoints()); + impl_->withNameServerResolver(std::move(name_server_resolver)); + impl_->withCredentialsProvider(configuration.credentialsProvider()); + impl_->withRequestTimeout(configuration.requestTimeout()); + return *this; +} + +ProducerBuilder& ProducerBuilder::withTopics(const std::vector& topics) { + impl_->topicsOfInterest(topics); + return *this; +} + +ProducerBuilder& ProducerBuilder::withTransactionChecker(const TransactionChecker& checker) { + return *this; +} + +Producer ProducerBuilder::build() { + Producer producer(impl_); + producer.start(); + return producer; +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/ProducerImpl.cpp b/src/main/cpp/rocketmq/ProducerImpl.cpp new file mode 100644 index 000000000..4b6c3f0f5 --- /dev/null +++ b/src/main/cpp/rocketmq/ProducerImpl.cpp @@ -0,0 +1,580 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ProducerImpl.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "Client.h" +#include "MessageGroupQueueSelector.h" +#include "MetadataConstants.h" +#include "MixAll.h" +#include "Protocol.h" +#include "PublishInfoCallback.h" +#include "RpcClient.h" +#include "SendContext.h" +#include "SendMessageContext.h" +#include "Signature.h" +#include "Tag.h" +#include "TracingUtility.h" +#include "TransactionImpl.h" +#include "UniqueIdGenerator.h" +#include "UtilAll.h" +#include "absl/strings/str_join.h" +#include "opencensus/trace/propagation/trace_context.h" +#include "opencensus/trace/span.h" +#include "rocketmq/ErrorCode.h" +#include "rocketmq/Message.h" +#include "rocketmq/SendReceipt.h" +#include "rocketmq/Tracing.h" +#include "rocketmq/Transaction.h" +#include "rocketmq/TransactionChecker.h" + +ROCKETMQ_NAMESPACE_BEGIN + +ProducerImpl::ProducerImpl() : ClientImpl(""), compress_body_threshold_(MixAll::DEFAULT_COMPRESS_BODY_THRESHOLD_) { + // TODO: initialize client_config_ and fault_strategy_ +} + +ProducerImpl::~ProducerImpl() { + SPDLOG_INFO("Producer instance is destructed"); + shutdown(); +} + +void ProducerImpl::start() { + ClientImpl::start(); + + State expecting = State::STARTING; + if (!state_.compare_exchange_strong(expecting, State::STARTED)) { + SPDLOG_ERROR("Start with unexpected state. Expecting: {}, Actual: {}", State::STARTING, + state_.load(std::memory_order_relaxed)); + return; + } + + client_manager_->addClientObserver(shared_from_this()); +} + +void ProducerImpl::shutdown() { + State expected = State::STARTED; + if (!state_.compare_exchange_strong(expected, State::STOPPING)) { + SPDLOG_ERROR("Shutdown with unexpected state. Expecting: {}, Actual: {}", State::STOPPING, + state_.load(std::memory_order_relaxed)); + return; + } + + notifyClientTermination(); + + ClientImpl::shutdown(); + assert(State::STOPPED == state_.load()); + SPDLOG_INFO("Producer instance stopped"); +} + +void ProducerImpl::notifyClientTermination() { +} + +bool ProducerImpl::isRunning() const { + return State::STARTED == state_.load(std::memory_order_relaxed); +} + +void ProducerImpl::ensureRunning(std::error_code& ec) const noexcept { + if (!isRunning()) { + ec = ErrorCode::IllegalState; + } +} + +bool ProducerImpl::validate(const Message& message) { + return MixAll::validate(message); +} + +void ProducerImpl::wrapSendMessageRequest(const Message& message, SendMessageRequest& request, + const rmq::MessageQueue& message_queue) { + auto msg = new rmq::Message(); + + msg->mutable_topic()->set_resource_namespace(resourceNamespace()); + msg->mutable_topic()->set_name(message.topic()); + + auto system_properties = msg->mutable_system_properties(); + + // Handle Tag + if (message.tag().has_value()) { + system_properties->set_tag(message.tag().value()); + } + + // Handle Key + const auto& keys = message.keys(); + if (!keys.empty()) { + system_properties->mutable_keys()->Add(keys.begin(), keys.end()); + } + + // TraceContext + if (message.traceContext().has_value()) { + const auto& trace_context = message.traceContext().value(); + if (!trace_context.empty()) { + system_properties->set_trace_context(trace_context); + } + } + + // Delivery Timestamp + if (message.deliveryTimestamp().has_value()) { + auto delivery_timestamp = message.deliveryTimestamp().value(); + if (delivery_timestamp.time_since_epoch().count()) { + auto duration = delivery_timestamp.time_since_epoch(); + system_properties->set_delivery_attempt(std::chrono::duration_cast(duration).count()); + } + } + + // Born-time + auto duration = absl::Now() - absl::UnixEpoch(); + int64_t seconds = absl::ToInt64Seconds(duration); + system_properties->mutable_born_timestamp()->set_seconds(seconds); + system_properties->mutable_born_timestamp()->set_nanos(absl::ToInt64Nanoseconds(duration - absl::Seconds(seconds))); + + system_properties->set_born_host(UtilAll::hostname()); + + if (message.deliveryTimestamp().has_value()) { + system_properties->set_message_type(rmq::MessageType::DELAY); + } else if (message.group().has_value()) { + system_properties->set_message_type(rmq::MessageType::FIFO); + } else { + system_properties->set_message_type(rmq::MessageType::NORMAL); + } + + if (message.body().size() >= compress_body_threshold_) { + std::string compressed_body; + UtilAll::compress(message.body(), compressed_body); + msg->set_body(compressed_body); + system_properties->set_body_encoding(rmq::Encoding::GZIP); + } else { + msg->set_body(message.body()); + system_properties->set_body_encoding(rmq::Encoding::IDENTITY); + } + + if (message.group().has_value()) { + system_properties->set_message_group(message.group().value()); + } + + system_properties->set_message_id(message.id()); + system_properties->set_queue_id(message_queue.id()); + + // Forward user-defined-properties + for (auto& item : message.properties()) { + msg->mutable_user_properties()->insert({item.first, item.second}); + } + + // Add into request + request.mutable_messages()->AddAllocated(msg); + SPDLOG_TRACE("SendMessageRequest: {}", request.DebugString()); +} + +SendReceipt ProducerImpl::send(MessageConstPtr message, std::error_code& ec) noexcept { + ensureRunning(ec); + if (ec) { + return {}; + } + + auto topic_publish_info = getPublishInfo(message->topic()); + if (!topic_publish_info) { + ec = ErrorCode::NotFound; + return {}; + } + + std::vector message_queue_list; + if (!topic_publish_info->selectMessageQueues(absl::make_optional(), message_queue_list)) { + ec = ErrorCode::NotFound; + return {}; + } + + auto mtx = std::make_shared(); + auto cv = std::make_shared(); + bool completed = false; + SendReceipt send_receipt; + + // Define callback procedureq + auto callback = [&, mtx, cv](const std::error_code& code, const SendReceipt& receipt) { + ec = code; + send_receipt = receipt; + { + absl::MutexLock lk(mtx.get()); + completed = true; + } + cv->Signal(); + }; + + send0(std::move(message), callback, message_queue_list); + + { + absl::MutexLock lk(mtx.get()); + if (!completed) { + cv->Wait(mtx.get()); + } + } + + return send_receipt; +} + +void ProducerImpl::send(MessageConstPtr message, SendCallback cb) { + std::error_code ec; + ensureRunning(ec); + if (ec) { + SendReceipt send_receipt; + cb(ec, send_receipt); + } + + std::string topic = message->topic(); + std::weak_ptr client(shared_from_this()); + + // Walk-around: Use capture by move when C++14 is possible + const Message* msg = message.release(); + auto callback = [client, cb, msg](const std::error_code& ec, const TopicPublishInfoPtr& publish_info) { + MessageConstPtr ptr(msg); + // No route entries of the given topic is available + if (ec) { + SendReceipt send_receipt; + cb(ec, send_receipt); + return; + } + + if (!publish_info) { + std::error_code ec = ErrorCode::NotFound; + SendReceipt send_receipt; + cb(ec, send_receipt); + return; + } + + auto publisher = client.lock(); + std::vector message_queue_list; + if (!publish_info->selectMessageQueues(ptr->group(), message_queue_list)) { + std::error_code ec = ErrorCode::NotFound; + SendReceipt send_receipt; + cb(ec, send_receipt); + return; + } + + publisher->send0(std::move(ptr), cb, message_queue_list); + }; + + getPublishInfoAsync(topic, callback); +} + +void ProducerImpl::setTransactionChecker(TransactionChecker checker) { + transaction_checker_ = std::move(checker); +} + +void ProducerImpl::sendImpl(std::shared_ptr context) { + const std::string& target = urlOf(context->messageQueue()); + if (target.empty()) { + SPDLOG_WARN("Failed to resolve broker address from MessageQueue"); + std::error_code ec = ErrorCode::BadGateway; + context->onFailure(ec); + return; + } + + { + // Trace Send RPC + if (context->message_->traceContext().has_value()) { + auto span_context = + opencensus::trace::propagation::FromTraceParentHeader(context->message_->traceContext().value()); + auto span = opencensus::trace::Span::BlankSpan(); + std::string span_name = resourceNamespace() + "/" + context->message_->topic() + " " + + MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_SEND_OPERATION; + if (span_context.IsValid()) { + span = opencensus::trace::Span::StartSpanWithRemoteParent(span_name, span_context, {traceSampler()}); + } else { + span = opencensus::trace::Span::StartSpan(span_name, nullptr, {traceSampler()}); + } + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_OPERATION, + MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_SEND_OPERATION); + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_OPERATION, + MixAll::SPAN_ATTRIBUTE_VALUE_MESSAGING_SEND_OPERATION); + TracingUtility::addUniversalSpanAttributes(*context->message_, config(), span); + // Note: attempt-time is 0-based + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_ATTEMPT, 1 + context->attempt_times_); + if (context->message_->deliveryTimestamp().has_value()) { + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_DELIVERY_TIMESTAMP, + absl::FormatTime(absl::FromChrono(context->message_->deliveryTimestamp().value()))); + } + auto ptr = const_cast(context->message_.get()); + ptr->traceContext(opencensus::trace::propagation::ToTraceParentHeader(span.context())); + context->span_ = span; + } + } + + SendMessageRequest request; + wrapSendMessageRequest(*context->message_, request, context->messageQueue()); + Metadata metadata; + Signature::sign(client_config_, metadata); + + auto callback = [context](const std::error_code& ec, const SendReceipt& send_receipt) { + if (ec) { + context->onFailure(ec); + return; + } + context->onSuccess(send_receipt); + }; + + client_manager_->send(target, metadata, request, callback); +} + +void ProducerImpl::send0(MessageConstPtr message, SendCallback callback, std::vector list) { + SendReceipt send_receipt; + std::error_code ec; + + if (!validate(*message)) { + ec = ErrorCode::BadRequest; + callback(ec, send_receipt); + return; + } + + if (list.empty()) { + ec = ErrorCode::NotFound; + callback(ec, send_receipt); + return; + } + + auto context = std::make_shared(shared_from_this(), std::move(message), callback, std::move(list)); + sendImpl(context); + // const_cast(message).traceContext( + // opencensus::trace::propagation::ToTraceParentHeader(context->span().context())); +} + +bool ProducerImpl::endTransaction0(const Transaction& transaction, TransactionState resolution) { + EndTransactionRequest request; + const std::string& topic = transaction.topic(); + request.mutable_topic()->set_name(topic); + request.mutable_topic()->set_resource_namespace(resourceNamespace()); + request.set_message_id(transaction.messageId()); + request.set_transaction_id(transaction.messageId()); + + std::string action; + switch (resolution) { + case TransactionState::COMMIT: + request.set_resolution(rmq::COMMIT); + action = "commit"; + break; + case TransactionState::ROLLBACK: + request.set_resolution(rmq::ROLLBACK); + action = "rollback"; + break; + } + absl::flat_hash_map metadata; + Signature::sign(config(), metadata); + bool completed = false; + bool success = false; + auto span = opencensus::trace::Span::BlankSpan(); + if (!transaction.traceContext().empty()) { + // Trace transactional message + opencensus::trace::SpanContext span_context = + opencensus::trace::propagation::FromTraceParentHeader(transaction.traceContext()); + std::string trace_operation_name = TransactionState::COMMIT == resolution + ? MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_COMMIT_OPERATION + : MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_ROLLBACK_OPERATION; + std::string span_name = resourceNamespace() + "/" + transaction.topic() + " " + trace_operation_name; + if (span_context.IsValid()) { + span = opencensus::trace::Span::StartSpanWithRemoteParent(span_name, span_context, {traceSampler()}); + } else { + span = opencensus::trace::Span::StartSpan(span_name, nullptr, {traceSampler()}); + } + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_OPERATION, trace_operation_name); + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_OPERATION, trace_operation_name); + // TracingUtility::addUniversalSpanAttributes(message, config(), span); + } + + auto mtx = std::make_shared(); + auto cv = std::make_shared(); + const auto& endpoint = transaction.endpoint(); + std::weak_ptr publisher(shared_from_this()); + + auto cb = [&, span, endpoint, mtx, cv, topic](const std::error_code& ec, const EndTransactionResponse& response) { + if (ec) { + { + span.SetStatus(opencensus::trace::StatusCode::ABORTED); + span.AddAnnotation(ec.message()); + span.End(); + } + SPDLOG_WARN("Failed to send {} transaction request to {}. Cause: ", action, endpoint, ec.message()); + success = false; + } else { + { + span.SetStatus(opencensus::trace::StatusCode::OK); + span.End(); + } + success = true; + } + + { + absl::MutexLock lk(mtx.get()); + completed = true; + cv->SignalAll(); + } + }; + + client_manager_->endTransaction(transaction.endpoint(), metadata, request, + absl::ToChronoMilliseconds(requestTimeout()), cb); + { + absl::MutexLock lk(mtx.get()); + cv->Wait(mtx.get()); + } + return success; +} + +void ProducerImpl::isolatedEndpoints(absl::flat_hash_set& endpoints) { + absl::MutexLock lk(&isolated_endpoints_mtx_); + endpoints.insert(isolated_endpoints_.begin(), isolated_endpoints_.end()); +} + +bool ProducerImpl::isEndpointIsolated(const std::string& target) { + absl::MutexLock lk(&isolated_endpoints_mtx_); + return isolated_endpoints_.contains(target); +} + +void ProducerImpl::isolateEndpoint(const std::string& target) { + absl::MutexLock lk(&isolated_endpoints_mtx_); + isolated_endpoints_.insert(target); +} + +std::unique_ptr ProducerImpl::prepare(MessageConstPtr message, std::error_code& ec) { + std::weak_ptr producer(shared_from_this()); + auto transaction = absl::make_unique(message->topic(), message->id(), + message->traceContext().value_or(""), producer); + SendReceipt send_receipt = send(std::move(message), ec); + if (ec) { + return nullptr; + } + + transaction->transactionId(send_receipt.transaction_id); + + // TODO: endpoint id + // transaction->endpoint(xxx); + return transaction; +} + +bool ProducerImpl::commit(const Transaction& transaction) { + return endTransaction0(transaction, TransactionState::COMMIT); +} + +bool ProducerImpl::rollback(const Transaction& transaction) { + return endTransaction0(transaction, TransactionState::ROLLBACK); +} + +void ProducerImpl::getPublishInfoAsync(const std::string& topic, const PublishInfoCallback& cb) { + TopicPublishInfoPtr ptr; + { + absl::MutexLock lock(&topic_publish_info_mtx_); + if (topic_publish_info_table_.contains(topic)) { + ptr = topic_publish_info_table_.at(topic); + } + } + + std::error_code ec; + if (ptr) { + // Serve with the cached one + cb(ec, ptr); + return; + } + + std::weak_ptr producer(shared_from_this()); + auto callback = [topic, cb, producer](const std::error_code& ec, const TopicRouteDataPtr& route) { + if (ec) { + cb(ec, nullptr); + return; + } + auto publish_info = std::make_shared(producer, topic, route); + auto impl = producer.lock(); + if (impl) { + impl->cachePublishInfo(topic, publish_info); + } + cb(ec, publish_info); + }; + + getRouteFor(topic, callback); +} + +void ProducerImpl::cachePublishInfo(const std::string& topic, TopicPublishInfoPtr info) { + absl::MutexLock lk(&topic_publish_info_mtx_); + topic_publish_info_table_.insert_or_assign(topic, info); +} + +TopicPublishInfoPtr ProducerImpl::getPublishInfo(const std::string& topic) { + bool complete = false; + auto mtx = std::make_shared(); + auto cv = std::make_shared(); + TopicPublishInfoPtr topic_publish_info; + std::error_code error_code; + auto cb = [&, mtx, cv](const std::error_code& ec, const TopicPublishInfoPtr& ptr) { + absl::MutexLock lk(mtx.get()); + topic_publish_info = ptr; + error_code = ec; + complete = true; + cv->SignalAll(); + }; + getPublishInfoAsync(topic, cb); + + // Wait till acquiring topic publish info completes + while (!complete) { + absl::MutexLock lk(mtx.get()); + cv->Wait(mtx.get()); + } + + // TODO: propogate error_code to caller + return topic_publish_info; +} + +void ProducerImpl::prepareHeartbeatData(HeartbeatRequest& request) { + request.set_client_type(rmq::ClientType::PRODUCER); +} + +void ProducerImpl::onOrphanedTransactionalMessage(MessageConstSharedPtr message) { + if (transaction_checker_) { + std::weak_ptr producer(shared_from_this()); + + auto transaction = absl::make_unique(message->topic(), message->id(), + message->traceContext().value_or(""), producer); + transaction->endpoint(message->extension().target_endpoint); + transaction->transactionId(message->extension().transaction_id); + TransactionState state = transaction_checker_(*message); + endTransaction0(*transaction, state); + } else { + SPDLOG_WARN("LocalTransactionStateChecker is unexpectedly nullptr"); + } +} + +void ProducerImpl::topicsOfInterest(std::vector topics) { + absl::MutexLock lk(&topics_mtx_); + topics_.swap(topics); +} + +void ProducerImpl::buildClientSettings(rmq::Settings& settings) { + settings.set_client_type(rmq::ClientType::PRODUCER); + + auto topics = settings.mutable_publishing()->mutable_topics(); + { + absl::MutexLock lk(&topics_mtx_); + for (const auto& item : topics_) { + auto topic = new rmq::Resource; + topic->set_resource_namespace(resourceNamespace()); + topic->set_name(item); + topics->AddAllocated(topic); + } + } +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/PushConsumer.cpp b/src/main/cpp/rocketmq/PushConsumer.cpp new file mode 100644 index 000000000..daabf015a --- /dev/null +++ b/src/main/cpp/rocketmq/PushConsumer.cpp @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +#include "DynamicNameServerResolver.h" +#include "PushConsumerImpl.h" +#include "StaticNameServerResolver.h" +#include "rocketmq/PushConsumer.h" + +ROCKETMQ_NAMESPACE_BEGIN + +void PushConsumer::subscribe(std::string topic, FilterExpression filter_expression) { + impl_->subscribe(std::move(topic), filter_expression.content_, filter_expression.type_); +} + +void PushConsumer::unsubscribe(const std::string& topic) { + impl_->unsubscribe(topic); +} + +PushConsumerBuilder PushConsumer::newBuilder() { + return {}; +} + +PushConsumer PushConsumerBuilder::build() { + auto impl = std::make_shared(group_); + impl->registerMessageListener(listener_); + for (const auto& entry : subscriptions_) { + impl->subscribe(entry.first, entry.second.content_, entry.second.type_); + } + impl->consumeThreadPoolSize(consume_thread_); + impl->withNameServerResolver(std::make_shared(configuration_.endpoints())); + impl->withCredentialsProvider(configuration_.credentialsProvider()); + impl->withRequestTimeout(configuration_.requestTimeout()); + impl->start(); + return PushConsumer(impl); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/PushConsumerImpl.cpp b/src/main/cpp/rocketmq/PushConsumerImpl.cpp new file mode 100644 index 000000000..89dc11223 --- /dev/null +++ b/src/main/cpp/rocketmq/PushConsumerImpl.cpp @@ -0,0 +1,562 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "PushConsumerImpl.h" + +#include +#include +#include +#include +#include + +#include "AsyncReceiveMessageCallback.h" +#include "ClientManagerFactory.h" +#include "ConsumeMessageServiceImpl.h" +#include "MixAll.h" +#include "ProcessQueueImpl.h" +#include "Protocol.h" +#include "RpcClient.h" +#include "Signature.h" +#include "google/protobuf/util/time_util.h" +#include "rocketmq/MQClientException.h" +#include "rocketmq/MessageListener.h" + +ROCKETMQ_NAMESPACE_BEGIN + +PushConsumerImpl::PushConsumerImpl(absl::string_view group_name) : ClientImpl(group_name) { +} + +PushConsumerImpl::~PushConsumerImpl() { + SPDLOG_DEBUG("DefaultMQPushConsumerImpl is destructed"); + shutdown(); +} + +void PushConsumerImpl::topicsOfInterest(std::vector& topics) { + absl::MutexLock lk(&topic_filter_expression_table_mtx_); + for (const auto& entry : topic_filter_expression_table_) { + topics.push_back(entry.first); + } +} + +void PushConsumerImpl::start() { + ClientImpl::start(); + + State expecting = State::STARTING; + if (!state_.compare_exchange_strong(expecting, State::STARTED)) { + SPDLOG_ERROR("Unexpected consumer state. Expecting: {}, Actual: {}", State::STARTING, + state_.load(std::memory_order_relaxed)); + return; + } + + if (!message_listener_) { + SPDLOG_ERROR("Required message listener is missing"); + abort(); + return; + } + + client_manager_->addClientObserver(shared_from_this()); + + fetchRoutes(); + + SPDLOG_INFO("start concurrently consume service: {}", client_config_.subscriber.group.name()); + consume_message_service_ = + std::make_shared(shared_from_this(), consume_thread_pool_size_, message_listener_); + consume_message_service_->start(); + + // Heartbeat depends on initialization of consume-message-service + heartbeat(); + + std::weak_ptr consumer_weak_ptr(shared_from_this()); + auto scan_assignment_functor = [consumer_weak_ptr]() { + std::shared_ptr consumer = consumer_weak_ptr.lock(); + if (consumer) { + consumer->scanAssignments(); + } + }; + + scan_assignment_handle_ = client_manager_->getScheduler()->schedule( + scan_assignment_functor, SCAN_ASSIGNMENT_TASK_NAME, std::chrono::milliseconds(100), std::chrono::seconds(5)); + SPDLOG_INFO("PushConsumer started, groupName={}", client_config_.subscriber.group.name()); +} + +const char* PushConsumerImpl::SCAN_ASSIGNMENT_TASK_NAME = "scan-assignment-task"; + +void PushConsumerImpl::shutdown() { + State expecting = State::STARTED; + if (state_.compare_exchange_strong(expecting, State::STOPPING)) { + if (scan_assignment_handle_) { + client_manager_->getScheduler()->cancel(scan_assignment_handle_); + SPDLOG_DEBUG("Scan assignment periodic task cancelled"); + } + + { + absl::MutexLock lock(&process_queue_table_mtx_); + process_queue_table_.clear(); + } + + if (consume_message_service_) { + consume_message_service_->shutdown(); + } + + // Shutdown services started by parent + ClientImpl::shutdown(); + + SPDLOG_INFO("PushConsumerImpl stopped"); + } else { + SPDLOG_ERROR("Shutdown with unexpected state. Expecting: {}, Actual: {}", State::STARTED, + state_.load(std::memory_order_relaxed)); + } +} + +void PushConsumerImpl::subscribe(const std::string& topic, const std::string& expression, + ExpressionType expression_type) { + absl::MutexLock lock(&topic_filter_expression_table_mtx_); + FilterExpression filter_expression{expression, expression_type}; + topic_filter_expression_table_.emplace(topic, filter_expression); +} + +void PushConsumerImpl::unsubscribe(const std::string& topic) { + absl::MutexLock lock(&topic_filter_expression_table_mtx_); + topic_filter_expression_table_.erase(topic); +} + +absl::optional PushConsumerImpl::getFilterExpression(const std::string& topic) const { + { + absl::MutexLock lock(&topic_filter_expression_table_mtx_); + if (topic_filter_expression_table_.contains(topic)) { + return absl::make_optional(topic_filter_expression_table_.at(topic)); + } else { + return {}; + } + } +} + +void PushConsumerImpl::scanAssignments() { + SPDLOG_DEBUG("Start of assignment scanning"); + if (!active()) { + SPDLOG_INFO("Client has stopped. Abort scanning immediately."); + return; + } + + { + absl::MutexLock lk(&topic_filter_expression_table_mtx_); + for (auto& entry : topic_filter_expression_table_) { + std::string topic = entry.first; + const auto& filter_expression = entry.second; + SPDLOG_DEBUG("Scan assignments for {}", topic); + auto callback = [this, topic, filter_expression](const std::error_code& ec, + const TopicAssignmentPtr& assignments) { + if (ec) { + SPDLOG_WARN("Failed to acquire assignments for topic={} from load balancer. Cause: {}", topic, ec.message()); + } else if (assignments && !assignments->assignmentList().empty()) { + syncProcessQueue(topic, assignments, filter_expression); + } + }; + queryAssignment(topic, callback); + } // end of for-loop + } + SPDLOG_DEBUG("End of assignment scanning."); +} + +bool PushConsumerImpl::selectBroker(const TopicRouteDataPtr& topic_route_data, std::string& broker_host) { + if (topic_route_data && !topic_route_data->messageQueues().empty()) { + uint32_t index = TopicAssignment::getAndIncreaseQueryWhichBroker(); + for (uint32_t i = index; i < index + topic_route_data->messageQueues().size(); i++) { + auto message_queue = topic_route_data->messageQueues().at(i % topic_route_data->messageQueues().size()); + if (MixAll::MASTER_BROKER_ID != message_queue.broker().id() || !readable(message_queue.permission())) { + continue; + } + broker_host = urlOf(message_queue); + return true; + } + } + return false; +} + +void PushConsumerImpl::wrapQueryAssignmentRequest(const std::string& topic, + const std::string& consumer_group, + const std::string& strategy_name, + QueryAssignmentRequest& request) { + request.mutable_endpoints()->CopyFrom(accessPoint()); + request.mutable_topic()->set_name(topic); + request.mutable_topic()->set_resource_namespace(resourceNamespace()); + request.mutable_group()->set_name(consumer_group); + request.mutable_group()->set_resource_namespace(resourceNamespace()); +} + +void PushConsumerImpl::queryAssignment( + const std::string& topic, const std::function& cb) { + auto callback = [this, topic, cb](const std::error_code& ec, const TopicRouteDataPtr& topic_route) { + TopicAssignmentPtr topic_assignment; + std::string broker_host; + if (!selectBroker(topic_route, broker_host)) { + SPDLOG_WARN("Failed to select a broker to query assignment for group={}, topic={}", + client_config_.subscriber.group.name(), topic); + } + + QueryAssignmentRequest request; + wrapQueryAssignmentRequest(topic, groupName(), MixAll::DEFAULT_LOAD_BALANCER_STRATEGY_NAME_, request); + SPDLOG_DEBUG("QueryAssignmentRequest: {}", request.DebugString()); + + absl::flat_hash_map metadata; + Signature::sign(client_config_, metadata); + auto assignment_callback = [this, cb, topic, broker_host](const std::error_code& ec, + const QueryAssignmentResponse& response) { + if (ec) { + SPDLOG_WARN("Failed to acquire queue assignment of topic={} from brokerAddress={}", topic, broker_host); + cb(ec, nullptr); + } else { + SPDLOG_DEBUG("Query topic assignment OK. Topic={}, group={}, assignment-size={}", topic, groupName(), + response.assignments().size()); + SPDLOG_TRACE("Query assignment response for {} is: {}", topic, response.DebugString()); + cb(ec, std::make_shared(response)); + } + }; + + client_manager_->queryAssignment(broker_host, metadata, request, + absl::ToChronoMilliseconds(client_config_.request_timeout), assignment_callback); + }; + getRouteFor(topic, callback); +} + +/** + * + * @param topic Topic to process + * @param assignment Latest assignment from load balancer + * @param filter_expression Filter expression + */ +void PushConsumerImpl::syncProcessQueue(const std::string& topic, + const std::shared_ptr& topic_assignment, + const FilterExpression& filter_expression) { + const std::vector& assignment_list = topic_assignment->assignmentList(); + std::vector message_queue_list; + message_queue_list.reserve(assignment_list.size()); + for (const auto& assignment : assignment_list) { + message_queue_list.push_back(assignment.message_queue()); + } + + std::vector current; + { + absl::MutexLock lock(&process_queue_table_mtx_); + for (auto it = process_queue_table_.begin(); it != process_queue_table_.end();) { + if (topic != it->second->messageQueue().topic().name()) { + it++; + continue; + } + + if (std::none_of( + message_queue_list.cbegin(), message_queue_list.cend(), + [&](const rmq::MessageQueue& message_queue) { return it->second->messageQueue() == message_queue; })) { + SPDLOG_INFO("Stop receiving messages from {} as it is not assigned to current client according to latest " + "assignment result from load balancer", + simpleNameOf(it->second->messageQueue())); + process_queue_table_.erase(it++); + } else { + if (!it->second || it->second->expired()) { + SPDLOG_WARN("ProcessQueue={} is expired. Remove it for now.", it->first); + process_queue_table_.erase(it++); + continue; + } + current.push_back(it->second->messageQueue()); + it++; + } + } + } + + for (const auto& message_queue : message_queue_list) { + if (std::none_of(current.cbegin(), current.cend(), + [&](const rmq::MessageQueue& item) { return item == message_queue; })) { + SPDLOG_INFO("Start to receive message from {} according to latest assignment info from load balancer", + simpleNameOf(message_queue)); + if (!receiveMessage(message_queue, filter_expression)) { + if (!active()) { + SPDLOG_WARN("Failed to initiate receive message request-response-cycle for {}", simpleNameOf(message_queue)); + // TODO: remove it from current assignment such that a second attempt will be made again in the next round. + } + } + } + } +} + +std::shared_ptr PushConsumerImpl::getOrCreateProcessQueue(const rmq::MessageQueue& message_queue, + const FilterExpression& filter_expression) { + std::shared_ptr process_queue; + { + absl::MutexLock lock(&process_queue_table_mtx_); + if (!active()) { + SPDLOG_INFO("PushConsumer has stopped. Drop creation of ProcessQueue"); + return process_queue; + } + + if (process_queue_table_.contains(simpleNameOf(message_queue))) { + process_queue = process_queue_table_.at(simpleNameOf(message_queue)); + } else { + SPDLOG_INFO("Create ProcessQueue for message queue[{}]", simpleNameOf(message_queue)); + // create ProcessQueue + process_queue = + std::make_shared(message_queue, filter_expression, shared_from_this(), client_manager_); + std::shared_ptr receive_callback = + std::make_shared(process_queue); + process_queue->callback(receive_callback); + process_queue_table_.emplace(std::make_pair(simpleNameOf(message_queue), process_queue)); + } + } + return process_queue; +} + +bool PushConsumerImpl::receiveMessage(const rmq::MessageQueue& message_queue, + const FilterExpression& filter_expression) { + if (!active()) { + SPDLOG_INFO("PushConsumer has stopped. Drop further receive message request"); + return false; + } + + auto process_queue_ptr = getOrCreateProcessQueue(message_queue, filter_expression); + if (!process_queue_ptr) { + SPDLOG_INFO("Consumer has stopped. Stop creating processQueue"); + return false; + } + const std::string& broker_host = urlOf(message_queue); + if (broker_host.empty()) { + SPDLOG_ERROR("Failed to resolve address for brokerName={}", message_queue.broker().name()); + return false; + } + process_queue_ptr->receiveMessage(); + return true; +} + +std::shared_ptr PushConsumerImpl::getConsumeMessageService() { + return consume_message_service_; +} + +void PushConsumerImpl::ack(const Message& msg, const std::function& callback) { + const std::string& target_host = msg.extension().target_endpoint; + assert(!target_host.empty()); + SPDLOG_DEBUG("Prepare to send ack to broker. BrokerAddress={}, topic={}, queueId={}, msgId={}", target_host, + msg.topic(), msg.extension().queue_id, msg.id()); + AckMessageRequest request; + wrapAckMessageRequest(msg, request); + absl::flat_hash_map metadata; + Signature::sign(client_config_, metadata); + client_manager_->ack(target_host, metadata, request, absl::ToChronoMilliseconds(client_config_.request_timeout), + callback); +} + +std::chrono::milliseconds PushConsumerImpl::invisibleDuration(std::size_t attempt) { + return std::chrono::milliseconds(client_config_.backoff_policy.backoff(attempt)); +} + +void PushConsumerImpl::nack(const Message& message, const std::function& callback) { + const auto& target_host = message.extension().target_endpoint; + SPDLOG_DEBUG("Prepare to nack message[topic={}, message-id={}]", message.topic(), message.id()); + auto duration = invisibleDuration(message.extension().delivery_attempt + 1); + Metadata metadata; + Signature::sign(client_config_, metadata); + rmq::ChangeInvisibleDurationRequest request; + request.mutable_group()->CopyFrom(client_config_.subscriber.group); + request.mutable_topic()->set_resource_namespace(resourceNamespace()); + request.mutable_topic()->set_name(message.topic()); + request.set_receipt_handle(message.extension().receipt_handle); + request.set_message_id(message.id()); + request.mutable_invisible_duration()->CopyFrom( + google::protobuf::util::TimeUtil::MillisecondsToDuration(duration.count())); + client_manager_->changeInvisibleDuration(target_host, metadata, request, + absl::ToChronoMilliseconds(client_config_.request_timeout), callback); +} + +void PushConsumerImpl::forwardToDeadLetterQueue(const Message& message, + const std::function& cb) { + std::string target_host = message.extension().target_endpoint; + + absl::flat_hash_map metadata; + Signature::sign(client_config_, metadata); + + ForwardMessageToDeadLetterQueueRequest request; + request.mutable_group()->set_resource_namespace(resourceNamespace()); + request.mutable_group()->set_name(groupName()); + + request.mutable_topic()->set_resource_namespace(resourceNamespace()); + request.mutable_topic()->set_name(message.topic()); + + request.set_message_id(message.id()); + + request.set_delivery_attempt(message.extension().delivery_attempt); + request.set_max_delivery_attempts(max_delivery_attempts_); + + client_manager_->forwardMessageToDeadLetterQueue(target_host, metadata, request, + absl::ToChronoMilliseconds(client_config_.request_timeout), cb); +} + +void PushConsumerImpl::wrapAckMessageRequest(const Message& msg, AckMessageRequest& request) { + request.mutable_group()->set_resource_namespace(resourceNamespace()); + request.mutable_group()->set_name(groupName()); + request.mutable_topic()->set_resource_namespace(resourceNamespace()); + request.mutable_topic()->set_name(msg.topic()); + auto entry = new rmq::AckMessageEntry(); + entry->set_message_id(msg.id()); + entry->set_receipt_handle(msg.extension().receipt_handle); + request.mutable_entries()->AddAllocated(entry); +} + +uint32_t PushConsumerImpl::consumeThreadPoolSize() const { + return consume_thread_pool_size_; +} + +void PushConsumerImpl::consumeThreadPoolSize(int thread_pool_size) { + if (thread_pool_size >= 1) { + consume_thread_pool_size_ = thread_pool_size; + } +} + +void PushConsumerImpl::registerMessageListener(MessageListener message_listener) { + message_listener_ = message_listener; +} + +std::size_t PushConsumerImpl::getProcessQueueTableSize() { + absl::MutexLock lock(&process_queue_table_mtx_); + return process_queue_table_.size(); +} + +void PushConsumerImpl::setThrottle(const std::string& topic, uint32_t threshold) { + absl::MutexLock lock(&throttle_table_mtx_); + throttle_table_.emplace(topic, threshold); +} + +void PushConsumerImpl::fetchRoutes() { + std::vector topics; + { + absl::MutexLock lk(&topic_filter_expression_table_mtx_); + for (const auto& item : topic_filter_expression_table_) { + topics.emplace_back(item.first); + } + } + + if (topics.empty()) { + return; + } + + std::vector::size_type countdown = topics.size(); + auto mtx = std::make_shared(); + auto cv = std::make_shared(); + int acquired = 0; + auto callback = [&, mtx, cv](const std::error_code& ec, const TopicRouteDataPtr& route) { + { + absl::MutexLock lk(mtx.get()); + countdown--; + if (!ec) { + acquired++; + } + } + + if (countdown <= 0) { + cv->SignalAll(); + } + }; + + for (const auto& topic : topics) { + getRouteFor(topic, callback); + } + + while (countdown) { + absl::MutexLock lk(mtx.get()); + cv->Wait(mtx.get()); + } + SPDLOG_INFO("Fetched route for {} out of {} topics", acquired, topics.size()); +} + +void PushConsumerImpl::buildClientSettings(rmq::Settings& settings) { + settings.set_client_type(rmq::ClientType::PUSH_CONSUMER); + auto subscription = settings.mutable_subscription(); + subscription->mutable_group()->CopyFrom(client_config_.subscriber.group); + auto polling_timeout = google::protobuf::util::TimeUtil::MillisecondsToDuration( + absl::ToInt64Milliseconds(client_config_.subscriber.polling_timeout)); + subscription->mutable_long_polling_timeout()->set_seconds(polling_timeout.seconds()); + subscription->mutable_long_polling_timeout()->set_nanos(polling_timeout.nanos()); + subscription->set_receive_batch_size(client_config_.subscriber.receive_batch_size); + + { + absl::MutexLock lk(&topic_filter_expression_table_mtx_); + for (const auto& entry : topic_filter_expression_table_) { + auto subscription_entry = new rmq::SubscriptionEntry; + subscription_entry->mutable_topic()->set_resource_namespace(resourceNamespace()); + subscription_entry->mutable_topic()->set_name(entry.first); + + subscription_entry->mutable_expression()->set_expression(entry.second.content_); + switch (entry.second.type_) { + case ExpressionType::TAG: { + subscription_entry->mutable_expression()->set_type(rmq::FilterType::TAG); + break; + } + case ExpressionType::SQL92: { + subscription_entry->mutable_expression()->set_type(rmq::FilterType::SQL); + break; + } + } + subscription->mutable_subscriptions()->AddAllocated(subscription_entry); + } + } +} + +void PushConsumerImpl::prepareHeartbeatData(HeartbeatRequest& request) { + request.set_client_type(rmq::ClientType::PUSH_CONSUMER); + request.mutable_group()->set_resource_namespace(resourceNamespace()); + request.mutable_group()->set_name(groupName()); +} + +void PushConsumerImpl::notifyClientTermination() { + NotifyClientTerminationRequest request; + request.mutable_group()->set_resource_namespace(resourceNamespace()); + request.mutable_group()->set_name(groupName()); + ClientImpl::notifyClientTermination(request); +} + +void PushConsumerImpl::onVerifyMessage(MessageConstSharedPtr message, std::function cb) { + auto listener = messageListener(); + TelemetryCommand cmd; + auto verify_result = cmd.mutable_verify_message_result(); + verify_result->set_nonce(message->extension().nonce); + if (message) { + if (!client_config_.subscriber.fifo) { + try { + auto result = listener(*message); + switch (result) { + case ConsumeResult::SUCCESS: { + cmd.mutable_status()->set_code(rmq::Code::OK); + cmd.mutable_status()->set_message("OK"); + } + case ConsumeResult::FAILURE: { + cmd.mutable_status()->set_code(rmq::Code::FAILED_TO_CONSUME_MESSAGE); + cmd.mutable_status()->set_message("Consume message failed"); + } + } + } catch (const std::exception& e) { + cmd.mutable_status()->set_code(rmq::Code::FAILED_TO_CONSUME_MESSAGE); + cmd.mutable_status()->set_message(e.what()); + } catch (...) { + cmd.mutable_status()->set_code(rmq::Code::FAILED_TO_CONSUME_MESSAGE); + cmd.mutable_status()->set_message("Unexpected exception raised"); + } + } else { + cmd.mutable_status()->set_code(rmq::Code::VERIFY_MESSAGE_FORBIDDEN); + cmd.mutable_status()->set_message("Unsupported Operation For FIFO Message"); + } + } else { + cmd.mutable_status()->set_code(rmq::Code::MESSAGE_CORRUPTED); + cmd.mutable_status()->set_message("Checksum Mismatch"); + } +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/SendContext.cpp b/src/main/cpp/rocketmq/SendContext.cpp new file mode 100644 index 000000000..9dee0e87f --- /dev/null +++ b/src/main/cpp/rocketmq/SendContext.cpp @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "SendContext.h" + +#include + +#include "ProducerImpl.h" +#include "PublishStats.h" +#include "Tag.h" +#include "TransactionImpl.h" +#include "opencensus/trace/propagation/trace_context.h" +#include "opencensus/trace/span.h" +#include "rocketmq/Logger.h" +#include "rocketmq/SendReceipt.h" +#include "spdlog/spdlog.h" + +ROCKETMQ_NAMESPACE_BEGIN + +void SendContext::onSuccess(const SendReceipt& send_receipt) noexcept { + { + // Mark end of send-message span. + span_.SetStatus(opencensus::trace::StatusCode::OK); + span_.End(); + } + + auto publisher = producer_.lock(); + if (!publisher) { + return; + } + + // Collect metrics + { + auto duration = std::chrono::steady_clock::now() - request_time_; + opencensus::stats::Record({{publisher->stats().latency(), MixAll::millisecondsOf(duration)}}, + { + {Tag::topicTag(), message_->topic()}, + {Tag::clientIdTag(), publisher->config().client_id}, + }); + + opencensus::stats::Record({{publisher->stats().success(), 1}}, + { + {Tag::topicTag(), message_->topic()}, + {Tag::clientIdTag(), publisher->config().client_id}, + }); + } + + // send_receipt.traceContext(opencensus::trace::propagation::ToTraceParentHeader(span_.context())); + std::error_code ec; + callback_(ec, send_receipt); +} + +void SendContext::onFailure(const std::error_code& ec) noexcept { + { + // Mark end of the send-message span. + span_.SetStatus(opencensus::trace::StatusCode::INTERNAL); + span_.End(); + } + + auto publisher = producer_.lock(); + if (!publisher) { + return; + } + + // Collect metrics + { + auto duration = std::chrono::steady_clock::now() - request_time_; + opencensus::stats::Record({{publisher->stats().latency(), MixAll::millisecondsOf(duration)}}, + { + {Tag::topicTag(), message_->topic()}, + {Tag::clientIdTag(), publisher->config().client_id}, + }); + + opencensus::stats::Record({{publisher->stats().failure(), 1}}, + { + {Tag::topicTag(), message_->topic()}, + {Tag::clientIdTag(), publisher->config().client_id}, + }); + } + + if (++attempt_times_ >= publisher->maxAttemptTimes()) { + SPDLOG_WARN("Retried {} times, which exceeds the limit: {}", attempt_times_, publisher->maxAttemptTimes()); + callback_(ec, {}); + return; + } + + std::shared_ptr producer = producer_.lock(); + if (!producer) { + SPDLOG_WARN("Producer has been destructed"); + callback_(ec, {}); + return; + } + + if (candidates_.empty()) { + SPDLOG_WARN("No alternative hosts to perform additional retries"); + callback_(ec, {}); + return; + } + + auto message_queue = candidates_[attempt_times_ % candidates_.size()]; + request_time_ = std::chrono::steady_clock::now(); + producer->sendImpl(shared_from_this()); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/SimpleConsumer.cpp b/src/main/cpp/rocketmq/SimpleConsumer.cpp new file mode 100644 index 000000000..0c902d4b2 --- /dev/null +++ b/src/main/cpp/rocketmq/SimpleConsumer.cpp @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rocketmq/SimpleConsumer.h" + +#include "SimpleConsumerImpl.h" +#include "StaticNameServerResolver.h" + +ROCKETMQ_NAMESPACE_BEGIN + +SimpleConsumerBuilder::SimpleConsumerBuilder() : configuration_(Configuration::newBuilder().build()) { +} + +SimpleConsumerBuilder SimpleConsumer::newBuilder() { + return {}; +} + +SimpleConsumer::SimpleConsumer(std::string group) : impl_(std::make_shared(group)) { +} + +SimpleConsumer::~SimpleConsumer() { + impl_->shutdown(); +} + +void SimpleConsumer::start() { + impl_->start(); +} + +void SimpleConsumer::subscribe(std::string topic, FilterExpression filter_expression) { + impl_->subscribe(topic, filter_expression); +} + +void SimpleConsumer::unsubscribe(const std::string& topic) { + impl_->unsubscribe(topic); +} + +void SimpleConsumer::receive(std::size_t limit, + std::chrono::milliseconds invisible_duration, + std::error_code& ec, + std::vector& messages) { + auto mtx = std::make_shared(); + auto cv = std::make_shared(); + bool completed = false; + auto callback = [&, mtx, cv](const std::error_code& code, const std::vector& result) { + { + absl::MutexLock lk(mtx.get()); + if (code) { + ec = code; + SPDLOG_WARN("Failed to receive message. Cause: {}", code.message()); + } + completed = true; + messages.insert(messages.end(), result.begin(), result.end()); + } + cv->SignalAll(); + }; + + impl_->receive(limit, invisible_duration, callback); + + { + absl::MutexLock lk(mtx.get()); + while (!completed) { + cv->Wait(mtx.get()); + } + } +} + +void SimpleConsumer::asyncReceive(std::size_t limit, + std::chrono::milliseconds invisible_duration, + ReceiveCallback callback) { + impl_->receive(limit, invisible_duration, callback); +} + +void SimpleConsumer::ack(const Message& message, std::error_code& ec) { + impl_->ack(message, ec); +} + +void SimpleConsumer::asyncAck(const Message& message, AckCallback callback) { + impl_->ackAsync(message, callback); +} + +void SimpleConsumer::changeInvisibleDuration(const Message& message, + std::chrono::milliseconds duration, + std::error_code& ec) { + auto mtx = std::make_shared(); + auto cv = std::make_shared(); + bool completed = false; + auto callback = [&, mtx, cv](const std::error_code& code) { + { + absl::MutexLock lk(mtx.get()); + completed = true; + ec = code; + } + cv->Signal(); + }; + + impl_->changeInvisibleDuration(message, duration, callback); + + { + absl::MutexLock lk(mtx.get()); + if (!completed) { + cv->Wait(mtx.get()); + } + } +} + +void SimpleConsumer::asyncChangeInvisibleDuration(const Message& message, + std::chrono::milliseconds duration, + ChangeInvisibleDurationCallback callback) { + impl_->changeInvisibleDuration(message, duration, callback); +} + +SimpleConsumer SimpleConsumerBuilder::build() { + SimpleConsumer simple_consumer(group_); + + simple_consumer.impl_->withRequestTimeout(configuration_.requestTimeout()); + simple_consumer.impl_->withNameServerResolver(std::make_shared(configuration_.endpoints())); + simple_consumer.impl_->withCredentialsProvider(configuration_.credentialsProvider()); + + for (const auto& entry : subscriptions_) { + simple_consumer.impl_->subscribe(entry.first, entry.second); + } + + simple_consumer.start(); + return simple_consumer; +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/SimpleConsumerImpl.cpp b/src/main/cpp/rocketmq/SimpleConsumerImpl.cpp new file mode 100644 index 000000000..82e6b4259 --- /dev/null +++ b/src/main/cpp/rocketmq/SimpleConsumerImpl.cpp @@ -0,0 +1,400 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SimpleConsumerImpl.h" + +#include "Signature.h" +#include "google/protobuf/util/time_util.h" +#include "rocketmq/ErrorCode.h" + +ROCKETMQ_NAMESPACE_BEGIN + +SimpleConsumerImpl::SimpleConsumerImpl(std::string group) : ClientImpl(group) { + client_config_.subscriber.polling_timeout = absl::FromChrono(MixAll::DefaultReceiveMessageTimeout); +} + +SimpleConsumerImpl::~SimpleConsumerImpl() { + shutdown(); +} + +void SimpleConsumerImpl::prepareHeartbeatData(rmq::HeartbeatRequest& request) { + request.set_client_type(rmq::ClientType::SIMPLE_CONSUMER); + request.mutable_group()->CopyFrom(client_config_.subscriber.group); +} + +void SimpleConsumerImpl::buildClientSettings(rmq::Settings& settings) { + settings.set_client_type(rmq::ClientType::SIMPLE_CONSUMER); + + settings.mutable_subscription()->mutable_group()->CopyFrom(client_config_.subscriber.group); + + auto subscriptions = settings.mutable_subscription()->mutable_subscriptions(); + + settings.mutable_access_point()->CopyFrom(accessPoint()); + { + absl::MutexLock lk(&subscriptions_mtx_); + for (const auto& entry : subscriptions_) { + auto subscription_entry = new rmq::SubscriptionEntry; + subscription_entry->mutable_topic()->set_name(entry.first); + subscription_entry->mutable_topic()->set_resource_namespace(resourceNamespace()); + + switch (entry.second.type_) { + case ExpressionType::TAG: { + subscription_entry->mutable_expression()->set_type(rmq::FilterType::TAG); + break; + } + case ExpressionType::SQL92: { + subscription_entry->mutable_expression()->set_type(rmq::FilterType::SQL); + break; + } + } + subscription_entry->mutable_expression()->set_expression(entry.second.content_); + subscriptions->AddAllocated(subscription_entry); + } + } +} + +void SimpleConsumerImpl::topicsOfInterest(std::vector& topics) { + absl::MutexLock lk(&subscriptions_mtx_); + for (const auto& entry : subscriptions_) { + if (std::find(topics.begin(), topics.end(), entry.first) == topics.end()) { + topics.push_back(entry.first); + } + } +} + +/** + * @brief Start SimpleConsumer + * + * During start, we need synchronously fetch routes and query assignments + */ +void SimpleConsumerImpl::start() { + ClientImpl::start(); + State expected = State::STARTING; + if (state_.compare_exchange_strong(expected, State::STARTED, std::memory_order_relaxed)) { + refreshAssignments(); + + std::weak_ptr consumer(shared_from_this()); + auto refresh_assignment_task = [consumer]() { + auto simple_consumer = consumer.lock(); + if (simple_consumer) { + simple_consumer->refreshAssignments0(); + } + }; + refresh_assignment_task_ = manager()->getScheduler()->schedule(refresh_assignment_task, "RefreshAssignmentTask", + std::chrono::seconds(3), std::chrono::seconds(3)); + } +} + +void SimpleConsumerImpl::shutdown() { + State expected = State::STARTED; + + if (state_.compare_exchange_strong(expected, State::STOPPING, std::memory_order_relaxed)) { + manager()->getScheduler()->cancel(refresh_assignment_task_); + ClientImpl::shutdown(); + } +} + +void SimpleConsumerImpl::subscribe(std::string topic, FilterExpression expression) { + absl::MutexLock lk(&subscriptions_mtx_); + subscriptions_.insert_or_assign(topic, expression); +} + +void SimpleConsumerImpl::unsubscribe(const std::string& topic) { + { + absl::MutexLock lk(&subscriptions_mtx_); + subscriptions_.erase(topic); + } + + removeAssignmentsByTopic(topic); +} + +void SimpleConsumerImpl::removeAssignmentsByTopic(const std::string& topic) { + std::vector assignments; + { + absl::MutexLock lk(&topic_assignments_mtx_); + if (!topic_assignments_.contains(topic)) { + return; + } + + const auto& items = topic_assignments_[topic]; + assignments.insert(assignments.end(), items.begin(), items.end()); + topic_assignments_.erase(topic); + } + + { + absl::MutexLock lk(&assignments_mtx_); + auto it = std::remove_if(assignments_.begin(), assignments_.end(), [&](const rmq::Assignment& assignment) { + return std::find_if(assignments.begin(), assignments.end(), + [&](const rmq::Assignment& e) { return e == assignment; }) != assignments.end(); + }); + assignments_.erase(it, assignments_.end()); + } +} + +void SimpleConsumerImpl::refreshAssignments0() { + std::vector topics; + { + absl::MutexLock lk(&subscriptions_mtx_); + for (const auto& entry : subscriptions_) { + topics.push_back(entry.first); + } + } + + auto no_op = [](const std::error_code& ec) {}; + for (const auto& topic : topics) { + refreshAssignment(topic, no_op); + } +} + +void SimpleConsumerImpl::updateAssignments(const std::string& topic, const std::vector& assignments) { + bool changed = false; + { + absl::MutexLock lk(&topic_assignments_mtx_); + if (!topic_assignments_.contains(topic)) { + changed = true; + topic_assignments_.insert({topic, assignments}); + { + absl::MutexLock assignment_lk(&assignments_mtx_); + assignments_.insert(assignments_.begin(), assignments.begin(), assignments.end()); + } + } else if (!assignments.empty()) { + const auto& prev = topic_assignments_[topic]; + std::vector to_remove; + std::vector to_add; + for (const auto& item : prev) { + if (std::find_if(assignments.begin(), assignments.end(), [&](const rmq::Assignment& e) { return item == e; }) == + assignments.end()) { + to_remove.push_back(item); + } + } + + for (const auto& entry : assignments) { + if (std::find_if(prev.begin(), prev.end(), [&](const rmq::Assignment e) { return e == entry; }) == prev.end()) { + to_add.push_back(entry); + } + } + + if (!to_remove.empty() || !to_add.empty()) { + changed = true; + absl::MutexLock lk(&assignments_mtx_); + for (const auto& item : to_remove) { + std::remove_if(assignments_.begin(), assignments_.end(), [&](const rmq::Assignment& e) { return e == item; }); + } + + for (const auto& item : to_add) { + assignments_.push_back(item); + } + topic_assignments_.insert_or_assign(topic, assignments); + } + } + } + + if (changed) { + SPDLOG_DEBUG("Assignments for topic={} change to: {}", topic, + absl::StrJoin(assignments.begin(), assignments.end(), ",", + [](std::string* out, const rmq::Assignment& assignment) { + out->append(assignment.DebugString()); + })); + } +} + +thread_local std::size_t SimpleConsumerImpl::assignment_index_ = 0; + +void SimpleConsumerImpl::refreshAssignment(const std::string& topic, std::function cb) { + absl::flat_hash_set endpoints; + endpointsInUse(endpoints); + if (endpoints.empty()) { + SPDLOG_WARN("No broker is available"); + return; + } + + rmq::QueryAssignmentRequest query_assignment_request; + query_assignment_request.mutable_topic()->set_name(topic); + query_assignment_request.mutable_topic()->set_resource_namespace(resourceNamespace()); + + query_assignment_request.mutable_group()->CopyFrom(client_config_.subscriber.group); + query_assignment_request.mutable_endpoints()->CopyFrom(accessPoint()); + + Metadata metadata; + Signature::sign(client_config_, metadata); + + std::weak_ptr consumer(shared_from_this()); + auto callback = [consumer, topic, cb](const std::error_code& ec, const rmq::QueryAssignmentResponse& response) { + auto simple_consumer = consumer.lock(); + const auto& assignments = response.assignments(); + if (assignments.empty()) { + cb(ec); + return; + } + + std::vector assigns; + assigns.insert(assigns.begin(), assignments.begin(), assignments.end()); + simple_consumer->updateAssignments(topic, assigns); + cb(ec); + }; + + manager()->queryAssignment(*endpoints.begin(), metadata, query_assignment_request, + absl::ToChronoMilliseconds(client_config_.request_timeout), callback); +} + +void SimpleConsumerImpl::refreshAssignments() { + std::vector topics; + { + absl::MutexLock lk(&subscriptions_mtx_); + for (const auto& entry : subscriptions_) { + topics.push_back(entry.first); + } + } + + auto mtx = std::make_shared(); + auto cv = std::make_shared(); + bool completed; + for (const auto& topic : topics) { + completed = false; + auto callback = [&, mtx, cv](const std::error_code& ec) { + absl::MutexLock lk(mtx.get()); + completed = true; + cv->Signal(); + }; + + refreshAssignment(topic, callback); + + { + absl::MutexLock lk(mtx.get()); + if (!completed) { + cv->Wait(mtx.get()); + } + } + SPDLOG_INFO("Assignments for {} received", topic); + } +} + +void SimpleConsumerImpl::receive(std::size_t limit, + std::chrono::milliseconds invisible_duration, + ReceiveCallback callback) { + rmq::Assignment assignment; + { + absl::MutexLock lk(&assignments_mtx_); + if (assignments_.empty()) { + std::error_code ec = ErrorCode::NotFound; + std::vector messages; + callback(ec, messages); + return; + } + std::size_t idx = ++assignment_index_ % assignments_.size(); + assignment.CopyFrom(assignments_[idx]); + } + + const auto& target = urlOf(assignment.message_queue()); + Metadata metadata; + Signature::sign(client_config_, metadata); + + rmq::ReceiveMessageRequest request; + request.set_auto_renew(false); + request.mutable_group()->CopyFrom(config().subscriber.group); + request.mutable_message_queue()->CopyFrom(assignment.message_queue()); + request.set_batch_size(limit); + + auto duration = google::protobuf::util::TimeUtil::MillisecondsToDuration(invisible_duration.count()); + + request.mutable_invisible_duration()->set_nanos(duration.nanos()); + request.mutable_invisible_duration()->set_seconds(duration.seconds()); + + auto cb = [callback](const std::error_code& ec, const ReceiveMessageResult& result) { + std::vector messages; + if (ec) { + callback(ec, messages); + return; + } + + callback(ec, result.messages); + }; + + auto timeout = absl::ToChronoMilliseconds(config().subscriber.polling_timeout); + SPDLOG_DEBUG("ReceiveMessage.polling_timeout: {}ms", timeout.count()); + manager()->receiveMessage(target, metadata, request, timeout, cb); +} + +void SimpleConsumerImpl::wrapAckRequest(const Message& message, AckMessageRequest& request) { + request.mutable_group()->CopyFrom(client_config_.subscriber.group); + + request.mutable_topic()->set_resource_namespace(resourceNamespace()); + request.mutable_topic()->set_name(message.topic()); + + auto entry = new rmq::AckMessageEntry(); + entry->set_message_id(message.id()); + entry->set_receipt_handle(message.extension().receipt_handle); + + request.mutable_entries()->AddAllocated(entry); +} + +void SimpleConsumerImpl::ack(const Message& message, std::error_code& ec) { + Metadata metadata; + Signature::sign(client_config_, metadata); + AckMessageRequest request; + wrapAckRequest(message, request); + + auto mtx = std::make_shared(); + auto cv = std::make_shared(); + bool completed = false; + + auto callback = [&, mtx, cv](const std::error_code& err) { + absl::MutexLock lk(mtx.get()); + completed = true; + ec = err; + cv->Signal(); + }; + + manager()->ack(message.extension().target_endpoint, metadata, request, + absl::ToChronoMilliseconds(client_config_.request_timeout), callback); + + { + absl::MutexLock lk(mtx.get()); + if (!completed) { + cv->Wait(mtx.get()); + } + } +} + +void SimpleConsumerImpl::ackAsync(const Message& message, AckCallback callback) { + Metadata metadata; + Signature::sign(client_config_, metadata); + AckMessageRequest request; + wrapAckRequest(message, request); + manager()->ack(message.extension().target_endpoint, metadata, request, + absl::ToChronoMilliseconds(client_config_.request_timeout), callback); +} + +void SimpleConsumerImpl::changeInvisibleDuration(const Message& message, + std::chrono::milliseconds duration, + ChangeInvisibleDurationCallback callback) { + Metadata metadata; + Signature::sign(client_config_, metadata); + + rmq::ChangeInvisibleDurationRequest request; + request.mutable_group()->CopyFrom(client_config_.subscriber.group); + request.mutable_topic()->set_resource_namespace(resourceNamespace()); + request.mutable_topic()->set_name(message.topic()); + request.set_message_id(message.id()); + request.set_receipt_handle(message.extension().receipt_handle); + auto d = google::protobuf::util::TimeUtil::MillisecondsToDuration(duration.count()); + request.mutable_invisible_duration()->CopyFrom(d); + + manager()->changeInvisibleDuration(message.extension().target_endpoint, metadata, request, duration, callback); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/StaticNameServerResolver.cpp b/src/main/cpp/rocketmq/StaticNameServerResolver.cpp new file mode 100644 index 000000000..c7f0804e5 --- /dev/null +++ b/src/main/cpp/rocketmq/StaticNameServerResolver.cpp @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "StaticNameServerResolver.h" + +#include "absl/strings/str_split.h" + +#include "LoggerImpl.h" + +ROCKETMQ_NAMESPACE_BEGIN + +StaticNameServerResolver::StaticNameServerResolver(absl::string_view name_server_list) { + std::vector segments = absl::StrSplit(name_server_list, ';'); + name_server_address_ = naming_scheme_.buildAddress(segments); + if (name_server_address_.empty()) { + SPDLOG_WARN("Failed to create gRPC naming scheme compliant address from {}", + std::string(name_server_list.data(), name_server_list.length())); + } +} + +std::string StaticNameServerResolver::resolve() { + return name_server_address_; +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/TopicPublishInfo.cpp b/src/main/cpp/rocketmq/TopicPublishInfo.cpp new file mode 100644 index 000000000..9eac1a265 --- /dev/null +++ b/src/main/cpp/rocketmq/TopicPublishInfo.cpp @@ -0,0 +1,125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "TopicPublishInfo.h" + +#include +#include + +#include "LoggerImpl.h" +#include "MixAll.h" +#include "ProducerImpl.h" +#include "TopicRouteData.h" +#include "absl/container/flat_hash_map.h" +#include "absl/strings/str_join.h" + +ROCKETMQ_NAMESPACE_BEGIN + +thread_local uint32_t TopicPublishInfo::send_which_queue_ = MixAll::random(0, 100); + +TopicPublishInfo::TopicPublishInfo(std::weak_ptr producer, + absl::string_view topic, + TopicRouteDataPtr topic_route_data) + : producer_(std::move(producer)), + topic_(topic.data(), topic.length()), + topic_route_data_(std::move(topic_route_data)) { + updatePublishInfo(); +} + +bool TopicPublishInfo::selectMessageQueues(absl::optional message_group, + std::vector& result) { + { + absl::MutexLock lock(&queue_list_mtx_); + if (queue_list_.empty()) { + SPDLOG_WARN("Failed to screen viable message queues from TopicPublishInfo because there is no candidates at all"); + return false; + } + } + + auto producer = producer_.lock(); + if (!producer) { + return false; + } + + // Select a message queue according to given message group, which is used to send FIFO message. + if (message_group.has_value()) { + std::size_t hash_code = std::hash{}(message_group.value()); + absl::MutexLock lk(&queue_list_mtx_); + std::size_t index = hash_code % queue_list_.size(); + result.push_back(queue_list_[index]); + return true; + } + + unsigned int index = ++send_which_queue_; + // For standard messages, select at most "count" message queues in case retries are required. + { + absl::MutexLock lock(&queue_list_mtx_); + for (std::vector::size_type i = 0; i < queue_list_.size(); ++i) { + const rmq::MessageQueue& message_queue = queue_list_[index++ % (queue_list_.size())]; + if (!producer->isEndpointIsolated(urlOf(message_queue))) { + auto search = std::find_if(result.begin(), result.end(), [&](const rmq::MessageQueue& item) { + return item.broker().name() == message_queue.broker().name(); + }); + if (std::end(result) == search) { + result.emplace_back(message_queue); + } + if (result.size() >= producer->maxAttemptTimes()) { + return true; + } + } + } + } + return !result.empty(); +} + +void TopicPublishInfo::updatePublishInfo() { + std::vector writable_queue_list; + { + for (const auto& queue : topic_route_data_->messageQueues()) { + assert(queue.topic().name() == topic_); + if (!writable(queue.permission())) { + continue; + } + if (MixAll::MASTER_BROKER_ID != queue.broker().id()) { + continue; + } + writable_queue_list.push_back(queue); + } + } + + if (writable_queue_list.empty()) { + SPDLOG_WARN("No writable queue is current available. Skip updating publish table for topic={}", topic_); + return; + } + + { + absl::MutexLock lk(&queue_list_mtx_); + queue_list_.swap(writable_queue_list); + } +} + +void TopicPublishInfo::topicRouteData(TopicRouteDataPtr topic_route_data) { + SPDLOG_DEBUG("Update publish info according to renewed route data of topic={}", topic_); + topic_route_data_ = std::move(topic_route_data); + updatePublishInfo(); +} + +std::vector TopicPublishInfo::getMessageQueueList() { + absl::MutexLock lock(&queue_list_mtx_); + return queue_list_; +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/TransactionImpl.cpp b/src/main/cpp/rocketmq/TransactionImpl.cpp new file mode 100644 index 000000000..2d2bf66cc --- /dev/null +++ b/src/main/cpp/rocketmq/TransactionImpl.cpp @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "TransactionImpl.h" +#include "ProducerImpl.h" +#include + +ROCKETMQ_NAMESPACE_BEGIN + +bool TransactionImpl::commit() { + std::shared_ptr producer = producer_.lock(); + if (!producer) { + return false; + } + + return producer->commit(*this); +} + +bool TransactionImpl::rollback() { + std::shared_ptr producer = producer_.lock(); + if (!producer) { + return false; + } + return producer->rollback(*this); +} + +const std::string& TransactionImpl::messageId() const { + return message_id_; +} + +const std::string& TransactionImpl::transactionId() const { + return transaction_id_; +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/AsyncReceiveMessageCallback.h b/src/main/cpp/rocketmq/include/AsyncReceiveMessageCallback.h new file mode 100644 index 000000000..b3fe2b193 --- /dev/null +++ b/src/main/cpp/rocketmq/include/AsyncReceiveMessageCallback.h @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include + +#include "ReceiveMessageResult.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ProcessQueue; + +class AsyncReceiveMessageCallback : public std::enable_shared_from_this { +public: + explicit AsyncReceiveMessageCallback(std::weak_ptr process_queue); + + void onCompletion(const std::error_code& ec, const ReceiveMessageResult& result); + + void receiveMessageLater(); + + void receiveMessageImmediately(); + +private: + /** + * Hold a weak_ptr to ProcessQueue. Once ProcessQueue was released, stop the + * pop-cycle immediately. + */ + std::weak_ptr process_queue_; + + std::function receive_message_later_; + + void checkThrottleThenReceive(); + + static const char* RECEIVE_LATER_TASK_NAME; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/ClientImpl.h b/src/main/cpp/rocketmq/include/ClientImpl.h new file mode 100644 index 000000000..ff61af376 --- /dev/null +++ b/src/main/cpp/rocketmq/include/ClientImpl.h @@ -0,0 +1,213 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "Client.h" +#include "ClientConfig.h" +#include "ClientManager.h" +#include "ClientResourceBundle.h" +#include "InvocationContext.h" +#include "MessageExt.h" +#include "NameServerResolver.h" +#include "RpcClient.h" +#include "Session.h" +#include "TelemetryBidiReactor.h" +#include "absl/strings/string_view.h" +#include "rocketmq/MessageListener.h" +#include "rocketmq/State.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ClientImpl : virtual public Client { +public: + explicit ClientImpl(absl::string_view group_name); + + virtual void start(); + + virtual void shutdown(); + + void getRouteFor(const std::string& topic, const std::function& cb) + LOCKS_EXCLUDED(inflight_route_requests_mtx_, topic_route_table_mtx_); + + /** + * Gather collection of endpoints that are reachable from latest topic route + * table. + * + * @param endpoints + */ + void endpointsInUse(absl::flat_hash_set& endpoints) override LOCKS_EXCLUDED(topic_route_table_mtx_); + + void heartbeat() override; + + bool active() override { + State state = state_.load(std::memory_order_relaxed); + return State::STARTING == state || State::STARTED == state; + } + + void onRemoteEndpointRemoval(const std::vector& hosts) override LOCKS_EXCLUDED(isolated_endpoints_mtx_); + + void schedule(const std::string& task_name, const std::function& task, + std::chrono::milliseconds delay) override; + + void createSession(const std::string& target, bool verify) override; + + void withNameServerResolver(std::shared_ptr name_server_resolver) { + name_server_resolver_ = std::move(name_server_resolver); + } + + void withCredentialsProvider(std::shared_ptr credentials_provider) override { + client_config_.credentials_provider = std::move(credentials_provider); + } + + void withRequestTimeout(std::chrono::milliseconds request_timeout) { + client_config_.request_timeout = absl::FromChrono(request_timeout); + } + + /** + * Expose for test purpose only. + */ + void state(State state) { + state_.store(state, std::memory_order_relaxed); + } + + void verify(MessageConstSharedPtr message, std::function cb) override; + + void recoverOrphanedTransaction(MessageConstSharedPtr message) override; + + virtual void doRecoverOrphanedTransaction(MessageConstSharedPtr message); + + ClientConfig& config() override { + return client_config_; + } + + std::shared_ptr manager() const override { + return client_manager_; + } + + rmq::Settings clientSettings() override; + + virtual void buildClientSettings(rmq::Settings& settings) { + } + +protected: + ClientConfig client_config_; + + ClientManagerPtr client_manager_; + + std::atomic state_; + + absl::flat_hash_map topic_route_table_ GUARDED_BY(topic_route_table_mtx_); + absl::Mutex topic_route_table_mtx_ ACQUIRED_AFTER(inflight_route_requests_mtx_); // protects topic_route_table_ + + absl::flat_hash_map>> + inflight_route_requests_ GUARDED_BY(inflight_route_requests_mtx_); + absl::Mutex inflight_route_requests_mtx_ ACQUIRED_BEFORE(topic_route_table_mtx_); // Protects inflight_route_requests_ + static const char* UPDATE_ROUTE_TASK_NAME; + std::uint32_t route_update_handle_{0}; + + // Set Name Server Resolver + std::shared_ptr name_server_resolver_; + + absl::flat_hash_map multiplexing_requests_; + absl::Mutex multiplexing_requests_mtx_; + + absl::flat_hash_set isolated_endpoints_ GUARDED_BY(isolated_endpoints_mtx_); + absl::Mutex isolated_endpoints_mtx_; + + absl::flat_hash_map> session_map_ GUARDED_BY(session_map_mtx_); + absl::Mutex session_map_mtx_; + + virtual void topicsOfInterest(std::vector& topics) { + } + + void updateRouteInfo() LOCKS_EXCLUDED(topic_route_table_mtx_); + + /** + * Sub-class is supposed to inherit from std::enable_shared_from_this. + */ + virtual std::shared_ptr self() = 0; + + virtual void prepareHeartbeatData(HeartbeatRequest& request) = 0; + + /** + * @brief Execute transaction-state-checker to commit or roll-back the orphan transactional message. + * + * It is no-op by default and Producer-subclass is supposed to override it. + * + * @param message + */ + virtual void onOrphanedTransactionalMessage(MessageConstSharedPtr message) { + } + + virtual void onVerifyMessage(MessageConstSharedPtr message, std::function cb); + + void notifyClientTermination() override; + + void notifyClientTermination(const NotifyClientTerminationRequest& request); + + const std::string& resourceNamespace() const { + return client_config_.resource_namespace; + } + + absl::Duration requestTimeout() const { + return client_config_.request_timeout; + } + + rmq::Endpoints accessPoint(); + +private: + /** + * This is a low-level API that fetches route data from name server through + * gRPC unary request/response. Once request/response is completed, either + * timeout or response arrival in time, callback would get invoked. + * @param topic + * @param cb + */ + void fetchRouteFor(const std::string& topic, + const std::function& cb); + + /** + * Callback to execute once route data is fetched from name server. + * @param topic + * @param route + */ + void onTopicRouteReady(const std::string& topic, const std::error_code& ec, const TopicRouteDataPtr& route) + LOCKS_EXCLUDED(inflight_route_requests_mtx_); + + /** + * Update local cache for the topic. Note, route differences are logged in + * INFO level since route bears fundamental importance. + * + * @param topic + * @param route + */ + void updateRouteCache(const std::string& topic, const std::error_code& ec, const TopicRouteDataPtr& route) + LOCKS_EXCLUDED(topic_route_table_mtx_); + + void doVerify(std::string target, std::string command_id, MessageConstPtr message); + + static std::string clientId(); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/common/MQClientErrorContainer.h b/src/main/cpp/rocketmq/include/ClientResourceBundle.h similarity index 69% rename from src/common/MQClientErrorContainer.h rename to src/main/cpp/rocketmq/include/ClientResourceBundle.h index 3e09f0a71..0cabca736 100644 --- a/src/common/MQClientErrorContainer.h +++ b/src/main/cpp/rocketmq/include/ClientResourceBundle.h @@ -14,23 +14,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef __MQ_CLIENT_ERROR_CONTAINER_H__ -#define __MQ_CLIENT_ERROR_CONTAINER_H__ +#include "rocketmq/RocketMQ.h" -#include #include +#include -namespace rocketmq { +ROCKETMQ_NAMESPACE_BEGIN -class MQClientErrorContainer { - public: - static void setErr(const std::string& str); - static const std::string& getErr(); - - private: - static thread_local std::string t_err; +enum class GroupType : int8_t +{ + PUBLISHER = 0, + SUBSCRIBER = 1, }; -} // namespace rocketmq +struct ClientResourceBundle { + std::string client_id; + std::vector topics; + std::string resource_namespace; + std::string group; + GroupType group_type{GroupType::PUBLISHER}; +}; -#endif // __MQ_CLIENT_ERROR_CONTAINER_H__ +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/ConsumeMessageService.h b/src/main/cpp/rocketmq/include/ConsumeMessageService.h new file mode 100644 index 000000000..0f8b49a85 --- /dev/null +++ b/src/main/cpp/rocketmq/include/ConsumeMessageService.h @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include + +#include "ProcessQueue.h" +#include "rocketmq/MessageListener.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ConsumeTask; + +class ConsumeMessageService { +public: + virtual ~ConsumeMessageService() = default; + + /** + * Start the dispatcher thread, which will dispatch messages in process queue to thread pool in form of runnable + * functor. + */ + virtual void start() = 0; + + /** + * Stop the dispatcher thread and then reset the thread pool. + */ + virtual void shutdown() = 0; + + virtual void dispatch(std::shared_ptr process_queue, std::vector messages) = 0; + + virtual void submit(std::shared_ptr task) = 0; + + virtual MessageListener& listener() = 0; + + virtual bool preHandle(const Message& message) = 0; + + virtual bool postHandle(const Message& message, ConsumeResult result) = 0; + + virtual void ack(const Message& message, std::function cb) = 0; + + virtual void nack(const Message& message, std::function cb) = 0; + + virtual void forward(const Message& message, std::function cb) = 0; + + virtual void schedule(std::shared_ptr task, std::chrono::milliseconds delay) = 0; + + virtual std::size_t maxDeliveryAttempt() = 0; + + virtual std::weak_ptr consumer() = 0; +}; + +using ConsumeMessageServiceWeakPtr = std::weak_ptr; +using ConsumeMessageServiceSharedPtr = std::shared_ptr; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/ConsumeMessageServiceImpl.h b/src/main/cpp/rocketmq/include/ConsumeMessageServiceImpl.h new file mode 100644 index 000000000..632a388e2 --- /dev/null +++ b/src/main/cpp/rocketmq/include/ConsumeMessageServiceImpl.h @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include + +#include "ConsumeMessageService.h" +#include "RateLimiter.h" +#include "ThreadPool.h" +#include "absl/container/flat_hash_map.h" +#include "rocketmq/State.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class PushConsumerImpl; + +class ConsumeMessageServiceImpl : public ConsumeMessageService, + public std::enable_shared_from_this { +public: + ConsumeMessageServiceImpl(std::weak_ptr consumer, + int thread_count, + MessageListener message_listener); + + ~ConsumeMessageServiceImpl() override = default; + + /** + * Make it noncopyable. + */ + ConsumeMessageServiceImpl(const ConsumeMessageServiceImpl& other) = delete; + ConsumeMessageServiceImpl& operator=(const ConsumeMessageServiceImpl& other) = delete; + + void start() override; + + void shutdown() override; + + MessageListener& listener() override { + return message_listener_; + } + + bool preHandle(const Message& message) override; + + bool postHandle(const Message& message, ConsumeResult result) override; + + void submit(std::shared_ptr task) override; + + void dispatch(std::shared_ptr process_queue, std::vector messages) override; + + void ack(const Message& message, std::function cb) override; + + void nack(const Message& message, std::function cb) override; + + void forward(const Message& message, std::function cb) override; + + void schedule(std::shared_ptr task, std::chrono::milliseconds delay) override; + + std::size_t maxDeliveryAttempt() override; + + std::weak_ptr consumer() override; + +protected: + std::atomic state_; + + int thread_count_; + std::unique_ptr pool_; + std::weak_ptr consumer_; + + MessageListener message_listener_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/ConsumeTask.h b/src/main/cpp/rocketmq/include/ConsumeTask.h new file mode 100644 index 000000000..80ca97151 --- /dev/null +++ b/src/main/cpp/rocketmq/include/ConsumeTask.h @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include + +#include "ConsumeMessageService.h" +#include "rocketmq/Message.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ProcessQueue; + +/** + * @brief Operation to take for the consume-task. + */ +enum class NextStep : std::uint8_t +{ + /** + * @brief Continue to consume the remaining messages. + */ + Consume = 0, + + /** + * @brief Ack the head, aka, messages_[0]. + */ + Ack, + + /** + * @brief Forward the head, aka, messages_[0], to dead-letter-queue. + */ + Forward, +}; + +class ConsumeTask : public std::enable_shared_from_this { +public: + ConsumeTask(ConsumeMessageServiceWeakPtr service, + std::weak_ptr process_queue, + MessageConstSharedPtr message); + + ConsumeTask(ConsumeMessageServiceWeakPtr service, + std::weak_ptr process_queue, + std::vector messages); + + void process(); + + void submit(); + + void schedule(); + +private: + ConsumeMessageServiceWeakPtr service_; + std::weak_ptr process_queue_; + std::vector messages_; + bool fifo_{false}; + NextStep next_step_{NextStep::Consume}; + + /** + * @brief messages_[0] has completed its life-cycle. + */ + void pop(); + + static void onAck(std::shared_ptr task, const std::error_code& ec); + + static void onNack(std::shared_ptr task, const std::error_code& ec); + + static void onForward(std::shared_ptr task, const std::error_code& ec); +}; + +using ConsumeTaskSharedPtr = std::shared_ptr; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/Consumer.h b/src/main/cpp/rocketmq/include/Consumer.h new file mode 100644 index 000000000..4d63fa225 --- /dev/null +++ b/src/main/cpp/rocketmq/include/Consumer.h @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "absl/container/flat_hash_map.h" +#include "absl/types/optional.h" + +#include "Client.h" +#include "ConsumeMessageService.h" +#include "FilterExpression.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class Consumer : virtual public Client { +public: + ~Consumer() override = default; + + virtual absl::optional getFilterExpression(const std::string& topic) const = 0; + + virtual uint32_t maxCachedMessageQuantity() const = 0; + + virtual uint64_t maxCachedMessageMemory() const = 0; + + virtual int32_t receiveBatchSize() const = 0; + + virtual std::shared_ptr getConsumeMessageService() = 0; + + virtual bool fifo() const = 0; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/DynamicNameServerResolver.h b/src/main/cpp/rocketmq/include/DynamicNameServerResolver.h new file mode 100644 index 000000000..5bc2c53f8 --- /dev/null +++ b/src/main/cpp/rocketmq/include/DynamicNameServerResolver.h @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include +#include + +#include "absl/base/thread_annotations.h" +#include "absl/memory/memory.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_split.h" +#include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" + +#include "NameServerResolver.h" +#include "NamingScheme.h" +#include "Scheduler.h" +#include "TopAddressing.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class DynamicNameServerResolver : public NameServerResolver, + public std::enable_shared_from_this { +public: + DynamicNameServerResolver(absl::string_view endpoint, std::chrono::milliseconds refresh_interval); + + void start() override; + + void shutdown() override; + + std::string resolve() override LOCKS_EXCLUDED(name_server_list_mtx_); + + void injectHttpClient(std::unique_ptr http_client); + +private: + std::string endpoint_; + + SchedulerSharedPtr scheduler_; + std::chrono::milliseconds refresh_interval_; + + void fetch(); + + void onNameServerListFetched(const std::vector& name_server_list) LOCKS_EXCLUDED(name_server_list_mtx_); + + std::vector name_server_list_ GUARDED_BY(name_server_list_mtx_); + absl::Mutex name_server_list_mtx_; + + std::atomic index_{0}; + + bool ssl_{false}; + std::unique_ptr top_addressing_; + + NamingScheme naming_scheme_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/MessageGroupQueueSelector.h b/src/main/cpp/rocketmq/include/MessageGroupQueueSelector.h new file mode 100644 index 000000000..dad3029be --- /dev/null +++ b/src/main/cpp/rocketmq/include/MessageGroupQueueSelector.h @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include + +#include "Protocol.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class MessageGroupQueueSelector { +public: + explicit MessageGroupQueueSelector(std::string message_group); + + rmq::MessageQueue select(const std::vector& mqs); + +private: + std::string message_group_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/include/BatchMessage.h b/src/main/cpp/rocketmq/include/NameServerResolver.h similarity index 73% rename from src/include/BatchMessage.h rename to src/main/cpp/rocketmq/include/NameServerResolver.h index bca467a00..00ec0d91e 100644 --- a/src/include/BatchMessage.h +++ b/src/main/cpp/rocketmq/include/NameServerResolver.h @@ -14,16 +14,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once -#ifndef __BATCHMESSAGE_H__ -#define __BATCHMESSAGE_H__ #include -#include "MQMessage.h" -namespace rocketmq { -class BatchMessage : public MQMessage { - public: - static std::string encode(std::vector& msgs); - static std::string encode(MQMessage& message); +#include + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class NameServerResolver { +public: + virtual ~NameServerResolver() = default; + + virtual void start() = 0; + + virtual void shutdown() = 0; + + virtual std::string resolve() = 0; }; -} // namespace rocketmq -#endif \ No newline at end of file + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/protocol/TopicList.h b/src/main/cpp/rocketmq/include/NamingScheme.h similarity index 59% rename from src/protocol/TopicList.h rename to src/main/cpp/rocketmq/include/NamingScheme.h index d8d14a763..433aef454 100644 --- a/src/protocol/TopicList.h +++ b/src/main/cpp/rocketmq/include/NamingScheme.h @@ -14,22 +14,37 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef __TOPICLIST_H__ -#define __TOPICLIST_H__ +#pragma once + #include #include -#include "dataBlock.h" -namespace rocketmq { -//& list); + + static const char* DnsPrefix; + static const char* IPv4Prefix; + static const char* IPv6Prefix; + +private: + static const char* IPv4Regex; + static const char* IPv6Regex; + + bool isIPv4(const std::string& host); + + bool isIPv6(const std::string& host); - private: - vector m_topicList; + re2::RE2 ipv4_pattern_; + re2::RE2 ipv6_pattern_; }; -// + +#include "AsyncReceiveMessageCallback.h" +#include "ConsumeMessageType.h" +#include "MessageExt.h" +#include "rocketmq/FilterExpression.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class PushConsumerImpl; + +class ClientManager; + +class ProcessQueue { +public: + virtual ~ProcessQueue() = default; + + virtual bool expired() const = 0; + + virtual void callback(std::shared_ptr callback) = 0; + + virtual void receiveMessage() = 0; + + virtual bool hasPendingMessages() const = 0; + + virtual std::string topic() const = 0; + + virtual bool take(uint32_t batch_size, std::vector& messages) = 0; + + virtual std::weak_ptr getConsumer() = 0; + + virtual const std::string& simpleName() const = 0; + + virtual void release(uint64_t body_size) = 0; + + virtual void cacheMessages(const std::vector& messages) = 0; + + virtual bool shouldThrottle() const = 0; + + virtual std::shared_ptr getClientManager() = 0; + + virtual void syncIdleState() = 0; + + virtual const FilterExpression& getFilterExpression() const = 0; + + virtual bool bindFifoConsumeTask() = 0; + + virtual bool unbindFifoConsumeTask() = 0; + + virtual const rmq::MessageQueue& messageQueue() const = 0; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/ProcessQueueImpl.h b/src/main/cpp/rocketmq/include/ProcessQueueImpl.h new file mode 100644 index 000000000..64797180c --- /dev/null +++ b/src/main/cpp/rocketmq/include/ProcessQueueImpl.h @@ -0,0 +1,176 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include +#include + +#include "ClientManager.h" +#include "MessageExt.h" +#include "MixAll.h" +#include "ProcessQueue.h" +#include "ReceiveMessageCallback.h" +#include "TopicAssignmentInfo.h" +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "gtest/gtest_prod.h" +#include "rocketmq/FilterExpression.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class PushConsumerImpl; + +/** + * @brief Once messages are fetched(either pulled or popped) from remote server, they are firstly put into cache. + * Dispatcher thread, after waking up, will submit them into thread-pool. Messages at this phase are called "inflight" + * state. Once messages are processed by user-passed-in callback, their quota will be released for future incoming + * messages. + */ +class ProcessQueueImpl : virtual public ProcessQueue { +public: + ProcessQueueImpl(rmq::MessageQueue message_queue, + FilterExpression filter_expression, + std::weak_ptr consumer, + std::shared_ptr client_instance); + + ~ProcessQueueImpl() override; + + void callback(std::shared_ptr callback) override; + + bool expired() const override; + + bool shouldThrottle() const override LOCKS_EXCLUDED(messages_mtx_); + + const FilterExpression& getFilterExpression() const override; + + std::weak_ptr getConsumer() override; + + std::shared_ptr getClientManager() override; + + void receiveMessage() override; + + const std::string& simpleName() const override { + return simple_name_; + } + + std::string topic() const override { + return message_queue_.topic().name(); + } + + bool hasPendingMessages() const override LOCKS_EXCLUDED(messages_mtx_); + + /** + * Put message fetched from broker into cache. + * + * @param messages + */ + void cacheMessages(const std::vector& messages) override LOCKS_EXCLUDED(messages_mtx_); + + /** + * @return Number of messages that is not yet dispatched to thread pool, likely, due to topic-rate-limiting. + */ + uint32_t cachedMessagesSize() const LOCKS_EXCLUDED(messages_mtx_) { + absl::MutexLock lk(&messages_mtx_); + return cached_messages_.size(); + } + + /** + * Dispatch messages from cache to thread pool in form of consumeTask. + * @param batch_size + * @param messages + * @return true if there are more messages to consume in cache + */ + bool take(uint32_t batch_size, std::vector& messages) override LOCKS_EXCLUDED(messages_mtx_); + + void syncIdleState() override { + idle_since_ = std::chrono::steady_clock::now(); + } + + void release(uint64_t body_size) override LOCKS_EXCLUDED(messages_mtx_); + + bool unbindFifoConsumeTask() override { + bool expected = true; + return has_fifo_task_bound_.compare_exchange_strong(expected, false, std::memory_order_relaxed); + } + + bool bindFifoConsumeTask() override { + bool expected = false; + return has_fifo_task_bound_.compare_exchange_strong(expected, true, std::memory_order_relaxed); + } + + const rmq::MessageQueue& messageQueue() const override { + return message_queue_; + } + +private: + rmq::MessageQueue message_queue_; + + /** + * Expression used to filter message in the server side. + */ + const FilterExpression filter_expression_; + + std::chrono::milliseconds invisible_time_; + + std::chrono::steady_clock::time_point idle_since_{std::chrono::steady_clock::now()}; + + absl::Time create_timestamp_{absl::Now()}; + + std::string simple_name_; + + std::weak_ptr consumer_; + std::shared_ptr client_manager_; + + std::shared_ptr receive_callback_; + + /** + * Messages that are pending to be submitted to thread pool. + */ + mutable std::vector cached_messages_ GUARDED_BY(messages_mtx_); + + mutable absl::Mutex messages_mtx_; + + /** + * @brief Quantity of the cached messages. + * + */ + std::atomic cached_message_quantity_; + + /** + * @brief Total body memory size of the cached messages. + * + */ + std::atomic cached_message_memory_; + + /** + * If this process queue is used in FIFO scenario, this field marks if there is an task in thread pool. + */ + std::atomic_bool has_fifo_task_bound_{false}; + + void popMessage(); + void wrapPopMessageRequest(absl::flat_hash_map& metadata, + rmq::ReceiveMessageRequest& request); + + void wrapFilterExpression(rmq::FilterExpression* filter_expression); + + FRIEND_TEST(ProcessQueueTest, testExpired); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/ProducerImpl.h b/src/main/cpp/rocketmq/include/ProducerImpl.h new file mode 100644 index 000000000..a50c6ef82 --- /dev/null +++ b/src/main/cpp/rocketmq/include/ProducerImpl.h @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include +#include + +#include "ClientImpl.h" +#include "ClientManagerImpl.h" +#include "MixAll.h" +#include "PublishInfoCallback.h" +#include "SendContext.h" +#include "TopicPublishInfo.h" +#include "TransactionImpl.h" +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "absl/strings/string_view.h" +#include "rocketmq/Message.h" +#include "rocketmq/SendCallback.h" +#include "rocketmq/SendReceipt.h" +#include "rocketmq/State.h" +#include "rocketmq/TransactionChecker.h" +#include "PublishStats.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ProducerImpl : virtual public ClientImpl, public std::enable_shared_from_this { +public: + explicit ProducerImpl(); + + ~ProducerImpl() override; + + void prepareHeartbeatData(HeartbeatRequest& request) override; + + void start() override; + + void shutdown() override; + + SendReceipt send(MessageConstPtr message, std::error_code& ec) noexcept; + + void send(MessageConstPtr message, SendCallback callback); + + void setTransactionChecker(TransactionChecker checker); + + std::unique_ptr prepare(MessageConstPtr message, std::error_code& ec); + + bool commit(const Transaction& transaction); + + bool rollback(const Transaction& transaction); + + /** + * Check if the RPC client for the target host is isolated or not + * @param endpoint Address of target host. + * @return true if client is active; false otherwise. + */ + bool isEndpointIsolated(const std::string& endpoint) LOCKS_EXCLUDED(isolated_endpoints_mtx_); + + /** + * Note: This function is purpose-made public such that the whole isolate/add-back mechanism can be properly tested. + * @param target Endpoint of the target host + */ + void isolateEndpoint(const std::string& target) LOCKS_EXCLUDED(isolated_endpoints_mtx_); + + std::size_t maxAttemptTimes() const { + return max_attempt_times_; + } + + void maxAttemptTimes(std::size_t times) { + max_attempt_times_ = times; + } + + int getFailedTimes() const { + return failed_times_; + } + + void setFailedTimes(int times) { + failed_times_ = times; + } + + uint32_t compressBodyThreshold() const { + return compress_body_threshold_; + } + + void compressBodyThreshold(uint32_t threshold) { + compress_body_threshold_ = threshold; + } + + void sendImpl(std::shared_ptr callback); + + void buildClientSettings(rmq::Settings& settings) override; + + void topicsOfInterest(std::vector topics) + LOCKS_EXCLUDED(topics_mtx_); + + const PublishStats& stats() const { return stats_; } + +protected: + std::shared_ptr self() override { + return shared_from_this(); + } + + void onOrphanedTransactionalMessage(MessageConstSharedPtr message) override; + + void notifyClientTermination() override; + +private: + absl::flat_hash_map topic_publish_info_table_ GUARDED_BY(topic_publish_info_mtx_); + absl::Mutex topic_publish_info_mtx_; // protects topic_publish_info_ + std::size_t max_attempt_times_{MixAll::MAX_SEND_MESSAGE_ATTEMPT_TIMES_}; + int32_t failed_times_{0}; // only for test + uint32_t compress_body_threshold_; + TransactionChecker transaction_checker_; + std::vector topics_ GUARDED_BY(topics_mtx_); + absl::Mutex topics_mtx_; + + PublishStats stats_; + + /** + * @brief Acquire PublishInfo for the given topic. + * Generally speaking, it first checks presence of the desired info in local cache, aka, topic_publish_table_; + * If not found, query name servers. + */ + void getPublishInfoAsync(const std::string& topic, const PublishInfoCallback& cb) + LOCKS_EXCLUDED(topic_publish_info_mtx_); + + void cachePublishInfo(const std::string&, TopicPublishInfoPtr info) LOCKS_EXCLUDED(topic_publish_info_mtx_); + + TopicPublishInfoPtr getPublishInfo(const std::string& topic); + + void wrapSendMessageRequest(const Message& message, + SendMessageRequest& request, + const rmq::MessageQueue& message_queue); + + bool isRunning() const; + + void ensureRunning(std::error_code& ec) const noexcept; + + bool validate(const Message& message); + + void send0(MessageConstPtr message, SendCallback callback, std::vector list); + + bool endTransaction0(const Transaction& transaction, TransactionState resolution); + + void isolatedEndpoints(absl::flat_hash_set& endpoints) LOCKS_EXCLUDED(isolated_endpoints_mtx_); + + friend class ProducerBuilder; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/PublishInfoCallback.h b/src/main/cpp/rocketmq/include/PublishInfoCallback.h new file mode 100644 index 000000000..a4d7a6e25 --- /dev/null +++ b/src/main/cpp/rocketmq/include/PublishInfoCallback.h @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include + +#include "TopicPublishInfo.h" + +ROCKETMQ_NAMESPACE_BEGIN + +using PublishInfoCallback = std::function; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/PushConsumerImpl.h b/src/main/cpp/rocketmq/include/PushConsumerImpl.h new file mode 100644 index 000000000..0067009a9 --- /dev/null +++ b/src/main/cpp/rocketmq/include/PushConsumerImpl.h @@ -0,0 +1,225 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include + +#include "ClientConfig.h" +#include "ClientImpl.h" +#include "ClientManagerImpl.h" +#include "ConsumeMessageService.h" +#include "ConsumeStats.h" +#include "ProcessQueue.h" +#include "Scheduler.h" +#include "TopicAssignmentInfo.h" +#include "TopicPublishInfo.h" +#include "UtilAll.h" +#include "absl/strings/string_view.h" +#include "rocketmq/Executor.h" +#include "rocketmq/FilterExpression.h" +#include "rocketmq/State.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ConsumeMessageService; +class ConsumeFifoMessageService; +class ConsumeStandardMessageService; + +class PushConsumerImpl : virtual public ClientImpl, public std::enable_shared_from_this { +public: + explicit PushConsumerImpl(absl::string_view group_name); + + ~PushConsumerImpl() override; + + void buildClientSettings(rmq::Settings& settings) override LOCKS_EXCLUDED(topic_filter_expression_table_mtx_); + + void prepareHeartbeatData(HeartbeatRequest& request) override; + + void topicsOfInterest(std::vector& topics) override LOCKS_EXCLUDED(topic_filter_expression_table_mtx_); + + void start() override; + + void shutdown() override; + + void subscribe(const std::string& topic, + const std::string& expression, + ExpressionType expression_type = ExpressionType::TAG) + LOCKS_EXCLUDED(topic_filter_expression_table_mtx_); + + void unsubscribe(const std::string& topic) LOCKS_EXCLUDED(topic_filter_expression_table_mtx_); + + absl::optional getFilterExpression(const std::string& topic) const + LOCKS_EXCLUDED(topic_filter_expression_table_mtx_); + + void registerMessageListener(MessageListener message_listener); + + void scanAssignments() LOCKS_EXCLUDED(topic_filter_expression_table_mtx_); + + static bool selectBroker(const TopicRouteDataPtr& route, std::string& broker_host); + + void wrapQueryAssignmentRequest(const std::string& topic, + const std::string& consumer_group, + const std::string& strategy_name, + QueryAssignmentRequest& request); + + /** + * Query assignment of the specified topic from load balancer directly if + * message consuming mode is clustering. In case current client is operating + * in the broadcasting mode, assignments are constructed locally from topic + * route entries. + * + * @param topic Topic to query + * @return shared pointer to topic assignment info + */ + void queryAssignment(const std::string& topic, + const std::function& cb); + + void syncProcessQueue(const std::string& topic, + const TopicAssignmentPtr& topic_assignment, + const FilterExpression& filter_expression) LOCKS_EXCLUDED(process_queue_table_mtx_); + + std::shared_ptr getOrCreateProcessQueue(const rmq::MessageQueue& message_queue, + const FilterExpression& filter_expression) + LOCKS_EXCLUDED(process_queue_table_mtx_); + + bool receiveMessage(const rmq::MessageQueue& message_queue, const FilterExpression& filter_expression) + LOCKS_EXCLUDED(process_queue_table_mtx_); + + uint32_t consumeThreadPoolSize() const; + + void consumeThreadPoolSize(int thread_pool_size); + + int32_t maxDeliveryAttempts() const { + return max_delivery_attempts_; + } + + int32_t receiveBatchSize() const { + return receive_batch_size_; + } + + std::shared_ptr getConsumeMessageService(); + + void ack(const Message& msg, const std::function& callback); + + void nack(const Message& message, const std::function& callback); + + void forwardToDeadLetterQueue(const Message& message, const std::function& cb); + + void wrapAckMessageRequest(const Message& msg, AckMessageRequest& request); + + // only for test + std::size_t getProcessQueueTableSize() LOCKS_EXCLUDED(process_queue_table_mtx_); + + void setCustomExecutor(const Executor& executor) { + custom_executor_ = executor; + } + + const Executor& customExecutor() const { + return custom_executor_; + } + + void setThrottle(const std::string& topic, uint32_t threshold); + + /** + * Max number of messages that may be cached per queue before applying + * back-pressure. + * @return + */ + uint32_t maxCachedMessageQuantity() const { + return MixAll::DEFAULT_CACHED_MESSAGE_COUNT; + } + + /** + * Threshold of total cached message body size by queue before applying + * back-pressure. + * @return + */ + uint64_t maxCachedMessageMemory() const { + return MixAll::DEFAULT_CACHED_MESSAGE_MEMORY; + } + + MessageListener& messageListener() { + return message_listener_; + } + + const std::string& groupName() const { + return client_config_.subscriber.group.name(); + } + + const ConsumeStats& stats() const { + return stats_; + } + +protected: + std::shared_ptr self() override { + return shared_from_this(); + } + + void notifyClientTermination() override; + + void onVerifyMessage(MessageConstSharedPtr, std::function) override; + +private: + absl::flat_hash_map topic_filter_expression_table_ + GUARDED_BY(topic_filter_expression_table_mtx_); + mutable absl::Mutex topic_filter_expression_table_mtx_; + + /** + * Consume message thread pool size. + */ + uint32_t consume_thread_pool_size_{MixAll::DEFAULT_CONSUME_THREAD_POOL_SIZE}; + + MessageListener message_listener_; + + std::shared_ptr consume_message_service_; + uint32_t consume_batch_size_{MixAll::DEFAULT_CONSUME_MESSAGE_BATCH_SIZE}; + + int32_t receive_batch_size_{MixAll::DEFAULT_RECEIVE_MESSAGE_BATCH_SIZE}; + + std::uintptr_t scan_assignment_handle_{0}; + static const char* SCAN_ASSIGNMENT_TASK_NAME; + + /** + * simple-queue-name ==> process-queue + */ + absl::flat_hash_map> process_queue_table_ + GUARDED_BY(process_queue_table_mtx_); + absl::Mutex process_queue_table_mtx_; + + Executor custom_executor_; + + absl::flat_hash_map throttle_table_ + GUARDED_BY(throttle_table_mtx_); + absl::Mutex throttle_table_mtx_; + + int32_t max_delivery_attempts_{MixAll::DEFAULT_MAX_DELIVERY_ATTEMPTS}; + + ConsumeStats stats_; + + void fetchRoutes() LOCKS_EXCLUDED(topic_filter_expression_table_mtx_); + + std::chrono::milliseconds invisibleDuration(std::size_t attempt); + + friend class ConsumeMessageService; + friend class ConsumeFifoMessageService; + friend class ConsumeStandardMessageService; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/SendContext.h b/src/main/cpp/rocketmq/include/SendContext.h new file mode 100644 index 000000000..4c05cebeb --- /dev/null +++ b/src/main/cpp/rocketmq/include/SendContext.h @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/synchronization/mutex.h" +#include "opencensus/trace/span.h" + +#include "Protocol.h" +#include "TransactionImpl.h" +#include "rocketmq/ErrorCode.h" +#include "rocketmq/Message.h" +#include "rocketmq/SendCallback.h" +#include "rocketmq/SendReceipt.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ProducerImpl; + +class SendContext : public std::enable_shared_from_this { +public: + SendContext(std::weak_ptr producer, + MessageConstPtr message, + SendCallback callback, + std::vector candidates) + : producer_(std::move(producer)), + message_(std::move(message)), + callback_(std::move(callback)), + candidates_(std::move(candidates)), + span_(opencensus::trace::Span::BlankSpan()) { + } + + void onSuccess(const SendReceipt& send_receipt) noexcept; + + void onFailure(const std::error_code& ec) noexcept; + + const rmq::MessageQueue& messageQueue() const { + int index = attempt_times_ % candidates_.size(); + return candidates_[index]; + } + + std::weak_ptr producer_; + MessageConstPtr message_; + std::size_t attempt_times_{0}; + SendCallback callback_; + + /** + * @brief Once the first publish attempt failed, the following routable + * message queues are employed. + * + */ + std::vector candidates_; + + /** + * @brief The on-going span. Should be terminated in the callback functions. + */ + opencensus::trace::Span span_; + + std::chrono::steady_clock::time_point request_time_{std::chrono::steady_clock::now()}; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/SimpleConsumerImpl.h b/src/main/cpp/rocketmq/include/SimpleConsumerImpl.h new file mode 100644 index 000000000..5a5a1b9a6 --- /dev/null +++ b/src/main/cpp/rocketmq/include/SimpleConsumerImpl.h @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "ClientImpl.h" +#include "rocketmq/FilterExpression.h" +#include "rocketmq/SimpleConsumer.h" + +using namespace std::chrono; +ROCKETMQ_NAMESPACE_BEGIN + +class SimpleConsumerImpl : public ClientImpl, public std::enable_shared_from_this { +public: + SimpleConsumerImpl(std::string group); + + ~SimpleConsumerImpl() override; + + void prepareHeartbeatData(rmq::HeartbeatRequest& request) override; + + void buildClientSettings(rmq::Settings& settings) override; + + std::shared_ptr self() override { + return shared_from_this(); + } + + void start() override; + + void shutdown() override; + + void subscribe(std::string topic, FilterExpression expression) LOCKS_EXCLUDED(subscriptions_mtx_); + + void unsubscribe(const std::string& topic) LOCKS_EXCLUDED(subscriptions_mtx_); + + void receive(std::size_t limit, std::chrono::milliseconds invisible_duration, ReceiveCallback callback); + + void ack(const Message& message, std::error_code& ec); + + void ackAsync(const Message& message, AckCallback callback); + + void changeInvisibleDuration(const Message& message, + std::chrono::milliseconds duration, + ChangeInvisibleDurationCallback callback); + +protected: + void topicsOfInterest(std::vector& topics) override; + +private: + absl::flat_hash_map subscriptions_ GUARDED_BY(subscriptions_mtx_); + absl::Mutex subscriptions_mtx_; + + absl::flat_hash_map> topic_assignments_ GUARDED_BY(topic_assignments_mtx_); + absl::Mutex topic_assignments_mtx_; + + std::vector assignments_; + absl::Mutex assignments_mtx_ ACQUIRED_AFTER(topic_assignments_mtx_); + + std::size_t refresh_assignment_task_{0}; + + static thread_local std::size_t assignment_index_; + + void refreshAssignments0() LOCKS_EXCLUDED(topic_assignments_mtx_, subscriptions_mtx_); + + void refreshAssignments() LOCKS_EXCLUDED(subscriptions_mtx_); + + void refreshAssignment(const std::string& topic, std::function cb); + + void updateAssignments(const std::string& topic, const std::vector& assignments) + LOCKS_EXCLUDED(assignments_mtx_, topic_assignments_mtx_); + + void wrapAckRequest(const Message& message, AckMessageRequest& request); + + void removeAssignmentsByTopic(const std::string& topic) LOCKS_EXCLUDED(topic_assignments_mtx_, assignments_mtx_); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/extern/CBatchMessage.cpp b/src/main/cpp/rocketmq/include/StaticNameServerResolver.h similarity index 51% rename from src/extern/CBatchMessage.cpp rename to src/main/cpp/rocketmq/include/StaticNameServerResolver.h index 3fb2a977f..b38a86e6a 100644 --- a/src/extern/CBatchMessage.cpp +++ b/src/main/cpp/rocketmq/include/StaticNameServerResolver.h @@ -14,46 +14,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once -#include +#include "absl/strings/string_view.h" -#include "CBatchMessage.h" -#include "CCommon.h" -#include "CMessage.h" -#include "MQMessage.h" +#include "NameServerResolver.h" +#include "NamingScheme.h" -using std::vector; +ROCKETMQ_NAMESPACE_BEGIN -#ifdef __cplusplus -extern "C" { -#endif +class StaticNameServerResolver : public NameServerResolver { +public: + explicit StaticNameServerResolver(absl::string_view name_server_list); -using namespace rocketmq; - -CBatchMessage* CreateBatchMessage() { - vector* msgs = new vector(); - return (CBatchMessage*)msgs; -} - -int AddMessage(CBatchMessage* batchMsg, CMessage* msg) { - if (msg == NULL) { - return NULL_POINTER; - } - if (batchMsg == NULL) { - return NULL_POINTER; + void start() override { } - MQMessage* message = (MQMessage*)msg; - ((vector*)batchMsg)->push_back(*message); - return OK; -} -int DestroyBatchMessage(CBatchMessage* batchMsg) { - if (batchMsg == NULL) { - return NULL_POINTER; + + void shutdown() override { } - delete (vector*)batchMsg; - return OK; -} -#ifdef __cplusplus + std::string resolve() override; + +private: + /** + * @brief Name server addresses, following gRPC URI schemes described in + * https://github.com/grpc/grpc/blob/master/doc/naming.md + * + * Sample values are: + * dns:[//authority/]host[:port] + * ipv4:address[:port][,address[:port],...] + * ipv6:address[:port][,address[:port],...] + */ + std::string name_server_address_; + + NamingScheme naming_scheme_; }; -#endif + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/TopicPublishInfo.h b/src/main/cpp/rocketmq/include/TopicPublishInfo.h new file mode 100644 index 000000000..b4c37b501 --- /dev/null +++ b/src/main/cpp/rocketmq/include/TopicPublishInfo.h @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include + +#include "TopicRouteData.h" +#include "absl/base/thread_annotations.h" +#include "absl/container/flat_hash_set.h" +#include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" +#include "absl/types/optional.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ProducerImpl; + +class TopicPublishInfo { +public: + TopicPublishInfo(std::weak_ptr producer, absl::string_view topic, TopicRouteDataPtr topic_route_data); + + bool selectMessageQueues(absl::optional message_group, std::vector& result) + LOCKS_EXCLUDED(queue_list_mtx_); + + void topicRouteData(TopicRouteDataPtr topic_route_data); + + /** + * Expose queue list in perspective of message queue list. + * + * @return + */ + std::vector getMessageQueueList() LOCKS_EXCLUDED(queue_list_mtx_); + +private: + std::vector queue_list_ GUARDED_BY(queue_list_mtx_); + absl::Mutex queue_list_mtx_; // protects message_queue_list_ + std::weak_ptr producer_; + std::string topic_; + TopicRouteDataPtr topic_route_data_; + + void updatePublishInfo(); + + thread_local static uint32_t send_which_queue_; +}; + +using TopicPublishInfoPtr = std::shared_ptr; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/include/TransactionImpl.h b/src/main/cpp/rocketmq/include/TransactionImpl.h new file mode 100644 index 000000000..ce633ed9e --- /dev/null +++ b/src/main/cpp/rocketmq/include/TransactionImpl.h @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include + +#include "rocketmq/Message.h" +#include "rocketmq/Transaction.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ProducerImpl; + +class TransactionImpl : public Transaction { +public: + TransactionImpl(std::string topic, std::string message_id, std::string trace_context, const std::weak_ptr& producer) + : topic_(std::move(topic)), message_id_(std::move(message_id)), trace_context_(std::move(trace_context)), producer_(producer) { + } + + ~TransactionImpl() override = default; + + bool commit() override; + + bool rollback() override; + + const std::string& messageId() const override; + + const std::string& transactionId() const override; + + void transactionId(std::string transaction_id) { + transaction_id_ = std::move(transaction_id); + } + + const std::string& traceContext() const override { + return trace_context_; + } + + void traceContext(std::string trace_context) { + trace_context_ = std::move(trace_context); + } + + const std::string& endpoint() const override { + return endpoint_; + } + + void endpoint(std::string endpoint) { endpoint_ = std::move(endpoint); } + + const std::string& topic() const override { + return topic_; + } + +private: + std::string topic_; + std::string message_id_; + std::string transaction_id_; + std::string endpoint_; + std::string trace_context_; + std::weak_ptr producer_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/mocks/BUILD.bazel b/src/main/cpp/rocketmq/mocks/BUILD.bazel new file mode 100644 index 000000000..21262fabc --- /dev/null +++ b/src/main/cpp/rocketmq/mocks/BUILD.bazel @@ -0,0 +1,28 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_library") +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "rocketmq_mocks", + hdrs = glob(["include/*.h"]), + strip_include_prefix = "//src/main/cpp/rocketmq/mocks/include", + deps = [ + "//src/main/cpp/rocketmq:rocketmq_library", + "//src/main/cpp/client/mocks:client_mocks", + ], +) \ No newline at end of file diff --git a/src/main/cpp/rocketmq/mocks/include/ConsumeMessageServiceMock.h b/src/main/cpp/rocketmq/mocks/include/ConsumeMessageServiceMock.h new file mode 100644 index 000000000..9811a8ce1 --- /dev/null +++ b/src/main/cpp/rocketmq/mocks/include/ConsumeMessageServiceMock.h @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "ConsumeMessageService.h" + +#include "gmock/gmock.h" + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ConsumeMessageServiceMock : public ConsumeMessageService { +public: + MOCK_METHOD(void, start, (), (override)); + + MOCK_METHOD(void, shutdown, (), (override)); + + MOCK_METHOD(void, submitConsumeTask, (const std::weak_ptr&), (override)); + + MOCK_METHOD(void, signalDispatcher, (), (override)); + + MOCK_METHOD(void, throttle, (const std::string&, std::uint32_t), (override)); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/mocks/include/ConsumerMock.h b/src/main/cpp/rocketmq/mocks/include/ConsumerMock.h new file mode 100644 index 000000000..9ed217ef0 --- /dev/null +++ b/src/main/cpp/rocketmq/mocks/include/ConsumerMock.h @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "ClientMock.h" +#include "Consumer.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ConsumerMock : virtual public Consumer, virtual public ClientMock { +public: + MOCK_METHOD((absl::optional), getFilterExpression, (const std::string&), (const override)); + + MOCK_METHOD(uint32_t, maxCachedMessageQuantity, (), (const override)); + + MOCK_METHOD(uint64_t, maxCachedMessageMemory, (), (const override)); + + MOCK_METHOD(int32_t, receiveBatchSize, (), (const override)); + + MOCK_METHOD(std::shared_ptr, getConsumeMessageService, (), (override)); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/mocks/include/NameServerResolverMock.h b/src/main/cpp/rocketmq/mocks/include/NameServerResolverMock.h new file mode 100644 index 000000000..4f8f7f3fd --- /dev/null +++ b/src/main/cpp/rocketmq/mocks/include/NameServerResolverMock.h @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "NameServerResolver.h" +#include "gmock/gmock.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class NameServerResolverMock : public NameServerResolver { +public: + MOCK_METHOD(void, start, (), (override)); + + MOCK_METHOD(void, shutdown, (), (override)); + + MOCK_METHOD(std::string, resolve, (), (override)); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/mocks/include/ProcessQueueMock.h b/src/main/cpp/rocketmq/mocks/include/ProcessQueueMock.h new file mode 100644 index 000000000..4ae20860d --- /dev/null +++ b/src/main/cpp/rocketmq/mocks/include/ProcessQueueMock.h @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ProcessQueue.h" +#include "gmock/gmock.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ProcessQueueMock : public ProcessQueue { +public: + MOCK_METHOD(bool, expired, (), (const override)); + + MOCK_METHOD(void, callback, (std::shared_ptr), (override)); + + MOCK_METHOD(void, receiveMessage, (), (override)); + + MOCK_METHOD(void, nextOffset, (int64_t), (override)); + + MOCK_METHOD(bool, hasPendingMessages, (), (const override)); + + MOCK_METHOD(std::string, topic, (), (const override)); + + MOCK_METHOD(bool, take, (uint32_t, (std::vector&)), (override)); + + MOCK_METHOD(std::weak_ptr, getConsumer, (), (override)); + + MOCK_METHOD(const std::string&, simpleName, (), (const override)); + + MOCK_METHOD(bool, committedOffset, (int64_t&), (override)); + + MOCK_METHOD(void, release, (uint64_t, int64_t), (override)); + + MOCK_METHOD(void, cacheMessages, (const std::vector&), (override)); + + MOCK_METHOD(bool, shouldThrottle, (), (const override)); + + MOCK_METHOD((std::shared_ptr), getClientManager, (), (override)); + + MOCK_METHOD(void, syncIdleState, (), (override)); + + MOCK_METHOD(const FilterExpression&, getFilterExpression, (), (const override)); + + MOCK_METHOD(bool, bindFifoConsumeTask, (), (override)); + + MOCK_METHOD(bool, unbindFifoConsumeTask, (), (override)); + + MOCK_METHOD(MQMessageQueue, getMQMessageQueue, (), (override)); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/mocks/include/PushConsumerMock.h b/src/main/cpp/rocketmq/mocks/include/PushConsumerMock.h new file mode 100644 index 000000000..c6050aec3 --- /dev/null +++ b/src/main/cpp/rocketmq/mocks/include/PushConsumerMock.h @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include + +#include "ConsumerMock.h" +#include "PushConsumer.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class PushConsumerMock : virtual public PushConsumer, virtual public ConsumerMock { +public: + MOCK_METHOD(MessageModel, messageModel, (), (const override)); + + MOCK_METHOD(void, ack, (const MQMessageExt&, const std::function&), (override)); + + MOCK_METHOD(void, forwardToDeadLetterQueue, (const MQMessageExt&, const std::function&), (override)); + + MOCK_METHOD(const Executor&, customExecutor, (), (const override)); + + MOCK_METHOD(uint32_t, consumeBatchSize, (), (const override)); + + MOCK_METHOD(int32_t, maxDeliveryAttempts, (), (const override)); + + MOCK_METHOD(void, updateOffset, (const MQMessageQueue&, int64_t), (override)); + + MOCK_METHOD(bool, receiveMessage, (const MQMessageQueue&, const FilterExpression&), (override)); + + MOCK_METHOD(MessageListener*, messageListener, (), (override)); + + MOCK_METHOD(void, setOffsetStore, (std::unique_ptr), (override)); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/libs/signature/CMakeLists.txt b/src/main/cpp/rocketmq/tests/BUILD.bazel old mode 100755 new mode 100644 similarity index 62% rename from libs/signature/CMakeLists.txt rename to src/main/cpp/rocketmq/tests/BUILD.bazel index 0348e48e8..83f627163 --- a/libs/signature/CMakeLists.txt +++ b/src/main/cpp/rocketmq/tests/BUILD.bazel @@ -1,29 +1,38 @@ +# # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_test") -project(signature) - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) -set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib) - -aux_source_directory(src/ DIR_LIB_SRCS) +base_deps = [ + "//src/main/cpp/rocketmq:rocketmq_library", + "@com_google_googletest//:gtest_main", +] -add_library(Signature STATIC ${DIR_LIB_SRCS}) -target_link_libraries(Signature ${deplibs}) -set_target_properties(Signature PROPERTIES OUTPUT_NAME "Signature") +cc_test( + name = "time_test", + srcs = [ + "TimeTest.cpp", + ], + deps = base_deps, +) -# install -install(TARGETS Signature DESTINATION lib) -#install (DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION include/rocketmq) +cc_test( + name = "send_context_test", + srcs = [ + "SendContextTest.cpp", + ], + deps = base_deps, +) diff --git a/src/main/cpp/rocketmq/tests/SendContextTest.cpp b/src/main/cpp/rocketmq/tests/SendContextTest.cpp new file mode 100644 index 000000000..3c29c2cd0 --- /dev/null +++ b/src/main/cpp/rocketmq/tests/SendContextTest.cpp @@ -0,0 +1,17 @@ +#include + +#include "SendContext.h" +#include "gtest/gtest.h" + +ROCKETMQ_NAMESPACE_BEGIN + +TEST(SendContextTest, testBasics) { + auto message = Message::newBuilder().withBody("body").withTopic("topic").withGroup("group0").withTag("TagA").build(); + auto callback = [](const std::error_code&, const SendReceipt&) {}; + std::weak_ptr producer; + std::vector message_queues; + auto send_context = std::make_shared(producer, std::move(message), callback, message_queues); + send_context.reset(); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/rocketmq/tests/TimeTest.cpp b/src/main/cpp/rocketmq/tests/TimeTest.cpp new file mode 100644 index 000000000..898aef02c --- /dev/null +++ b/src/main/cpp/rocketmq/tests/TimeTest.cpp @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "absl/time/time.h" +#include "gtest/gtest.h" +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +TEST(TimeTest, testTimeHelpers) { + auto duration = absl::Seconds(1) + absl::Nanoseconds(100); + auto seconds = absl::ToInt64Seconds(duration); + ASSERT_EQ(1, seconds); + ASSERT_EQ(100, absl::ToInt64Nanoseconds(duration - absl::Seconds(seconds))); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/scheduler/BUILD.bazel b/src/main/cpp/scheduler/BUILD.bazel new file mode 100644 index 000000000..9997c630a --- /dev/null +++ b/src/main/cpp/scheduler/BUILD.bazel @@ -0,0 +1,32 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_library") +cc_library( + name = "scheduler_library", + hdrs = glob(["include/*.h"]), + srcs = glob(["*.cpp"]), + strip_include_prefix = "//src/main/cpp/scheduler/include", + deps = [ + "//api:rocketmq_interface", + "//src/main/cpp/log:log_library", + "@com_google_absl//absl/base", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/container:flat_hash_map", + "@asio//:asio", + ], + visibility = ["//visibility:public"], +) \ No newline at end of file diff --git a/src/main/cpp/scheduler/SchedulerImpl.cpp b/src/main/cpp/scheduler/SchedulerImpl.cpp new file mode 100644 index 000000000..7eb4da384 --- /dev/null +++ b/src/main/cpp/scheduler/SchedulerImpl.cpp @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "SchedulerImpl.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "absl/memory/memory.h" +#include "asio/error_code.hpp" +#include "asio/executor_work_guard.hpp" +#include "asio/io_context.hpp" +#include "asio/steady_timer.hpp" +#include "spdlog/spdlog.h" + +ROCKETMQ_NAMESPACE_BEGIN + +SchedulerImpl::SchedulerImpl(std::uint32_t worker_num) + : work_guard_( + absl::make_unique>(context_.get_executor())), + worker_num_(worker_num) { +} + +SchedulerImpl::SchedulerImpl() : SchedulerImpl(std::thread::hardware_concurrency()) { +} + +SchedulerImpl::~SchedulerImpl() { + shutdown0(); +} + +void SchedulerImpl::start() { + State expected = State::CREATED; + if (state_.compare_exchange_strong(expected, State::STARTING, std::memory_order_relaxed)) { + for (std::uint32_t i = 0; i < worker_num_; i++) { + auto worker = std::thread([this]() { + { + State expect = State::STARTING; + if (state_.compare_exchange_strong(expect, State::STARTED, std::memory_order_relaxed)) { + absl::MutexLock lk(&start_mtx_); + start_cv_.SignalAll(); + } + } + + while (true) { +#ifdef __EXCEPTIONS + try { +#endif + std::error_code ec; + context_.run(ec); + if (ec) { + SPDLOG_WARN("Error raised from thread-pool: {}", ec.message()); + } +#ifdef __EXCEPTIONS + } catch (std::exception& e) { + SPDLOG_WARN("Exception raised from thread-pool: {}", e.what()); + } +#endif + + if (State::STARTED != state_.load(std::memory_order_relaxed)) { + SPDLOG_INFO("One scheduler worker thread quit"); + break; + } + } + }); + threads_.emplace_back(std::move(worker)); + } + + { + absl::MutexLock lk(&start_mtx_); + if (State::STARTING == state_.load(std::memory_order_relaxed)) { + start_cv_.Wait(&start_mtx_); + SPDLOG_INFO("Scheduler threads start to loop"); + } + } + } +} + +void SchedulerImpl::shutdown() { + shutdown0(); +} + +void SchedulerImpl::shutdown0() { + State expected = State::STARTED; + if (state_.compare_exchange_strong(expected, State::STOPPING, std::memory_order_relaxed)) { + work_guard_->reset(); + { + absl::MutexLock lk(&tasks_mtx_); + tasks_.clear(); + } + context_.stop(); + + for (auto& worker : threads_) { + if (worker.joinable()) { + worker.join(); + } + } + threads_.clear(); + + state_.store(State::STOPPED); + } +} + +std::uint32_t SchedulerImpl::schedule(const std::function& functor, const std::string& task_name, + std::chrono::milliseconds delay, std::chrono::milliseconds interval) { + static std::uint32_t task_id = 0; + + auto task = std::make_shared(); + task->task_name = task_name; + task->callback = functor; + task->interval = interval; + + std::uint32_t id; + { + absl::MutexLock lk(&tasks_mtx_); + id = ++task_id; + tasks_.insert({id, task}); + } + task->task_id = id; + task->timer = absl::make_unique(context_, delay); + task->scheduler = shared_from_this(); + SPDLOG_DEBUG("Timer-task[name={}] to fire in {}ms", task_name, delay.count()); + auto timer_task_weak_ptr = std::weak_ptr(task); + task->timer->async_wait(std::bind(&SchedulerImpl::execute, std::placeholders::_1, timer_task_weak_ptr)); + return id; +} + +void SchedulerImpl::cancel(std::uint32_t task_id) { + absl::MutexLock lk(&tasks_mtx_); + if (!tasks_.contains(task_id)) { + SPDLOG_ERROR("Scheduler does not have the task to delete. Task-ID specified is: {}", task_id); + return; + } + auto search = tasks_.find(task_id); + assert(search != tasks_.end()); + SPDLOG_INFO("Cancel task[task-id={}, name={}]", task_id, search->second->task_name); + tasks_.erase(search); +} + +void SchedulerImpl::execute(const asio::error_code& ec, std::weak_ptr task) { + std::shared_ptr timer_task = task.lock(); + if (!timer_task) { + return; + } + + SPDLOG_INFO("Execute task: {}. Use-count: {}", timer_task->task_name, timer_task.use_count()); + + // Execute the actual callback. +#ifdef __EXCEPTIONS + try { +#endif + timer_task->callback(); +#ifdef __EXCEPTIONS + } catch (std::exception& e) { + SPDLOG_WARN("Exception raised: {}", e.what()); + } catch (std::string& e) { + SPDLOG_WARN("Exception raised: {}", e); + } catch (...) { + SPDLOG_WARN("Unknown exception type raised"); + } +#endif + + if (timer_task->interval.count()) { + auto& timer = timer_task->timer; + timer->expires_at(timer->expiry() + timer_task->interval); + timer->async_wait(std::bind(&SchedulerImpl::execute, std::placeholders::_1, task)); + SPDLOG_DEBUG("Repeated timer-task {} to fire in {}ms", timer_task->task_name, timer_task->interval.count()); + } else { + auto scheduler = timer_task->scheduler.lock(); + if (scheduler) { + scheduler->cancel(timer_task->task_id); + } + } +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/scheduler/include/Scheduler.h b/src/main/cpp/scheduler/include/Scheduler.h new file mode 100644 index 000000000..65feabb85 --- /dev/null +++ b/src/main/cpp/scheduler/include/Scheduler.h @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include +#include +#include +#include +#include + +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class Scheduler { +public: + virtual ~Scheduler() = default; + + virtual void start() = 0; + + virtual void shutdown() = 0; + + virtual std::uint32_t schedule(const std::function& functor, const std::string& task_name, + std::chrono::milliseconds delay, std::chrono::milliseconds interval) = 0; + + virtual void cancel(std::uint32_t task_id) = 0; +}; + +using SchedulerPtr = std::weak_ptr; +using SchedulerSharedPtr = std::shared_ptr; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/scheduler/include/SchedulerImpl.h b/src/main/cpp/scheduler/include/SchedulerImpl.h new file mode 100644 index 000000000..00066eb4b --- /dev/null +++ b/src/main/cpp/scheduler/include/SchedulerImpl.h @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +#include "absl/base/thread_annotations.h" +#include "absl/container/flat_hash_map.h" +#include "absl/synchronization/mutex.h" +#include "asio.hpp" + +#include "Scheduler.h" +#include "rocketmq/State.h" + +ROCKETMQ_NAMESPACE_BEGIN + +struct TimerTask { + std::uint32_t task_id; + std::string task_name; + std::function callback; + std::chrono::milliseconds interval; + std::unique_ptr timer; + SchedulerPtr scheduler; +}; + +class SchedulerImpl : public std::enable_shared_from_this, public Scheduler { +public: + SchedulerImpl(); + + explicit SchedulerImpl(std::uint32_t worker_num); + + ~SchedulerImpl() override; + + void start() override; + + void shutdown() override LOCKS_EXCLUDED(tasks_mtx_); + + /** + * @functor Pointer to the functor. Lifecycle of this functor should be maintained by the caller. + * @task_name Name of the task. Task name would be very helpful at debug site. + * @delay The amount of time to wait before the first shot. + * @interval The interval between each fire-shot. If it is 0ms, callable will just fired once. + */ + std::uint32_t schedule(const std::function& functor, const std::string& task_name, + std::chrono::milliseconds delay, std::chrono::milliseconds interval) override + LOCKS_EXCLUDED(tasks_mtx_); + + /** + * Note: + * Periodic tasks should be explicitly cancelled once they are no longer needed. + */ + void cancel(std::uint32_t task_id) override LOCKS_EXCLUDED(tasks_mtx_); + +private: + asio::io_context context_; + std::unique_ptr> work_guard_; + absl::Mutex start_mtx_; + absl::CondVar start_cv_; + std::uint32_t worker_num_{std::thread::hardware_concurrency()}; + std::vector threads_; + std::atomic state_{State::CREATED}; + + absl::flat_hash_map> tasks_ GUARDED_BY(tasks_mtx_); + absl::Mutex tasks_mtx_; + + static void execute(const asio::error_code& ec, std::weak_ptr task); + + void shutdown0(); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/stats/BUILD.bazel b/src/main/cpp/stats/BUILD.bazel new file mode 100644 index 000000000..fbf6af20d --- /dev/null +++ b/src/main/cpp/stats/BUILD.bazel @@ -0,0 +1,30 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_library") +cc_library( + name = "stats", + hdrs = glob(["include/*.h"]), + srcs = glob(["*.cpp"]), + strip_include_prefix = "//src/main/cpp/stats/include", + deps = [ + "//api:rocketmq_interface", + "//src/main/cpp/client:client_library", + "@io_opencensus_cpp//opencensus/stats", + "@opencensus_proto//opencensus/proto/agent/metrics/v1:metrics_service_grpc_cc", + ], + visibility = ["//visibility:public"], +) \ No newline at end of file diff --git a/src/main/cpp/stats/ConsumeStats.cpp b/src/main/cpp/stats/ConsumeStats.cpp new file mode 100644 index 000000000..e563c8cf3 --- /dev/null +++ b/src/main/cpp/stats/ConsumeStats.cpp @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ConsumeStats.h" + +#include "Tag.h" + +ROCKETMQ_NAMESPACE_BEGIN + +ConsumeStats::ConsumeStats() + : process_success_( + opencensus::stats::MeasureInt64::Register("process_success", "Number of messages processed", "1")), + process_failure_(opencensus::stats::MeasureInt64::Register( + "process_failure", "Number of failures when processing messages", "1")), + ack_success_(opencensus::stats::MeasureInt64::Register("ack_success", "Number of messages acknowledged", "1")), + ack_failure_(opencensus::stats::MeasureInt64::Register( + "ack_failure", "Number of failures when acknowledging messages", "1")), + change_invisible_time_success_(opencensus::stats::MeasureInt64::Register( + "change_invisible_time_success", "Number of change-invisible-time performed", "1")), + change_invisible_time_failure_(opencensus::stats::MeasureInt64::Register( + "change_invisible_time_failure", "Number of failures when changing message invisible time", "1")), + cached_message_quantity_(opencensus::stats::MeasureInt64::Register( + "cached_message_quantity", "Number of locally cached messages", "1")), + cached_message_bytes_(opencensus::stats::MeasureInt64::Register( + "cached_message_bytes", "Number of locally cached messages in bytes", "1")), + delivery_latency_(opencensus::stats::MeasureInt64::Register( + "delivery_latency", "Time spent delivering messages from servers to clients", "1")), + await_time_(opencensus::stats::MeasureInt64::Register( + "await_time", "Client side queuing time of messages before getting processed", "1")), + process_time_(opencensus::stats::MeasureInt64::Register("process_time", "Process message time", "1")) { + opencensus::stats::ViewDescriptor() + .set_name("rocketmq_process_success_total") + .set_description("Number of messages processed") + .set_measure("process_success") + .set_aggregation(opencensus::stats::Aggregation::Sum()) + .add_column(Tag::topicTag()) + .add_column(Tag::clientIdTag()) + .RegisterForExport(); + + opencensus::stats::ViewDescriptor() + .set_name("rocketmq_process_failure_total") + .set_description("Number of failures on processing messages") + .set_measure("process_failure") + .set_aggregation(opencensus::stats::Aggregation::Sum()) + .add_column(Tag::topicTag()) + .add_column(Tag::clientIdTag()) + .RegisterForExport(); + + opencensus::stats::ViewDescriptor() + .set_name("rocketmq_ack_success_total") + .set_description("Number of messages acknowledged") + .set_measure("ack_success") + .set_aggregation(opencensus::stats::Aggregation::Sum()) + .add_column(Tag::topicTag()) + .add_column(Tag::clientIdTag()) + .RegisterForExport(); + + opencensus::stats::ViewDescriptor() + .set_name("rocketmq_ack_failure_total") + .set_description("Number of failures on acknowledging messages") + .set_measure("ack_failure") + .set_aggregation(opencensus::stats::Aggregation::Sum()) + .add_column(Tag::topicTag()) + .add_column(Tag::clientIdTag()) + .RegisterForExport(); + + opencensus::stats::ViewDescriptor() + .set_name("rocketmq_change_invisible_time_success_total") + .set_description("Number of change-invisible-time operations") + .set_measure("change_invisible_time_success") + .set_aggregation(opencensus::stats::Aggregation::Sum()) + .add_column(Tag::topicTag()) + .add_column(Tag::clientIdTag()) + .RegisterForExport(); + + opencensus::stats::ViewDescriptor() + .set_name("rocketmq_change_invisible_time_failure_total") + .set_description("Number of failed change-invisible-time operations") + .set_measure("change_invisible_time_failure") + .set_aggregation(opencensus::stats::Aggregation::Sum()) + .add_column(Tag::topicTag()) + .add_column(Tag::clientIdTag()) + .RegisterForExport(); + + opencensus::stats::ViewDescriptor() + .set_name("rocketmq_consumer_cached_messages") + .set_description("Number of messages locally cached") + .set_measure("cached_message_quantity") + .set_aggregation(opencensus::stats::Aggregation::LastValue()) + .add_column(Tag::topicTag()) + .add_column(Tag::clientIdTag()) + .RegisterForExport(); + + opencensus::stats::ViewDescriptor() + .set_name("rocketmq_consumer_cached_bytes") + .set_description("Number of locally cached messages in bytes") + .set_measure("cached_message_bytes") + .set_aggregation(opencensus::stats::Aggregation::LastValue()) + .add_column(Tag::topicTag()) + .add_column(Tag::clientIdTag()) + .RegisterForExport(); + + opencensus::stats::ViewDescriptor() + .set_name("rocketmq_delivery_latency") + .set_description("Message delivery latency") + .set_measure("delivery_latency") + .set_aggregation(opencensus::stats::Aggregation::Distribution( + opencensus::stats::BucketBoundaries::Explicit({5, 10, 20, 50, 500}))) + .add_column(Tag::topicTag()) + .add_column(Tag::clientIdTag()) + .RegisterForExport(); + + opencensus::stats::ViewDescriptor() + .set_name("rocketmq_await_time") + .set_description("Message await time") + .set_measure("await_time") + .set_aggregation(opencensus::stats::Aggregation::Distribution( + opencensus::stats::BucketBoundaries::Explicit({1, 1000, 60000, 900000}))) + .add_column(Tag::topicTag()) + .add_column(Tag::clientIdTag()) + .RegisterForExport(); + + opencensus::stats::ViewDescriptor() + .set_name("rocketmq_process_time") + .set_description("Process time") + .set_measure("process_time") + .set_aggregation(opencensus::stats::Aggregation::Distribution( + opencensus::stats::BucketBoundaries::Explicit({100, 1000, 60000, 900000}))) + .add_column(Tag::topicTag()) + .add_column(Tag::clientIdTag()) + .RegisterForExport(); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/stats/MetricBidiReactor.cpp b/src/main/cpp/stats/MetricBidiReactor.cpp new file mode 100644 index 000000000..62983ee4b --- /dev/null +++ b/src/main/cpp/stats/MetricBidiReactor.cpp @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "MetricBidiReactor.h" + +#include "LoggerImpl.h" +#include "OpencensusExporter.h" +#include "Signature.h" + +ROCKETMQ_NAMESPACE_BEGIN + +MetricBidiReactor::MetricBidiReactor(std::weak_ptr client, std::weak_ptr exporter) + : client_(client), exporter_(exporter) { + grpc::ClientContext context; + auto ptr = client_.lock(); + + Metadata metadata; + Signature::sign(ptr->config(), metadata); + + for (const auto& entry : metadata) { + context.AddMetadata(entry.first, entry.second); + } + context.set_deadline(std::chrono::system_clock::now() + absl::ToChronoMilliseconds(ptr->config().request_timeout)); + + auto exporter_ptr = exporter_.lock(); + if (!exporter_ptr) { + return; + } + + exporter_ptr->stub()->async()->Export(&context, this); + StartCall(); +} + +void MetricBidiReactor::OnReadDone(bool ok) { + if (!ok) { + SPDLOG_WARN("Failed to read response"); + return; + } + + StartRead(&response_); +} + +void MetricBidiReactor::OnWriteDone(bool ok) { + if (!ok) { + SPDLOG_WARN("Failed to report metrics"); + return; + } + + bool expected = true; + if (inflight_.compare_exchange_strong(expected, false, std::memory_order_relaxed)) { + fireWrite(); + } +} + +void MetricBidiReactor::OnDone(const grpc::Status& s) { + auto client = client_.lock(); + if (!client) { + return; + } + + if (s.ok()) { + SPDLOG_DEBUG("Bi-directional stream ended. status.code={}, status.message={}", s.error_code(), s.error_message()); + } else { + SPDLOG_WARN("Bi-directional stream ended. status.code={}, status.message={}", s.error_code(), s.error_message()); + } +} + +void MetricBidiReactor::write(ExportMetricsServiceRequest request) { + { + absl::MutexLock lk(&requests_mtx_); + requests_.emplace_back(std::move(request)); + } + + fireWrite(); +} + +void MetricBidiReactor::fireWrite() { + { + absl::MutexLock lk(&requests_mtx_); + if (requests_.empty()) { + SPDLOG_DEBUG("No more metric data to write"); + return; + } + } + + bool expected = false; + if (inflight_.compare_exchange_strong(expected, true, std::memory_order_relaxed)) { + absl::MutexLock lk(&requests_mtx_); + request_.CopyFrom(requests_[0]); + requests_.erase(requests_.begin()); + StartWrite(&request_); + fireRead(); + } +} + +void MetricBidiReactor::fireRead() { + bool expected = false; + if (read_.compare_exchange_strong(expected, true, std::memory_order_relaxed)) { + StartRead(&response_); + } +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/stats/OpencensusExporter.cpp b/src/main/cpp/stats/OpencensusExporter.cpp new file mode 100644 index 000000000..0bf13a48f --- /dev/null +++ b/src/main/cpp/stats/OpencensusExporter.cpp @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OpencensusExporter.h" + +#include "MetricBidiReactor.h" +#include "google/protobuf/util/time_util.h" + +ROCKETMQ_NAMESPACE_BEGIN + +namespace opencensus_proto = opencensus::proto::metrics::v1; + +OpencensusExporter::OpencensusExporter(std::string endpoints, std::weak_ptr client) : client_(client) { +} + +void OpencensusExporter::wrap(const MetricData& data, ExportMetricsServiceRequest& request) { + auto metrics = request.mutable_metrics(); + + for (const auto& entry : data) { + const auto& view_descriptor = entry.first; + + auto metric = new opencensus::proto::metrics::v1::Metric(); + auto descriptor = metric->mutable_metric_descriptor(); + descriptor->set_name(view_descriptor.name()); + descriptor->set_description(view_descriptor.description()); + descriptor->set_unit(view_descriptor.measure_descriptor().units()); + switch (view_descriptor.aggregation().type()) { + case opencensus::stats::Aggregation::Type::kCount: { + descriptor->set_type(opencensus_proto::MetricDescriptor_Type::MetricDescriptor_Type_CUMULATIVE_INT64); + break; + } + + case opencensus::stats::Aggregation::Type::kSum: { + descriptor->set_type(opencensus_proto::MetricDescriptor_Type::MetricDescriptor_Type_CUMULATIVE_INT64); + break; + } + + case opencensus::stats::Aggregation::Type::kLastValue: { + descriptor->set_type(opencensus_proto::MetricDescriptor_Type::MetricDescriptor_Type_GAUGE_INT64); + break; + } + + case opencensus::stats::Aggregation::Type::kDistribution: { + descriptor->set_type(opencensus_proto::MetricDescriptor_Type::MetricDescriptor_Type_GAUGE_DISTRIBUTION); + break; + } + } + + auto label_keys = descriptor->mutable_label_keys(); + for (const auto& column : view_descriptor.columns()) { + auto label_key = new opencensus::proto::metrics::v1::LabelKey; + label_key->set_key(column.name()); + label_keys->AddAllocated(label_key); + } + + auto time_series = metric->mutable_timeseries(); + const auto& view_data = entry.second; + + auto start_times = view_data.start_times(); + + switch (view_data.type()) { + case opencensus::stats::ViewData::Type::kInt64: { + for (const auto& entry : view_data.int_data()) { + auto time_series_element = new opencensus::proto::metrics::v1::TimeSeries(); + + auto search = start_times.find(entry.first); + if (search != start_times.end()) { + absl::Time time = search->second; + time_series_element->mutable_start_timestamp()->CopyFrom( + google::protobuf::util::TimeUtil::TimeTToTimestamp(absl::ToTimeT(time))); + } + + auto label_values = time_series_element->mutable_label_values(); + for (const auto& value : entry.first) { + auto label_value = new opencensus::proto::metrics::v1::LabelValue; + label_value->set_value(value); + label_value->set_has_value(true); + label_values->AddAllocated(label_value); + } + + auto point = new opencensus::proto::metrics::v1::Point(); + point->set_int64_value(entry.second); + time_series_element->mutable_points()->AddAllocated(point); + + time_series->AddAllocated(time_series_element); + } + break; + } + case opencensus::stats::ViewData::Type::kDouble: { + for (const auto& entry : view_data.double_data()) { + auto time_series_element = new opencensus::proto::metrics::v1::TimeSeries(); + auto search = start_times.find(entry.first); + if (search != start_times.end()) { + absl::Time time = search->second; + time_series_element->mutable_start_timestamp()->CopyFrom( + google::protobuf::util::TimeUtil::TimeTToTimestamp(absl::ToTimeT(time))); + } + + auto label_values = time_series_element->mutable_label_values(); + for (const auto& value : entry.first) { + auto label_value = new opencensus::proto::metrics::v1::LabelValue; + label_value->set_value(value); + label_value->set_has_value(true); + label_values->AddAllocated(label_value); + } + + auto point = new opencensus::proto::metrics::v1::Point(); + point->set_double_value(entry.second); + time_series_element->mutable_points()->AddAllocated(point); + + time_series->AddAllocated(time_series_element); + } + break; + } + case opencensus::stats::ViewData::Type::kDistribution: { + for (const auto& entry : view_data.distribution_data()) { + auto time_series_element = new opencensus::proto::metrics::v1::TimeSeries(); + auto search = start_times.find(entry.first); + if (search != start_times.end()) { + absl::Time time = search->second; + time_series_element->mutable_start_timestamp()->CopyFrom( + google::protobuf::util::TimeUtil::TimeTToTimestamp(absl::ToTimeT(time))); + } + + auto label_values = time_series_element->mutable_label_values(); + for (const auto& value : entry.first) { + auto label_value = new opencensus::proto::metrics::v1::LabelValue; + label_value->set_value(value); + label_value->set_has_value(true); + label_values->AddAllocated(label_value); + } + auto point = new opencensus::proto::metrics::v1::Point(); + auto distribution_value = new opencensus::proto::metrics::v1::DistributionValue; + point->set_allocated_distribution_value(distribution_value); + time_series_element->mutable_points()->AddAllocated(point); + distribution_value->set_count(entry.second.count()); + distribution_value->set_sum_of_squared_deviation(entry.second.sum_of_squared_deviation()); + for (const auto& cnt : entry.second.bucket_counts()) { + auto bucket = new opencensus::proto::metrics::v1::DistributionValue::Bucket(); + bucket->set_count(cnt); + distribution_value->mutable_buckets()->AddAllocated(bucket); + } + + auto bucket_options = distribution_value->mutable_bucket_options(); + + for (const auto& boundary : entry.second.bucket_boundaries().lower_boundaries()) { + bucket_options->mutable_explicit_()->mutable_bounds()->Add(boundary); + } + + time_series->AddAllocated(time_series_element); + } + break; + } + } + + metrics->AddAllocated(metric); + } +} + +void OpencensusExporter::exportMetrics( + const std::vector>& data) { + opencensus::proto::agent::metrics::v1::ExportMetricsServiceRequest request; + wrap(data, request); + std::weak_ptr exporter{shared_from_this()}; + if (!bidi_reactor_) { + bidi_reactor_ = absl::make_unique(client_, exporter); + } + bidi_reactor_->write(request); +} + +void OpencensusExporter::resetStream() { + std::weak_ptr exporter{shared_from_this()}; + bidi_reactor_.reset(new MetricBidiReactor(client_, exporter)); +} + +ROCKETMQ_NAMESPACE_END diff --git a/src/main/cpp/stats/PublishStats.cpp b/src/main/cpp/stats/PublishStats.cpp new file mode 100644 index 000000000..37ce613ad --- /dev/null +++ b/src/main/cpp/stats/PublishStats.cpp @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "PublishStats.h" + +#include "Tag.h" + +ROCKETMQ_NAMESPACE_BEGIN + +PublishStats::PublishStats() + : success_(opencensus::stats::MeasureInt64::Register("publish_success", "Number of message published", "1")), + failure_(opencensus::stats::MeasureInt64::Register("pubish_failure", "Number of publish failures", "1")), + latency_(opencensus::stats::MeasureInt64::Register("publish_latency", "Publish latency in milliseconds", "ms")) { + opencensus::stats::ViewDescriptor() + .set_name("rocketmq_send_success_total") + .set_description("Number of messages published") + .set_measure("publish_success") + .set_aggregation(opencensus::stats::Aggregation::Sum()) + .add_column(Tag::topicTag()) + .add_column(Tag::clientIdTag()) + .RegisterForExport(); + + opencensus::stats::ViewDescriptor() + .set_name("rocketmq_send_failure_total") + .set_description("Number of publish failures") + .set_measure("publish_failure") + .set_aggregation(opencensus::stats::Aggregation::Sum()) + .add_column(Tag::topicTag()) + .add_column(Tag::clientIdTag()) + .RegisterForExport(); + + opencensus::stats::ViewDescriptor() + .set_name("rocketmq_send_cost_time") + .set_description("Publish latency") + .set_measure("publish_latency") + .set_aggregation(opencensus::stats::Aggregation::Distribution( + opencensus::stats::BucketBoundaries::Explicit({5, 10, 20, 50, 500}))) + .add_column(Tag::topicTag()) + .add_column(Tag::clientIdTag()) + .RegisterForExport(); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/stats/Tag.cpp b/src/main/cpp/stats/Tag.cpp new file mode 100644 index 000000000..959923346 --- /dev/null +++ b/src/main/cpp/stats/Tag.cpp @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "Tag.h" + +ROCKETMQ_NAMESPACE_BEGIN + +opencensus::tags::TagKey& Tag::topicTag() { + static opencensus::tags::TagKey topic_tag = opencensus::tags::TagKey::Register("topic"); + return topic_tag; +} + +opencensus::tags::TagKey& Tag::clientIdTag() { + static opencensus::tags::TagKey client_id_tag = opencensus::tags::TagKey::Register("client_id"); + return client_id_tag; +} + +opencensus::tags::TagKey& Tag::userIdTag() { + static opencensus::tags::TagKey uid_tag = opencensus::tags::TagKey::Register("uid"); + return uid_tag; +} + +opencensus::tags::TagKey& Tag::deploymentTag() { + static opencensus::tags::TagKey deployment_tag = opencensus::tags::TagKey::Register("deployment"); + return deployment_tag; +} + +ROCKETMQ_NAMESPACE_END diff --git a/src/main/cpp/stats/include/ConsumeStats.h b/src/main/cpp/stats/include/ConsumeStats.h new file mode 100644 index 000000000..a70f32467 --- /dev/null +++ b/src/main/cpp/stats/include/ConsumeStats.h @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "opencensus/stats/stats.h" +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class ConsumeStats { +public: + ConsumeStats(); + + const opencensus::stats::MeasureInt64& processSuccess() const { + return process_success_; + } + + const opencensus::stats::MeasureInt64& processFailure() const { + return process_failure_; + } + + const opencensus::stats::MeasureInt64& ackSuccess() const { + return ack_success_; + } + + const opencensus::stats::MeasureInt64& ackFailure() const { + return ack_failure_; + } + + const opencensus::stats::MeasureInt64& changeInvisibleTimeSuccess() const { + return change_invisible_time_success_; + } + + const opencensus::stats::MeasureInt64& changeInvisibleTimeFailure() const { + return change_invisible_time_failure_; + } + + const opencensus::stats::MeasureInt64& cachedMessageQuantity() const { + return cached_message_quantity_; + } + + const opencensus::stats::MeasureInt64& cachedMessageBytes() const { + return cached_message_bytes_; + } + + const opencensus::stats::MeasureInt64& deliveryLatency() const { + return delivery_latency_; + } + + const opencensus::stats::MeasureInt64& awaitTime() const { + return await_time_; + } + + const opencensus::stats::MeasureInt64& processTime() const { + return process_time_; + } + +private: + opencensus::stats::MeasureInt64 process_success_; + opencensus::stats::MeasureInt64 process_failure_; + opencensus::stats::MeasureInt64 ack_success_; + opencensus::stats::MeasureInt64 ack_failure_; + opencensus::stats::MeasureInt64 change_invisible_time_success_; + opencensus::stats::MeasureInt64 change_invisible_time_failure_; + opencensus::stats::MeasureInt64 cached_message_quantity_; + opencensus::stats::MeasureInt64 cached_message_bytes_; + + opencensus::stats::MeasureInt64 delivery_latency_; + opencensus::stats::MeasureInt64 await_time_; + opencensus::stats::MeasureInt64 process_time_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/include/MQClient.h b/src/main/cpp/stats/include/Exporter.h similarity index 73% rename from include/MQClient.h rename to src/main/cpp/stats/include/Exporter.h index db48d2092..7f2f24a38 100644 --- a/include/MQClient.h +++ b/src/main/cpp/stats/include/Exporter.h @@ -14,21 +14,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once -#ifndef __MQADMIN_H__ -#define __MQADMIN_H__ +#include "opencensus/stats/stats.h" +#include "rocketmq/RocketMQ.h" -namespace rocketmq { +ROCKETMQ_NAMESPACE_BEGIN -enum elogLevel { - eLOG_LEVEL_FATAL = 1, - eLOG_LEVEL_ERROR = 2, - eLOG_LEVEL_WARN = 3, - eLOG_LEVEL_INFO = 4, - eLOG_LEVEL_DEBUG = 5, - eLOG_LEVEL_TRACE = 6, - eLOG_LEVEL_LEVEL_NUM = 7 +class Exporter { +public: + virtual void exportMetrics( + const std::vector>& data) = 0; }; -} // namespace rocketmq -#endif +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/stats/include/MetricBidiReactor.h b/src/main/cpp/stats/include/MetricBidiReactor.h new file mode 100644 index 000000000..cc08c1d01 --- /dev/null +++ b/src/main/cpp/stats/include/MetricBidiReactor.h @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "Client.h" +#include "grpcpp/grpcpp.h" +#include "grpcpp/impl/codegen/client_callback.h" +#include "opencensus/proto/agent/metrics/v1/metrics_service.grpc.pb.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class OpencensusExporter; + +using ExportMetricsServiceRequest = opencensus::proto::agent::metrics::v1::ExportMetricsServiceRequest; +using ExportMetricsServiceResponse = opencensus::proto::agent::metrics::v1::ExportMetricsServiceResponse; + +class MetricBidiReactor : public grpc::ClientBidiReactor { +public: + MetricBidiReactor(std::weak_ptr client, std::weak_ptr exporter); + + /// Notifies the application that a StartRead operation completed. + /// + /// \param[in] ok Was it successful? If false, no new read/write operation + /// will succeed, and any further Start* should not be called. + void OnReadDone(bool /*ok*/) override; + + /// Notifies the application that a StartWrite or StartWriteLast operation + /// completed. + /// + /// \param[in] ok Was it successful? If false, no new read/write operation + /// will succeed, and any further Start* should not be called. + void OnWriteDone(bool /*ok*/) override; + + /// Notifies the application that all operations associated with this RPC + /// have completed and all Holds have been removed. OnDone provides the RPC + /// status outcome for both successful and failed RPCs and will be called in + /// all cases. If it is not called, it indicates an application-level problem + /// (like failure to remove a hold). + /// + /// \param[in] s The status outcome of this RPC + void OnDone(const grpc::Status& /*s*/) override; + + void write(ExportMetricsServiceRequest request) LOCKS_EXCLUDED(requests_mtx_); + +private: + std::weak_ptr client_; + std::weak_ptr exporter_; + + ExportMetricsServiceRequest request_; + + std::vector requests_ GUARDED_BY(requests_mtx_); + absl::Mutex requests_mtx_; + + std::atomic_bool inflight_{false}; + std::atomic_bool read_{false}; + + ExportMetricsServiceResponse response_; + + void fireWrite(); + + void fireRead(); +}; + +ROCKETMQ_NAMESPACE_END diff --git a/src/main/cpp/stats/include/OpencensusExporter.h b/src/main/cpp/stats/include/OpencensusExporter.h new file mode 100644 index 000000000..7920ff5c1 --- /dev/null +++ b/src/main/cpp/stats/include/OpencensusExporter.h @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "Client.h" +#include "Exporter.h" +#include "grpcpp/grpcpp.h" +#include "opencensus/proto/agent/metrics/v1/metrics_service.grpc.pb.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class MetricBidiReactor; + +using Stub = opencensus::proto::agent::metrics::v1::MetricsService::Stub; +using StubPtr = std::unique_ptr; +using MetricData = std::vector>; +using ExportMetricsServiceRequest = opencensus::proto::agent::metrics::v1::ExportMetricsServiceRequest; + +class OpencensusExporter : public Exporter, public std::enable_shared_from_this { +public: + OpencensusExporter(std::string endpoints, std::weak_ptr client); + + void exportMetrics(const MetricData& data) override; + + static void wrap(const MetricData& data, ExportMetricsServiceRequest& request); + + void resetStream(); + + Stub* stub() { + return stub_.get(); + } + +private: + std::weak_ptr client_; + StubPtr stub_; + std::unique_ptr bidi_reactor_; +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/protocol/KVTable.h b/src/main/cpp/stats/include/PublishStats.h similarity index 58% rename from src/protocol/KVTable.h rename to src/main/cpp/stats/include/PublishStats.h index e9b6a53fc..d9d750afd 100644 --- a/src/protocol/KVTable.h +++ b/src/main/cpp/stats/include/PublishStats.h @@ -14,31 +14,36 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once -#ifndef __KVTABLE_H__ -#define __KVTABLE_H__ -#include #include -#include "RemotingSerializable.h" -using std::map; -using std::string; +#include "Tag.h" +#include "opencensus/stats/stats.h" +#include "rocketmq/RocketMQ.h" -namespace rocketmq { -//& getTable() { return m_table; } + const opencensus::stats::MeasureInt64& success() const { + return success_; + } - void setTable(const map& table) { m_table = table; } + const opencensus::stats::MeasureInt64& failure() const { + return failure_; + } - private: - map m_table; + const opencensus::stats::MeasureInt64& latency() const { + return latency_; + } + +private: + opencensus::stats::MeasureInt64 success_; + opencensus::stats::MeasureInt64 failure_; + opencensus::stats::MeasureInt64 latency_; }; -} // namespace rocketmq -#endif +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/stats/include/Tag.h b/src/main/cpp/stats/include/Tag.h new file mode 100644 index 000000000..ae69fcb82 --- /dev/null +++ b/src/main/cpp/stats/include/Tag.h @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "opencensus/stats/stats.h" +#include "rocketmq/RocketMQ.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class Tag { +public: + static opencensus::tags::TagKey& topicTag(); + + static opencensus::tags::TagKey& clientIdTag(); + + static opencensus::tags::TagKey& userIdTag(); + + static opencensus::tags::TagKey& deploymentTag(); +}; + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/stats/tests/BUILD.bazel b/src/main/cpp/stats/tests/BUILD.bazel new file mode 100644 index 000000000..d1a67285c --- /dev/null +++ b/src/main/cpp/stats/tests/BUILD.bazel @@ -0,0 +1,28 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_test") + +cc_test( + name = "publish_stats_test", + srcs = [ + "PublishStatsTest.cpp", + ], + deps = [ + "//src/main/cpp/stats", + "@com_google_googletest//:gtest_main", + ], +) \ No newline at end of file diff --git a/src/main/cpp/stats/tests/PublishStatsTest.cpp b/src/main/cpp/stats/tests/PublishStatsTest.cpp new file mode 100644 index 000000000..b6fb7d3af --- /dev/null +++ b/src/main/cpp/stats/tests/PublishStatsTest.cpp @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "PublishStats.h" +#include "gtest/gtest.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class Handler : public opencensus::stats::StatsExporter::Handler { +public: + void ExportViewData( + const std::vector>& data) override { + std::cout << "================================================================================" << std::endl; + for (const auto& datum : data) { + const auto& view_data = datum.second; + const auto& descriptor = datum.first; + auto start_times = view_data.start_times(); + auto columns = descriptor.columns(); + + switch (view_data.type()) { + case opencensus::stats::ViewData::Type::kInt64: { + auto data_map = view_data.int_data(); + for (const auto& entry : data_map) { + absl::Time time = start_times[entry.first]; + std::string line; + line.append(absl::FormatTime(time)).append(" "); + line.append(descriptor.name()); + line.append("{"); + for (std::size_t i = 0; i < columns.size(); i++) { + line.append(columns[i].name()).append("=").append(entry.first[i]); + if (i < columns.size() - 1) { + line.append(", "); + } else { + line.append("} ==> "); + } + } + line.append(std::to_string(entry.second)); + println(line); + } + break; + } + case opencensus::stats::ViewData::Type::kDouble: { + exportDatum(datum.first, view_data.start_time(), view_data.end_time(), view_data.double_data()); + break; + } + case opencensus::stats::ViewData::Type::kDistribution: { + for (const auto& entry : view_data.distribution_data()) { + std::string line(descriptor.name()); + line.append("{"); + for (std::size_t i = 0; i < columns.size(); i++) { + line.append(columns[i].name()).append("=").append(entry.first[i]); + if (i < columns.size() - 1) { + line.append(", "); + } else { + line.append("} ==> "); + } + } + line.append(entry.second.DebugString()); + println(line); + + println(absl::StrJoin(entry.second.bucket_boundaries().lower_boundaries(), ",")); + } + break; + } + } + } + } + + template + void exportDatum(const opencensus::stats::ViewDescriptor& descriptor, + absl::Time start_time, + absl::Time end_time, + const opencensus::stats::ViewData::DataMap& data) { + if (data.empty()) { + // std::cout << "No data for " << descriptor.name() << std::endl; + return; + } + + for (const auto& row : data) { + for (std::size_t column = 0; column < descriptor.columns().size(); column++) { + std::cout << descriptor.name() << "[" << descriptor.columns()[column].name() << "=" << row.first[column] << "]" + << DataToString(row.second) << std::endl; + } + } + } + + std::mutex console_mtx; + void println(const std::string& line) { + std::lock_guard lk(console_mtx); + std::cout << line << std::endl; + } + + // Functions to format data for different aggregation types. + std::string DataToString(double data) { + return absl::StrCat(": ", data, "\n"); + } + std::string DataToString(int64_t data) { + return absl::StrCat(": ", data, "\n"); + } + std::string DataToString(const opencensus::stats::Distribution& data) { + std::string output = "\n"; + std::vector lines = absl::StrSplit(data.DebugString(), '\n'); + // Add indent. + for (const auto& line : lines) { + absl::StrAppend(&output, " ", line, "\n"); + } + return output; + } +}; + +TEST(StatsTest, testBasics) { + std::string t1("T1"); + std::string t2("T2"); + PublishStats metrics; + opencensus::stats::StatsExporter::SetInterval(absl::Seconds(5)); + opencensus::stats::StatsExporter::RegisterPushHandler(absl::make_unique()); + std::atomic_bool stopped{false}; + auto generator = [&]() { + while (!stopped) { + opencensus::stats::Record({{metrics.success(), 1}}, {{Tag::topicTag(), t1}, {Tag::clientIdTag(), "client-0"}}); + opencensus::stats::Record({{metrics.success(), 100}}, {{Tag::topicTag(), t2}, {Tag::clientIdTag(), "client-0"}}); + for (std::size_t i = 0; i < 10; i++) { + opencensus::stats::Record({{metrics.latency(), i * 10}}, + {{Tag::topicTag(), t1}, {Tag::clientIdTag(), "client-0"}}); + } + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + }; + std::thread feeder(generator); + + std::this_thread::sleep_for(std::chrono::seconds(10)); + stopped.store(true); + if (feeder.joinable()) { + feeder.join(); + } +} + +ROCKETMQ_NAMESPACE_END diff --git a/src/main/cpp/trace/BUILD.bazel b/src/main/cpp/trace/BUILD.bazel new file mode 100644 index 000000000..b44fe4c0e --- /dev/null +++ b/src/main/cpp/trace/BUILD.bazel @@ -0,0 +1,29 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +load("@rules_cc//cc:defs.bzl", "cc_library") +cc_library( + name = "trace", + hdrs = glob(["include/*.h"]), + srcs = glob(["*.cpp"]), + strip_include_prefix = "//src/main/cpp/trace/include", + deps = [ + "//api:rocketmq_interface", + "//src/main/cpp/client:client_library", + "@io_opencensus_cpp//opencensus/trace", + ], + visibility = ["//visibility:public"], +) \ No newline at end of file diff --git a/src/main/cpp/trace/TracingUtility.cpp b/src/main/cpp/trace/TracingUtility.cpp new file mode 100644 index 000000000..4cd7a8dd8 --- /dev/null +++ b/src/main/cpp/trace/TracingUtility.cpp @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "TracingUtility.h" +#include "MessageExt.h" +#include "MixAll.h" +#include "absl/strings/str_join.h" +#include "rocketmq/CredentialsProvider.h" +#include "spdlog/spdlog.h" + +ROCKETMQ_NAMESPACE_BEGIN + +void TracingUtility::addUniversalSpanAttributes(const Message& message, const ClientConfig& client_config, + opencensus::trace::Span& span) { + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_ID, message.id()); + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_PAYLOAD_SIZE_BYTES, message.body().length()); + if (message.tag().has_value()) { + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_TAG, message.tag().value()); + } + + const std::vector& keys = message.keys(); + if (!keys.empty()) { + span.AddAnnotation(MixAll::SPAN_ANNOTATION_MESSAGE_KEYS, + {{MixAll::SPAN_ANNOTATION_MESSAGE_KEYS, + absl::StrJoin(keys.begin(), keys.end(), MixAll::MESSAGE_KEY_SEPARATOR)}}); + } + switch (typeOf(message)) { + case rmq::MessageType::FIFO: + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_MESSAGE_TYPE, + MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_FIFO_MESSAGE); + break; + case rmq::MessageType::DELAY: + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_MESSAGE_TYPE, + MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_DELAY_MESSAGE); + break; + case rmq::MessageType::TRANSACTION: + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_MESSAGE_TYPE, + MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_TRANSACTION_MESSAGE); + break; + default: + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_MESSAGE_TYPE, + MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_NORMAL_MESSAGE); + break; + } + + if (message.deliveryTimestamp().has_value()) { + std::chrono::system_clock::time_point timestamp = message.deliveryTimestamp().value(); + auto duration = absl::FromChrono(timestamp.time_since_epoch()); + int64_t timestamp_millis = absl::ToInt64Milliseconds(duration); + if (timestamp_millis > 0) { + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_DELIVERY_TIMESTAMP, timestamp_millis); + } + } + + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_SYSTEM, + MixAll::SPAN_ATTRIBUTE_VALUE_ROCKETMQ_MESSAGING_SYSTEM); + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_DESTINATION, message.topic()); + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_DESTINATION_KIND, + MixAll::SPAN_ATTRIBUTE_VALUE_DESTINATION_KIND); + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_PROTOCOL, MixAll::SPAN_ATTRIBUTE_VALUE_MESSAGING_PROTOCOL); + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_PROTOCOL_VERSION, + MixAll::SPAN_ATTRIBUTE_VALUE_MESSAGING_PROTOCOL_VERSION); + // span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_MESSAGING_URL, "abc") + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_NAMESPACE, client_config.resource_namespace); + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_CLIENT_ID, client_config.client_id); + + // span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_CLIENT_GROUP, client_config.getGroupName()); + + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_ACCESS_KEY, + client_config.credentials_provider->getCredentials().accessKey()); + span.AddAttribute(MixAll::SPAN_ATTRIBUTE_KEY_ROCKETMQ_NAMESPACE, client_config.resource_namespace); +} + +ROCKETMQ_NAMESPACE_END \ No newline at end of file diff --git a/src/main/cpp/trace/include/TracingUtility.h b/src/main/cpp/trace/include/TracingUtility.h new file mode 100644 index 000000000..8dbe48830 --- /dev/null +++ b/src/main/cpp/trace/include/TracingUtility.h @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +#pragma once + +#include "opencensus/trace/propagation/trace_context.h" +#include "opencensus/trace/span.h" + +#include "ClientConfig.h" +#include "rocketmq/Message.h" + +ROCKETMQ_NAMESPACE_BEGIN + +class TracingUtility { +public: + static void addUniversalSpanAttributes(const Message& message, const ClientConfig&, opencensus::trace::Span& span); +}; + +ROCKETMQ_NAMESPACE_END diff --git a/src/message/BatchMessage.cpp b/src/message/BatchMessage.cpp deleted file mode 100644 index 9bcca1cf0..000000000 --- a/src/message/BatchMessage.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "include/BatchMessage.h" - -#include "MQDecoder.h" -#include "StringIdMaker.h" - -namespace rocketmq { - -std::string BatchMessage::encode(std::vector& msgs) { - std::string encodedBody; - for (auto message : msgs) { - std::string unique_id = StringIdMaker::getInstance().createUniqID(); - message.setProperty(MQMessage::PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, unique_id); - encodedBody.append(encode(message)); - } - return encodedBody; -} - -std::string BatchMessage::encode(MQMessage& message) { - string encodeMsg; - const string& body = message.getBody(); - int bodyLen = body.length(); - string properties = MQDecoder::messageProperties2String(message.getProperties()); - short propertiesLength = (short)properties.length(); - int storeSize = 20 + bodyLen + 2 + propertiesLength; - // TOTALSIZE|MAGICCOD|BODYCRC|FLAG|BODYLen|Body|propertiesLength|properties - int magicCode = 0; - int bodyCrc = 0; - int flag = message.getFlag(); - int storeSize_net = htonl(storeSize); - int magicCode_net = htonl(magicCode); - int bodyCrc_net = htonl(bodyCrc); - int flag_net = htonl(flag); - int bodyLen_net = htonl(bodyLen); - int propertiesLength_net = htons(propertiesLength); - encodeMsg.append((char*)&storeSize_net, sizeof(int)); - encodeMsg.append((char*)&magicCode_net, sizeof(int)); - encodeMsg.append((char*)&bodyCrc_net, sizeof(int)); - encodeMsg.append((char*)&flag_net, sizeof(int)); - encodeMsg.append((char*)&bodyLen_net, sizeof(int)); - encodeMsg.append(body.c_str(), body.length()); - encodeMsg.append((char*)&propertiesLength_net, sizeof(short)); - encodeMsg.append(properties.c_str(), propertiesLength); - return encodeMsg; -} - -} // namespace rocketmq diff --git a/src/message/MQDecoder.cpp b/src/message/MQDecoder.cpp deleted file mode 100644 index 1ba8a951f..000000000 --- a/src/message/MQDecoder.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "MQDecoder.h" -#include -#include -#include -#include -#include "Logging.h" -#include "MemoryOutputStream.h" -#include "MessageSysFlag.h" -#include "UtilAll.h" - -namespace rocketmq { - -//(outputmen.getData()); - int len = outputmen.getDataSize(); - - return UtilAll::bytes2string(bytes, len); -} - -MQMessageId MQDecoder::decodeMessageId(const string& msgId) { - string ipStr = msgId.substr(0, 8); - string portStr = msgId.substr(8, 8); - string offsetStr = msgId.substr(16, 16); - - int num = strspn(offsetStr.c_str(), "F"); - offsetStr = offsetStr.substr(num, 16 - num); - - char* end; - int ipInt = strtoul(ipStr.c_str(), &end, 16); - int portInt = strtoul(portStr.c_str(), &end, 16); - uint64 offset = strtoul(offsetStr.c_str(), &end, 16); - // int64 offset = UtilAll::hexstr2ull(offsetStr.c_str()); - - struct sockaddr_in sa; - sa.sin_family = AF_INET; - sa.sin_port = htons(portInt); - sa.sin_addr.s_addr = htonl(ipInt); - sockaddr addr; - memcpy(&addr, &sa, sizeof(sockaddr)); - - MQMessageId id(addr, offset); - return id; -} - -MQMessageExt* MQDecoder::decode(MemoryInputStream& byteBuffer) { - return decode(byteBuffer, true); -} - -MQMessageExt* MQDecoder::decode(MemoryInputStream& byteBuffer, bool readBody) { - MQMessageExt* msgExt = new MQMessageExt(); - - // 1 TOTALSIZE - int storeSize = byteBuffer.readIntBigEndian(); - msgExt->setStoreSize(storeSize); - - // 2 MAGICCODE sizeof(int) - byteBuffer.skipNextBytes(sizeof(int)); - - // 3 BODYCRC - int bodyCRC = byteBuffer.readIntBigEndian(); - msgExt->setBodyCRC(bodyCRC); - - // 4 QUEUEID - int queueId = byteBuffer.readIntBigEndian(); - msgExt->setQueueId(queueId); - - // 5 FLAG - int flag = byteBuffer.readIntBigEndian(); - msgExt->setFlag(flag); - - // 6 QUEUEOFFSET - int64 queueOffset = byteBuffer.readInt64BigEndian(); - msgExt->setQueueOffset(queueOffset); - - // 7 PHYSICALOFFSET - int64 physicOffset = byteBuffer.readInt64BigEndian(); - msgExt->setCommitLogOffset(physicOffset); - - // 8 SYSFLAG - int sysFlag = byteBuffer.readIntBigEndian(); - msgExt->setSysFlag(sysFlag); - - // 9 BORNTIMESTAMP - int64 bornTimeStamp = byteBuffer.readInt64BigEndian(); - msgExt->setBornTimestamp(bornTimeStamp); - - // 10 BORNHOST - int bornHost = byteBuffer.readIntBigEndian(); - int port = byteBuffer.readIntBigEndian(); - sockaddr bornAddr = IPPort2socketAddress(bornHost, port); - msgExt->setBornHost(bornAddr); - - // 11 STORETIMESTAMP - int64 storeTimestamp = byteBuffer.readInt64BigEndian(); - msgExt->setStoreTimestamp(storeTimestamp); - - // // 12 STOREHOST - int storeHost = byteBuffer.readIntBigEndian(); - port = byteBuffer.readIntBigEndian(); - sockaddr storeAddr = IPPort2socketAddress(storeHost, port); - msgExt->setStoreHost(storeAddr); - - // 13 RECONSUMETIMES - int reconsumeTimes = byteBuffer.readIntBigEndian(); - msgExt->setReconsumeTimes(reconsumeTimes); - - // 14 Prepared Transaction Offset - int64 preparedTransactionOffset = byteBuffer.readInt64BigEndian(); - msgExt->setPreparedTransactionOffset(preparedTransactionOffset); - - // 15 BODY - int bodyLen = byteBuffer.readIntBigEndian(); - if (bodyLen > 0) { - if (readBody) { - MemoryBlock block; - byteBuffer.readIntoMemoryBlock(block, bodyLen); - - const char* const pBody = static_cast(block.getData()); - int len = block.getSize(); - string msgbody(pBody, len); - - // decompress body - if ((sysFlag & MessageSysFlag::CompressedFlag) == MessageSysFlag::CompressedFlag) { - string outbody; - if (UtilAll::inflate(msgbody, outbody)) { - msgExt->setBody(outbody); - } - } else { - msgExt->setBody(msgbody); - } - } else { - byteBuffer.skipNextBytes(bodyLen); - } - } - - // 16 TOPIC - int topicLen = (int)byteBuffer.readByte(); - MemoryBlock block; - byteBuffer.readIntoMemoryBlock(block, topicLen); - const char* const pTopic = static_cast(block.getData()); - topicLen = block.getSize(); - msgExt->setTopic(pTopic, topicLen); - - // 17 properties - short propertiesLen = byteBuffer.readShortBigEndian(); - if (propertiesLen > 0) { - MemoryBlock block; - byteBuffer.readIntoMemoryBlock(block, propertiesLen); - const char* const pProperty = static_cast(block.getData()); - int len = block.getSize(); - string propertiesString(pProperty, len); - - map propertiesMap; - string2messageProperties(propertiesString, propertiesMap); - msgExt->setPropertiesInternal(propertiesMap); - propertiesMap.clear(); - } - - // 18 msg ID - string offsetMsgId = createMessageId(msgExt->getStoreHost(), (int64)msgExt->getCommitLogOffset()); - msgExt->setOffsetMsgId(offsetMsgId); - - string msgId = msgExt->getProperty(MQMessage::PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX); - if (msgId.empty()) { - msgId = offsetMsgId; - } - msgExt->setMsgId(msgId); - - // LOG_INFO("get msgExt from remote server, its contents are:%s", msgExt->toString().c_str()); - return msgExt; -} - -void MQDecoder::decodes(const MemoryBlock* mem, vector& mqvec) { - mqvec.clear(); - decodes(mem, mqvec, true); -} - -void MQDecoder::decodes(const MemoryBlock* mem, vector& mqvec, bool readBody) { - MemoryInputStream rawInput(*mem, true); - - while (rawInput.getNumBytesRemaining() > 0) { - unique_ptr msg(decode(rawInput, readBody)); - mqvec.push_back(*msg); - } -} - -string MQDecoder::messageProperties2String(const map& properties) { - string os; - - for (const auto& it : properties) { - // os << it->first << NAME_VALUE_SEPARATOR << it->second << PROPERTY_SEPARATOR; - os.append(it.first); - os += NAME_VALUE_SEPARATOR; - os.append(it.second); - os += PROPERTY_SEPARATOR; - } - - return os; -} - -void MQDecoder::string2messageProperties(const string& propertiesString, map& properties) { - vector out; - UtilAll::Split(out, propertiesString, PROPERTY_SEPARATOR); - - for (size_t i = 0; i < out.size(); i++) { - vector outValue; - UtilAll::Split(outValue, out[i], NAME_VALUE_SEPARATOR); - - if (outValue.size() == 2) { - properties[outValue[0]] = outValue[1]; - } - } -} -} // namespace rocketmq diff --git a/src/message/MQDecoder.h b/src/message/MQDecoder.h deleted file mode 100644 index d9c94ad48..000000000 --- a/src/message/MQDecoder.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __MESSAGEDECODER_H__ -#define __MESSAGEDECODER_H__ - -#include "MQClientException.h" -#include "MQMessageExt.h" -#include "MQMessageId.h" -#include "MemoryInputStream.h" -#include "SocketUtil.h" - -namespace rocketmq { -//& mqvec); - - static void decodes(const MemoryBlock* mem, vector& mqvec, bool readBody); - - static string messageProperties2String(const map& properties); - static void string2messageProperties(const string& propertiesString, map& properties); - - private: - static MQMessageExt* decode(MemoryInputStream& byteBuffer); - static MQMessageExt* decode(MemoryInputStream& byteBuffer, bool readBody); - - public: - static const char NAME_VALUE_SEPARATOR; - static const char PROPERTY_SEPARATOR; - static const int MSG_ID_LENGTH; - static int MessageMagicCodePostion; - static int MessageFlagPostion; - static int MessagePhysicOffsetPostion; - static int MessageStoreTimestampPostion; -}; -} //::const_iterator it = m_properties.find(name); - if (it == m_properties.end()) { - return EMPTY_STRING; - } else { - return it->second; - } -} - -const string& MQMessage::getTopic() const { - return m_topic; -} - -void MQMessage::setTopic(const string& topic) { - m_topic = topic; -} - -void MQMessage::setTopic(const char* body, int len) { - m_topic.clear(); - m_topic.append(body, len); -} - -const string& MQMessage::getTags() const { - return getProperty(PROPERTY_TAGS); -} - -void MQMessage::setTags(const string& tags) { - setPropertyInternal(PROPERTY_TAGS, tags); -} - -const string& MQMessage::getKeys() const { - return getProperty(PROPERTY_KEYS); -} - -void MQMessage::setKeys(const string& keys) { - setPropertyInternal(PROPERTY_KEYS, keys); -} - -void MQMessage::setKeys(const vector& keys) { - if (keys.empty()) { - return; - } - - vector::const_iterator it = keys.begin(); - string str; - str += *it; - it++; - - for (; it != keys.end(); it++) { - str += KEY_SEPARATOR; - str += *it; - } - - setKeys(str); -} - -int MQMessage::getDelayTimeLevel() const { - string tmp = getProperty(PROPERTY_DELAY_TIME_LEVEL); - if (!tmp.empty()) { - return atoi(tmp.c_str()); - } - return 0; -} - -void MQMessage::setDelayTimeLevel(int level) { - char tmp[16]; - sprintf(tmp, "%d", level); - - setPropertyInternal(PROPERTY_DELAY_TIME_LEVEL, tmp); -} - -bool MQMessage::isWaitStoreMsgOK() const { - string tmp = getProperty(PROPERTY_WAIT_STORE_MSG_OK); - if (tmp.empty()) { - return true; - } else { - return (tmp == "true") ? true : false; - } -} - -void MQMessage::setWaitStoreMsgOK(bool waitStoreMsgOK) { - if (waitStoreMsgOK) { - setPropertyInternal(PROPERTY_WAIT_STORE_MSG_OK, "true"); - } else { - setPropertyInternal(PROPERTY_WAIT_STORE_MSG_OK, "false"); - } -} - -int MQMessage::getFlag() const { - return m_flag; -} - -void MQMessage::setFlag(int flag) { - m_flag = flag; -} - -int MQMessage::getSysFlag() const { - return m_sysFlag; -} - -void MQMessage::setSysFlag(int sysFlag) { - m_sysFlag = sysFlag; -} - -const string& MQMessage::getBody() const { - return m_body; -} - -void MQMessage::setBody(const char* body, int len) { - m_body.clear(); - m_body.append(body, len); -} - -void MQMessage::setBody(const string& body) { - m_body.clear(); - m_body.append(body); -} - -map MQMessage::getProperties() const { - return m_properties; -} - -void MQMessage::setProperties(map& properties) { - m_properties = properties; - - map::const_iterator it = m_properties.find(PROPERTY_TRANSACTION_PREPARED); - if (it != m_properties.end()) { - string tranMsg = it->second; - if (!tranMsg.empty() && tranMsg == "true") { - m_sysFlag |= MessageSysFlag::TransactionPreparedType; - } else { - m_sysFlag &= ~MessageSysFlag::TransactionPreparedType; - } - } -} - -void MQMessage::setPropertiesInternal(map& properties) { - m_properties = properties; -} - -void MQMessage::Init(const string& topic, - const string& tags, - const string& keys, - const int flag, - const string& body, - bool waitStoreMsgOK) { - m_topic = topic; - m_flag = flag; - m_sysFlag = 0; - m_body = body; - - if (tags.length() > 0) { - setTags(tags); - } - - if (keys.length() > 0) { - setKeys(keys); - } - - setWaitStoreMsgOK(waitStoreMsgOK); -} -} // - -#include "DefaultMQProducerImpl.h" - -namespace rocketmq { - -DefaultMQProducer::DefaultMQProducer(const std::string& groupName) { - impl = new DefaultMQProducerImpl(groupName); -} - -DefaultMQProducer::~DefaultMQProducer() { - delete impl; -} -void DefaultMQProducer::start() { - impl->start(); -} - -void DefaultMQProducer::shutdown() { - impl->shutdown(); -} - -std::string DefaultMQProducer::version() { - std::string versions = impl->getClientVersionString(); - /* - versions.append(", PROTOCOL VERSION: ") - .append(MQVersion::GetVersionDesc(MQVersion::s_CurrentVersion)) - .append(", LANGUAGE: ") - .append(MQVersion::s_CurrentLanguage); - */ - return versions; -} - -// start mqclient set -const std::string& DefaultMQProducer::getNamesrvAddr() const { - return impl->getNamesrvAddr(); -} - -void DefaultMQProducer::setNamesrvAddr(const std::string& namesrvAddr) { - impl->setNamesrvAddr(namesrvAddr); -} - -const std::string& DefaultMQProducer::getNamesrvDomain() const { - return impl->getNamesrvDomain(); -} - -void DefaultMQProducer::setNamesrvDomain(const std::string& namesrvDomain) { - impl->setNamesrvDomain(namesrvDomain); -} -void DefaultMQProducer::setSessionCredentials(const std::string& accessKey, - const std::string& secretKey, - const std::string& accessChannel) { - impl->setSessionCredentials(accessKey, secretKey, accessChannel); -} - -const SessionCredentials& DefaultMQProducer::getSessionCredentials() const { - return impl->getSessionCredentials(); -} -const std::string& DefaultMQProducer::getInstanceName() const { - return impl->getInstanceName(); -} - -void DefaultMQProducer::setInstanceName(const std::string& instanceName) { - impl->setInstanceName(instanceName); -} - -const std::string& DefaultMQProducer::getNameSpace() const { - return impl->getNameSpace(); -} - -void DefaultMQProducer::setNameSpace(const std::string& nameSpace) { - impl->setNameSpace(nameSpace); -} -const std::string& DefaultMQProducer::getGroupName() const { - return impl->getGroupName(); -} - -void DefaultMQProducer::setGroupName(const std::string& groupName) { - impl->setGroupName(groupName); -} -void DefaultMQProducer::setSendMsgTimeout(int sendMsgTimeout) { - impl->setSendMsgTimeout(sendMsgTimeout); -} - -int DefaultMQProducer::getSendMsgTimeout() const { - return impl->getSendMsgTimeout(); -} - -void DefaultMQProducer::setRetryTimes(int times) { - impl->setRetryTimes(times); -} - -int DefaultMQProducer::getRetryTimes() const { - return impl->getRetryTimes(); -} - -int DefaultMQProducer::getCompressMsgBodyOverHowmuch() const { - return impl->getCompressMsgBodyOverHowmuch(); -} - -void DefaultMQProducer::setCompressMsgBodyOverHowmuch(int compressMsgBodyThreshold) { - impl->setCompressMsgBodyOverHowmuch(compressMsgBodyThreshold); -} - -int DefaultMQProducer::getCompressLevel() const { - return impl->getCompressLevel(); -} - -void DefaultMQProducer::setCompressLevel(int compressLevel) { - impl->setCompressLevel(compressLevel); -} - -void DefaultMQProducer::setMaxMessageSize(int maxMessageSize) { - impl->setMaxMessageSize(maxMessageSize); -} - -int DefaultMQProducer::getMaxMessageSize() const { - return impl->getMaxMessageSize(); -} - -void DefaultMQProducer::setRetryTimes4Async(int times) { - impl->setRetryTimes4Async(times); -} - -int DefaultMQProducer::getRetryTimes4Async() const { - return impl->getRetryTimes4Async(); -} - -void DefaultMQProducer::setLogLevel(elogLevel inputLevel) { - impl->setLogLevel(inputLevel); -} - -elogLevel DefaultMQProducer::getLogLevel() { - return impl->getLogLevel(); -} -void DefaultMQProducer::setLogFileSizeAndNum(int fileNum, long perFileSize) { - impl->setLogFileSizeAndNum(fileNum, perFileSize); -} - -void DefaultMQProducer::setTcpTransportPullThreadNum(int num) { - impl->setTcpTransportPullThreadNum(num); -} -int DefaultMQProducer::getTcpTransportPullThreadNum() const { - return impl->getTcpTransportPullThreadNum(); -} - -void DefaultMQProducer::setTcpTransportConnectTimeout(uint64_t timeout) { - impl->setTcpTransportConnectTimeout(timeout); -} -uint64_t DefaultMQProducer::getTcpTransportConnectTimeout() const { - return impl->getTcpTransportConnectTimeout(); -} -void DefaultMQProducer::setTcpTransportTryLockTimeout(uint64_t timeout) { - impl->setTcpTransportTryLockTimeout(timeout); -} -uint64_t DefaultMQProducer::getTcpTransportTryLockTimeout() const { - return impl->getTcpTransportTryLockTimeout(); -} - -void DefaultMQProducer::setUnitName(std::string unitName) { - impl->setUnitName(unitName); -} -const std::string& DefaultMQProducer::getUnitName() const { - return impl->getUnitName(); -} -void DefaultMQProducer::setMessageTrace(bool messageTrace) { - impl->setMessageTrace(messageTrace); -} -bool DefaultMQProducer::getMessageTrace() const { - return impl->getMessageTrace(); -} -SendResult DefaultMQProducer::send(MQMessage& msg, bool bSelectActiveBroker) { - return impl->send(msg, bSelectActiveBroker); -} - -SendResult DefaultMQProducer::send(MQMessage& msg, const MQMessageQueue& mq) { - return impl->send(msg, mq); -} - -SendResult DefaultMQProducer::send(MQMessage& msg, MessageQueueSelector* selector, void* arg) { - return impl->send(msg, selector, arg); -} - -SendResult DefaultMQProducer::send(MQMessage& msg, - MessageQueueSelector* selector, - void* arg, - int autoRetryTimes, - bool bActiveBroker) { - return impl->send(msg, selector, arg, autoRetryTimes, bActiveBroker); -} - -SendResult DefaultMQProducer::send(std::vector& msgs) { - return impl->send(msgs); -} - -SendResult DefaultMQProducer::send(std::vector& msgs, const MQMessageQueue& mq) { - return impl->send(msgs, mq); -} - -void DefaultMQProducer::send(MQMessage& msg, SendCallback* pSendCallback, bool bSelectActiveBroker) { - impl->send(msg, pSendCallback, bSelectActiveBroker); -} - -void DefaultMQProducer::send(MQMessage& msg, const MQMessageQueue& mq, SendCallback* pSendCallback) { - impl->send(msg, mq, pSendCallback); -} - -void DefaultMQProducer::send(MQMessage& msg, MessageQueueSelector* selector, void* arg, SendCallback* pSendCallback) { - impl->send(msg, selector, arg, pSendCallback); -} - -void DefaultMQProducer::sendOneway(MQMessage& msg, bool bSelectActiveBroker) { - impl->sendOneway(msg, bSelectActiveBroker); -} - -void DefaultMQProducer::sendOneway(MQMessage& msg, const MQMessageQueue& mq) { - impl->sendOneway(msg, mq); -} - -void DefaultMQProducer::sendOneway(MQMessage& msg, MessageQueueSelector* selector, void* arg) { - impl->sendOneway(msg, selector, arg); -} - -void DefaultMQProducer::setEnableSsl(bool enableSsl) { - impl->setEnableSsl(enableSsl); -} - -bool DefaultMQProducer::getEnableSsl() const { - return impl->getEnableSsl(); -} - -void DefaultMQProducer::setSslPropertyFile(const std::string& sslPropertyFile) { - impl->setSslPropertyFile(sslPropertyFile); -} - -const std::string& DefaultMQProducer::getSslPropertyFile() const { - return impl->getSslPropertyFile(); -} - -} // namespace rocketmq \ No newline at end of file diff --git a/src/producer/DefaultMQProducerImpl.cpp b/src/producer/DefaultMQProducerImpl.cpp deleted file mode 100644 index 20a9dc3a4..000000000 --- a/src/producer/DefaultMQProducerImpl.cpp +++ /dev/null @@ -1,777 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "DefaultMQProducerImpl.h" - -#include -#include - -#include "BatchMessage.h" -#include "CommandHeader.h" -#include "CommunicationMode.h" -#include "Logging.h" -#include "MQClientException.h" -#include "MQClientFactory.h" -#include "MQDecoder.h" -#include "MessageAccessor.h" -#include "NameSpaceUtil.h" -#include "SendMessageHookImpl.h" -#include "StringIdMaker.h" -#include "TopicPublishInfo.h" -#include "TraceConstant.h" -#include "Validators.h" - -namespace rocketmq { - -DefaultMQProducerImpl::DefaultMQProducerImpl(const string& groupname) - : m_sendMsgTimeout(3000), - m_compressMsgBodyOverHowmuch(4 * 1024), - m_maxMessageSize(1024 * 128), - // m_retryAnotherBrokerWhenNotStoreOK(false), - m_compressLevel(5), - m_retryTimes(5), - m_retryTimes4Async(1), - m_trace_ioService_work(m_trace_ioService) { - //registerProducer(this); - if (!registerOK) { - m_serviceState = CREATE_JUST; - THROW_MQEXCEPTION( - MQClientException, - "The producer group[" + getGroupName() + "] has been created before, specify another name please.", -1); - } - if (factoryStart) { - getFactory()->start(); - getFactory()->sendHeartbeatToAllBroker(); - } - m_serviceState = RUNNING; - break; - } - case RUNNING: - case START_FAILED: - case SHUTDOWN_ALREADY: - break; - default: - break; - } -} - -void DefaultMQProducerImpl::shutdown() { - shutdown(true); -} -void DefaultMQProducerImpl::shutdown(bool factoryStart) { - switch (m_serviceState) { - case RUNNING: { - LOG_INFO("DefaultMQProducerImpl shutdown"); - if (getMessageTrace()) { - LOG_INFO("DefaultMQProducerImpl message trace thread pool shutdown."); - m_trace_ioService.stop(); - m_trace_threadpool.join_all(); - } - getFactory()->unregisterProducer(this); - if (factoryStart) { - getFactory()->shutdown(); - } - m_serviceState = SHUTDOWN_ALREADY; - break; - } - case SHUTDOWN_ALREADY: - case CREATE_JUST: - break; - default: - break; - } -} - -SendResult DefaultMQProducerImpl::send(MQMessage& msg, bool bSelectActiveBroker) { - Validators::checkMessage(msg, getMaxMessageSize()); - if (!NameSpaceUtil::hasNameSpace(msg.getTopic(), getNameSpace())) { - MessageAccessor::withNameSpace(msg, getNameSpace()); - } - try { - return sendDefaultImpl(msg, ComMode_SYNC, NULL, bSelectActiveBroker); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - throw e; - } - return SendResult(); -} - -void DefaultMQProducerImpl::send(MQMessage& msg, SendCallback* pSendCallback, bool bSelectActiveBroker) { - Validators::checkMessage(msg, getMaxMessageSize()); - if (!NameSpaceUtil::hasNameSpace(msg.getTopic(), getNameSpace())) { - MessageAccessor::withNameSpace(msg, getNameSpace()); - } - try { - sendDefaultImpl(msg, ComMode_ASYNC, pSendCallback, bSelectActiveBroker); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - throw e; - } -} - -SendResult DefaultMQProducerImpl::send(std::vector& msgs) { - SendResult result; - try { - BatchMessage batchMessage = buildBatchMessage(msgs); - result = sendDefaultImpl(batchMessage, ComMode_SYNC, NULL); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - throw e; - } - return result; -} - -SendResult DefaultMQProducerImpl::send(std::vector& msgs, const MQMessageQueue& mq) { - SendResult result; - try { - BatchMessage batchMessage = buildBatchMessage(msgs); - result = sendKernelImpl(batchMessage, mq, ComMode_SYNC, NULL); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - throw e; - } - return result; -} - -BatchMessage DefaultMQProducerImpl::buildBatchMessage(std::vector& msgs) { - if (msgs.size() < 1) { - THROW_MQEXCEPTION(MQClientException, "msgs need one message at least", -1); - } - BatchMessage batchMessage; - bool firstFlag = true; - string topic; - bool waitStoreMsgOK = false; - for (auto& msg : msgs) { - Validators::checkMessage(msg, getMaxMessageSize()); - if (!NameSpaceUtil::hasNameSpace(msg.getTopic(), getNameSpace())) { - MessageAccessor::withNameSpace(msg, getNameSpace()); - } - if (firstFlag) { - topic = msg.getTopic(); - waitStoreMsgOK = msg.isWaitStoreMsgOK(); - firstFlag = false; - - if (UtilAll::startsWith_retry(topic)) { - THROW_MQEXCEPTION(MQClientException, "Retry Group is not supported for batching", -1); - } - } else { - if (msg.getDelayTimeLevel() > 0) { - THROW_MQEXCEPTION(MQClientException, "TimeDelayLevel in not supported for batching", -1); - } - if (msg.getTopic() != topic) { - THROW_MQEXCEPTION(MQClientException, "msgs need one message at least", -1); - } - if (msg.isWaitStoreMsgOK() != waitStoreMsgOK) { - THROW_MQEXCEPTION(MQClientException, "msgs need one message at least", -2); - } - } - } - batchMessage.setBody(BatchMessage::encode(msgs)); - batchMessage.setTopic(topic); - batchMessage.setWaitStoreMsgOK(waitStoreMsgOK); - return batchMessage; -} - -SendResult DefaultMQProducerImpl::send(MQMessage& msg, const MQMessageQueue& mq) { - Validators::checkMessage(msg, getMaxMessageSize()); - if (!NameSpaceUtil::hasNameSpace(msg.getTopic(), getNameSpace())) { - MessageAccessor::withNameSpace(msg, getNameSpace()); - } - if (msg.getTopic() != mq.getTopic()) { - LOG_WARN("message's topic not equal mq's topic"); - } - try { - return sendKernelImpl(msg, mq, ComMode_SYNC, NULL); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - throw e; - } - return SendResult(); -} - -void DefaultMQProducerImpl::send(MQMessage& msg, const MQMessageQueue& mq, SendCallback* pSendCallback) { - Validators::checkMessage(msg, getMaxMessageSize()); - if (!NameSpaceUtil::hasNameSpace(msg.getTopic(), getNameSpace())) { - MessageAccessor::withNameSpace(msg, getNameSpace()); - } - if (msg.getTopic() != mq.getTopic()) { - LOG_WARN("message's topic not equal mq's topic"); - } - try { - sendKernelImpl(msg, mq, ComMode_ASYNC, pSendCallback); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - throw e; - } -} - -void DefaultMQProducerImpl::sendOneway(MQMessage& msg, bool bSelectActiveBroker) { - Validators::checkMessage(msg, getMaxMessageSize()); - if (!NameSpaceUtil::hasNameSpace(msg.getTopic(), getNameSpace())) { - MessageAccessor::withNameSpace(msg, getNameSpace()); - } - try { - sendDefaultImpl(msg, ComMode_ONEWAY, NULL, bSelectActiveBroker); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - throw e; - } -} - -void DefaultMQProducerImpl::sendOneway(MQMessage& msg, const MQMessageQueue& mq) { - Validators::checkMessage(msg, getMaxMessageSize()); - if (!NameSpaceUtil::hasNameSpace(msg.getTopic(), getNameSpace())) { - MessageAccessor::withNameSpace(msg, getNameSpace()); - } - if (msg.getTopic() != mq.getTopic()) { - LOG_WARN("message's topic not equal mq's topic"); - } - try { - sendKernelImpl(msg, mq, ComMode_ONEWAY, NULL); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - throw e; - } -} - -SendResult DefaultMQProducerImpl::send(MQMessage& msg, MessageQueueSelector* pSelector, void* arg) { - try { - if (!NameSpaceUtil::hasNameSpace(msg.getTopic(), getNameSpace())) { - MessageAccessor::withNameSpace(msg, getNameSpace()); - } - return sendSelectImpl(msg, pSelector, arg, ComMode_SYNC, NULL); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - throw e; - } - return SendResult(); -} - -SendResult DefaultMQProducerImpl::send(MQMessage& msg, - MessageQueueSelector* pSelector, - void* arg, - int autoRetryTimes, - bool bActiveBroker) { - try { - if (!NameSpaceUtil::hasNameSpace(msg.getTopic(), getNameSpace())) { - MessageAccessor::withNameSpace(msg, getNameSpace()); - } - return sendAutoRetrySelectImpl(msg, pSelector, arg, ComMode_SYNC, NULL, autoRetryTimes, bActiveBroker); - } catch (MQException& e) { - LOG_ERROR("%s", e.what()); - throw e; - } - return SendResult(); -} - -void DefaultMQProducerImpl::send(MQMessage& msg, - MessageQueueSelector* pSelector, - void* arg, - SendCallback* pSendCallback) { - try { - if (!NameSpaceUtil::hasNameSpace(msg.getTopic(), getNameSpace())) { - MessageAccessor::withNameSpace(msg, getNameSpace()); - } - sendSelectImpl(msg, pSelector, arg, ComMode_ASYNC, pSendCallback); - } catch (MQException& e) { - LOG_ERROR(e.what()); - throw e; - } -} - -void DefaultMQProducerImpl::sendOneway(MQMessage& msg, MessageQueueSelector* pSelector, void* arg) { - try { - if (!NameSpaceUtil::hasNameSpace(msg.getTopic(), getNameSpace())) { - MessageAccessor::withNameSpace(msg, getNameSpace()); - } - sendSelectImpl(msg, pSelector, arg, ComMode_ONEWAY, NULL); - } catch (MQException& e) { - LOG_ERROR(e.what()); - throw e; - } -} - -int DefaultMQProducerImpl::getSendMsgTimeout() const { - return m_sendMsgTimeout; -} - -void DefaultMQProducerImpl::setSendMsgTimeout(int sendMsgTimeout) { - m_sendMsgTimeout = sendMsgTimeout; -} - -int DefaultMQProducerImpl::getCompressMsgBodyOverHowmuch() const { - return m_compressMsgBodyOverHowmuch; -} - -void DefaultMQProducerImpl::setCompressMsgBodyOverHowmuch(int compressMsgBodyOverHowmuch) { - m_compressMsgBodyOverHowmuch = compressMsgBodyOverHowmuch; -} - -int DefaultMQProducerImpl::getMaxMessageSize() const { - return m_maxMessageSize; -} - -void DefaultMQProducerImpl::setMaxMessageSize(int maxMessageSize) { - m_maxMessageSize = maxMessageSize; -} - -int DefaultMQProducerImpl::getCompressLevel() const { - return m_compressLevel; -} - -void DefaultMQProducerImpl::setCompressLevel(int compressLevel) { - assert((compressLevel >= 0 && compressLevel <= 9) || compressLevel == -1); - - m_compressLevel = compressLevel; -} - -// weak_topicPublishInfo( - getFactory()->tryToFindTopicPublishInfo(msg.getTopic(), getSessionCredentials())); - boost::shared_ptr topicPublishInfo(weak_topicPublishInfo.lock()); - if (topicPublishInfo) { - if (times == 1) { - mq_index = topicPublishInfo->getWhichQueue(); - } else { - mq_index++; - } - - SendResult sendResult; - MQMessageQueue mq; - if (bActiveMQ) - mq = topicPublishInfo->selectOneActiveMessageQueue(lastmq, mq_index); - else - mq = topicPublishInfo->selectOneMessageQueue(lastmq, mq_index); - - lastmq = mq; - if (mq.getQueueId() == -1) { - // THROW_MQEXCEPTION(MQClientException, "the MQMessageQueue is - // invalide", -1); - continue; - } - - try { - LOG_DEBUG("send to mq:%s", mq.toString().data()); - sendResult = sendKernelImpl(msg, mq, communicationMode, pSendCallback); - switch (communicationMode) { - case ComMode_ASYNC: - return sendResult; - case ComMode_ONEWAY: - return sendResult; - case ComMode_SYNC: - if (sendResult.getSendStatus() != SEND_OK) { - if (bActiveMQ) { - topicPublishInfo->updateNonServiceMessageQueue(mq, getSendMsgTimeout()); - } - continue; - } - return sendResult; - default: - break; - } - } catch (std::exception& e) { - send_failed = true; - failed_detail = e.what(); - LOG_ERROR("send failed of times:%d,brokerName:%s,details:%s", times, mq.getBrokerName().c_str(), e.what()); - if (bActiveMQ) { - topicPublishInfo->updateNonServiceMessageQueue(mq, getSendMsgTimeout()); - } - continue; - } catch (...) { - LOG_ERROR("Unknown error, send failed of times:%d, brokerName:%s", times, mq.getBrokerName().c_str()); - } - } // end of for - LOG_WARN("Retry many times, still failed"); - } - if (send_failed) { - THROW_MQEXCEPTION(MQClientException, failed_detail, -1); - } - string info = "No route info of this topic: " + msg.getTopic(); - THROW_MQEXCEPTION(MQClientException, info, -1); -} - -SendResult DefaultMQProducerImpl::sendKernelImpl(MQMessage& msg, - const MQMessageQueue& mq, - int communicationMode, - SendCallback* sendCallback) { - string brokerAddr = getFactory()->findBrokerAddressInPublish(mq.getBrokerName()); - - if (brokerAddr.empty()) { - getFactory()->tryToFindTopicPublishInfo(mq.getTopic(), getSessionCredentials()); - brokerAddr = getFactory()->findBrokerAddressInPublish(mq.getBrokerName()); - } - - if (!brokerAddr.empty()) { - boost::scoped_ptr pSendMesgContext(new SendMessageContext()); - try { - bool isBatchMsg = std::type_index(typeid(msg)) == std::type_index(typeid(BatchMessage)); - // msgId is produced by client, offsetMsgId produced by broker. (same with java sdk) - if (!isBatchMsg) { - string unique_id = StringIdMaker::getInstance().createUniqID(); - msg.setProperty(MQMessage::PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, unique_id); - - // batch does not support compressing right now, - tryToCompressMessage(msg); - } - - LOG_DEBUG("produce before:%s to %s", msg.toString().c_str(), mq.toString().c_str()); - if (!isMessageTraceTopic(msg.getTopic()) && getMessageTrace() && hasSendMessageHook()) { - pSendMesgContext.reset(new SendMessageContext); - pSendMesgContext->setDefaultMqProducer(this); - pSendMesgContext->setProducerGroup(NameSpaceUtil::withoutNameSpace(getGroupName(), getNameSpace())); - pSendMesgContext->setCommunicationMode(static_cast(communicationMode)); - pSendMesgContext->setBornHost(UtilAll::getLocalAddress()); - pSendMesgContext->setBrokerAddr(brokerAddr); - pSendMesgContext->setMessage(msg); - pSendMesgContext->setMessageQueue(mq); - pSendMesgContext->setMsgType(TRACE_NORMAL_MSG); - pSendMesgContext->setNameSpace(getNameSpace()); - string tranMsg = msg.getProperty(MQMessage::PROPERTY_TRANSACTION_PREPARED); - if (!tranMsg.empty() && tranMsg == "true") { - pSendMesgContext->setMsgType(TRACE_TRANS_HALF_MSG); - } - - if (msg.getProperty("__STARTDELIVERTIME") != "" || - msg.getProperty(MQMessage::PROPERTY_DELAY_TIME_LEVEL) != "") { - pSendMesgContext->setMsgType(TRACE_DELAY_MSG); - } - executeSendMessageHookBefore(pSendMesgContext.get()); - } - SendMessageRequestHeader requestHeader; - requestHeader.producerGroup = getGroupName(); - requestHeader.topic = (msg.getTopic()); - requestHeader.defaultTopic = DEFAULT_TOPIC; - requestHeader.defaultTopicQueueNums = 4; - requestHeader.queueId = (mq.getQueueId()); - requestHeader.sysFlag = (msg.getSysFlag()); - requestHeader.bornTimestamp = UtilAll::currentTimeMillis(); - requestHeader.flag = (msg.getFlag()); - requestHeader.consumeRetryTimes = 16; - requestHeader.batch = isBatchMsg; - requestHeader.properties = (MQDecoder::messageProperties2String(msg.getProperties())); - - SendResult sendResult = getFactory()->getMQClientAPIImpl()->sendMessage( - brokerAddr, mq.getBrokerName(), msg, requestHeader, getSendMsgTimeout(), getRetryTimes4Async(), - communicationMode, sendCallback, getSessionCredentials()); - if (!isMessageTraceTopic(msg.getTopic()) && getMessageTrace() && hasSendMessageHook() && sendCallback == NULL && - communicationMode == ComMode_SYNC) { - pSendMesgContext->setSendResult(sendResult); - executeSendMessageHookAfter(pSendMesgContext.get()); - } - return sendResult; - } catch (MQException& e) { - throw e; - } - } - THROW_MQEXCEPTION(MQClientException, "The broker[" + mq.getBrokerName() + "] not exist", -1); -} - -SendResult DefaultMQProducerImpl::sendSelectImpl(MQMessage& msg, - MessageQueueSelector* pSelector, - void* pArg, - int communicationMode, - SendCallback* sendCallback) { - Validators::checkMessage(msg, getMaxMessageSize()); - - boost::weak_ptr weak_topicPublishInfo( - getFactory()->tryToFindTopicPublishInfo(msg.getTopic(), getSessionCredentials())); - boost::shared_ptr topicPublishInfo(weak_topicPublishInfo.lock()); - if (topicPublishInfo) //&& topicPublishInfo->ok()) - { - MQMessageQueue mq = pSelector->select(topicPublishInfo->getMessageQueueList(), msg, pArg); - return sendKernelImpl(msg, mq, communicationMode, sendCallback); - } - THROW_MQEXCEPTION(MQClientException, "No route info for this topic", -1); -} - -SendResult DefaultMQProducerImpl::sendAutoRetrySelectImpl(MQMessage& msg, - MessageQueueSelector* pSelector, - void* pArg, - int communicationMode, - SendCallback* pSendCallback, - int autoRetryTimes, - bool bActiveMQ) { - Validators::checkMessage(msg, getMaxMessageSize()); - - MQMessageQueue lastmq; - MQMessageQueue mq; - int mq_index = 0; - bool send_failed = false; - string failed_detail; - for (int times = 1; times <= autoRetryTimes + 1; times++) { - boost::weak_ptr weak_topicPublishInfo( - getFactory()->tryToFindTopicPublishInfo(msg.getTopic(), getSessionCredentials())); - boost::shared_ptr topicPublishInfo(weak_topicPublishInfo.lock()); - if (topicPublishInfo) { - SendResult sendResult; - if (times == 1) { - // always send to selected MQ firstly, evenif bActiveMQ was setted to true - mq = pSelector->select(topicPublishInfo->getMessageQueueList(), msg, pArg); - lastmq = mq; - } else { - LOG_INFO("sendAutoRetrySelectImpl with times:%d", times); - std::vector mqs(topicPublishInfo->getMessageQueueList()); - for (size_t i = 0; i < mqs.size(); i++) { - if (mqs[i] == lastmq) - mq_index = i; - } - if (bActiveMQ) - mq = topicPublishInfo->selectOneActiveMessageQueue(lastmq, mq_index); - else - mq = topicPublishInfo->selectOneMessageQueue(lastmq, mq_index); - lastmq = mq; - if (mq.getQueueId() == -1) { - // THROW_MQEXCEPTION(MQClientException, "the MQMessageQueue is - // invalide", -1); - continue; - } - } - - try { - LOG_DEBUG("send to broker:%s", mq.toString().c_str()); - sendResult = sendKernelImpl(msg, mq, communicationMode, pSendCallback); - switch (communicationMode) { - case ComMode_ASYNC: - return sendResult; - case ComMode_ONEWAY: - return sendResult; - case ComMode_SYNC: - if (sendResult.getSendStatus() != SEND_OK) { - if (bActiveMQ) { - topicPublishInfo->updateNonServiceMessageQueue(mq, getSendMsgTimeout()); - } - continue; - } - return sendResult; - default: - break; - } - } catch (std::exception& e) { - send_failed = true; - failed_detail = e.what(); - LOG_ERROR("send failed of times:%d,mq:%s,details:%s", times, mq.toString().c_str(), e.what()); - if (bActiveMQ) { - topicPublishInfo->updateNonServiceMessageQueue(mq, getSendMsgTimeout()); - } - continue; - } catch (...) { - LOG_ERROR("An unknown exception occurred,send failed of times:%d,mq:%s", times, mq.toString().c_str()); - } - } // end of for - LOG_WARN("Retry many times, still failed"); - if (send_failed) { - THROW_MQEXCEPTION(MQClientException, failed_detail, -1); - } - } - THROW_MQEXCEPTION(MQClientException, "No route info of this topic, ", -1); -} - -bool DefaultMQProducerImpl::tryToCompressMessage(MQMessage& msg) { - int sysFlag = msg.getSysFlag(); - if ((sysFlag & MessageSysFlag::CompressedFlag) == MessageSysFlag::CompressedFlag) { - return true; - } - - string body = msg.getBody(); - if ((int)body.length() >= getCompressMsgBodyOverHowmuch()) { - string outBody; - if (UtilAll::deflate(body, outBody, getCompressLevel())) { - msg.setBody(outBody); - msg.setSysFlag(sysFlag | MessageSysFlag::CompressedFlag); - return true; - } - } - - return false; -} - -int DefaultMQProducerImpl::getRetryTimes() const { - return m_retryTimes; -} - -void DefaultMQProducerImpl::setRetryTimes(int times) { - if (times <= 0) { - LOG_WARN("set retry times illegal, use default value:5"); - return; - } - - if (times > 15) { - LOG_WARN("set retry times illegal, use max value:15"); - m_retryTimes = 15; - return; - } - LOG_WARN("set retry times to:%d", times); - m_retryTimes = times; -} - -int DefaultMQProducerImpl::getRetryTimes4Async() const { - return m_retryTimes4Async; -} - -void DefaultMQProducerImpl::setRetryTimes4Async(int times) { - if (times <= 0) { - LOG_WARN("set retry times illegal, use default value:1"); - m_retryTimes4Async = 1; - return; - } - - if (times > 15) { - LOG_WARN("set retry times illegal, use max value:15"); - m_retryTimes4Async = 15; - return; - } - LOG_INFO("set retry times to:%d", times); - m_retryTimes4Async = times; -} - -// we should deal with name space before producer start. -bool DefaultMQProducerImpl::dealWithNameSpace() { - string ns = getNameSpace(); - if (ns.empty()) { - string nsAddr = getNamesrvAddr(); - if (!NameSpaceUtil::checkNameSpaceExistInNameServer(nsAddr)) { - return true; - } - ns = NameSpaceUtil::getNameSpaceFromNsURL(nsAddr); - // reset namespace - setNameSpace(ns); - } - // reset group name - if (!NameSpaceUtil::hasNameSpace(getGroupName(), ns)) { - string fullGID = NameSpaceUtil::withNameSpace(getGroupName(), ns); - setGroupName(fullGID); - } - return true; -} - -void DefaultMQProducerImpl::logConfigs() { - showClientConfigs(); - - LOG_WARN("SendMsgTimeout:%d ms", m_sendMsgTimeout); - LOG_WARN("CompressMsgBodyOverHowmuch:%d", m_compressMsgBodyOverHowmuch); - LOG_WARN("MaxMessageSize:%d", m_maxMessageSize); - LOG_WARN("CompressLevel:%d", m_compressLevel); - LOG_WARN("RetryTimes:%d", m_retryTimes); - LOG_WARN("RetryTimes4Async:%d", m_retryTimes4Async); -} - -// we should create trace message poll before producer send messages. -bool DefaultMQProducerImpl::dealWithMessageTrace() { - if (!getMessageTrace()) { - LOG_INFO("Message Trace set to false, Will not send trace messages."); - return false; - } - size_t threadpool_size = boost::thread::hardware_concurrency(); - LOG_INFO("Create send message trace threadpool: %d", threadpool_size); - for (size_t i = 0; i < threadpool_size; ++i) { - m_trace_threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &m_trace_ioService)); - } - LOG_INFO("DefaultMQProducer Open meassage trace.."); - std::shared_ptr hook(new SendMessageHookImpl); - registerSendMessageHook(hook); - return true; -} -bool DefaultMQProducerImpl::isMessageTraceTopic(const string& source) { - return source.find(TraceConstant::TRACE_TOPIC) != string::npos; -} -bool DefaultMQProducerImpl::hasSendMessageHook() { - return !m_sendMessageHookList.empty(); -} - -void DefaultMQProducerImpl::registerSendMessageHook(std::shared_ptr& hook) { - m_sendMessageHookList.push_back(hook); - LOG_INFO("Register sendMessageHook success,hookname is %s", hook->getHookName().c_str()); -} - -void DefaultMQProducerImpl::executeSendMessageHookBefore(SendMessageContext* context) { - if (!m_sendMessageHookList.empty()) { - std::vector >::iterator it = m_sendMessageHookList.begin(); - for (; it != m_sendMessageHookList.end(); ++it) { - try { - (*it)->executeHookBefore(context); - } catch (exception e) { - } - } - } -} - -void DefaultMQProducerImpl::executeSendMessageHookAfter(SendMessageContext* context) { - if (!m_sendMessageHookList.empty()) { - std::vector >::iterator it = m_sendMessageHookList.begin(); - for (; it != m_sendMessageHookList.end(); ++it) { - try { - (*it)->executeHookAfter(context); - } catch (exception e) { - } - } - } -} - -void DefaultMQProducerImpl::submitSendTraceRequest(const MQMessage& msg, SendCallback* pSendCallback) { - m_trace_ioService.post(boost::bind(&DefaultMQProducerImpl::sendTraceMessage, this, msg, pSendCallback)); -} - -void DefaultMQProducerImpl::sendTraceMessage(MQMessage& msg, SendCallback* pSendCallback) { - try { - LOG_DEBUG("=====Send Trace Messages,Topic[%s],Key[%s],Body[%s]", msg.getTopic().c_str(), msg.getKeys().c_str(), - msg.getBody().c_str()); - send(msg, pSendCallback, true); - } catch (MQException e) { - LOG_ERROR(e.what()); - // throw e; - } -} -} // namespace rocketmq diff --git a/src/producer/DefaultMQProducerImpl.h b/src/producer/DefaultMQProducerImpl.h deleted file mode 100644 index d2eb1879d..000000000 --- a/src/producer/DefaultMQProducerImpl.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __DEFAULTMQPRODUCERIMPL_H__ -#define __DEFAULTMQPRODUCERIMPL_H__ - -#include "BatchMessage.h" -#include "MQMessageQueue.h" -#include "MQProducer.h" -#include "RocketMQClient.h" -#include "SendMessageContext.h" -#include "SendMessageHook.h" -#include "SendResult.h" - -namespace rocketmq { -//& msgs); - virtual SendResult send(std::vector& msgs, const MQMessageQueue& mq); - virtual void send(MQMessage& msg, SendCallback* pSendCallback, bool bSelectActiveBroker = false); - virtual void send(MQMessage& msg, const MQMessageQueue& mq, SendCallback* pSendCallback); - virtual void send(MQMessage& msg, MessageQueueSelector* selector, void* arg, SendCallback* pSendCallback); - virtual void sendOneway(MQMessage& msg, bool bSelectActiveBroker = false); - virtual void sendOneway(MQMessage& msg, const MQMessageQueue& mq); - virtual void sendOneway(MQMessage& msg, MessageQueueSelector* selector, void* arg); - //& msgs); - bool dealWithNameSpace(); - void logConfigs(); - bool dealWithMessageTrace(); - bool isMessageTraceTopic(const std::string& topic); - bool hasSendMessageHook(); - void registerSendMessageHook(std::shared_ptr& hook); - void executeSendMessageHookBefore(SendMessageContext* context); - void executeSendMessageHookAfter(SendMessageContext* context); - - void sendTraceMessage(MQMessage& msg, SendCallback* pSendCallback); - - private: - int m_sendMsgTimeout; - int m_compressMsgBodyOverHowmuch; - int m_maxMessageSize; // > m_sendMessageHookList; - boost::asio::io_service m_trace_ioService; - boost::thread_group m_trace_threadpool; - boost::asio::io_service::work m_trace_ioService_work; -}; -// -#include -#include "DefaultMQProducerImpl.h" -#include "Logging.h" -#include "MQClientException.h" -#include "SendMessageContext.h" -#include "TraceConstant.h" -#include "TraceTransferBean.h" -#include "TraceUtil.h" -#include "UtilAll.h" - -using namespace std; -namespace rocketmq { - -class TraceMessageSendCallback : public SendCallback { - virtual void onSuccess(SendResult& sendResult) { - LOG_DEBUG("TraceMessageSendCallback, MsgId:[%s],OffsetMsgId[%s]", sendResult.getMsgId().c_str(), - sendResult.getOffsetMsgId().c_str()); - } - virtual void onException(MQException& e) {} -}; -static TraceMessageSendCallback* callback = new TraceMessageSendCallback(); -std::string SendMessageHookImpl::getHookName() { - return "RocketMQSendMessageHookImpl"; -} - -void SendMessageHookImpl::executeHookBefore(SendMessageContext* context) { - if (context != NULL) { - string topic = context->getMessage()->getTopic(); - // Check if contains TraceConstants::TRACE_TOPIC - if (topic.find(TraceConstant::TRACE_TOPIC) != string::npos) { - // trace message itself - return; - } - TraceContext* traceContext = new TraceContext(); - context->setTraceContext(traceContext); - } - return; -} - -void SendMessageHookImpl::executeHookAfter(SendMessageContext* context) { - if (context == NULL || context->getSendResult() == NULL) { - return; - } - string topic = context->getMessage()->getTopic(); - // Check if contains TraceConstants::TRACE_TOPIC - if (topic.find(TraceConstant::TRACE_TOPIC) != string::npos - || context->getSendResult()->getTraceOn() == false) { - // trace message itself - return; - } - std::shared_ptr traceContext; - traceContext.reset(context->getTraceContext()); - - // OnsTraceContext* onsContext = context->getMqTraceContext(); - traceContext->setTraceType(Pub); - traceContext->setGroupName(context->getProducerGroup()); - // boost::scoped_ptr traceBean(new OnsTraceBean()); - TraceBean traceBean; - traceBean.setTopic(context->getMessage()->getTopic()); - traceBean.setTags(context->getMessage()->getTags()); - traceBean.setKeys(context->getMessage()->getKeys()); - traceBean.setStoreHost(context->getBrokerAddr()); - traceBean.setBodyLength(context->getMessage()->getBody().size()); - traceBean.setMsgType(context->getMsgType()); - - int costTime = static_cast(UtilAll::currentTimeMillis() - traceContext->getTimeStamp()); - traceContext->setCostTime(costTime); - if (context->getSendResult()->getSendStatus() == SEND_OK) { - traceContext->setStatus(true); - } else { - traceContext->setStatus(false); - } - - traceContext->setRegionId(context->getSendResult()->getRegionId()); - traceBean.setMsgId(context->getMessage()->getProperty(MQMessage::PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX)); - traceBean.setOffsetMsgId(context->getSendResult()->getOffsetMsgId()); - traceBean.setStoreTime(traceContext->getTimeStamp() + (costTime / 2)); - - traceContext->setTraceBean(traceBean); - - topic = TraceConstant::TRACE_TOPIC + traceContext->getRegionId(); - TraceTransferBean ben = TraceUtil::CovertTraceContextToTransferBean(traceContext.get()); - // encode data - MQMessage message(topic, ben.getTransData()); - message.setKeys(ben.getTransKey()); - // send trace message. - context->getDefaultMqProducer()->submitSendTraceRequest(message, callback); - return; -} -} // namespace rocketmq diff --git a/src/producer/SendMessageHookImpl.h b/src/producer/SendMessageHookImpl.h deleted file mode 100644 index 54a2ebcfd..000000000 --- a/src/producer/SendMessageHookImpl.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __ROCKETMQ_SEND_MESSAGE_RPC_HOOK_IMPL_H__ -#define __ROCKETMQ_SEND_MESSAGE_RPC_HOOK_IMPL_H__ - -#include -#include "SendMessageContext.h" -#include "SendMessageHook.h" -namespace rocketmq { -class SendMessageHookImpl : public SendMessageHook { - public: - virtual ~SendMessageHookImpl() {} - virtual std::string getHookName(); - virtual void executeHookBefore(SendMessageContext* context); - virtual void executeHookAfter(SendMessageContext* context); -}; -} // namespace rocketmq -#endif \ No newline at end of file diff --git a/src/producer/SendResult.cpp b/src/producer/SendResult.cpp deleted file mode 100644 index f6926d500..000000000 --- a/src/producer/SendResult.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "SendResult.h" -#include -#include "UtilAll.h" -#include "VirtualEnvUtil.h" - -namespace rocketmq { -// -#include -#include -#include - -#include "ByteOrder.h" -#include "UtilAll.h" - -namespace rocketmq { - -const char StringIdMaker::sHexAlphabet[16] = {'0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - -StringIdMaker::StringIdMaker() { - std::srand((uint32_t)std::time(NULL)); - - uint32_t pid = ByteOrder::swapIfLittleEndian(static_cast(getpid())); - uint32_t ip = ByteOrder::swapIfLittleEndian(getIP()); - uint32_t random_num = ByteOrder::swapIfLittleEndian(static_cast(std::rand())); - - unsigned char bin_buf[10]; - std::memcpy(bin_buf + 2, &pid, 4); - std::memcpy(bin_buf, &ip, 4); - std::memcpy(bin_buf + 6, &random_num, 4); - - hexdump(bin_buf, kFixString, 10); - kFixString[20] = '\0'; - - setStartTime(UtilAll::currentTimeMillis()); - - mCounter = 0; -} - -StringIdMaker::~StringIdMaker() {} - -uint32_t StringIdMaker::getIP() { - std::string ip = UtilAll::getLocalAddress(); - if (ip.empty()) { - return 0; - } - - char* ip_str = new char[ip.length() + 1]; - std::strncpy(ip_str, ip.c_str(), ip.length()); - ip_str[ip.length()] = '\0'; - - int i = 3; - uint32_t nResult = 0; - for (char* token = std::strtok(ip_str, "."); token != nullptr && i >= 0; token = std::strtok(nullptr, ".")) { - uint32_t n = std::atoi(token); - nResult |= n << (8 * i--); - } - - delete[] ip_str; - - return nResult; -} - -void StringIdMaker::setStartTime(uint64_t millis) { - // std::time_t - // Although not defined, this is almost always an integral value holding the number of seconds - // (not counting leap seconds) since 00:00, Jan 1 1970 UTC, corresponding to POSIX time. - std::time_t tmNow = millis / 1000; - std::tm* ptmNow = std::localtime(&tmNow); // may not be thread-safe - - std::tm curMonthBegin = {0}; - curMonthBegin.tm_year = ptmNow->tm_year; // since 1900 - curMonthBegin.tm_mon = ptmNow->tm_mon; // [0, 11] - curMonthBegin.tm_mday = 1; // [1, 31] - curMonthBegin.tm_hour = 0; // [0, 23] - curMonthBegin.tm_min = 0; // [0, 59] - curMonthBegin.tm_sec = 0; // [0, 60] - - std::tm nextMonthBegin = {0}; - if (ptmNow->tm_mon >= 11) { - nextMonthBegin.tm_year = ptmNow->tm_year + 1; - nextMonthBegin.tm_mon = 0; - } else { - nextMonthBegin.tm_year = ptmNow->tm_year; - nextMonthBegin.tm_mon = ptmNow->tm_mon + 1; - } - nextMonthBegin.tm_mday = 1; - nextMonthBegin.tm_hour = 0; - nextMonthBegin.tm_min = 0; - nextMonthBegin.tm_sec = 0; - - mStartTime = std::mktime(&curMonthBegin) * 1000; - mNextStartTime = std::mktime(&nextMonthBegin) * 1000; -} - -std::string StringIdMaker::createUniqID() { - uint64_t current = UtilAll::currentTimeMillis(); - if (current >= mNextStartTime) { - setStartTime(current); - current = UtilAll::currentTimeMillis(); - } - - uint32_t period = ByteOrder::swapIfLittleEndian(static_cast(current - mStartTime)); - uint16_t seqid = ByteOrder::swapIfLittleEndian(mCounter++); - - unsigned char bin_buf[6]; - std::memcpy(bin_buf, &period, 4); - std::memcpy(bin_buf + 4, &seqid, 2); - - char hex_buf[12]; - hexdump(bin_buf, hex_buf, 6); - - return std::string(kFixString, 20) + std::string(hex_buf, 12); -} - -void StringIdMaker::hexdump(unsigned char* buffer, char* out_buff, std::size_t index) { - for (std::size_t i = 0; i < index; i++) { - unsigned char v = buffer[i]; - out_buff[i * 2] = sHexAlphabet[v >> 4]; - out_buff[i * 2 + 1] = sHexAlphabet[v & 0x0FU]; - } -} - -} // namespace rocketmq diff --git a/src/producer/TopicPublishInfo.h b/src/producer/TopicPublishInfo.h deleted file mode 100644 index c57253508..000000000 --- a/src/producer/TopicPublishInfo.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __TOPICPUBLISHINFO_H__ -#define __TOPICPUBLISHINFO_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "Logging.h" -#include "MQMessageQueue.h" -#include "UtilAll.h" - -namespace rocketmq { -//interrupt(); - m_async_service_thread->join(); - - m_nonSerivceQueues.clear(); - m_onSerivceQueues.clear(); - m_brokerTimerMap.clear(); - m_queues.clear(); - } - - bool ok() { - boost::lock_guard lock(m_queuelock); - return !m_queues.empty(); - } - - void updateMessageQueueList(const MQMessageQueue& mq) { - boost::lock_guard lock(m_queuelock); - m_queues.push_back(mq); - string key = mq.getBrokerName() + UtilAll::to_string(mq.getQueueId()); - m_onSerivceQueues[key] = mq; - if (m_nonSerivceQueues.find(key) != m_nonSerivceQueues.end()) { - m_nonSerivceQueues.erase(key); // if topicPublishInfo changed, erase this - // mq from m_nonSerivceQueues to avoid 2 - // copies both in m_onSerivceQueues and - // m_nonSerivceQueues - } - } - - void op_resumeNonServiceMessageQueueList(boost::system::error_code& ec, boost::asio::deadline_timer* t) { - resumeNonServiceMessageQueueList(); - boost::system::error_code e; - t->expires_from_now(t->expires_from_now() + boost::posix_time::seconds(60), e); - t->async_wait(boost::bind(&TopicPublishInfo::op_resumeNonServiceMessageQueueList, this, e, t)); - } - - void resumeNonServiceMessageQueueList() { - boost::lock_guard lock(m_queuelock); - for (map::iterator it = m_brokerTimerMap.begin(); it != m_brokerTimerMap.end(); ++it) { - if (UtilAll::currentTimeMillis() - it->second >= 1000 * 60 * 5) { - string key = it->first.getBrokerName() + UtilAll::to_string(it->first.getQueueId()); - if (m_nonSerivceQueues.find(key) != m_nonSerivceQueues.end()) { - m_nonSerivceQueues.erase(key); - } - m_onSerivceQueues[key] = it->first; - } - } - } - - void updateNonServiceMessageQueue(const MQMessageQueue& mq, int timeoutMilliseconds) { - boost::lock_guard lock(m_queuelock); - - string key = mq.getBrokerName() + UtilAll::to_string(mq.getQueueId()); - if (m_nonSerivceQueues.find(key) != m_nonSerivceQueues.end()) { - return; - } - LOG_INFO("updateNonServiceMessageQueue of mq:%s", mq.toString().c_str()); - m_brokerTimerMap[mq] = UtilAll::currentTimeMillis(); - m_nonSerivceQueues[key] = mq; - if (m_onSerivceQueues.find(key) != m_onSerivceQueues.end()) { - m_onSerivceQueues.erase(key); - } - } - - vector& getMessageQueueList() { - boost::lock_guard lock(m_queuelock); - return m_queues; - } - - int getWhichQueue() { return m_sendWhichQueue.load(boost::memory_order_acquire); } - - MQMessageQueue selectOneMessageQueue(const MQMessageQueue& lastmq, int& mq_index) { - boost::lock_guard lock(m_queuelock); - - if (m_queues.size() > 0) { - LOG_DEBUG("selectOneMessageQueue Enter, queue size:" SIZET_FMT "", m_queues.size()); - unsigned int pos = 0; - if (mq_index >= 0) { - pos = mq_index % m_queues.size(); - } else { - LOG_ERROR("mq_index is negative"); - return MQMessageQueue(); - } - if (!lastmq.getBrokerName().empty()) { - for (size_t i = 0; i < m_queues.size(); i++) { - if (m_sendWhichQueue.load(boost::memory_order_acquire) == (numeric_limits::max)()) { - m_sendWhichQueue.store(0, boost::memory_order_release); - } - - if (pos >= m_queues.size()) - pos = pos % m_queues.size(); - - ++m_sendWhichQueue; - MQMessageQueue mq = m_queues.at(pos); - LOG_DEBUG("lastmq broker not empty, m_sendWhichQueue:%d, pos:%d", - m_sendWhichQueue.load(boost::memory_order_acquire), pos); - if (mq.getBrokerName().compare(lastmq.getBrokerName()) != 0) { - mq_index = pos; - return mq; - } - ++pos; - } - LOG_ERROR("could not find property mq"); - return MQMessageQueue(); - } else { - if (m_sendWhichQueue.load(boost::memory_order_acquire) == (numeric_limits::max)()) { - m_sendWhichQueue.store(0, boost::memory_order_release); - } - - ++m_sendWhichQueue; - LOG_DEBUG("lastmq broker empty, m_sendWhichQueue:%d, pos:%d", - m_sendWhichQueue.load(boost::memory_order_acquire), pos); - mq_index = pos; - return m_queues.at(pos); - } - } else { - LOG_ERROR("m_queues empty"); - return MQMessageQueue(); - } - } - - MQMessageQueue selectOneActiveMessageQueue(const MQMessageQueue& lastmq, int& mq_index) { - boost::lock_guard lock(m_queuelock); - - if (m_queues.size() > 0) { - unsigned int pos = 0; - if (mq_index >= 0) { - pos = mq_index % m_queues.size(); - } else { - LOG_ERROR("mq_index is negative"); - return MQMessageQueue(); - } - if (!lastmq.getBrokerName().empty()) { - for (size_t i = 0; i < m_queues.size(); i++) { - if (m_sendWhichQueue.load(boost::memory_order_acquire) == (numeric_limits::max)()) { - m_sendWhichQueue.store(0, boost::memory_order_release); - } - - if (pos >= m_queues.size()) - pos = pos % m_queues.size(); - - ++m_sendWhichQueue; - MQMessageQueue mq = m_queues.at(pos); - string key = mq.getBrokerName() + UtilAll::to_string(mq.getQueueId()); - if ((mq.getBrokerName().compare(lastmq.getBrokerName()) != 0) && - (m_onSerivceQueues.find(key) != m_onSerivceQueues.end())) { - mq_index = pos; - return mq; - } - ++pos; - } - - for (MQMAP::iterator it = m_nonSerivceQueues.begin(); it != m_nonSerivceQueues.end(); - ++it) { // if no MQMessageQueue(except lastmq) in - // m_onSerivceQueues, search m_nonSerivceQueues - if (it->second.getBrokerName().compare(lastmq.getBrokerName()) != 0) - return it->second; - } - LOG_ERROR("can not find property mq"); - return MQMessageQueue(); - } else { - for (size_t i = 0; i < m_queues.size(); i++) { - if (m_sendWhichQueue.load(boost::memory_order_acquire) == (numeric_limits::max)()) { - m_sendWhichQueue.store(0, boost::memory_order_release); - } - if (pos >= m_queues.size()) - pos = pos % m_queues.size(); - - ++m_sendWhichQueue; - LOG_DEBUG("lastmq broker empty, m_sendWhichQueue:%d, pos:%d", - m_sendWhichQueue.load(boost::memory_order_acquire), pos); - mq_index = pos; - MQMessageQueue mq = m_queues.at(pos); - string key = mq.getBrokerName() + UtilAll::to_string(mq.getQueueId()); - if (m_onSerivceQueues.find(key) != m_onSerivceQueues.end()) { - return mq; - } else { - ++pos; - } - } - - for (MQMAP::iterator it = m_nonSerivceQueues.begin(); it != m_nonSerivceQueues.end(); - ++it) { // if no MQMessageQueue(except lastmq) in - // m_onSerivceQueues, search m_nonSerivceQueues - if (it->second.getBrokerName().compare(lastmq.getBrokerName()) != 0) - return it->second; - } - LOG_ERROR("can not find property mq"); - return MQMessageQueue(); - } - } else { - LOG_ERROR("m_queues empty"); - return MQMessageQueue(); - } - } - - private: - boost::mutex m_queuelock; - typedef vector QueuesVec; - QueuesVec m_queues; - typedef map MQMAP; - MQMAP m_onSerivceQueues; - MQMAP m_nonSerivceQueues; - boost::atomic m_sendWhichQueue; - map m_brokerTimerMap; - boost::asio::io_service m_async_ioService; - boost::scoped_ptr m_async_service_thread; -}; - -// - -#include "TransactionMQProducerImpl.h" - -namespace rocketmq { - -TransactionMQProducer::TransactionMQProducer(const std::string& groupName) { - impl = new TransactionMQProducerImpl(groupName); -} - -TransactionMQProducer::~TransactionMQProducer() { - delete impl; -} -void TransactionMQProducer::start() { - impl->start(); -} - -void TransactionMQProducer::shutdown() { - impl->shutdown(); -} -std::string TransactionMQProducer::version() { - std::string versions = impl->getClientVersionString(); - /* - versions.append(", PROTOCOL VERSION: ") - .append(MQVersion::GetVersionDesc(MQVersion::s_CurrentVersion)) - .append(", LANGUAGE: ") - .append(MQVersion::s_CurrentLanguage); - */ - return versions; -} -// start mqclient set -const std::string& TransactionMQProducer::getNamesrvAddr() const { - return impl->getNamesrvAddr(); -} - -void TransactionMQProducer::setNamesrvAddr(const std::string& namesrvAddr) { - impl->setNamesrvAddr(namesrvAddr); -} - -const std::string& TransactionMQProducer::getNamesrvDomain() const { - return impl->getNamesrvDomain(); -} - -void TransactionMQProducer::setNamesrvDomain(const std::string& namesrvDomain) { - impl->setNamesrvDomain(namesrvDomain); -} -void TransactionMQProducer::setSessionCredentials(const std::string& accessKey, - const std::string& secretKey, - const std::string& accessChannel) { - impl->setSessionCredentials(accessKey, secretKey, accessChannel); -} - -const SessionCredentials& TransactionMQProducer::getSessionCredentials() const { - return impl->getSessionCredentials(); -} -const std::string& TransactionMQProducer::getInstanceName() const { - return impl->getInstanceName(); -} - -void TransactionMQProducer::setInstanceName(const std::string& instanceName) { - impl->setInstanceName(instanceName); -} - -const std::string& TransactionMQProducer::getNameSpace() const { - return impl->getNameSpace(); -} - -void TransactionMQProducer::setNameSpace(const std::string& nameSpace) { - impl->setNameSpace(nameSpace); -} -const std::string& TransactionMQProducer::getGroupName() const { - return impl->getGroupName(); -} - -void TransactionMQProducer::setGroupName(const std::string& groupName) { - impl->setGroupName(groupName); -} -void TransactionMQProducer::setSendMsgTimeout(int sendMsgTimeout) { - impl->setSendMsgTimeout(sendMsgTimeout); -} - -int TransactionMQProducer::getSendMsgTimeout() const { - return impl->getSendMsgTimeout(); -} -void TransactionMQProducer::setTcpTransportPullThreadNum(int num) { - impl->setTcpTransportPullThreadNum(num); -} -int TransactionMQProducer::getTcpTransportPullThreadNum() const { - return impl->getTcpTransportPullThreadNum(); -} - -void TransactionMQProducer::setTcpTransportConnectTimeout(uint64_t timeout) { - impl->setTcpTransportConnectTimeout(timeout); -} -uint64_t TransactionMQProducer::getTcpTransportConnectTimeout() const { - return impl->getTcpTransportConnectTimeout(); -} -void TransactionMQProducer::setTcpTransportTryLockTimeout(uint64_t timeout) { - impl->setTcpTransportTryLockTimeout(timeout); -} -uint64_t TransactionMQProducer::getTcpTransportTryLockTimeout() const { - return impl->getTcpTransportTryLockTimeout(); -} -int TransactionMQProducer::getCompressMsgBodyOverHowmuch() const { - return impl->getCompressMsgBodyOverHowmuch(); -} - -void TransactionMQProducer::setCompressMsgBodyOverHowmuch(int compressMsgBodyThreshold) { - impl->setCompressMsgBodyOverHowmuch(compressMsgBodyThreshold); -} - -int TransactionMQProducer::getCompressLevel() const { - return impl->getCompressLevel(); -} - -void TransactionMQProducer::setCompressLevel(int compressLevel) { - impl->setCompressLevel(compressLevel); -} - -void TransactionMQProducer::setMaxMessageSize(int maxMessageSize) { - impl->setMaxMessageSize(maxMessageSize); -} - -int TransactionMQProducer::getMaxMessageSize() const { - return impl->getMaxMessageSize(); -} - -void TransactionMQProducer::setLogLevel(elogLevel inputLevel) { - impl->setLogLevel(inputLevel); -} - -elogLevel TransactionMQProducer::getLogLevel() { - return impl->getLogLevel(); -} -void TransactionMQProducer::setLogFileSizeAndNum(int fileNum, long perFileSize) { - impl->setLogFileSizeAndNum(fileNum, perFileSize); -} - -void TransactionMQProducer::setUnitName(std::string unitName) { - impl->setUnitName(unitName); -} -const std::string& TransactionMQProducer::getUnitName() const { - return impl->getUnitName(); -} -void TransactionMQProducer::setMessageTrace(bool messageTrace) { - impl->setMessageTrace(messageTrace); -} -bool TransactionMQProducer::getMessageTrace() const { - return impl->getMessageTrace(); -} -void TransactionMQProducer::setEnableSsl(bool enableSsl) { - impl->setEnableSsl(enableSsl); -} -bool TransactionMQProducer::getEnableSsl() const { - return impl->getEnableSsl(); -} -void TransactionMQProducer::setSslPropertyFile(const std::string& sslPropertyFile) { - impl->setSslPropertyFile(sslPropertyFile); -} -const std::string& TransactionMQProducer::getSslPropertyFile() const { - return impl->getSslPropertyFile(); -} -std::shared_ptr TransactionMQProducer::getTransactionListener() { - return impl->getTransactionListener(); -} -void TransactionMQProducer::setTransactionListener(TransactionListener* listener) { - impl->setTransactionListener(listener); -} -TransactionSendResult TransactionMQProducer::sendMessageInTransaction(MQMessage& msg, void* arg) { - return impl->sendMessageInTransaction(msg, arg); -} -void TransactionMQProducer::checkTransactionState(const std::string& addr, - const MQMessageExt& message, - long tranStateTableOffset, - long commitLogOffset, - const std::string& msgId, - const std::string& transactionId, - const std::string& offsetMsgId) { - impl->checkTransactionState(addr, message, tranStateTableOffset, commitLogOffset, msgId, transactionId, offsetMsgId); -} -} // namespace rocketmq \ No newline at end of file diff --git a/src/producer/TransactionMQProducerImpl.cpp b/src/producer/TransactionMQProducerImpl.cpp deleted file mode 100644 index 849dd55b6..000000000 --- a/src/producer/TransactionMQProducerImpl.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "TransactionMQProducerImpl.h" -#include -#include "CommandHeader.h" -#include "Logging.h" -#include "MQClientFactory.h" -#include "MQDecoder.h" -#include "MessageSysFlag.h" -#include "TransactionListener.h" -#include "TransactionSendResult.h" - -using namespace std; -namespace rocketmq { - -void TransactionMQProducerImpl::initTransactionEnv() { - for (int i = 0; i < m_thread_num; ++i) { - m_threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &m_ioService)); - } -} - -void TransactionMQProducerImpl::destroyTransactionEnv() { - m_ioService.stop(); - m_threadpool.join_all(); -} - -TransactionSendResult TransactionMQProducerImpl::sendMessageInTransaction(MQMessage& msg, void* arg) { - if (!m_transactionListener) { - THROW_MQEXCEPTION(MQClientException, "transactionListener is null", -1); - } - - SendResult sendResult; - msg.setProperty(MQMessage::PROPERTY_TRANSACTION_PREPARED, "true"); - msg.setProperty(MQMessage::PROPERTY_PRODUCER_GROUP, getGroupName()); - try { - sendResult = send(msg); - } catch (MQException& e) { - THROW_MQEXCEPTION(MQClientException, e.what(), -1); - } - - LocalTransactionState localTransactionState = LocalTransactionState::UNKNOWN; - switch (sendResult.getSendStatus()) { - case SendStatus::SEND_OK: - try { - if (sendResult.getTransactionId() != "") { - msg.setProperty("__transactionId__", sendResult.getTransactionId()); - } - string transactionId = msg.getProperty(MQMessage::PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX); - if (transactionId != "") { - msg.setTransactionId(transactionId); - } - LOG_DEBUG("sendMessageInTransaction, msgId:%s, transactionId:%s", sendResult.getMsgId().data(), - transactionId.data()); - localTransactionState = m_transactionListener->executeLocalTransaction(msg, arg); - if (localTransactionState != LocalTransactionState::COMMIT_MESSAGE) { - LOG_WARN("executeLocalTransaction ret not LocalTransactionState::commit, msg:%s", msg.toString().data()); - } - } catch (MQException& e) { - THROW_MQEXCEPTION(MQClientException, e.what(), -1); - } - break; - case SendStatus::SEND_FLUSH_DISK_TIMEOUT: - case SendStatus::SEND_FLUSH_SLAVE_TIMEOUT: - case SendStatus::SEND_SLAVE_NOT_AVAILABLE: - localTransactionState = LocalTransactionState::ROLLBACK_MESSAGE; - LOG_WARN("sendMessageInTransaction, send not ok, rollback, result:%s", sendResult.toString().data()); - break; - default: - break; - } - - try { - endTransaction(sendResult, localTransactionState); - } catch (MQException& e) { - LOG_WARN("endTransaction exception:%s", e.what()); - } - - TransactionSendResult transactionSendResult(sendResult.getSendStatus(), sendResult.getMsgId(), - sendResult.getOffsetMsgId(), sendResult.getMessageQueue(), - sendResult.getQueueOffset()); - transactionSendResult.setTransactionId(msg.getTransactionId()); - transactionSendResult.setLocalTransactionState(localTransactionState); - return transactionSendResult; -} - -void TransactionMQProducerImpl::endTransaction(SendResult& sendResult, LocalTransactionState& localTransactionState) { - MQMessageId id; - if (sendResult.getOffsetMsgId() != "") { - id = MQDecoder::decodeMessageId(sendResult.getOffsetMsgId()); - } else { - id = MQDecoder::decodeMessageId(sendResult.getMsgId()); - } - string transId = sendResult.getTransactionId(); - - int commitOrRollback = MessageSysFlag::TransactionNotType; - switch (localTransactionState) { - case COMMIT_MESSAGE: - commitOrRollback = MessageSysFlag::TransactionCommitType; - break; - case ROLLBACK_MESSAGE: - commitOrRollback = MessageSysFlag::TransactionRollbackType; - break; - case UNKNOWN: - commitOrRollback = MessageSysFlag::TransactionNotType; - break; - default: - break; - } - - bool fromTransCheck = false; - EndTransactionRequestHeader* requestHeader = - new EndTransactionRequestHeader(getGroupName(), sendResult.getQueueOffset(), id.getOffset(), commitOrRollback, - fromTransCheck, sendResult.getMsgId(), transId); - LOG_DEBUG("endTransaction: msg:%s", requestHeader->toString().data()); - getFactory()->endTransactionOneway(sendResult.getMessageQueue(), requestHeader, getSessionCredentials()); -} - -void TransactionMQProducerImpl::checkTransactionState(const std::string& addr, - const MQMessageExt& message, - long tranStateTableOffset, - long commitLogOffset, - const std::string& msgId, - const std::string& transactionId, - const std::string& offsetMsgId) { - LOG_DEBUG("checkTransactionState: msgId:%s, transactionId:%s", msgId.data(), transactionId.data()); - if (!m_transactionListener) { - LOG_WARN("checkTransactionState, transactionListener null"); - THROW_MQEXCEPTION(MQClientException, "checkTransactionState, transactionListener null", -1); - } - - m_ioService.post(boost::bind(&TransactionMQProducerImpl::checkTransactionStateImpl, this, addr, message, - tranStateTableOffset, commitLogOffset, msgId, transactionId, offsetMsgId)); -} - -void TransactionMQProducerImpl::checkTransactionStateImpl(const std::string& addr, - const MQMessageExt& message, - long tranStateTableOffset, - long commitLogOffset, - const std::string& msgId, - const std::string& transactionId, - const std::string& offsetMsgId) { - LOG_DEBUG("checkTransactionStateImpl: msgId:%s, transactionId:%s", msgId.data(), transactionId.data()); - LocalTransactionState localTransactionState = UNKNOWN; - try { - localTransactionState = m_transactionListener->checkLocalTransaction(message); - } catch (MQException& e) { - LOG_INFO("checkTransactionState, checkLocalTransaction exception: %s", e.what()); - } - - EndTransactionRequestHeader* endHeader = new EndTransactionRequestHeader(); - endHeader->m_commitLogOffset = commitLogOffset; - endHeader->m_producerGroup = getGroupName(); - endHeader->m_tranStateTableOffset = tranStateTableOffset; - endHeader->m_fromTransactionCheck = true; - - string uniqueKey = transactionId; - if (transactionId.empty()) { - uniqueKey = message.getMsgId(); - } - - endHeader->m_msgId = uniqueKey; - endHeader->m_transactionId = transactionId; - switch (localTransactionState) { - case COMMIT_MESSAGE: - endHeader->m_commitOrRollback = MessageSysFlag::TransactionCommitType; - break; - case ROLLBACK_MESSAGE: - endHeader->m_commitOrRollback = MessageSysFlag::TransactionRollbackType; - LOG_WARN("when broker check, client rollback this transaction, %s", endHeader->toString().data()); - break; - case UNKNOWN: - endHeader->m_commitOrRollback = MessageSysFlag::TransactionNotType; - LOG_WARN("when broker check, client does not know this transaction state, %s", endHeader->toString().data()); - break; - default: - break; - } - - LOG_INFO("checkTransactionState, endTransactionOneway: uniqueKey:%s, client state:%d, end header: %s", - uniqueKey.data(), localTransactionState, endHeader->toString().data()); - - string remark; - try { - getFactory()->getMQClientAPIImpl()->endTransactionOneway(addr, endHeader, remark, getSessionCredentials()); - } catch (MQException& e) { - LOG_ERROR("endTransactionOneway exception:%s", e.what()); - throw e; - } -} - -void TransactionMQProducerImpl::start() { - initTransactionEnv(); - DefaultMQProducerImpl::start(); -} - -void TransactionMQProducerImpl::shutdown() { - DefaultMQProducerImpl::shutdown(); - destroyTransactionEnv(); -} - -} // namespace rocketmq diff --git a/src/producer/TransactionMQProducerImpl.h b/src/producer/TransactionMQProducerImpl.h deleted file mode 100644 index 319ee885a..000000000 --- a/src/producer/TransactionMQProducerImpl.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __TRANSACTIONMQPRODUCERIMPL_H__ -#define __TRANSACTIONMQPRODUCERIMPL_H__ - -#include -#include -#include -#include -#include -#include -#include -#include "DefaultMQProducerImpl.h" -#include "MQMessageExt.h" -#include "TransactionListener.h" -#include "TransactionSendResult.h" - -namespace rocketmq { - -class TransactionMQProducerImpl : public DefaultMQProducerImpl { - public: - TransactionMQProducerImpl(const std::string& producerGroup) - : DefaultMQProducerImpl(producerGroup), m_thread_num(1), m_ioServiceWork(m_ioService) {} - virtual ~TransactionMQProducerImpl() {} - void start(); - void shutdown(); - std::shared_ptr getTransactionListener() { return m_transactionListener; } - void setTransactionListener(TransactionListener* listener) { m_transactionListener.reset(listener); } - TransactionSendResult sendMessageInTransaction(MQMessage& msg, void* arg); - void checkTransactionState(const std::string& addr, - const MQMessageExt& message, - long tranStateTableOffset, - long commitLogOffset, - const std::string& msgId, - const std::string& transactionId, - const std::string& offsetMsgId); - - private: - void initTransactionEnv(); - void destroyTransactionEnv(); - void endTransaction(SendResult& sendResult, LocalTransactionState& localTransactionState); - void checkTransactionStateImpl(const std::string& addr, - const MQMessageExt& message, - long tranStateTableOffset, - long commitLogOffset, - const std::string& msgId, - const std::string& transactionId, - const std::string& offsetMsgId); - - private: - std::shared_ptr m_transactionListener; - int m_thread_num; - boost::thread_group m_threadpool; - boost::asio::io_service m_ioService; - boost::asio::io_service::work m_ioServiceWork; -}; -} // namespace rocketmq - -#endif diff --git a/src/protocol/CommandHeader.cpp b/src/protocol/CommandHeader.cpp deleted file mode 100644 index 20477a3fd..000000000 --- a/src/protocol/CommandHeader.cpp +++ /dev/null @@ -1,683 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "CommandHeader.h" -#include -#include -#include "Logging.h" -#include "UtilAll.h" - -namespace rocketmq { -//& requestMap) { - requestMap.insert(pair("topic", topic)); -} -//& requestMap) { - requestMap.insert(pair("clientID", clientID)); - requestMap.insert(pair("producerGroup", producerGroup)); - requestMap.insert(pair("consumerGroup", consumerGroup)); -} -//& requestMap) { - requestMap.insert(pair("topic", topic)); - requestMap.insert(pair("defaultTopic", defaultTopic)); - requestMap.insert(pair("readQueueNums", UtilAll::to_string(readQueueNums))); - requestMap.insert(pair("writeQueueNums", UtilAll::to_string(writeQueueNums))); - requestMap.insert(pair("perm", UtilAll::to_string(perm))); - requestMap.insert(pair("topicFilterType", topicFilterType)); -} - -void CheckTransactionStateRequestHeader::Encode(Json::Value& outData) {} - -CommandHeader* CheckTransactionStateRequestHeader::Decode(Json::Value& ext) { - CheckTransactionStateRequestHeader* h = new CheckTransactionStateRequestHeader(); - Json::Value& tempValue = ext["msgId"]; - if (tempValue.isString()) { - h->m_msgId = tempValue.asString(); - } - - tempValue = ext["transactionId"]; - if (tempValue.isString()) { - h->m_transactionId = tempValue.asString(); - } - - tempValue = ext["offsetMsgId"]; - if (tempValue.isString()) { - h->m_offsetMsgId = tempValue.asString(); - } - - tempValue = ext["tranStateTableOffset"]; - if (tempValue.isString()) { - h->m_tranStateTableOffset = UtilAll::str2ll(tempValue.asCString()); - } - - tempValue = ext["commitLogOffset"]; - if (tempValue.isString()) { - h->m_commitLogOffset = UtilAll::str2ll(tempValue.asCString()); - } - - return h; -} - -void CheckTransactionStateRequestHeader::SetDeclaredFieldOfCommandHeader(map& requestMap) { - requestMap.insert(pair("msgId", m_msgId)); - requestMap.insert(pair("transactionId", m_transactionId)); - requestMap.insert(pair("offsetMsgId", m_offsetMsgId)); - requestMap.insert(pair("commitLogOffset", UtilAll::to_string(m_commitLogOffset))); - requestMap.insert(pair("tranStateTableOffset", UtilAll::to_string(m_tranStateTableOffset))); -} - -std::string CheckTransactionStateRequestHeader::toString() { - stringstream ss; - ss << "CheckTransactionStateRequestHeader:"; - ss << " msgId:" << m_msgId; - ss << " transactionId:" << m_transactionId; - ss << " offsetMsgId:" << m_offsetMsgId; - ss << " commitLogOffset:" << m_commitLogOffset; - ss << " tranStateTableOffset:" << m_tranStateTableOffset; - return ss.str(); -} - -void EndTransactionRequestHeader::Encode(Json::Value& outData) { - outData["msgId"] = m_msgId; - outData["transactionId"] = m_transactionId; - outData["producerGroup"] = m_producerGroup; - outData["tranStateTableOffset"] = UtilAll::to_string(m_tranStateTableOffset); - outData["commitLogOffset"] = UtilAll::to_string(m_commitLogOffset); - outData["commitOrRollback"] = UtilAll::to_string(m_commitOrRollback); - outData["fromTransactionCheck"] = UtilAll::to_string(m_fromTransactionCheck); -} - -void EndTransactionRequestHeader::SetDeclaredFieldOfCommandHeader(map& requestMap) { - requestMap.insert(pair("msgId", m_msgId)); - requestMap.insert(pair("transactionId", m_transactionId)); - requestMap.insert(pair("producerGroup", m_producerGroup)); - requestMap.insert(pair("tranStateTableOffset", UtilAll::to_string(m_tranStateTableOffset))); - requestMap.insert(pair("commitLogOffset", UtilAll::to_string(m_commitLogOffset))); - requestMap.insert(pair("commitOrRollback", UtilAll::to_string(m_commitOrRollback))); - requestMap.insert(pair("fromTransactionCheck", UtilAll::to_string(m_fromTransactionCheck))); -} - -std::string EndTransactionRequestHeader::toString() { - stringstream ss; - ss << "EndTransactionRequestHeader:"; - ss << " m_msgId:" << m_msgId; - ss << " m_transactionId:" << m_transactionId; - ss << " m_producerGroup:" << m_producerGroup; - ss << " m_tranStateTableOffset:" << m_tranStateTableOffset; - ss << " m_commitLogOffset:" << m_commitLogOffset; - ss << " m_commitOrRollback:" << m_commitOrRollback; - ss << " m_fromTransactionCheck:" << m_fromTransactionCheck; - return ss.str(); -} - -//& requestMap) { - LOG_DEBUG( - "SendMessageRequestHeader producerGroup is:%s,topic is:%s, defaulttopic " - "is:%s, properties is:%s,UtilAll::to_string( defaultTopicQueueNums) " - "is:%s,UtilAll::to_string( queueId):%s, UtilAll::to_string( sysFlag) " - "is:%s, UtilAll::to_string( bornTimestamp) is:%s,UtilAll::to_string( " - "flag) is:%s", - producerGroup.c_str(), topic.c_str(), defaultTopic.c_str(), properties.c_str(), - UtilAll::to_string(defaultTopicQueueNums).c_str(), UtilAll::to_string(queueId).c_str(), - UtilAll::to_string(sysFlag).c_str(), UtilAll::to_string(bornTimestamp).c_str(), UtilAll::to_string(flag).c_str()); - - requestMap.insert(pair("producerGroup", producerGroup)); - requestMap.insert(pair("topic", topic)); - requestMap.insert(pair("defaultTopic", defaultTopic)); - requestMap.insert(pair("defaultTopicQueueNums", UtilAll::to_string(defaultTopicQueueNums))); - requestMap.insert(pair("queueId", UtilAll::to_string(queueId))); - requestMap.insert(pair("sysFlag", UtilAll::to_string(sysFlag))); - requestMap.insert(pair("bornTimestamp", UtilAll::to_string(bornTimestamp))); - requestMap.insert(pair("flag", UtilAll::to_string(flag))); - requestMap.insert(pair("properties", properties)); - requestMap.insert(pair("reconsumeTimes", UtilAll::to_string(reconsumeTimes))); - requestMap.insert(pair("unitMode", UtilAll::to_string(unitMode))); - requestMap.insert(pair("batch", UtilAll::to_string(batch))); -} - -//& requestMap) { - LOG_DEBUG( - "SendMessageRequestHeaderV2 producerGroup is:%s,topic is:%s, defaulttopic " - "is:%s, properties is:%s,UtilAll::to_string( defaultTopicQueueNums) " - "is:%s,UtilAll::to_string( queueId):%s, UtilAll::to_string( sysFlag) " - "is:%s, UtilAll::to_string( bornTimestamp) is:%s,UtilAll::to_string( " - "flag) is:%s,UtilAll::to_string( reconsumeTimes) is:%s,UtilAll::to_string( unitMode) is:%s,UtilAll::to_string( " - "batch) is:%s", - a.c_str(), b.c_str(), c.c_str(), i.c_str(), UtilAll::to_string(d).c_str(), UtilAll::to_string(e).c_str(), - UtilAll::to_string(f).c_str(), UtilAll::to_string(g).c_str(), UtilAll::to_string(g).c_str(), - UtilAll::to_string(j).c_str(), UtilAll::to_string(k).c_str(), UtilAll::to_string(m).c_str()); - - requestMap.insert(pair("a", a)); - requestMap.insert(pair("b", b)); - requestMap.insert(pair("c", c)); - requestMap.insert(pair("d", UtilAll::to_string(d))); - requestMap.insert(pair("e", UtilAll::to_string(e))); - requestMap.insert(pair("f", UtilAll::to_string(f))); - requestMap.insert(pair("g", UtilAll::to_string(g))); - requestMap.insert(pair("h", UtilAll::to_string(h))); - requestMap.insert(pair("i", i)); - requestMap.insert(pair("j", UtilAll::to_string(j))); - requestMap.insert(pair("k", UtilAll::to_string(k))); - requestMap.insert(pair("l", UtilAll::to_string(l))); - requestMap.insert(pair("m", UtilAll::to_string(m))); -} -void SendMessageRequestHeaderV2::CreateSendMessageRequestHeaderV1(SendMessageRequestHeader& v1) { - v1.producerGroup = a; - v1.topic = b; - v1.defaultTopic = c; - v1.defaultTopicQueueNums = d; - v1.queueId = e; - v1.sysFlag = f; - v1.bornTimestamp = g; - v1.flag = h; - v1.properties = i; - v1.reconsumeTimes = j; - v1.unitMode = k; - v1.consumeRetryTimes = l; - v1.batch = m; -} -//msgId = tempValue.asString(); - } - - tempValue = ext["queueId"]; - if (tempValue.isString()) { - h->queueId = atoi(tempValue.asCString()); - } - - tempValue = ext["queueOffset"]; - if (tempValue.isString()) { - h->queueOffset = UtilAll::str2ll(tempValue.asCString()); - } - - tempValue = ext["transactionId"]; - if (tempValue.isString()) { - h->transactionId = tempValue.asCString(); - } - - tempValue = ext["MSG_REGION"]; - if (tempValue.isString()) { - h->regionId = tempValue.asCString(); - } - return h; -} - -void SendMessageResponseHeader::SetDeclaredFieldOfCommandHeader(map& requestMap) { - requestMap.insert(pair("msgId", msgId)); - requestMap.insert(pair("queueId", UtilAll::to_string(queueId))); - requestMap.insert(pair("queueOffset", UtilAll::to_string(queueOffset))); - requestMap.insert(pair("transactionId", transactionId)); - requestMap.insert(pair("MSG_REGION", regionId)); -} -//& requestMap) { - requestMap.insert(pair("consumerGroup", consumerGroup)); - requestMap.insert(pair("topic", topic)); - requestMap.insert(pair("queueId", UtilAll::to_string(queueId))); - requestMap.insert(pair("queueOffset", UtilAll::to_string(queueOffset))); - requestMap.insert(pair("maxMsgNums", UtilAll::to_string(maxMsgNums))); - requestMap.insert(pair("sysFlag", UtilAll::to_string(sysFlag))); - requestMap.insert(pair("commitOffset", UtilAll::to_string(commitOffset))); - requestMap.insert(pair("subVersion", UtilAll::to_string(subVersion))); - requestMap.insert(pair("suspendTimeoutMillis", UtilAll::to_string(suspendTimeoutMillis))); - requestMap.insert(pair("subscription", subscription)); -} -//suggestWhichBrokerId = UtilAll::str2ll(tempValue.asCString()); - } - - tempValue = ext["nextBeginOffset"]; - if (tempValue.isString()) { - h->nextBeginOffset = UtilAll::str2ll(tempValue.asCString()); - } - - tempValue = ext["minOffset"]; - if (tempValue.isString()) { - h->minOffset = UtilAll::str2ll(tempValue.asCString()); - } - - tempValue = ext["maxOffset"]; - if (tempValue.isString()) { - h->maxOffset = UtilAll::str2ll(tempValue.asCString()); - } - - return h; -} - -void PullMessageResponseHeader::SetDeclaredFieldOfCommandHeader(map& requestMap) { - requestMap.insert(pair("suggestWhichBrokerId", UtilAll::to_string(suggestWhichBrokerId))); - requestMap.insert(pair("nextBeginOffset", UtilAll::to_string(nextBeginOffset))); - requestMap.insert(pair("minOffset", UtilAll::to_string(minOffset))); - requestMap.insert(pair("maxOffset", UtilAll::to_string(maxOffset))); -} -//& requestMap) {} -//& requestMap) { - requestMap.insert(pair("topic", topic)); - requestMap.insert(pair("queueId", UtilAll::to_string(queueId))); -} -//offset = UtilAll::str2ll(tempValue.asCString()); - } - return h; -} - -void GetMinOffsetResponseHeader::SetDeclaredFieldOfCommandHeader(map& requestMap) { - requestMap.insert(pair("offset", UtilAll::to_string(offset))); -} -//& requestMap) { - requestMap.insert(pair("topic", topic)); - requestMap.insert(pair("queueId", UtilAll::to_string(queueId))); -} -//offset = UtilAll::str2ll(tempValue.asCString()); - } - return h; -} - -void GetMaxOffsetResponseHeader::SetDeclaredFieldOfCommandHeader(map& requestMap) { - requestMap.insert(pair("offset", UtilAll::to_string(offset))); -} -//& requestMap) { - requestMap.insert(pair("topic", topic)); - requestMap.insert(pair("queueId", UtilAll::to_string(queueId))); - requestMap.insert(pair("timestamp", UtilAll::to_string(timestamp))); -} -//offset = UtilAll::str2ll(tempValue.asCString()); - } - return h; -} - -void SearchOffsetResponseHeader::SetDeclaredFieldOfCommandHeader(map& requestMap) { - requestMap.insert(pair("offset", UtilAll::to_string(offset))); -} -//& requestMap) { - requestMap.insert(pair("offset", UtilAll::to_string(offset))); -} -//& requestMap) { - requestMap.insert(pair("topic", topic)); - requestMap.insert(pair("queueId", UtilAll::to_string(queueId))); -} -//timestamp = UtilAll::str2ll(tempValue.asCString()); - } - return h; -} - -void GetEarliestMsgStoretimeResponseHeader::SetDeclaredFieldOfCommandHeader(map& requestMap) { - requestMap.insert(pair("timestamp", UtilAll::to_string(timestamp))); -} -//& requestMap) { - requestMap.insert(pair("consumerGroup", consumerGroup)); -} -//& requestMap) { - requestMap.insert(pair("consumerGroup", consumerGroup)); - requestMap.insert(pair("topic", topic)); - requestMap.insert(pair("queueId", UtilAll::to_string(queueId))); -} -//offset = UtilAll::str2ll(tempValue.asCString()); - } - return h; -} - -void QueryConsumerOffsetResponseHeader::SetDeclaredFieldOfCommandHeader(map& requestMap) { - requestMap.insert(pair("offset", UtilAll::to_string(offset))); -} -//& requestMap) { - requestMap.insert(pair("consumerGroup", consumerGroup)); - requestMap.insert(pair("topic", topic)); - requestMap.insert(pair("queueId", UtilAll::to_string(queueId))); - requestMap.insert(pair("commitOffset", UtilAll::to_string(commitOffset))); -} -//& requestMap) { - requestMap.insert(pair("group", group)); - requestMap.insert(pair("delayLevel", UtilAll::to_string(delayLevel))); - requestMap.insert(pair("offset", UtilAll::to_string(offset))); - requestMap.insert(pair("unitMode", UtilAll::to_string(unitMode))); - requestMap.insert(pair("originMsgId", originMsgId)); - requestMap.insert(pair("originTopic", originTopic)); - requestMap.insert(pair("maxReconsumeTimes", UtilAll::to_string(maxReconsumeTimes))); -} -//& cids) { - cids.clear(); - //getData(), mem->getSize()); - - Json::Reader reader; - Json::Value root; - if (!reader.parse(pData, root)) { - LOG_ERROR("GetConsumerListByGroupResponse error"); - return; - } - - Json::Value ids = root["consumerIdList"]; - for (unsigned int i = 0; i < ids.size(); i++) { - if (ids[i].isString()) { - cids.push_back(ids[i].asString()); - } - } -} - -void GetConsumerListByGroupResponseBody::SetDeclaredFieldOfCommandHeader(map& requestMap) {} - -void ResetOffsetRequestHeader::setTopic(const string& tmp) { - topic = tmp; -} - -void ResetOffsetRequestHeader::setGroup(const string& tmp) { - group = tmp; -} - -void ResetOffsetRequestHeader::setTimeStamp(const int64& tmp) { - timestamp = tmp; -} - -void ResetOffsetRequestHeader::setForceFlag(const bool& tmp) { - isForce = tmp; -} - -const string ResetOffsetRequestHeader::getTopic() const { - return topic; -} - -const string ResetOffsetRequestHeader::getGroup() const { - return group; -} - -const int64 ResetOffsetRequestHeader::getTimeStamp() const { - return timestamp; -} - -const bool ResetOffsetRequestHeader::getForceFlag() const { - return isForce; -} - -CommandHeader* ResetOffsetRequestHeader::Decode(Json::Value& ext) { - ResetOffsetRequestHeader* h = new ResetOffsetRequestHeader(); - - Json::Value& tempValue = ext["topic"]; - if (tempValue.isString()) { - h->topic = tempValue.asString(); - } - - tempValue = ext["group"]; - if (tempValue.isString()) { - h->group = tempValue.asString(); - } - - tempValue = ext["timestamp"]; - if (tempValue.isString()) { - h->timestamp = UtilAll::str2ll(tempValue.asCString()); - } - - tempValue = ext["isForce"]; - if (tempValue.isString()) { - h->isForce = UtilAll::to_bool(tempValue.asCString()); - } - LOG_INFO("topic:%s, group:%s, timestamp:%lld, isForce:%d", h->topic.c_str(), h->group.c_str(), h->timestamp, - h->isForce); - return h; -} - -CommandHeader* GetConsumerRunningInfoRequestHeader::Decode(Json::Value& ext) { - GetConsumerRunningInfoRequestHeader* h = new GetConsumerRunningInfoRequestHeader(); - - Json::Value& tempValue = ext["consumerGroup"]; - if (tempValue.isString()) { - h->consumerGroup = tempValue.asString(); - } - - tempValue = ext["clientId"]; - if (tempValue.isString()) { - h->clientId = tempValue.asString(); - } - - tempValue = ext["jstackEnable"]; - if (tempValue.isBool()) { - h->jstackEnable = tempValue.asBool(); - } else if (tempValue.isString()) { - h->jstackEnable = UtilAll::to_bool(tempValue.asCString()); - } - LOG_INFO("consumerGroup:%s, clientId:%s, jstackEnable:%d", h->consumerGroup.c_str(), h->clientId.c_str(), - h->jstackEnable); - return h; -} - -void GetConsumerRunningInfoRequestHeader::Encode(Json::Value& outData) { - outData["consumerGroup"] = consumerGroup; - outData["clientId"] = clientId; - outData["jstackEnable"] = jstackEnable; -} - -void GetConsumerRunningInfoRequestHeader::SetDeclaredFieldOfCommandHeader(map& requestMap) { - requestMap.insert(pair("consumerGroup", consumerGroup)); - requestMap.insert(pair("clientId", clientId)); - requestMap.insert(pair("jstackEnable", UtilAll::to_string(jstackEnable))); -} - -const string GetConsumerRunningInfoRequestHeader::getConsumerGroup() const { - return consumerGroup; -} - -void GetConsumerRunningInfoRequestHeader::setConsumerGroup(const string& Group) { - consumerGroup = Group; -} - -const string GetConsumerRunningInfoRequestHeader::getClientId() const { - return clientId; -} - -void GetConsumerRunningInfoRequestHeader::setClientId(const string& input_clientId) { - clientId = input_clientId; -} - -const bool GetConsumerRunningInfoRequestHeader::isJstackEnable() const { - return jstackEnable; -} - -void GetConsumerRunningInfoRequestHeader::setJstackEnable(const bool& input_jstackEnable) { - jstackEnable = input_jstackEnable; -} - -CommandHeader* NotifyConsumerIdsChangedRequestHeader::Decode(Json::Value& ext) { - NotifyConsumerIdsChangedRequestHeader* h = new NotifyConsumerIdsChangedRequestHeader(); - - Json::Value& tempValue = ext["consumerGroup"]; - if (tempValue.isString()) { - h->consumerGroup = tempValue.asString(); - } - - return h; -} - -void NotifyConsumerIdsChangedRequestHeader::setGroup(const string& tmp) { - consumerGroup = tmp; -} -const string NotifyConsumerIdsChangedRequestHeader::getGroup() const { - return consumerGroup; -} - -// -#include -#include "MQClientException.h" -#include "MessageSysFlag.h" -#include "UtilAll.h" -#include "dataBlock.h" -#include "json/json.h" - -namespace rocketmq { -//& requestMap) {} -}; - -class CheckTransactionStateRequestHeader : public CommandHeader { - public: - CheckTransactionStateRequestHeader() {} - CheckTransactionStateRequestHeader(long tableOffset, - long commLogOffset, - const std::string& msgid, - const std::string& transactionId, - const std::string& offsetMsgId) - : m_tranStateTableOffset(tableOffset), - m_commitLogOffset(commLogOffset), - m_msgId(msgid), - m_transactionId(transactionId), - m_offsetMsgId(offsetMsgId) {} - virtual ~CheckTransactionStateRequestHeader() {} - virtual void Encode(Json::Value& outData); - static CommandHeader* Decode(Json::Value& ext); - virtual void SetDeclaredFieldOfCommandHeader(std::map& requestMap); - std::string toString(); - - public: - long m_tranStateTableOffset; - long m_commitLogOffset; - std::string m_msgId; - std::string m_transactionId; - std::string m_offsetMsgId; -}; - -class EndTransactionRequestHeader : public CommandHeader { - public: - EndTransactionRequestHeader() {} - EndTransactionRequestHeader(const std::string& groupName, - long tableOffset, - long commLogOffset, - int commitOrRoll, - bool fromTransCheck, - const std::string& msgid, - const std::string& transId) - : m_producerGroup(groupName), - m_tranStateTableOffset(tableOffset), - m_commitLogOffset(commLogOffset), - m_commitOrRollback(commitOrRoll), - m_fromTransactionCheck(fromTransCheck), - m_msgId(msgid), - m_transactionId(transId) {} - virtual ~EndTransactionRequestHeader() {} - virtual void Encode(Json::Value& outData); - virtual void SetDeclaredFieldOfCommandHeader(std::map& requestMap); - std::string toString(); - - public: - std::string m_producerGroup; - long m_tranStateTableOffset; - long m_commitLogOffset; - int m_commitOrRollback; - bool m_fromTransactionCheck; - std::string m_msgId; - std::string m_transactionId; -}; - -//& requestMap); - - private: - string topic; -}; - -//& requestMap); - - private: - string clientID; - string producerGroup; - string consumerGroup; -}; - -//& requestMap); - - public: - string topic; - string defaultTopic; - int readQueueNums; - int writeQueueNums; - int perm; - string topicFilterType; -}; - -//& requestMap); - - public: - string producerGroup; - string topic; - string defaultTopic; - int defaultTopicQueueNums; - int queueId; - int sysFlag; - int64 bornTimestamp; - int flag; - string properties; - int reconsumeTimes; - bool unitMode; - int consumeRetryTimes; - bool batch; -}; - -//& requestMap); - virtual void CreateSendMessageRequestHeaderV1(SendMessageRequestHeader& v1); - - public: - string a; // producerGroup - string b; // topic; - string c; // defaultTopic; - int d; // defaultTopicQueueNums; - int e; // queueId; - int f; // sysFlag; - int64 g; // bornTimestamp; - int h; // flag; - string i; // properties; - int j; // reconsumeTimes; - bool k; // unitMode; - int l; // consumeRetryTimes; - bool m; // batch; -}; - -//& requestMap); - - public: - string msgId; - int queueId; - int64 queueOffset; - string regionId; - string transactionId; -}; - -//& requestMap); - - public: - string consumerGroup; - string topic; - int queueId; - int maxMsgNums; - int sysFlag; - string subscription; - int64 queueOffset; - int64 commitOffset; - int64 suspendTimeoutMillis; - int64 subVersion; -}; - -//& requestMap); - - public: - int64 suggestWhichBrokerId; - int64 nextBeginOffset; - int64 minOffset; - int64 maxOffset; -}; - -//& requestMap); -}; - -//& requestMap); - - public: - string topic; - int queueId; -}; - -//& requestMap); - - public: - int64 offset; -}; - -//& requestMap); - - public: - string topic; - int queueId; -}; - -//& requestMap); - - public: - int64 offset; -}; - -//& requestMap); - - public: - string topic; - int queueId; - int64 timestamp; -}; - -//& requestMap); - - public: - int64 offset; -}; - -//& requestMap); - - public: - int64 offset; -}; - -//& requestMap); - - public: - string topic; - int queueId; -}; - -//& requestMap); - - public: - int64 timestamp; -}; - -//& requestMap); - - public: - string consumerGroup; -}; - -//& requestMap); - - public: - string consumerGroup; - string topic; - int queueId; -}; - -//& requestMap); - - public: - int64 offset; -}; - -//& requestMap); - - public: - string consumerGroup; - string topic; - int queueId; - int64 commitOffset; -}; - -//& requestMap); - - public: - string group; - int delayLevel; - int64 offset; - bool unitMode = false; - string originMsgId; - string originTopic; - int maxReconsumeTimes = 16; -}; - -//& requestMap); - - public: - static void Decode(const MemoryBlock* mem, vector& cids); -}; - -class ResetOffsetRequestHeader : public CommandHeader { - public: - ResetOffsetRequestHeader() {} - ~ResetOffsetRequestHeader() {} - static CommandHeader* Decode(Json::Value& ext); - void setTopic(const string& tmp); - void setGroup(const string& tmp); - void setTimeStamp(const int64& tmp); - void setForceFlag(const bool& tmp); - const string getTopic() const; - const string getGroup() const; - const int64 getTimeStamp() const; - const bool getForceFlag() const; - - private: - string topic; - string group; - int64 timestamp; - bool isForce; -}; - -class GetConsumerRunningInfoRequestHeader : public CommandHeader { - public: - GetConsumerRunningInfoRequestHeader() {} - virtual ~GetConsumerRunningInfoRequestHeader() {} - virtual void Encode(Json::Value& outData); - virtual void SetDeclaredFieldOfCommandHeader(map& requestMap); - static CommandHeader* Decode(Json::Value& ext); - const string getConsumerGroup() const; - void setConsumerGroup(const string& consumerGroup); - const string getClientId() const; - void setClientId(const string& clientId); - const bool isJstackEnable() const; - void setJstackEnable(const bool& jstackEnable); - - private: - string consumerGroup; - string clientId; - bool jstackEnable; -}; - -class NotifyConsumerIdsChangedRequestHeader : public CommandHeader { - public: - NotifyConsumerIdsChangedRequestHeader() {} - virtual ~NotifyConsumerIdsChangedRequestHeader() {} - static CommandHeader* Decode(Json::Value& ext); - void setGroup(const string& tmp); - const string getGroup() const; - - private: - string consumerGroup; -}; - -// ConsumerRunningInfo::getProperties() const { - return properties; -} - -void ConsumerRunningInfo::setProperties(const map& input_properties) { - properties = input_properties; -} - -void ConsumerRunningInfo::setProperty(const string& key, const string& value) { - properties[key] = value; -} - -const map ConsumerRunningInfo::getMqTable() const { - return mqTable; -} - -void ConsumerRunningInfo::setMqTable(const MessageQueue& queue, const ProcessQueueInfo& queueInfo) { - mqTable[queue] = queueInfo; -} - -const map ConsumerRunningInfo::getStatusTable() const { - return statusTable; -} - -void ConsumerRunningInfo::setStatusTable(const string& topic, const ConsumeStats& consumeStats) { - statusTable[topic] = consumeStats; -} - -const vector ConsumerRunningInfo::getSubscriptionSet() const { - return subscriptionSet; -} - -void ConsumerRunningInfo::setSubscriptionSet(const vector& input_subscriptionSet) { - subscriptionSet = input_subscriptionSet; -} - -const string ConsumerRunningInfo::getJstack() const { - return jstack; -} - -void ConsumerRunningInfo::setJstack(const string& input_jstack) { - jstack = input_jstack; -} - -string ConsumerRunningInfo::encode() { - Json::Value outData; - - outData[PROP_NAMESERVER_ADDR] = properties[PROP_NAMESERVER_ADDR]; - outData[PROP_CONSUME_TYPE] = properties[PROP_CONSUME_TYPE]; - outData[PROP_CLIENT_VERSION] = properties[PROP_CLIENT_VERSION]; - outData[PROP_CONSUMER_START_TIMESTAMP] = properties[PROP_CONSUMER_START_TIMESTAMP]; - outData[PROP_CONSUME_ORDERLY] = properties[PROP_CONSUME_ORDERLY]; - outData[PROP_THREADPOOL_CORE_SIZE] = properties[PROP_THREADPOOL_CORE_SIZE]; - outData[PROP_CLIENT_SDK_VERSION] = properties[PROP_CLIENT_SDK_VERSION]; - - Json::Value root; - root["jstack"] = jstack; - root["properties"] = outData; - - { - vector::const_iterator it = subscriptionSet.begin(); - for (; it != subscriptionSet.end(); it++) { - root["subscriptionSet"].append(it->toJson()); - } - } - { - Json::Value stats; - for (map::iterator it = statusTable.begin(); it != statusTable.end(); ++it) { - stats[it->first] = it->second.toJson(); - } - if (!stats.isNull()) { - root["statusTable"] = stats; - } - } - - Json::FastWriter fastwrite; - string finals = fastwrite.write(root); - string key = "\"mqTable\":"; - key.append("{"); - for (map::iterator it = mqTable.begin(); it != mqTable.end(); ++it) { - key.append((it->first).toJson().toStyledString()); - key.erase(key.end() - 1); - key.append(":"); - key.append((it->second).toJson().toStyledString()); - key.append(","); - } - key.erase(key.end() - 1); - key.append("}"); - - // insert mqTable to final string - key.append(","); - finals.insert(1, key); - - return finals; -} -} // namespace rocketmq diff --git a/src/protocol/ConsumerRunningInfo.h b/src/protocol/ConsumerRunningInfo.h deleted file mode 100644 index e61c43da7..000000000 --- a/src/protocol/ConsumerRunningInfo.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __CONSUMERRUNNINGINFO_H__ -#define __CONSUMERRUNNINGINFO_H__ - -#include "ConsumeStats.h" -#include "MessageQueue.h" -#include "ProcessQueueInfo.h" -#include "SubscriptionData.h" - -namespace rocketmq { - -class ConsumerRunningInfo { - public: - ConsumerRunningInfo() {} - virtual ~ConsumerRunningInfo() { - properties.clear(); - mqTable.clear(); - subscriptionSet.clear(); - } - - public: - static const string PROP_NAMESERVER_ADDR; - static const string PROP_THREADPOOL_CORE_SIZE; - static const string PROP_CONSUME_ORDERLY; - static const string PROP_CONSUME_TYPE; - static const string PROP_CLIENT_VERSION; - static const string PROP_CLIENT_SDK_VERSION; - static const string PROP_CONSUMER_START_TIMESTAMP; - - public: - const map getProperties() const; - void setProperties(const map& input_properties); - void setProperty(const string& key, const string& value); - const map getMqTable() const; - void setMqTable(const MessageQueue& queue, const ProcessQueueInfo& queueInfo); - const map getStatusTable() const; - void setStatusTable(const string& topic, const ConsumeStats& consumeStats); - const vector getSubscriptionSet() const; - void setSubscriptionSet(const vector& input_subscriptionSet); - const string getJstack() const; - void setJstack(const string& input_jstack); - string encode(); - - private: - map properties; - vector subscriptionSet; - map mqTable; - map statusTable; - string jstack; -}; -} // namespace rocketmq -#endif diff --git a/src/protocol/HeartbeatData.h b/src/protocol/HeartbeatData.h deleted file mode 100644 index 2bd4aa71a..000000000 --- a/src/protocol/HeartbeatData.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __HEARTBEATDATA_H__ -#define __HEARTBEATDATA_H__ -#include -#include -#include -#include -#include "ConsumeType.h" -#include "SubscriptionData.h" - -namespace rocketmq { -//::const_iterator it = subscriptionDataSet.begin(); - for (; it != subscriptionDataSet.end(); it++) { - outJson["subscriptionDataSet"].append((*it).toJson()); - } - - return outJson; - } - - public: - string groupName; - ConsumeType consumeType; - MessageModel messageModel; - ConsumeFromWhere consumeFromWhere; - vector subscriptionDataSet; -}; - -// lock(m_consumerDataMutex); - vector::iterator itc = m_consumerDataSet.begin(); - for (; itc != m_consumerDataSet.end(); itc++) { - root["consumerDataSet"].append((*itc).toJson()); - } - } - - // lock(m_producerDataMutex); - vector::iterator itp = m_producerDataSet.begin(); - for (; itp != m_producerDataSet.end(); itp++) { - root["producerDataSet"].append((*itp).toJson()); - } - } - // lock(m_producerDataMutex); - return m_producerDataSet.empty(); - } - - void insertDataToProducerDataSet(ProducerData& producerData) { - boost::lock_guard lock(m_producerDataMutex); - m_producerDataSet.push_back(producerData); - } - - bool isConsumerDataSetEmpty() { - boost::lock_guard lock(m_consumerDataMutex); - return m_consumerDataSet.empty(); - } - - void insertDataToConsumerDataSet(ConsumerData& consumerData) { - boost::lock_guard lock(m_consumerDataMutex); - m_consumerDataSet.push_back(consumerData); - } - - private: - string m_clientID; - vector m_producerDataSet; - vector m_consumerDataSet; - boost::mutex m_producerDataMutex; - boost::mutex m_consumerDataMutex; -}; -} // LockBatchRequestBody::getMqSet() { - return mqSet; -} -void LockBatchRequestBody::setMqSet(const vector& in_mqSet) { - mqSet = in_mqSet; -} -void LockBatchRequestBody::Encode(string& outData) { - Json::Value root; - root["consumerGroup"] = consumerGroup; - root["clientId"] = clientId; - - vector::const_iterator it = mqSet.begin(); - for (; it != mqSet.end(); it++) { - root["mqSet"].append(toJson(*it)); - } - - Json::FastWriter fastwrite; - outData = fastwrite.write(root); -} - -Json::Value LockBatchRequestBody::toJson(const MQMessageQueue& mq) const { - Json::Value outJson; - outJson["topic"] = mq.getTopic(); - outJson["brokerName"] = mq.getBrokerName(); - outJson["queueId"] = mq.getQueueId(); - return outJson; -} - -vector LockBatchResponseBody::getLockOKMQSet() { - return lockOKMQSet; -} -void LockBatchResponseBody::setLockOKMQSet(vector in_lockOKMQSet) { - lockOKMQSet.swap(in_lockOKMQSet); -} - -void LockBatchResponseBody::Decode(const MemoryBlock* mem, vector& messageQueues) { - messageQueues.clear(); - //getData(), mem->getSize()); - - Json::Reader reader; - Json::Value root; - if (!reader.parse(pData, root)) { - LOG_WARN("decode LockBatchResponseBody error"); - return; - } - - Json::Value mqs = root["lockOKMQSet"]; - LOG_DEBUG("LockBatchResponseBody mqs size:%d", mqs.size()); - for (unsigned int i = 0; i < mqs.size(); i++) { - MQMessageQueue mq; - Json::Value qd = mqs[i]; - mq.setTopic(qd["topic"].asString()); - mq.setBrokerName(qd["brokerName"].asString()); - mq.setQueueId(qd["queueId"].asInt()); - LOG_INFO("LockBatchResponseBody MQ:%s", mq.toString().c_str()); - messageQueues.push_back(mq); - } -} - -string UnlockBatchRequestBody::getConsumerGroup() { - return consumerGroup; -} -void UnlockBatchRequestBody::setConsumerGroup(const string& in_consumerGroup) { - consumerGroup = in_consumerGroup; -} -string UnlockBatchRequestBody::getClientId() { - return clientId; -} -void UnlockBatchRequestBody::setClientId(const string& in_clientId) { - clientId = in_clientId; -} -vector UnlockBatchRequestBody::getMqSet() { - return mqSet; -} -void UnlockBatchRequestBody::setMqSet(const vector& in_mqSet) { - mqSet = in_mqSet; -} -void UnlockBatchRequestBody::Encode(string& outData) { - Json::Value root; - root["consumerGroup"] = consumerGroup; - root["clientId"] = clientId; - - vector::const_iterator it = mqSet.begin(); - for (; it != mqSet.end(); it++) { - root["mqSet"].append(toJson(*it)); - } - - Json::FastWriter fastwrite; - outData = fastwrite.write(root); -} - -Json::Value UnlockBatchRequestBody::toJson(const MQMessageQueue& mq) const { - Json::Value outJson; - outJson["topic"] = mq.getTopic(); - outJson["brokerName"] = mq.getBrokerName(); - outJson["queueId"] = mq.getQueueId(); - return outJson; -} -} diff --git a/src/protocol/LockBatchBody.h b/src/protocol/LockBatchBody.h deleted file mode 100644 index fd60c28d2..000000000 --- a/src/protocol/LockBatchBody.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __LOCKBATCHBODY_H__ -#define __LOCKBATCHBODY_H__ -#include -#include -#include "MQMessageQueue.h" -#include "RemotingSerializable.h" -#include "dataBlock.h" -#include "json/json.h" -#include "UtilAll.h" - -namespace rocketmq { -// getMqSet(); - void setMqSet(const vector& mqSet); - void Encode(string& outData); - Json::Value toJson(const MQMessageQueue& mq) const; - - private: - string consumerGroup; - string clientId; - vector mqSet; -}; - -class LockBatchResponseBody { - public: - virtual ~LockBatchResponseBody() { lockOKMQSet.clear(); } - vector getLockOKMQSet(); - void setLockOKMQSet(vector lockOKMQSet); - static void Decode(const MemoryBlock* mem, vector& messageQueues); - - private: - vector lockOKMQSet; -}; - -class UnlockBatchRequestBody { - public: - virtual ~UnlockBatchRequestBody() { mqSet.clear(); } - string getConsumerGroup(); - void setConsumerGroup(const string& consumerGroup); - string getClientId(); - void setClientId(const string& clientId); - vector getMqSet(); - void setMqSet(const vector& mqSet); - void Encode(string& outData); - Json::Value toJson(const MQMessageQueue& mq) const; - - private: - string consumerGroup; - string clientId; - vector mqSet; -}; - -} // -#include "json/json.h" - -namespace rocketmq { -// RemotingCommand::s_seqNumber; - -//::max(); -} - -RemotingCommand::RemotingCommand(int code, - string language, - int version, - int opaque, - int flag, - string remark, - CommandHeader* pExtHeader) - : m_code(code), - m_language(language), - m_version(version), - m_opaque(opaque), - m_flag(flag), - m_remark(remark), - m_pExtHeader(pExtHeader) {} - -RemotingCommand::RemotingCommand(const RemotingCommand& command) { - Assign(command); -} - -RemotingCommand& RemotingCommand::operator=(const RemotingCommand& command) { - if (this != &command) { - Assign(command); - } - return *this; -} - -RemotingCommand::~RemotingCommand() { - m_pExtHeader = NULL; -} - -void RemotingCommand::Assign(const RemotingCommand& command) { - m_code = command.m_code; - m_language = command.m_language; - m_version = command.m_version; - m_opaque = command.m_opaque; - m_flag = command.m_flag; - m_remark = command.m_remark; - m_msgBody = command.m_msgBody; - - for (auto& it : command.m_extFields) { - m_extFields[it.first] = it.second; - } - - m_head = command.m_head; - m_body = command.m_body; - m_parsedJson = command.m_parsedJson; - // m_pExtHeader = command.m_pExtHeader; //ignore this filed at this moment, if need please add it -} - -void RemotingCommand::Encode() { - Json::Value root; - root["code"] = m_code; - root["language"] = m_language; - root["version"] = m_version; - root["opaque"] = m_opaque; - root["flag"] = m_flag; - root["remark"] = m_remark; - - if (m_pExtHeader) { - Json::Value extJson; - m_pExtHeader->Encode(extJson); - - extJson[SessionCredentials::Signature] = m_extFields[SessionCredentials::Signature]; - extJson[SessionCredentials::AccessKey] = m_extFields[SessionCredentials::AccessKey]; - extJson[SessionCredentials::ONSChannelKey] = m_extFields[SessionCredentials::ONSChannelKey]; - - root["extFields"] = extJson; - } else { // for heartbeat - Json::Value extJson; - extJson[SessionCredentials::Signature] = m_extFields[SessionCredentials::Signature]; - extJson[SessionCredentials::AccessKey] = m_extFields[SessionCredentials::AccessKey]; - extJson[SessionCredentials::ONSChannelKey] = m_extFields[SessionCredentials::ONSChannelKey]; - root["extFields"] = extJson; - } - - Json::FastWriter fastwrite; - string data = fastwrite.write(root); - - uint32 headLen = data.size(); - uint32 totalLen = 4 + headLen + m_body.getSize(); - - uint32 messageHeader[2]; - messageHeader[0] = htonl(totalLen); - messageHeader[1] = htonl(headLen); - - //(mem.getData()); - Json::Reader reader; - Json::Value object; - const char* begin = pData + 4; - const char* end = pData + 4 + headLen; - - if (!reader.parse(begin, end, object)) { - THROW_MQEXCEPTION(MQClientException, "conn't parse json", -1); - } - - int code = object["code"].asInt(); - - string language = object["language"].asString(); - int version = object["version"].asInt(); - int opaque = object["opaque"].asInt(); - int flag = object["flag"].asInt(); - Json::Value v = object["remark"]; - string remark = ""; - if (!v.isNull()) { - remark = object["remark"].asString(); - } - LOG_DEBUG( - "code:%d, language:%s, version:%d, opaque:%d, flag:%d, remark:%s, " - "headLen:%d, bodyLen:%d ", - code, language.c_str(), version, opaque, flag, remark.c_str(), headLen, bodyLen); - RemotingCommand* cmd = new RemotingCommand(code, language, version, opaque, flag, remark, NULL); - cmd->setParsedJson(object); - if (bodyLen > 0) { - cmd->SetBody(pData + 4 + headLen, bodyLen); - } - if (object.isMember("extFields")) { - Json::Value& extFields = object["extFields"]; - for (auto& it : extFields.getMemberNames()) { - cmd->m_extFields[it] = extFields[it].asString(); - } - } - return cmd; -} - -void RemotingCommand::markResponseType() { - int bits = 1 << RPC_TYPE; - m_flag |= bits; -} - -bool RemotingCommand::isResponseType() { - int bits = 1 << RPC_TYPE; - return (m_flag & bits) == bits; -} - -void RemotingCommand::markOnewayRPC() { - int bits = 1 << RPC_ONEWAY; - m_flag |= bits; -} - -bool RemotingCommand::isOnewayRPC() { - int bits = 1 << RPC_ONEWAY; - return (m_flag & bits) == bits; -} - -void RemotingCommand::setOpaque(const int opa) { - m_opaque = opa; -} - -void RemotingCommand::SetExtHeader(int code) { - try { - Json::Value ext = m_parsedJson["extFields"]; - if (!ext.isNull()) { - m_pExtHeader = NULL; - switch (code) { - case SEND_MESSAGE: - case SEND_MESSAGE_V2: - m_pExtHeader.reset(SendMessageResponseHeader::Decode(ext)); - break; - case PULL_MESSAGE: - m_pExtHeader.reset(PullMessageResponseHeader::Decode(ext)); - break; - case GET_MIN_OFFSET: - m_pExtHeader.reset(GetMinOffsetResponseHeader::Decode(ext)); - break; - case GET_MAX_OFFSET: - m_pExtHeader.reset(GetMaxOffsetResponseHeader::Decode(ext)); - break; - case SEARCH_OFFSET_BY_TIMESTAMP: - m_pExtHeader.reset(SearchOffsetResponseHeader::Decode(ext)); - break; - case GET_EARLIEST_MSG_STORETIME: - m_pExtHeader.reset(GetEarliestMsgStoretimeResponseHeader::Decode(ext)); - break; - case QUERY_CONSUMER_OFFSET: - m_pExtHeader.reset(QueryConsumerOffsetResponseHeader::Decode(ext)); - break; - case RESET_CONSUMER_CLIENT_OFFSET: - m_pExtHeader.reset(ResetOffsetRequestHeader::Decode(ext)); - break; - case GET_CONSUMER_RUNNING_INFO: - m_pExtHeader.reset(GetConsumerRunningInfoRequestHeader::Decode(ext)); - break; - case NOTIFY_CONSUMER_IDS_CHANGED: - m_pExtHeader.reset(NotifyConsumerIdsChangedRequestHeader::Decode(ext)); - break; - case CHECK_TRANSACTION_STATE: - m_pExtHeader.reset(CheckTransactionStateRequestHeader::Decode(ext)); - break; - default: - break; - } - } - } catch (MQException& e) { - LOG_ERROR("set response head error"); - } -} - -void RemotingCommand::setCode(int code) { - m_code = code; -} - -int RemotingCommand::getCode() const { - return m_code; -} - -int RemotingCommand::getOpaque() const { - return m_opaque; -} - -string RemotingCommand::getRemark() const { - return m_remark; -} - -void RemotingCommand::setRemark(string mark) { - m_remark = mark; -} - -CommandHeader* RemotingCommand::getCommandHeader() const { - return m_pExtHeader.get(); -} - -void RemotingCommand::setParsedJson(const Json::Value& json) { - m_parsedJson = json; -} - -const int RemotingCommand::getFlag() const { - return m_flag; -} - -const int RemotingCommand::getVersion() const { - return m_version; -} - -void RemotingCommand::setMsgBody(const string& body) { - m_msgBody = body; -} - -string RemotingCommand::getMsgBody() const { - return m_msgBody; -} - -void RemotingCommand::addExtField(const string& key, const string& value) { - m_extFields[key] = value; -} - -const unordered_map* RemotingCommand::getExtFields() const{ - return &m_extFields; -} - -std::string RemotingCommand::ToString() const { - std::stringstream ss; - ss << "code:" << m_code << ",opaque:" << m_opaque << ",flag:" << m_flag << ",body.size:" << m_body.getSize() - << ",header.size:" << m_head.getSize(); - return ss.str(); -} - -} // namespace rocketmq diff --git a/src/protocol/RemotingCommand.h b/src/protocol/RemotingCommand.h deleted file mode 100644 index b0525b72a..000000000 --- a/src/protocol/RemotingCommand.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __REMOTINGCOMMAND_H__ -#define __REMOTINGCOMMAND_H__ -#include -#include -#include -#include -#include -#include -#include "CommandHeader.h" -#include "dataBlock.h" - -namespace rocketmq { -//* getExtFields() const; - string getMsgBody() const; - void setMsgBody(const string& body); - - public: - void Encode(); - static RemotingCommand* Decode(const MemoryBlock& mem); - std::string ToString() const; - - private: - void Assign(const RemotingCommand& command); - - private: - int m_code; - string m_language; - int m_version; - int m_opaque; - int m_flag; - string m_remark; - string m_msgBody; - unordered_map m_extFields; - - MemoryBlock m_head; - MemoryBlock m_body; - // m_pExtHeader; - - static boost::atomic s_seqNumber; -}; - -} // -#include -#include "Logging.h" -#include "UtilAll.h" -#include "dataBlock.h" -#include "json/json.h" - -namespace rocketmq { - -// brokerAddrs; //(mem->getData()); - string data(pData, mem->getSize()); - - Json::CharReaderBuilder charReaderBuilder; - charReaderBuilder.settings_["allowNumericKeys"] = true; - unique_ptr pCharReaderPtr(charReaderBuilder.newCharReader()); - - const char* begin = pData; - const char* end = pData + mem->getSize(); - Json::Value root; - string errs; - - if (!pCharReaderPtr->parse(begin, end, &root, &errs)) { - LOG_ERROR("parse json error:%s, value isArray:%d, isObject:%d", errs.c_str(), root.isArray(), root.isObject()); - return nullptr; - } - - auto* trd = new TopicRouteData(); - trd->setOrderTopicConf(root["orderTopicConf"].asString()); - - Json::Value qds = root["queueDatas"]; - for (auto qd : qds) { - QueueData d; - d.brokerName = qd["brokerName"].asString(); - d.readQueueNums = qd["readQueueNums"].asInt(); - d.writeQueueNums = qd["writeQueueNums"].asInt(); - d.perm = qd["perm"].asInt(); - trd->getQueueDatas().push_back(d); - } - sort(trd->getQueueDatas().begin(), trd->getQueueDatas().end()); - - Json::Value bds = root["brokerDatas"]; - for (auto bd : bds) { - BrokerData d; - d.brokerName = bd["brokerName"].asString(); - LOG_DEBUG("brokerName:%s", d.brokerName.c_str()); - Json::Value bas = bd["brokerAddrs"]; - Json::Value::Members mbs = bas.getMemberNames(); - for (const auto& key : mbs) { - int id = atoi(key.c_str()); - string addr = bas[key].asString(); - d.brokerAddrs[id] = addr; - LOG_DEBUG("brokerId:%d, brokerAddr:%s", id, addr.c_str()); - } - trd->getBrokerDatas().push_back(d); - } - sort(trd->getBrokerDatas().begin(), trd->getBrokerDatas().end()); - - return trd; - } - - /** - * Selects a (preferably master) broker address from the registered list. - * If the master's address cannot be found, a slave broker address is selected in a random manner. - * - * @return Broker address. - */ - std::string selectBrokerAddr() { - int bdSize = m_brokerDatas.size(); - if (bdSize > 0) { - int bdIndex = std::rand() % bdSize; - auto bd = m_brokerDatas[bdIndex]; - auto iter = bd.brokerAddrs.find(MASTER_ID); - if (iter == bd.brokerAddrs.end()) { - int baSize = bd.brokerAddrs.size(); - int baIndex = std::rand() % baSize; - iter = bd.brokerAddrs.begin(); - for (; baIndex > 0; baIndex--) { - iter++; - } - } - return iter->second; - } - return ""; - } - - std::vector& getQueueDatas() { return m_queueDatas; } - - std::vector& getBrokerDatas() { return m_brokerDatas; } - - const std::string& getOrderTopicConf() const { return m_orderTopicConf; } - - void setOrderTopicConf(const string& orderTopicConf) { m_orderTopicConf = orderTopicConf; } - - bool operator==(const TopicRouteData& other) const { - return m_brokerDatas == other.m_brokerDatas && m_orderTopicConf == other.m_orderTopicConf && - m_queueDatas == other.m_queueDatas; - } - - private: - std::string m_orderTopicConf; - std::vector m_queueDatas; - std::vector m_brokerDatas; -}; - -} // namespace rocketmq - -#endif diff --git a/src/status/ConsumeStats.cpp b/src/status/ConsumeStats.cpp deleted file mode 100644 index 3272347df..000000000 --- a/src/status/ConsumeStats.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "ConsumeStats.h" - -namespace rocketmq { -ConsumeStats::ConsumeStats() { - pullRT = 0.0; - pullTPS = 0.0; - consumeRT = 0.0; - consumeOKTPS = 0.0; - consumeFailedTPS = 0.0; - consumeFailedMsgs = 0; -} -Json::Value ConsumeStats::toJson() const { - Json::Value outJson; - outJson["pullRT"] = pullRT; - outJson["pullTPS"] = pullTPS; - outJson["consumeRT"] = consumeRT; - outJson["consumeOKTPS"] = consumeOKTPS; - outJson["consumeFailedTPS"] = consumeFailedTPS; - outJson["consumeFailedMsgs"] = consumeFailedMsgs; - return outJson; -} -} // namespace rocketmq diff --git a/src/status/StatsItem.h b/src/status/StatsItem.h deleted file mode 100644 index 5fd3f3dec..000000000 --- a/src/status/StatsItem.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __CONSUMER_STATUS_ITEM_H__ -#define __CONSUMER_STATUS_ITEM_H__ - -#include "RocketMQClient.h" - -namespace rocketmq { -class StatsItem { - public: - StatsItem() { - pullRT = 0; - pullRTCount = 0; - pullCount = 0; - consumeRT = 0; - consumeRTCount = 0; - consumeOKCount = 0; - consumeFailedCount = 0; - consumeFailedMsgs = 0; - }; - virtual ~StatsItem() {} - - public: - uint64 pullRT; - uint64 pullRTCount; - uint64 pullCount; - uint64 consumeRT; - uint64 consumeRTCount; - uint64 consumeOKCount; - uint64 consumeFailedCount; - uint64 consumeFailedMsgs; -}; - -} // namespace rocketmq - -#endif diff --git a/src/status/StatsServer.cpp b/src/status/StatsServer.cpp deleted file mode 100644 index 0ac306379..000000000 --- a/src/status/StatsServer.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "StatsServer.h" -#include -#include -#include "Logging.h" -#include "RocketMQClient.h" -#include "StatsItem.h" - -namespace rocketmq { -const std::string StatsServer::TOPIC_AND_GROUP_CONSUME_OK_TPS = "CONSUME_OK_TPS"; -const std::string StatsServer::TOPIC_AND_GROUP_CONSUME_FAILED_TPS = "CONSUME_FAILED_TPS"; -const std::string StatsServer::TOPIC_AND_GROUP_CONSUME_RT = "CONSUME_RT"; -const std::string StatsServer::TOPIC_AND_GROUP_PULL_TPS = "PULL_TPS"; -const std::string StatsServer::TOPIC_AND_GROUP_PULL_RT = "PULL_RT"; -const int StatsServer::SAMPLING_PERIOD = 10; -StatsServer::StatsServer() { - m_status = CREATE_JUST; - serverName = "default"; -} -StatsServer::StatsServer(std::string sName) { - m_status = CREATE_JUST; - serverName = sName; -} -StatsServer::~StatsServer() {} -void StatsServer::start() { - switch (m_status) { - case CREATE_JUST: - m_status = START_FAILED; - startScheduledTask(); - LOG_INFO("Default Status Service Start."); - m_status = RUNNING; - break; - case RUNNING: - case SHUTDOWN_ALREADY: - case START_FAILED: - break; - default: - break; - } -} -void StatsServer::shutdown() { - switch (m_status) { - case CREATE_JUST: - case RUNNING: - LOG_INFO("Default Status Service ShutDown."); - stopScheduledTask(); - m_status = SHUTDOWN_ALREADY; - break; - case SHUTDOWN_ALREADY: - case START_FAILED: - break; - default: - break; - } -} -ConsumeStats StatsServer::getConsumeStats(std::string topic, std::string groupName) { - ConsumeStats consumeStats; - LOG_DEBUG("getConsumeStats Topic:%s, Group:%s", topic.c_str(), groupName.c_str()); - if (m_status == RUNNING) { - std::string key = topic + "@" + groupName; - LOG_DEBUG("getConsumeStats Key:%s", key.c_str()); - return getConsumeStats(key); - } - return consumeStats; -} -void StatsServer::incPullRT(std::string topic, std::string groupName, uint64 rt) { - std::string key = topic + "@" + groupName; - std::lock_guard lock(m_consumeStatsItemMutex); - if (m_consumeStatsItems.find(key) == m_consumeStatsItems.end()) { - StatsItem item; - m_consumeStatsItems[key] = item; - } - m_consumeStatsItems[key].pullRT += rt; - m_consumeStatsItems[key].pullRTCount += 1; -} -void StatsServer::incPullTPS(std::string topic, std::string groupName, uint64 msgCount) { - std::string key = topic + "@" + groupName; - std::lock_guard lock(m_consumeStatsItemMutex); - if (m_consumeStatsItems.find(key) == m_consumeStatsItems.end()) { - StatsItem item; - m_consumeStatsItems[key] = item; - } - m_consumeStatsItems[key].pullCount += msgCount; -} -void StatsServer::incConsumeRT(std::string topic, std::string groupName, uint64 rt, uint64 msgCount) { - std::string key = topic + "@" + groupName; - LOG_DEBUG("incConsumeRT before Key:%s, RT:%lld, Count: %lld", key.c_str(), rt, msgCount); - - std::lock_guard lock(m_consumeStatsItemMutex); - if (m_consumeStatsItems.find(key) == m_consumeStatsItems.end()) { - StatsItem item; - m_consumeStatsItems[key] = item; - } - m_consumeStatsItems[key].consumeRT += rt; - m_consumeStatsItems[key].consumeRTCount += msgCount; - LOG_DEBUG("incConsumeRT After Key:%s, RT:%lld, Count: %lld", key.c_str(), m_consumeStatsItems[key].consumeRT, - m_consumeStatsItems[key].consumeRTCount); -} -void StatsServer::incConsumeOKTPS(std::string topic, std::string groupName, uint64 msgCount) { - std::string key = topic + "@" + groupName; - LOG_DEBUG("incConsumeOKTPS Before Key:%s, Count: %lld", key.c_str(), msgCount); - std::lock_guard lock(m_consumeStatsItemMutex); - if (m_consumeStatsItems.find(key) == m_consumeStatsItems.end()) { - StatsItem item; - m_consumeStatsItems[key] = item; - } - m_consumeStatsItems[key].consumeOKCount += msgCount; - LOG_DEBUG("incConsumeOKTPS After Key:%s, Count: %lld", key.c_str(), m_consumeStatsItems[key].consumeOKCount); -} -void StatsServer::incConsumeFailedTPS(std::string topic, std::string groupName, uint64 msgCount) { - std::string key = topic + "@" + groupName; - LOG_DEBUG("incConsumeFailedTPS Key:%s, Count: %lld", key.c_str(), msgCount); - std::lock_guard lock(m_consumeStatsItemMutex); - if (m_consumeStatsItems.find(key) == m_consumeStatsItems.end()) { - StatsItem item; - m_consumeStatsItems[key] = item; - } - m_consumeStatsItems[key].consumeFailedCount += msgCount; - m_consumeStatsItems[key].consumeFailedMsgs += msgCount; -} -void StatsServer::incConsumeFailedMsgs(std::string topic, std::string groupName, uint64 msgCount) { - std::string key = topic + "@" + groupName; - LOG_DEBUG("incConsumeFailedTPS Key:%s, Count: %lld", key.c_str(), msgCount); - std::lock_guard lock(m_consumeStatsItemMutex); - if (m_consumeStatsItems.find(key) == m_consumeStatsItems.end()) { - StatsItem item; - m_consumeStatsItems[key] = item; - } - m_consumeStatsItems[key].consumeFailedMsgs += msgCount; -} -void StatsServer::startScheduledTask() { - m_consumer_status_service_thread.reset(new boost::thread(boost::bind(&StatsServer::doStartScheduledTask, this))); -} -void StatsServer::stopScheduledTask() { - if (m_consumer_status_service_thread) { - m_consumerStatus_ioService.stop(); - m_consumer_status_service_thread->interrupt(); - m_consumer_status_service_thread->join(); - m_consumer_status_service_thread.reset(); - } -} -void StatsServer::doStartScheduledTask() { - boost::asio::io_service::work work(m_consumerStatus_ioService); - boost::system::error_code ec1; - std::shared_ptr t1 = std::make_shared( - m_consumerStatus_ioService, boost::posix_time::seconds(SAMPLING_PERIOD)); - t1->async_wait(boost::bind(&StatsServer::scheduledTaskInSeconds, this, ec1, t1)); - - boost::system::error_code errorCode; - m_consumerStatus_ioService.run(errorCode); -} -void StatsServer::scheduledTaskInSeconds(boost::system::error_code& ec, - std::shared_ptr t) { - samplingInSeconds(); - - boost::system::error_code e; - t->expires_from_now(t->expires_from_now() + boost::posix_time::seconds(SAMPLING_PERIOD), e); - t->async_wait(boost::bind(&StatsServer::scheduledTaskInSeconds, this, ec, t)); -} -void StatsServer::samplingInSeconds() { - LOG_DEBUG("samplingInSeconds=="); - - // do samplings - std::lock_guard lock(m_consumeStatsItemMutex); - for (std::map::iterator it = m_consumeStatsItems.begin(); it != m_consumeStatsItems.end(); - ++it) { - ConsumeStats consumeStats; - if (it->second.pullRTCount != 0) { - consumeStats.pullRT = (1.0 * (it->second.pullRT)) / (it->second.pullRTCount); - } - it->second.pullRT = 0; - it->second.pullRTCount = 0; - consumeStats.pullTPS = (1.0 * (it->second.pullCount)) / SAMPLING_PERIOD; - it->second.pullCount = 0; - if (it->second.consumeRTCount != 0) { - consumeStats.consumeRT = (1.0 * (it->second.consumeRT)) / (it->second.consumeRTCount); - LOG_DEBUG("samplingInSeconds Key[%s], consumeRT:%.2f,Total RT:%lld, Count: %lld", it->first.c_str(), - consumeStats.consumeRT, it->second.consumeRT, it->second.consumeRTCount); - } - it->second.consumeRT = 0; - it->second.consumeRTCount = 0; - consumeStats.consumeOKTPS = (1.0 * (it->second.consumeOKCount)) / SAMPLING_PERIOD; - LOG_DEBUG("samplingInSeconds Key[%s], consumeOKTPS:%.2f, Count: %lld", it->first.c_str(), consumeStats.consumeOKTPS, - it->second.consumeOKCount); - it->second.consumeOKCount = 0; - consumeStats.consumeFailedTPS = (1.0 * (it->second.consumeFailedCount)) / SAMPLING_PERIOD; - it->second.consumeFailedCount = 0; - LOG_DEBUG("samplingInSeconds Key[%s], consumeFailedTPS:%.2f, Count: %lld", it->first.c_str(), - consumeStats.consumeFailedTPS, it->second.consumeFailedCount); - consumeStats.consumeFailedMsgs = it->second.consumeFailedMsgs; - // it->second.consumeFailedMsgs = 0; - updateConsumeStats(it->first, consumeStats); - } -} - -void StatsServer::updateConsumeStats(std::string topic, std::string groupName, ConsumeStats consumeStats) { - if (m_status == RUNNING) { - std::string key = topic + "@" + groupName; - updateConsumeStats(key, consumeStats); - } -} -void StatsServer::updateConsumeStats(std::string key, ConsumeStats consumeStats) { - LOG_DEBUG("updateConsumeStats Key:%s, Count: %lld", key.c_str(), consumeStats.consumeOKTPS); - - std::lock_guard lock(m_consumeStatusMutex); - m_consumeStatus[key] = consumeStats; -} -ConsumeStats StatsServer::getConsumeStats(std::string key) { - ConsumeStats consumeStats; - std::lock_guard lock(m_consumeStatusMutex); - if (m_consumeStatus.find(key) != m_consumeStatus.end()) { - return m_consumeStatus[key]; - } - return consumeStats; -} -} // namespace rocketmq diff --git a/src/status/StatsServer.h b/src/status/StatsServer.h deleted file mode 100644 index e105f23df..000000000 --- a/src/status/StatsServer.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __CONSUMER_STATUS_SERVICE_H__ -#define __CONSUMER_STATUS_SERVICE_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ConsumeStats.h" -#include "RocketMQClient.h" -#include "ServiceState.h" -#include "StatsItem.h" - -namespace rocketmq { -class StatsServer { - public: - static const std::string TOPIC_AND_GROUP_CONSUME_OK_TPS; - static const std::string TOPIC_AND_GROUP_CONSUME_FAILED_TPS; - static const std::string TOPIC_AND_GROUP_CONSUME_RT; - static const std::string TOPIC_AND_GROUP_PULL_TPS; - static const std::string TOPIC_AND_GROUP_PULL_RT; - static const int SAMPLING_PERIOD; - StatsServer(); - StatsServer(std::string serverName); - virtual ~StatsServer(); - void start(); - void shutdown(); - ConsumeStats getConsumeStats(std::string topic, std::string groupName); - void incPullRT(std::string topic, std::string groupName, uint64 rt); - void incPullTPS(std::string topic, std::string groupName, uint64 msgCount); - void incConsumeRT(std::string topic, std::string groupName, uint64 rt, uint64 msgCount = 1); - void incConsumeOKTPS(std::string topic, std::string groupName, uint64 msgCount); - void incConsumeFailedTPS(std::string topic, std::string groupName, uint64 msgCount); - void incConsumeFailedMsgs(std::string topic, std::string groupName, uint64 msgCount); - - private: - void startScheduledTask(); - void stopScheduledTask(); - void doStartScheduledTask(); - void scheduledTaskInSeconds(boost::system::error_code& ec, std::shared_ptr t); - void samplingInSeconds(); - void updateConsumeStats(std::string topic, std::string groupName, ConsumeStats consumeStats); - void updateConsumeStats(std::string key, ConsumeStats consumeStats); - ConsumeStats getConsumeStats(std::string key); - - public: - std::string serverName; - - private: - ServiceState m_status; - std::mutex m_consumeStatusMutex; - std::map m_consumeStatus; - boost::asio::io_service m_consumerStatus_ioService; - // boost::asio::io_service::work m_consumerStatus_work; - std::unique_ptr m_consumer_status_service_thread; - std::mutex m_consumeStatsItemMutex; - std::map m_consumeStatsItems; -}; - -} // namespace rocketmq - -#endif diff --git a/src/status/StatsServerManager.cpp b/src/status/StatsServerManager.cpp deleted file mode 100644 index f3a6d1cdb..000000000 --- a/src/status/StatsServerManager.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "StatsServerManager.h" -#include "RocketMQClient.h" -#include "StatsServer.h" -#include "string" - -namespace rocketmq { -StatsServerManager::StatsServerManager() { - serverName = "default"; -} - -StatsServerManager::~StatsServerManager() { - m_consumeStatusServers.clear(); -} -std::shared_ptr StatsServerManager::getConsumeStatServer() { - return getConsumeStatServer(serverName); -} -std::shared_ptr StatsServerManager::getConsumeStatServer(std::string serverName) { - std::map>::iterator it = m_consumeStatusServers.find(serverName); - if (it != m_consumeStatusServers.end()) { - return it->second; - } else { - std::shared_ptr server = std::make_shared(); - m_consumeStatusServers[serverName] = server; - return server; - } -} -void StatsServerManager::removeConsumeStatServer(std::string serverName) { - std::map>::iterator it = m_consumeStatusServers.find(serverName); - if (it != m_consumeStatusServers.end()) { - m_consumeStatusServers.erase(it); - } -} - -StatsServerManager* StatsServerManager::getInstance() { - static StatsServerManager instance; - return &instance; -} -} // namespace rocketmq diff --git a/src/status/StatsServerManager.h b/src/status/StatsServerManager.h deleted file mode 100644 index 923ea6110..000000000 --- a/src/status/StatsServerManager.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __CONSUMER_STATUS_SERVICE_MANAGER_H__ -#define __CONSUMER_STATUS_SERVICE_MANAGER_H__ - -#include -#include -#include -#include "ConsumeStats.h" -#include "RocketMQClient.h" -#include "ServiceState.h" -#include "StatsServer.h" - -namespace rocketmq { -class StatsServerManager { - public: - virtual ~StatsServerManager(); - // void start(); - // void shutdown(); - std::shared_ptr getConsumeStatServer(); - std::shared_ptr getConsumeStatServer(std::string serverName); - void removeConsumeStatServer(std::string serverName); - - static StatsServerManager* getInstance(); - - private: - StatsServerManager(); - - public: - std::string serverName; - - private: - std::map> m_consumeStatusServers; -}; - -} // namespace rocketmq - -#endif diff --git a/src/thread/disruptor/batch_descriptor.h b/src/thread/disruptor/batch_descriptor.h deleted file mode 100755 index ba1a035f2..000000000 --- a/src/thread/disruptor/batch_descriptor.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2011, François Saint-Jacques -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the disruptor-- nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL FRANÇOIS SAINT-JACQUES BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DISRUPTOR_BATCH_DESCRIPTOR_H_ // NOLINT -#define DISRUPTOR_BATCH_DESCRIPTOR_H_ // NOLINT - -#include "sequence.h" - -namespace rocketmq { - -// Used to record the batch of sequences claimed via {@link Sequencer}. -class BatchDescriptor { - public: - // Create a holder for tracking a batch of claimed sequences in a - // {@link Sequencer} - // - // @param size of the batch to claim. - BatchDescriptor(int size) : - size_(size), - end_(kInitialCursorValue) {} - - // Get the size of the batch - int size() const { return size_; } - - // Get the end sequence of a batch. - // - // @return the end sequence in the batch. - int64_t end() const { return end_; } - - // Set the end sequence of a batch. - // - // @param end sequence in the batch. - void set_end(int64_t end) { end_ = end; } - - - // Get the starting sequence of the batch. - // - // @return starting sequence in the batch. - int64_t Start() const { return end_ - size_ + 1L; } - - private: - int size_; - int64_t end_; -}; - -}; // namespace rocketmq - -#endif // DISRUPTOR_SEQUENCE_BATCH_H_ NOLINT diff --git a/src/thread/disruptor/claim_strategy.h b/src/thread/disruptor/claim_strategy.h deleted file mode 100755 index 0f3263a39..000000000 --- a/src/thread/disruptor/claim_strategy.h +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright (c) 2011, François Saint-Jacques -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the disruptor-- nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL FRANÇOIS SAINT-JACQUES BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DISRUPTOR_CLAIM_STRATEGY_H_ // NOLINT -#define DISRUPTOR_CLAIM_STRATEGY_H_ // NOLINT - -#include -#include -#include - -#include "interface.h" - -namespace rocketmq { - -enum ClaimStrategyOption { - kSingleThreadedStrategy, - kMultiThreadedStrategy -}; - -// Optimised strategy can be used when there is a single publisher thread -// claiming {@link AbstractEvent}s. -class SingleThreadedStrategy :public noncopyable, public ClaimStrategyInterface { - public: - SingleThreadedStrategy(const int& buffer_size) : - buffer_size_(buffer_size), - sequence_(kInitialCursorValue), - min_gating_sequence_(kInitialCursorValue) {} - - virtual int64_t IncrementAndGet( - const std::vector& dependent_sequences) { - int64_t next_sequence = sequence_.IncrementAndGet(1L); - WaitForFreeSlotAt(next_sequence, dependent_sequences); - return next_sequence; - } - - virtual int64_t IncrementAndGet(const int& delta, - const std::vector& dependent_sequences) { - int64_t next_sequence = sequence_.IncrementAndGet(delta); - WaitForFreeSlotAt(next_sequence, dependent_sequences); - return next_sequence; - } - - virtual bool HasAvalaibleCapacity( - const std::vector& dependent_sequences) { - int64_t wrap_point = sequence_.sequence() + 1L - buffer_size_; - if (wrap_point > min_gating_sequence_.sequence()) { - int64_t min_sequence = GetMinimumSequence(dependent_sequences); - min_gating_sequence_.set_sequence(min_sequence); - if (wrap_point > min_sequence) - return false; - } - return true; - } - - virtual void SetSequence(const int64_t& sequence, - const std::vector& dependent_sequences) { - sequence_.set_sequence(sequence); - WaitForFreeSlotAt(sequence, dependent_sequences); - } - - virtual void SerialisePublishing(const int64_t& sequence, - const Sequence& cursor, - const int64_t& batch_size) {} - - private: - SingleThreadedStrategy(); - - void WaitForFreeSlotAt(const int64_t& sequence, - const std::vector& dependent_sequences) { - int64_t wrap_point = sequence - buffer_size_; - if (wrap_point > min_gating_sequence_.sequence()) { - int64_t min_sequence; - while (wrap_point > (min_sequence = GetMinimumSequence(dependent_sequences))) { - boost::this_thread::yield(); - } - } - } - - const int buffer_size_; - PaddedLong sequence_; - PaddedLong min_gating_sequence_; - -}; - -// Strategy to be used when there are multiple publisher threads claiming -// {@link AbstractEvent}s. -/* -class MultiThreadedStrategy : public ClaimStrategyInterface { - public: - MultiThreadedStrategy(const int& buffer_size) : - buffer_size_(buffer_size), - sequence_(kInitialCursorValue), - min_processor_sequence_(kInitialCursorValue) {} - - virtual int64_t IncrementAndGet( - const std::vector& dependent_sequences) { - WaitForCapacity(dependent_sequences, min_gating_sequence_local_); - int64_t next_sequence = sequence_.IncrementAndGet(); - WaitForFreeSlotAt(next_sequence, - dependent_sequences, - min_gating_sequence_local_); - return next_sequence; - } - - virtual int64_t IncrementAndGet(const int& delta, - const std::vector& dependent_sequences) { - int64_t next_sequence = sequence_.IncrementAndGet(delta); - WaitForFreeSlotAt(next_sequence, - dependent_sequences, - min_gating_sequence_local_); - return next_sequence; - } - virtual void SetSequence(const int64_t& sequence, - const std::vector& dependent_sequences) { - sequence_.set_sequence(sequence); - WaitForFreeSlotAt(sequence, - dependent_sequences, - min_gating_sequence_local_); - } - - virtual bool HasAvalaibleCapacity( - const std::vector& dependent_sequences) { - const int64_t wrap_point = sequence_.sequence() + 1L - buffer_size_; - if (wrap_point > min_gating_sequence_local_.sequence()) { - int64_t min_sequence = GetMinimumSequence(dependent_sequences); - min_gating_sequence_local_.set_sequence(min_sequence); - if (wrap_point > min_sequence) - return false; - } - return true; - } - - virtual void SerialisePublishing(const Sequence& cursor, - const int64_t& sequence, - const int64_t& batch_size) { - int64_t expected_sequence = sequence - batch_size; - int counter = retries; - - while (expected_sequence != cursor.sequence()) { - if (0 == --counter) { - counter = retries; - std::this_thread::yield(); - } - } - } - - private: - // Methods - void WaitForCapacity(const std::vector& dependent_sequences, - const MutableLong& min_gating_sequence) { - const int64_t wrap_point = sequence_.sequence() + 1L - buffer_size_; - if (wrap_point > min_gating_sequence.sequence()) { - int counter = retries; - int64_t min_sequence; - while (wrap_point > (min_sequence = GetMinimumSequence(dependent_sequences))) { - counter = ApplyBackPressure(counter); - } - min_gating_sequence.set_sequence(min_sequence); - } - } - - void WaitForFreeSlotAt(const int64_t& sequence, - const std::vector& dependent_sequences, - const MutableLong& min_gating_sequence) { - const int64_t wrap_point = sequence - buffer_size_; - if (wrap_point > min_gating_sequence.sequence()) { - int64_t min_sequence; - while (wrap_point > (min_sequence = GetMinimumSequence(dependent_sequences))) { - std::this_thread::yield(); - } - min_gating_sequence.set_sequence(min_sequence); - } - } - - int ApplyBackPressure(int counter) { - if (0 != counter) { - --counter; - std::this_thread::yield(); - } else { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - - return counter; - } - - const int buffer_size_; - PaddedSequence sequence_; - thread_local PaddedLong min_gating_sequence_local_; - - const int retries = 100; - -}; -*/ - -ClaimStrategyInterface* CreateClaimStrategy(ClaimStrategyOption option, - const int& buffer_size) { - switch (option) { - case kSingleThreadedStrategy: - return new SingleThreadedStrategy(buffer_size); - // case kMultiThreadedStrategy: - // return new MultiThreadedStrategy(buffer_size); - default: - return NULL; - } -}; - -}; // namespace rocketmq - -#endif // DISRUPTOR_CLAIM_STRATEGY_H_ NOLINT diff --git a/src/thread/disruptor/event_processor.h b/src/thread/disruptor/event_processor.h deleted file mode 100755 index 3ad080ddd..000000000 --- a/src/thread/disruptor/event_processor.h +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) 2011, François Saint-Jacques -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the disruptor-- nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL FRANÇOIS SAINT-JACQUES BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DISRUPTOR_EVENT_PROCESSOR_H_ // NOLINT -#define DISRUPTOR_EVENT_PROCESSOR_H_ // NOLINT - -#include -#include "ring_buffer.h" - -namespace rocketmq { - -template -class NoOpEventProcessor : public EventProcessorInterface { - public: - NoOpEventProcessor(RingBuffer* ring_buffer) : - ring_buffer_(ring_buffer) { } - - virtual Sequence* GetSequence() { - return ring_buffer_->GetSequencePtr(); - } - - virtual void Halt() {} - - virtual void Run() {} - - private: - RingBuffer* ring_buffer_; -}; - -template -class BatchEventProcessor : public boost::noncopyable, public EventProcessorInterface { - public: - BatchEventProcessor(RingBuffer* ring_buffer, - SequenceBarrierInterface* sequence_barrier, - EventHandlerInterface* event_handler, - ExceptionHandlerInterface* exception_handler) : - running_(false), - ring_buffer_(ring_buffer), - sequence_barrier_(sequence_barrier), - event_handler_(event_handler), - exception_handler_(exception_handler) {} - - - virtual Sequence* GetSequence() { return &sequence_; } - - virtual void Halt() { - running_.store(false); - sequence_barrier_->Alert(); - } - - virtual void Run() { - if (running_.load()) - { - printf("Thread is already running\r\n"); - } - running_.store(true); - sequence_barrier_->ClearAlert(); - event_handler_->OnStart(); - - T* event = NULL; - int64_t next_sequence = sequence_.sequence() + 1L; - - while (true) { - try { - int64_t avalaible_sequence = \ - sequence_barrier_->WaitFor(next_sequence, 300*1000);//wait 300 milliseconds to avoid taskThread blocking on BlockingStrategy::WaitFor when shutdown - //rocketmq::LOG_INFO("avalaible_sequence:%d, next_sequence:%d", avalaible_sequence,next_sequence); - while (next_sequence <= avalaible_sequence) { - event = ring_buffer_->Get(next_sequence); - event_handler_->OnEvent(next_sequence, - next_sequence == avalaible_sequence, event); - next_sequence++; - } - - sequence_.set_sequence(next_sequence - 1L); - } catch(const AlertException& e) { - //rocketmq::LOG_INFO("catch alertException"); - if (!running_.load()) - break; - } catch(const std::exception& e) { - //rocketmq::LOG_ERROR("catch stdException"); - exception_handler_->Handle(e, next_sequence, event); - sequence_.set_sequence(next_sequence); - next_sequence++; - } - } - //rocketmq::LOG_INFO("BatchEventProcessor shutdown"); - event_handler_->OnShutdown(); - running_.store(false); - } - - void operator()() { Run(); } - - private: - boost::atomic running_; - Sequence sequence_; - - RingBuffer* ring_buffer_; - SequenceBarrierInterface* sequence_barrier_; - EventHandlerInterface* event_handler_; - ExceptionHandlerInterface* exception_handler_; - -}; - - -}; // namespace rocketmq - -#endif // DISRUPTOR_EVENT_PROCESSOR_H_ NOLINT diff --git a/src/thread/disruptor/event_publisher.h b/src/thread/disruptor/event_publisher.h deleted file mode 100755 index ae0efd9ec..000000000 --- a/src/thread/disruptor/event_publisher.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2011, François Saint-Jacques -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the disruptor-- nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL FRANÇOIS SAINT-JACQUES BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DISRUPTOR_EVENT_PUBLISHER_H_ // NOLINT -#define DISRUPTOR_EVENT_PUBLISHER_H_ // NOLINT - -#include "ring_buffer.h" - -namespace rocketmq { - -template -class EventPublisher { - public: - EventPublisher(RingBuffer* ring_buffer) : ring_buffer_(ring_buffer) {} - - void PublishEvent(EventTranslatorInterface* translator) { - int64_t sequence = ring_buffer_->Next(); - translator->TranslateTo(sequence, ring_buffer_->Get(sequence)); - ring_buffer_->Publish(sequence); - } - - private: - RingBuffer* ring_buffer_; -}; - -}; // namespace rocketmq - -#endif diff --git a/src/thread/disruptor/exception_handler.h b/src/thread/disruptor/exception_handler.h deleted file mode 100755 index e7979a04f..000000000 --- a/src/thread/disruptor/exception_handler.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2011, François Saint-Jacques -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the disruptor-- nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL FRANÇOIS SAINT-JACQUES BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DISRUPTOR_EXCEPTION_HANDLER_H_ // NOLINT -#define DISRUPTOR_EXCEPTION_HANDLER_H_ // NOLINT - -#include - -#include "interface.h" - -namespace rocketmq { - -template -class IgnoreExceptionHandler: public ExceptionHandlerInterface { - public: - virtual void Handle(const std::exception& exception, - const int64_t& sequence, - T* event) { - // do nothing with the exception. - ; - } -}; - -template -class FatalExceptionHandler: public ExceptionHandlerInterface { - public: - virtual void Handle(const std::exception& exception, - const int64_t& sequence, - T* event) { - // rethrow the exception - throw exception; - } -}; - -}; // namespace rocketmq - -#endif // DISRUPTOR_EXCEPTION_HANDLER_H_ NOLINT diff --git a/src/thread/disruptor/exceptions.h b/src/thread/disruptor/exceptions.h deleted file mode 100755 index f968043a2..000000000 --- a/src/thread/disruptor/exceptions.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2011, François Saint-Jacques -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the disruptor-- nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL FRANÇOIS SAINT-JACQUES BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DISRUPTOR_EXCEPTIONS_H_ // NOLINT -#define DISRUPTOR_EXCEPTIONS_H_ // NOLINT - -#include - -namespace rocketmq { - -class AlertException : public std::exception { -}; - -}; // namespace rocketmq - -#endif // DISRUPTOR_EXCEPTIONS_H_ NOLINT diff --git a/src/thread/disruptor/interface.h b/src/thread/disruptor/interface.h deleted file mode 100755 index 0c07774c3..000000000 --- a/src/thread/disruptor/interface.h +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright (c) 2011, François Saint-Jacques -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the disruptor-- nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL FRANÇOIS SAINT-JACQUES BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DISRUPTOR_INTERFACE_H_ // NOLINT -#define DISRUPTOR_INTERFACE_H_ // NOLINT - -#include -#include - -#include "sequence.h" -#include "batch_descriptor.h" - -namespace rocketmq { - -// Strategies employed for claiming the sequence of events in the -// {@link Seqencer} by publishers. -class ClaimStrategyInterface { - public: - // Is there available capacity in the buffer for the requested sequence. - // - // @param dependent_sequences to be checked for range. - // @return true if the buffer has capacity for the requested sequence. - virtual ~ClaimStrategyInterface() {} - virtual bool HasAvalaibleCapacity( - const std::vector& dependent_sequences) = 0; - - // Claim the next sequence in the {@link Sequencer}. - // - // @param dependent_sequences to be checked for range. - // @return the index to be used for the publishing. - virtual int64_t IncrementAndGet( - const std::vector& dependent_sequences) = 0; - - // Claim the next sequence in the {@link Sequencer}. - // - // @param delta to increment by. - // @param dependent_sequences to be checked for range. - // @return the index to be used for the publishing. - virtual int64_t IncrementAndGet(const int& delta, - const std::vector& dependent_sequences) = 0; - - // Set the current sequence value for claiming an event in the - // {@link Sequencer}. - // - // @param sequence to be set as the current value. - // @param dependent_sequences to be checked for range. - virtual void SetSequence(const int64_t& sequence, - const std::vector& dependent_sequences) = 0; - - // Serialise publishing in sequence. - // - // @param sequence to be applied. - // @param cursor to be serialise against. - // @param batch_size of the sequence. - virtual void SerialisePublishing(const int64_t& sequence, - const Sequence& cursor, - const int64_t& batch_size) = 0; -}; - -// Coordination barrier for tracking the cursor for publishers and sequence of -// dependent {@link EventProcessor}s for processing a data structure. -class SequenceBarrierInterface { - public: - // Wait for the given sequence to be available for consumption. - // - // @param sequence to wait for. - // @return the sequence up to which is available. - // - // @throws AlertException if a status change has occurred for the - // Disruptor. - virtual ~SequenceBarrierInterface(){} - virtual int64_t WaitFor(const int64_t& sequence) = 0; - - // Wait for the given sequence to be available for consumption with a - // time out. - // - // @param sequence to wait for. - // @param timeout in microseconds. - // @return the sequence up to which is available. - // - // @throws AlertException if a status change has occurred for the - // Disruptor. - virtual int64_t WaitFor(const int64_t& sequence, - const int64_t& timeout_micro) = 0; - - // Delegate a call to the {@link Sequencer#getCursor()} - // - // @return value of the cursor for entries that have been published. - virtual int64_t GetCursor() const = 0; - - // The current alert status for the barrier. - // - // @return true if in alert otherwise false. - virtual bool IsAlerted() const = 0; - - // Alert the {@link EventProcessor}s of a status change and stay in this - // status until cleared. - virtual void Alert() = 0; - - // Clear the current alert status. - virtual void ClearAlert() = 0; - - // Check if barrier is alerted, if so throws an AlertException - // - // @throws AlertException if barrier is alerted - virtual void CheckAlert() const = 0; -}; - -// Called by the {@link RingBuffer} to pre-populate all the events to fill the -// RingBuffer. -// -// @param event implementation storing the data for sharing during exchange -// or parallel coordination of an event. -template -class EventFactoryInterface { - public: - virtual ~EventFactoryInterface(){} - virtual T* NewInstance(const int& size) const = 0; -}; - -// Callback interface to be implemented for processing events as they become -// available in the {@link RingBuffer}. -// -// @param event implementation storing the data for sharing during exchange -// or parallel coordination of an event. -template -class EventHandlerInterface { - public: - // Called when a publisher has published an event to the {@link RingBuffer} - // - // @param event published to the {@link RingBuffer} - // @param sequence of the event being processed - // @param end_of_batch flag to indicate if this is the last event in a batch - // from the {@link RingBuffer} - // - // @throws Exception if the EventHandler would like the exception handled - // further up the chain. - virtual ~EventHandlerInterface(){} - virtual void OnEvent(const int64_t& sequence, - const bool& end_of_batch, - T* event) = 0; - - // Called once on thread start before processing the first event. - virtual void OnStart() = 0; - - // Called once on thread stop just before shutdown. - virtual void OnShutdown() = 0; -}; - -// Implementations translate another data representations into events claimed -// for the {@link RingBuffer}. -// -// @param event implementation storing the data for sharing during exchange -// or parallel coordination of an event. -template -class EventTranslatorInterface { - public: - // Translate a data representation into fields set in given event - // - // @param event into which the data should be translated. - // @param sequence that is assigned to events. - // @return the resulting event after it has been translated. - virtual ~EventTranslatorInterface(){} - virtual T* TranslateTo(const int64_t& sequence, T* event) { return NULL;} -}; - -// EventProcessors wait for events to become available for consumption from -// the {@link RingBuffer}. An event processor should be associated with a -// thread. -// -// @param event implementation storing the data for sharing during exchange -// or parallel coordination of an event. -template -class EventProcessorInterface { - public: - // Get a pointer to the {@link Sequence} being used by this - // {@link EventProcessor}. - // - // @return pointer to the {@link Sequence} for this - // {@link EventProcessor} - virtual ~EventProcessorInterface(){} - virtual Sequence* GetSequence() = 0; - - // Signal that this EventProcessor should stop when it has finished - // consuming at the next clean break. - // It will call {@link DependencyBarrier#alert()} to notify the thread to - // check status. - virtual void Halt() = 0; -}; - -// Callback handler for uncaught exception in the event processing cycle -// of the {@link BatchEventProcessor}. -// -// @param event type stored in the {@link RingBuffer}. -template -class ExceptionHandlerInterface { - public: - // Strategy for handling uncaught exceptions when processing an event. - // If the strategy wishes to suspend further processing by the - // {@link BatchEventProcessor} then it should throw a std::runtime_error. - // - // @param exception that propagated from the {@link EventHandler}. - // @param sequence of the event which caused the exception. - // @param event being processed when the exception occured. - virtual ~ExceptionHandlerInterface(){} - virtual void Handle(const std::exception& exception, - const int64_t& sequence, - T* event) = 0; -}; - -// Strategy employed for making {@link EventProcessor}s wait on a cursor -// {@link Sequence}. -class WaitStrategyInterface: public boost::noncopyable { - public: - // Wait for the given sequence to be available for consumption. - // - // @param dependents further back the chain that must advance first. - // @param cursor on which to wait. - // @param barrier the consumer is waiting on. - // @param sequence to be waited on. - // @return the sequence that is available which may be greater than the - // requested sequence. - // - // @throws AlertException if the status of the Disruptor has changed. - virtual ~WaitStrategyInterface(){} - virtual int64_t WaitFor(const std::vector& dependents, - const Sequence& cursor, - const SequenceBarrierInterface& barrier, - const int64_t& sequence) = 0; - - // Wait for the given sequence to be available for consumption in a - // {@link RingBuffer} with a timeout specified. - // - // @param dependents further back the chain that must advance first - // @param cursor on which to wait. - // @param barrier the consumer is waiting on. - // @param sequence to be waited on. - // @param timeout value in micro seconds to abort after. - // @return the sequence that is available which may be greater than the - // requested sequence. - // - // @throws AlertException if the status of the Disruptor has changed. - // @throws InterruptedException if the thread is interrupted. - virtual int64_t WaitFor(const std::vector& dependents, - const Sequence& cursor, - const SequenceBarrierInterface& barrier, - const int64_t & sequence, - const int64_t & timeout_micros) = 0; - - // Signal those waiting that the cursor has advanced. - virtual void SignalAllWhenBlocking() = 0; -}; - -}; // namespace rocketmq - -#endif // DISRUPTOR_INTERFACE_H_ NOLINT diff --git a/src/thread/disruptor/ring_buffer.h b/src/thread/disruptor/ring_buffer.h deleted file mode 100755 index c7150f152..000000000 --- a/src/thread/disruptor/ring_buffer.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2011, François Saint-Jacques -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the disruptor-- nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL FRANÇOIS SAINT-JACQUES BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DISRUPTOR_RING_BUFFER_H_ // NOLINT -#define DISRUPTOR_RING_BUFFER_H_ // NOLINT - -#include -#include - -#include "interface.h" -#include "claim_strategy.h" -#include "wait_strategy.h" -#include "sequencer.h" -#include "sequence_barrier.h" - -namespace rocketmq { - -// Ring based store of reusable entries containing the data representing an -// event beign exchanged between publisher and {@link EventProcessor}s. -// -// @param implementation storing the data for sharing during exchange -// or parallel coordination of an event. -template -class RingBuffer : public Sequencer { - public: - // Construct a RingBuffer with the full option set. - // - // @param event_factory to instance new entries for filling the RingBuffer. - // @param buffer_size of the RingBuffer, must be a power of 2. - // @param claim_strategy_option threading strategy for publishers claiming - // entries in the ring. - // @param wait_strategy_option waiting strategy employed by - // processors_to_track waiting in entries becoming available. - RingBuffer(EventFactoryInterface* event_factory, - int buffer_size, - ClaimStrategyOption claim_strategy_option, - WaitStrategyOption wait_strategy_option) : - Sequencer(buffer_size, - claim_strategy_option, - wait_strategy_option), - buffer_size_(buffer_size), - mask_(buffer_size - 1), - events_(event_factory->NewInstance(buffer_size)) { - } - - ~RingBuffer() { - delete[] events_; - } - - // Get the event for a given sequence in the RingBuffer. - // - // @param sequence for the event - // @return event pointer at the specified sequence position. - T* Get(const int64_t& sequence) { - return &events_[sequence & mask_]; - } - - private: - // Members - int buffer_size_; - int mask_; - T* events_; - -}; - -}; // namespace rocketmq - -#endif // DISRUPTOR_RING_BUFFER_H_ NOLINT diff --git a/src/thread/disruptor/sequence.h b/src/thread/disruptor/sequence.h deleted file mode 100755 index 4a5c75cec..000000000 --- a/src/thread/disruptor/sequence.h +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2011, François Saint-Jacques -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the disruptor-- nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL FRANÇOIS SAINT-JACQUES BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef CACHE_LINE_SIZE_IN_BYTES // NOLINT -#define CACHE_LINE_SIZE_IN_BYTES 64 // NOLINT -#endif // NOLINT -#define ATOMIC_SEQUENCE_PADDING_LENGTH \ - (CACHE_LINE_SIZE_IN_BYTES - sizeof(boost::atomic))/8 -#define SEQUENCE_PADDING_LENGTH \ - (CACHE_LINE_SIZE_IN_BYTES - sizeof(int64_t))/8 - -#ifndef DISRUPTOR_SEQUENCE_H_ // NOLINT -#define DISRUPTOR_SEQUENCE_H_ // NOLINT - -#include -#include -#include -#include -#include -using namespace boost; -namespace rocketmq { - -const int64_t kInitialCursorValue = -1L; - -// Sequence counter. -class Sequence:public noncopyable { - public: - // Construct a sequence counter that can be tracked across threads. - // - // @param initial_value for the counter. - Sequence(int64_t initial_value = kInitialCursorValue) : - value_(initial_value) {} - - // Get the current value of the {@link Sequence}. - // - // @return the current value. - int64_t sequence() const { return value_.load(boost::memory_order_acquire); } - - // Set the current value of the {@link Sequence}. - // - // @param the value to which the {@link Sequence} will be set. - void set_sequence(int64_t value) { value_.store(value, boost::memory_order_release); } - - // Increment and return the value of the {@link Sequence}. - // - // @param increment the {@link Sequence}. - // @return the new value incremented. - int64_t IncrementAndGet(const int64_t& increment) { - return value_.fetch_add(increment, boost::memory_order_release) + increment; - } - - private: - // members - boost::atomic value_; - -}; - -// Cache line padded sequence counter. -// -// Can be used across threads without worrying about false sharing if a -// located adjacent to another counter in memory. -class PaddedSequence : public Sequence { - public: - PaddedSequence(int64_t initial_value = kInitialCursorValue) : - Sequence(initial_value) {} - - //private: - // padding - //int64_t padding_[ATOMIC_SEQUENCE_PADDING_LENGTH]; - -}; - -// Non-atomic sequence counter. -// -// This counter is not thread safe. -class MutableLong { - public: - MutableLong(int64_t initial_value = kInitialCursorValue) : - sequence_(initial_value) {} - - int64_t sequence() const { return sequence_; } - - void set_sequence(const int64_t& sequence) { sequence_ = sequence; }; - - int64_t IncrementAndGet(const int64_t& delta) { sequence_ += delta; return sequence_; } - - private: - volatile int64_t sequence_; -}; - -// Cache line padded non-atomic sequence counter. -// -// This counter is not thread safe. -class PaddedLong : public MutableLong { - public: - PaddedLong(int64_t initial_value = kInitialCursorValue) : - MutableLong(initial_value) {} - //private: - //int64_t padding_[SEQUENCE_PADDING_LENGTH]; -}; - -int64_t GetMinimumSequence( - const std::vector& sequences) { - int64_t minimum = std::numeric_limits::max(); - - std::vector::const_iterator it= sequences.begin(); - for (;it!=sequences.end();it++) { - int64_t sequence = (*it)->sequence(); - minimum = minimum < sequence ? minimum : sequence; - } - - return minimum; -}; - -}; // namespace rocketmq - -#endif // DISRUPTOR_SEQUENCE_H_ NOLINT diff --git a/src/thread/disruptor/sequence_barrier.h b/src/thread/disruptor/sequence_barrier.h deleted file mode 100755 index 5882e39db..000000000 --- a/src/thread/disruptor/sequence_barrier.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2011, François Saint-Jacques -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the disruptor-- nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL FRANÇOIS SAINT-JACQUES BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DISRUPTOR_SEQUENCE_BARRIER_H_ // NOLINT -#define DISRUPTOR_SEQUENCE_BARRIER_H_ // NOLINT - -#include -#include - -#include "exceptions.h" -#include "interface.h" -namespace rocketmq { - -class ProcessingSequenceBarrier : SequenceBarrierInterface { - public: - ProcessingSequenceBarrier(WaitStrategyInterface* wait_strategy, - Sequence* sequence, - const std::vector& sequences) : - wait_strategy_(wait_strategy), - cursor_(sequence), - dependent_sequences_(sequences), - alerted_(false) { - } - - virtual int64_t WaitFor(const int64_t& sequence) { - return wait_strategy_->WaitFor(dependent_sequences_, *cursor_, *this, - sequence); - } - - virtual int64_t WaitFor(const int64_t& sequence, - const int64_t& timeout_micros) { - return wait_strategy_->WaitFor(dependent_sequences_, *cursor_, *this, - sequence, timeout_micros); - } - - virtual int64_t GetCursor() const { - return cursor_->sequence(); - } - - virtual bool IsAlerted() const { - return alerted_.load(boost::memory_order_acquire); - } - - virtual void Alert() { - //rocketmq::LOG_INFO("set alert to true"); - alerted_.store(true, boost::memory_order_release); - } - - virtual void ClearAlert() { - alerted_.store(false, boost::memory_order_release); - } - - virtual void CheckAlert() const { - if (IsAlerted()) - { - //rocketmq::LOG_INFO("throw alert exception\r\n"); - throw AlertException(); - } - } - - private: - WaitStrategyInterface* wait_strategy_; - Sequence* cursor_; - std::vector dependent_sequences_; - boost::atomic alerted_; -}; - -}; // namespace rocketmq - -#endif // DISRUPTOR_DEPENDENCY_BARRIER_H_ NOLINT diff --git a/src/thread/disruptor/sequencer.h b/src/thread/disruptor/sequencer.h deleted file mode 100755 index 98d617f5e..000000000 --- a/src/thread/disruptor/sequencer.h +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (c) 2011, François Saint-Jacques -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the disruptor-- nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL FRANÇOIS SAINT-JACQUES BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DISRUPTOR_SEQUENCER_H_ // NOLINT -#define DISRUPTOR_SEQUENCER_H_ // NOLINT - -#include - -#include "batch_descriptor.h" -#include "claim_strategy.h" -#include "interface.h" -#include "sequence_barrier.h" -#include "wait_strategy.h" - -namespace rocketmq { - -// Coordinator for claiming sequences for access to a data structures while -// tracking dependent {@link Sequence}s -class Sequencer: public boost::noncopyable { - public: - // Construct a Sequencer with the selected strategies. - // - // @param buffer_size over which sequences are valid. - // @param claim_strategy_option for those claiming sequences. - // @param wait_strategy_option for those waiting on sequences. - Sequencer(int buffer_size, - ClaimStrategyOption claim_strategy_option, - WaitStrategyOption wait_strategy_option) : - buffer_size_(buffer_size), - claim_strategy_(CreateClaimStrategy(claim_strategy_option, - buffer_size_)), - wait_strategy_(CreateWaitStrategy(wait_strategy_option)) { } - - ~Sequencer() { - delete claim_strategy_; - delete wait_strategy_; - } - - // Set the sequences that will gate publishers to prevent the buffer - // wrapping. - // - // @param sequences to be gated on. - void set_gating_sequences( - const std::vector& sequences) { - gating_sequences_ = sequences; - } - - // Create a {@link SequenceBarrier} that gates on the cursor and a list of - // {@link Sequence}s. - // - // @param sequences_to_track this barrier will track. - // @return the barrier gated as required. - ProcessingSequenceBarrier* NewBarrier( - const std::vector& sequences_to_track) { - return new ProcessingSequenceBarrier(wait_strategy_, &cursor_, - sequences_to_track); - } - - // Create a new {@link BatchDescriptor} that is the minimum of the - // requested size and the buffer_size. - // - // @param size for the new batch. - // @return the new {@link BatchDescriptor}. - BatchDescriptor* NewBatchDescriptor(const int& size) { - return new BatchDescriptor(sizeHasAvalaibleCapacity(gating_sequences_); - } - - // Claim the next event in sequence for publishing to the {@link RingBuffer}. - // - // @return the claimed sequence. - int64_t Next() { - return claim_strategy_->IncrementAndGet(gating_sequences_); - } - - // Claim the next batch of sequence numbers for publishing. - // - // @param batch_descriptor to be updated for the batch range. - // @return the updated batch_descriptor. - BatchDescriptor* Next(BatchDescriptor* batch_descriptor) { - int64_t sequence = claim_strategy_->IncrementAndGet(batch_descriptor->size(), gating_sequences_); - batch_descriptor->set_end(sequence); - return batch_descriptor; - } - - // Claim a specific sequence when only one publisher is involved. - // - // @param sequence to be claimed. - // @return sequence just claime. - int64_t Claim(const int64_t& sequence) { - claim_strategy_->SetSequence(sequence, gating_sequences_); - return sequence; - } - - // Publish an event and make it visible to {@link EventProcessor}s. - // - // @param sequence to be published. - void Publish(const int64_t& sequence) { - Publish(sequence, 1); - } - - // Publish the batch of events in sequence. - // - // @param sequence to be published. - void Publish(const BatchDescriptor& batch_descriptor) { - Publish(batch_descriptor.end(), batch_descriptor.size()); - } - - // Force the publication of a cursor sequence. - // - // Only use this method when forcing a sequence and you are sure only one - // publisher exists. This will cause the cursor to advance to this - // sequence. - // - // @param sequence to which is to be forced for publication. - void ForcePublish(const int64_t& sequence) { - cursor_.set_sequence(sequence); - wait_strategy_->SignalAllWhenBlocking(); - } - - // TODO(fsaintjacques): This was added to overcome - // NoOpEventProcessor::GetSequence(), this is not a clean solution. - Sequence* GetSequencePtr() { - return &cursor_; - } - - private: - // Helpers - void Publish(const int64_t& sequence, const int64_t& batch_size) { - //LOG_DEBUG("publish sequence:%d", sequence); - claim_strategy_->SerialisePublishing(sequence, cursor_, batch_size); - cursor_.set_sequence(sequence); - wait_strategy_->SignalAllWhenBlocking(); - } - - // Members - const int buffer_size_; - - PaddedSequence cursor_; - std::vector gating_sequences_; - - ClaimStrategyInterface* claim_strategy_; - WaitStrategyInterface* wait_strategy_; - -}; - -}; // namespace rocketmq - -#endif // DISRUPTOR_RING_BUFFER_H_ NOLINT diff --git a/src/thread/disruptor/utils.h b/src/thread/disruptor/utils.h deleted file mode 100755 index 0730093e2..000000000 --- a/src/thread/disruptor/utils.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2011, François Saint-Jacques -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the disruptor-- nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL FRANÇOIS SAINT-JACQUES BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DISRUPTOR_UTILS_H_ // NOLINT -#define DISRUPTOR_UTILS_H_ // NOLINT - -// From Google C++ Standard, modified to use C++11 deleted functions. -// A macro to disallow the copy constructor and operator= functions. -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&) delete \ - void operator=(const TypeName&) delete; - -#endif // DISRUPTOR_UTILS_H_ NOLINT diff --git a/src/thread/disruptor/wait_strategy.h b/src/thread/disruptor/wait_strategy.h deleted file mode 100755 index 92044a8b0..000000000 --- a/src/thread/disruptor/wait_strategy.h +++ /dev/null @@ -1,372 +0,0 @@ -// Copyright (c) 2011, François Saint-Jacques -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the disruptor-- nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL FRANÇOIS SAINT-JACQUES BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef DISRUPTOR_WAITSTRATEGY_H_ // NOLINT -#define DISRUPTOR_WAITSTRATEGY_H_ // NOLINT - -#include -#include -#include -#include - -#include "exceptions.h" -#include "interface.h" -#include "sequence.h" - -namespace rocketmq { - -// Strategy options which are available to those waiting on a -// {@link RingBuffer} -enum WaitStrategyOption { - // This strategy uses a condition variable inside a lock to block the - // event procesor which saves CPU resource at the expense of lock - // contention. - kBlockingStrategy, - // This strategy uses a progressive back off strategy by first spinning, - // then yielding, then sleeping for 1ms period. This is a good strategy - // for burst traffic then quiet periods when latency is not critical. - kSleepingStrategy, - // This strategy calls Thread.yield() in a loop as a waiting strategy - // which reduces contention at the expense of CPU resource. - kYieldingStrategy, - // This strategy call spins in a loop as a waiting strategy which is - // lowest and most consistent latency but ties up a CPU. - kBusySpinStrategy -}; - -// Blocking strategy that uses a lock and condition variable for -// {@link Consumer}s waiting on a barrier. -// This strategy should be used when performance and low-latency are not as -// important as CPU resource. -class BlockingStrategy : public WaitStrategyInterface { - public: - BlockingStrategy() {} - - virtual int64_t WaitFor(const std::vector& dependents, - const Sequence& cursor, - const SequenceBarrierInterface& barrier, - const int64_t& sequence) { - int64_t available_sequence = 0; - // We need to wait. - if ((available_sequence = cursor.sequence()) < sequence) { - // acquire lock - boost::unique_lock ulock(mutex_); - while ((available_sequence = cursor.sequence()) < sequence) { - barrier.CheckAlert(); - consumer_notify_condition_.wait(ulock); - } - } // unlock happens here, on ulock destruction. - - if (0 != dependents.size()) { - while ((available_sequence = GetMinimumSequence(dependents)) < sequence) { - barrier.CheckAlert(); - } - } - - return available_sequence; - } - - virtual int64_t WaitFor(const std::vector& dependents, - const Sequence& cursor, - const SequenceBarrierInterface& barrier, - const int64_t& sequence, - const int64_t& timeout_micros) { - int64_t available_sequence = 0; - // We have to wait - if ((available_sequence = cursor.sequence()) < sequence) { - boost::unique_lock ulock(mutex_); - while ((available_sequence = cursor.sequence()) < sequence) { - barrier.CheckAlert(); - if (boost::cv_status::timeout == - consumer_notify_condition_.wait_for( - ulock, boost::chrono::microseconds(timeout_micros))) - break; - } - } // unlock happens here, on ulock destruction - - if (0 != dependents.size()) { - while ((available_sequence = GetMinimumSequence(dependents)) < sequence) { - barrier.CheckAlert(); - } - } - - return available_sequence; - } - - virtual void SignalAllWhenBlocking() { - boost::unique_lock ulock(mutex_); - consumer_notify_condition_.notify_all(); - } - - private: - boost::recursive_mutex mutex_; - boost::condition_variable_any consumer_notify_condition_; -}; - -// Sleeping strategy -class SleepingStrategy : public WaitStrategyInterface { - public: - SleepingStrategy() {} - - virtual int64_t WaitFor(const std::vector& dependents, - const Sequence& cursor, - const SequenceBarrierInterface& barrier, - const int64_t& sequence) { - int64_t available_sequence = 0; - int counter = kRetries; - - if (0 == dependents.size()) { - while ((available_sequence = cursor.sequence()) < sequence) { - counter = ApplyWaitMethod(barrier, counter); - } - } else { - while ((available_sequence = GetMinimumSequence(dependents)) < sequence) { - counter = ApplyWaitMethod(barrier, counter); - } - } - - return available_sequence; - } - - virtual int64_t WaitFor(const std::vector& dependents, - const Sequence& cursor, - const SequenceBarrierInterface& barrier, - const int64_t& sequence, - const int64_t& timeout_micros) { - // timing - boost::posix_time::ptime current_date_microseconds = - boost::posix_time::microsec_clock::local_time(); - int64_t start_micro = - current_date_microseconds.time_of_day().total_milliseconds(); - - int64_t available_sequence = 0; - int counter = kRetries; - - if (0 == dependents.size()) { - while ((available_sequence = cursor.sequence()) < sequence) { - counter = ApplyWaitMethod(barrier, counter); - boost::posix_time::ptime current_date_microseconds = - boost::posix_time::microsec_clock::local_time(); - int64_t end_micro = - current_date_microseconds.time_of_day().total_milliseconds(); - if (timeout_micros < (end_micro - start_micro)) break; - } - } else { - while ((available_sequence = GetMinimumSequence(dependents)) < sequence) { - counter = ApplyWaitMethod(barrier, counter); - boost::posix_time::ptime current_date_microseconds = - boost::posix_time::microsec_clock::local_time(); - int64_t end_micro = - current_date_microseconds.time_of_day().total_milliseconds(); - if (timeout_micros < (end_micro - start_micro)) break; - } - } - - return available_sequence; - } - - virtual void SignalAllWhenBlocking() {} - - static const int kRetries = 200; - - private: - int ApplyWaitMethod(const SequenceBarrierInterface& barrier, int counter) { - barrier.CheckAlert(); - if (counter > 100) { - counter--; - } else if (counter > 0) { - counter--; - boost::this_thread::yield(); - } else { - boost::this_thread::sleep_for(boost::chrono::milliseconds(1)); - } - - return counter; - } -}; - -// Yielding strategy that uses a sleep(0) for {@link EventProcessor}s waiting -// on a barrier. This strategy is a good compromise between performance and -// CPU resource. -class YieldingStrategy : public WaitStrategyInterface { - public: - YieldingStrategy() {} - - virtual int64_t WaitFor(const std::vector& dependents, - const Sequence& cursor, - const SequenceBarrierInterface& barrier, - const int64_t& sequence) { - int64_t available_sequence = 0; - int counter = kSpinTries; - - if (0 == dependents.size()) { - while ((available_sequence = cursor.sequence()) < sequence) { - counter = ApplyWaitMethod(barrier, counter); - } - } else { - while ((available_sequence = GetMinimumSequence(dependents)) < sequence) { - counter = ApplyWaitMethod(barrier, counter); - } - } - - return available_sequence; - } - - virtual int64_t WaitFor(const std::vector& dependents, - const Sequence& cursor, - const SequenceBarrierInterface& barrier, - const int64_t& sequence, - const int64_t& timeout_micros) { - boost::posix_time::ptime current_date_microseconds = - boost::posix_time::microsec_clock::local_time(); - int64_t start_micro = - current_date_microseconds.time_of_day().total_milliseconds(); - - int64_t available_sequence = 0; - int counter = kSpinTries; - - if (0 == dependents.size()) { - while ((available_sequence = cursor.sequence()) < sequence) { - counter = ApplyWaitMethod(barrier, counter); - boost::posix_time::ptime current_date_microseconds = - boost::posix_time::microsec_clock::local_time(); - int64_t end_micro = - current_date_microseconds.time_of_day().total_milliseconds(); - if (timeout_micros < (end_micro - start_micro)) break; - } - } else { - while ((available_sequence = GetMinimumSequence(dependents)) < sequence) { - counter = ApplyWaitMethod(barrier, counter); - boost::posix_time::ptime current_date_microseconds = - boost::posix_time::microsec_clock::local_time(); - int64_t end_micro = - current_date_microseconds.time_of_day().total_milliseconds(); - if (timeout_micros < (end_micro - start_micro)) break; - } - } - - return available_sequence; - } - - virtual void SignalAllWhenBlocking() {} - - static const int kSpinTries = 100; - - private: - int ApplyWaitMethod(const SequenceBarrierInterface& barrier, int counter) { - barrier.CheckAlert(); - if (counter == 0) { - boost::this_thread::yield(); - } else { - counter--; - } - - return counter; - } -}; - -// Busy Spin strategy that uses a busy spin loop for {@link EventProcessor}s -// waiting on a barrier. -// This strategy will use CPU resource to avoid syscalls which can introduce -// latency jitter. It is best used when threads can be bound to specific -// CPU cores. -class BusySpinStrategy : public WaitStrategyInterface { - public: - BusySpinStrategy() {} - - virtual int64_t WaitFor(const std::vector& dependents, - const Sequence& cursor, - const SequenceBarrierInterface& barrier, - const int64_t& sequence) { - int64_t available_sequence = 0; - if (0 == dependents.size()) { - while ((available_sequence = cursor.sequence()) < sequence) { - barrier.CheckAlert(); - } - } else { - while ((available_sequence = GetMinimumSequence(dependents)) < sequence) { - barrier.CheckAlert(); - } - } - - return available_sequence; - } - - virtual int64_t WaitFor(const std::vector& dependents, - const Sequence& cursor, - const SequenceBarrierInterface& barrier, - const int64_t& sequence, - const int64_t& timeout_micros) { - boost::posix_time::ptime current_date_microseconds = - boost::posix_time::microsec_clock::local_time(); - int64_t start_micro = - current_date_microseconds.time_of_day().total_milliseconds(); - int64_t available_sequence = 0; - - if (0 == dependents.size()) { - while ((available_sequence = cursor.sequence()) < sequence) { - barrier.CheckAlert(); - boost::posix_time::ptime current_date_microseconds = - boost::posix_time::microsec_clock::local_time(); - int64_t end_micro = - current_date_microseconds.time_of_day().total_milliseconds(); - if (timeout_micros < (end_micro - start_micro)) break; - } - } else { - while ((available_sequence = GetMinimumSequence(dependents)) < sequence) { - barrier.CheckAlert(); - boost::posix_time::ptime current_date_microseconds = - boost::posix_time::microsec_clock::local_time(); - int64_t end_micro = - current_date_microseconds.time_of_day().total_milliseconds(); - if (timeout_micros < (end_micro - start_micro)) break; - } - } - - return available_sequence; - } - - virtual void SignalAllWhenBlocking() {} -}; - -WaitStrategyInterface* CreateWaitStrategy(WaitStrategyOption wait_option) { - switch (wait_option) { - case kBlockingStrategy: - return new BlockingStrategy(); - case kSleepingStrategy: - return new SleepingStrategy(); - case kYieldingStrategy: - return new YieldingStrategy(); - case kBusySpinStrategy: - return new BusySpinStrategy(); - default: - return NULL; - } -} - -}; // namespace rocketmq - -#endif // DISRUPTOR_WAITSTRATEGY_H_ NOLINT diff --git a/src/thread/disruptorLFQ.h b/src/thread/disruptorLFQ.h deleted file mode 100644 index 30e5a1858..000000000 --- a/src/thread/disruptorLFQ.h +++ /dev/null @@ -1,117 +0,0 @@ -/* -* Licensed to the Apache Software Foundation (ASF) under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The ASF licenses this file to You under the Apache License, Version 2.0 -* (the "License"); you may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -#ifndef _DISRUPTORLFQ_ -#define _DISRUPTORLFQ_ - -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace rocketmq { -class Task; -class taskEventFactory : public EventFactoryInterface { - public: - virtual Task* NewInstance(const int& size) const; -}; - -class taskBatchHandler : public EventHandlerInterface { - public: - taskBatchHandler(int pullMsgThreadPoolNum); - virtual ~taskBatchHandler() {} - - virtual void OnEvent(const int64_t& sequence, const bool& end_of_batch, Task* event); - virtual void OnStart() {} - virtual void OnShutdown() {} - void runTaskEvent(Task event, int64_t sequence); - void stopIOService(); - - private: - boost::asio::io_service m_ioService; - boost::thread_group m_threadpool; - boost::asio::io_service::work m_ioServiceWork; -}; - -class taskEventTranslator : public EventTranslatorInterface { - public: - taskEventTranslator(Task* event); - virtual ~taskEventTranslator() {} - virtual Task* TranslateTo(const int64_t& sequence, Task* event); - - private: - Task* m_taskEvent; -}; - -class taskExceptionHandler : public ExceptionHandlerInterface { - public: - virtual void Handle(const std::exception& exception, const int64_t& sequence, Task* event) {} -}; - -class disruptorLFQ { - public: - disruptorLFQ(int threadCount) { - m_task_factory.reset(new taskEventFactory()); - m_ring_buffer.reset(new RingBuffer(m_task_factory.get(), - 1024, // default size is 1024, must be n power of 2 - kSingleThreadedStrategy, - kBlockingStrategy)); // load normal, lowest CPU occupy, but - // largest consume latency - - m_sequence_to_track.reset(new std::vector(0)); - m_sequenceBarrier.reset(m_ring_buffer->NewBarrier(*(m_sequence_to_track.get()))); - - m_task_handler.reset(new taskBatchHandler(threadCount)); - m_task_exception_handler.reset(new taskExceptionHandler()); - m_processor.reset(new BatchEventProcessor(m_ring_buffer.get(), - (SequenceBarrierInterface*)m_sequenceBarrier.get(), - m_task_handler.get(), m_task_exception_handler.get())); - - /* - Publisher will try to publish BUFFER_SIZE + 1 events. - The last event should wait for at least one consume before publishing, thus - preventing an overwrite. - After the single consume, the publisher should resume and publish the last - event. - */ - m_gating_sequences.push_back(m_processor.get()->GetSequence()); - m_ring_buffer->set_gating_sequences(m_gating_sequences); // prevent overlap, publishEvent will be blocked - // on ring_buffer_->Next(); - - m_publisher.reset(new EventPublisher(m_ring_buffer.get())); - } - virtual ~disruptorLFQ() {} - - public: - boost::scoped_ptr m_task_factory; - boost::scoped_ptr m_task_handler; - boost::scoped_ptr m_task_exception_handler; - boost::scoped_ptr> m_sequence_to_track; - boost::scoped_ptr> m_ring_buffer; - boost::scoped_ptr m_sequenceBarrier; - boost::scoped_ptr> m_processor; - boost::scoped_ptr> m_publisher; - std::vector m_gating_sequences; -}; -} -// -#endif -#include "UtilAll.h" -#include "disruptorLFQ.h" - -namespace rocketmq { -//m_task_handler->stopIOService(); - m_disruptorLFQ->m_processor->Halt(); -} - -bool TaskQueue::bTaskQueueStatusOK() { - return m_flag.load(boost::memory_order_acquire) == true; -} - -void TaskQueue::produce(const Task& task) { - boost::mutex::scoped_lock lock(m_publishLock); - taskEventTranslator pTranslator(const_cast(&task)); - m_disruptorLFQ->m_publisher->PublishEvent(&pTranslator); -} - -int TaskQueue::run() { - while (true) { - m_disruptorLFQ->m_processor->Run(); - if (m_flag.load(boost::memory_order_acquire) == false) { - break; - } - } - return 0; -} - -// -#include -#include -#include -using namespace std; - -namespace rocketmq { - -//fork()) {} - Task() { m_pTaskImpl = new Task_impl(&Task::dumy, 0); } - virtual ~Task() { delete m_pTaskImpl; } - Task& operator=(const Task& src_) { - delete m_pTaskImpl; - m_pTaskImpl = src_.m_pTaskImpl->fork(); - return *this; - } - void run() { - if (m_pTaskImpl) - m_pTaskImpl->run(); - } - - private: - ITask_impl* m_pTaskImpl; -}; - -// TaskList; - - public: - virtual ~ITaskQueue() {} - virtual void close() = 0; - virtual void produce(const Task& task) = 0; - // virtual void multi_produce(const TaskList& tasks) = 0; - // virtual int consume(Task& task) = 0; - // virtual int consume_all(TaskList& tasks) = 0; - virtual int run() = 0; - // virtual int batch_run() = 0; - virtual bool bTaskQueueStatusOK() = 0; -}; - -// - static Task gen(RET (*func)(void)) { - struct lambda { - static void taskfunc(void* p_) { (*(RET(*)(void))p_)(); }; - }; - return Task(lambda::taskfunc, (void*)func); - } - - template - static Task gen(FUNCT func, ARG1 arg1) { - struct lambda : public ITask_impl { - FUNCT dest_func; - ARG1 arg1; - lambda(FUNCT func, const ARG1& arg1) : dest_func(func), arg1(arg1) {} - virtual void run() { (*dest_func)(arg1); } - virtual ITask_impl* fork() { return new lambda(dest_func, arg1); } - }; - return Task(new lambda(func, arg1)); - } - - template - static Task gen(FUNCT func, ARG1 arg1, ARG2 arg2) { - struct lambda : public ITask_impl { - FUNCT dest_func; - ARG1 arg1; - ARG2 arg2; - lambda(FUNCT func, const ARG1& arg1, const ARG2& arg2) : dest_func(func), arg1(arg1), arg2(arg2) {} - virtual void run() { (*dest_func)(arg1, arg2); } - virtual ITask_impl* fork() { return new lambda(dest_func, arg1, arg2); } - }; - return Task(new lambda(func, arg1, arg2)); - } - - template - static Task gen(FUNCT func, ARG1 arg1, ARG2 arg2, ARG3 arg3) { - struct lambda : public ITask_impl { - FUNCT dest_func; - ARG1 arg1; - ARG2 arg2; - ARG3 arg3; - lambda(FUNCT func, const ARG1& arg1, const ARG2& arg2, const ARG3& arg3) - : dest_func(func), arg1(arg1), arg2(arg2), arg3(arg3) {} - virtual void run() { (*dest_func)(arg1, arg2, arg3); } - virtual ITask_impl* fork() { return new lambda(dest_func, arg1, arg2, arg3); } - }; - return Task(new lambda(func, arg1, arg2, arg3)); - } - - template - static Task gen(FUNCT func, ARG1 arg1, ARG2 arg2, ARG3 arg3, ARG4 arg4) { - struct lambda : public ITask_impl { - FUNCT dest_func; - ARG1 arg1; - ARG2 arg2; - ARG3 arg3; - ARG4 arg4; - lambda(FUNCT func, const ARG1& arg1, const ARG2& arg2, const ARG3& arg3, const ARG4& arg4) - : dest_func(func), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) {} - virtual void run() { (*dest_func)(arg1, arg2, arg3, arg4); } - virtual ITask_impl* fork() { return new lambda(dest_func, arg1, arg2, arg3, arg4); } - }; - return Task(new lambda(func, arg1, arg2, arg3, arg4)); - } - - template - static Task gen(FUNCT func, ARG1 arg1, ARG2 arg2, ARG3 arg3, ARG4 arg4, ARG5 arg5) { - struct lambda : public ITask_impl { - FUNCT dest_func; - ARG1 arg1; - ARG2 arg2; - ARG3 arg3; - ARG4 arg4; - ARG5 arg5; - lambda(FUNCT func, const ARG1& arg1, const ARG2& arg2, const ARG3& arg3, const ARG4& arg4, const ARG5& arg5) - : dest_func(func), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) {} - virtual void run() { (*dest_func)(arg1, arg2, arg3, arg4, arg5); } - virtual ITask_impl* fork() { return new lambda(dest_func, arg1, arg2, arg3, arg4, arg5); } - }; - return Task(new lambda(func, arg1, arg2, arg3, arg4, arg5)); - } - - template - static Task gen(FUNCT func, ARG1 arg1, ARG2 arg2, ARG3 arg3, ARG4 arg4, ARG5 arg5, ARG6 arg6) { - struct lambda : public ITask_impl { - FUNCT dest_func; - ARG1 arg1; - ARG2 arg2; - ARG3 arg3; - ARG4 arg4; - ARG5 arg5; - ARG6 arg6; - lambda(FUNCT func, - const ARG1& arg1, - const ARG2& arg2, - const ARG3& arg3, - const ARG4& arg4, - const ARG5& arg5, - const ARG6& arg6) - : dest_func(func), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5), arg6(arg6) {} - virtual void run() { (*dest_func)(arg1, arg2, arg3, arg4, arg5, arg6); } - virtual ITask_impl* fork() { return new lambda(dest_func, arg1, arg2, arg3, arg4, arg5, arg6); } - }; - return Task(new lambda(func, arg1, arg2, arg3, arg4, arg5, arg6)); - } - - template - static Task gen(FUNCT func, ARG1 arg1, ARG2 arg2, ARG3 arg3, ARG4 arg4, ARG5 arg5, ARG6 arg6, ARG7 arg7) { - struct lambda : public ITask_impl { - FUNCT dest_func; - ARG1 arg1; - ARG2 arg2; - ARG3 arg3; - ARG4 arg4; - ARG5 arg5; - ARG6 arg6; - ARG7 arg7; - lambda(FUNCT func, - const ARG1& arg1, - const ARG2& arg2, - const ARG3& arg3, - const ARG4& arg4, - const ARG5& arg5, - const ARG6& arg6, - const ARG7& arg7) - : dest_func(func), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5), arg6(arg6), arg7(arg7) {} - virtual void run() { (*dest_func)(arg1, arg2, arg3, arg4, arg5, arg6, arg7); } - virtual ITask_impl* fork() { return new lambda(dest_func, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } - }; - return Task(new lambda(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7)); - } - - template - static Task gen(FUNCT func, ARG1 arg1, ARG2 arg2, ARG3 arg3, ARG4 arg4, ARG5 arg5, ARG6 arg6, ARG7 arg7, ARG8 arg8) { - struct lambda : public ITask_impl { - FUNCT dest_func; - ARG1 arg1; - ARG2 arg2; - ARG3 arg3; - ARG4 arg4; - ARG5 arg5; - ARG6 arg6; - ARG7 arg7; - ARG8 arg8; - lambda(FUNCT func, - const ARG1& arg1, - const ARG2& arg2, - const ARG3& arg3, - const ARG4& arg4, - const ARG5& arg5, - const ARG6& arg6, - const ARG7& arg7, - const ARG8& arg8) - : dest_func(func), - arg1(arg1), - arg2(arg2), - arg3(arg3), - arg4(arg4), - arg5(arg5), - arg6(arg6), - arg7(arg7), - arg8(arg8) {} - virtual void run() { (*dest_func)(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } - virtual ITask_impl* fork() { return new lambda(dest_func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } - }; - return Task(new lambda(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); - } - - template - static Task - gen(FUNCT func, ARG1 arg1, ARG2 arg2, ARG3 arg3, ARG4 arg4, ARG5 arg5, ARG6 arg6, ARG7 arg7, ARG8 arg8, ARG9 arg9) { - struct lambda : public ITask_impl { - FUNCT dest_func; - ARG1 arg1; - ARG2 arg2; - ARG3 arg3; - ARG4 arg4; - ARG5 arg5; - ARG6 arg6; - ARG7 arg7; - ARG8 arg8; - ARG9 arg9; - lambda(FUNCT func, - const ARG1& arg1, - const ARG2& arg2, - const ARG3& arg3, - const ARG4& arg4, - const ARG5& arg5, - const ARG6& arg6, - const ARG7& arg7, - const ARG8& arg8, - const ARG9& arg9) - : dest_func(func), - arg1(arg1), - arg2(arg2), - arg3(arg3), - arg4(arg4), - arg5(arg5), - arg6(arg6), - arg7(arg7), - arg8(arg8), - arg9(arg9) {} - virtual void run() { (*dest_func)(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } - virtual ITask_impl* fork() { return new lambda(dest_func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } - }; - return Task(new lambda(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)); - } - - // - static Task gen(RET (T::*func)(void), T* obj) { - struct lambda : public ITask_impl { - RET (T::*dest_func)(void); - T* obj; - lambda(RET (T::*func)(void), T* obj) : dest_func(func), obj(obj) {} - virtual void run() { (obj->*dest_func)(); } - virtual ITask_impl* fork() { return new lambda(dest_func, obj); } - }; - return Task(new lambda(func, obj)); - } - - template - static Task gen(RET (T::*func)(FARG1), T* obj, ARG1 arg1) { - struct lambda : public ITask_impl { - RET (T::*dest_func)(FARG1); - T* obj; - ARG1 arg1; - lambda(RET (T::*pfunc)(FARG1), T* obj, const ARG1& arg1) : dest_func(pfunc), obj(obj), arg1(arg1) {} - virtual void run() { (obj->*dest_func)(arg1); } - virtual ITask_impl* fork() { return new lambda(dest_func, obj, arg1); } - }; - return Task(new lambda(func, obj, arg1)); - } - - template - static Task gen(RET (T::*func)(FARG1, FARG2), T* obj, ARG1 arg1, ARG2 arg2) { - struct lambda : public ITask_impl { - RET (T::*dest_func)(FARG1, FARG2); - T* obj; - ARG1 arg1; - ARG2 arg2; - lambda(RET (T::*func)(FARG1, FARG2), T* obj, const ARG1& arg1, const ARG2& arg2) - : dest_func(func), obj(obj), arg1(arg1), arg2(arg2) {} - virtual void run() { (obj->*dest_func)(arg1, arg2); } - virtual ITask_impl* fork() { return new lambda(dest_func, obj, arg1, arg2); } - }; - return Task(new lambda(func, obj, arg1, arg2)); - } - - template - static Task gen(RET (T::*func)(FARG1, FARG2, FARG3), T* obj, ARG1 arg1, ARG2 arg2, ARG3 arg3) { - struct lambda : public ITask_impl { - RET (T::*dest_func)(FARG1, FARG2, FARG3); - T* obj; - ARG1 arg1; - ARG2 arg2; - ARG3 arg3; - lambda(RET (T::*func)(FARG1, FARG2, FARG3), T* obj, const ARG1& arg1, const ARG2& arg2, const ARG3& arg3) - : dest_func(func), obj(obj), arg1(arg1), arg2(arg2), arg3(arg3) {} - virtual void run() { (obj->*dest_func)(arg1, arg2, arg3); } - virtual ITask_impl* fork() { return new lambda(dest_func, obj, arg1, arg2, arg3); } - }; - return Task(new lambda(func, obj, arg1, arg2, arg3)); - } - - template - static Task gen(RET (T::*func)(FARG1, FARG2, FARG3, FARG4), T* obj, ARG1 arg1, ARG2 arg2, ARG3 arg3, ARG4 arg4) { - struct lambda : public ITask_impl { - RET (T::*dest_func)(FARG1, FARG2, FARG3, FARG4); - T* obj; - ARG1 arg1; - ARG2 arg2; - ARG3 arg3; - ARG4 arg4; - lambda(RET (T::*func)(FARG1, FARG2, FARG3, FARG4), - T* obj, - const ARG1& arg1, - const ARG2& arg2, - const ARG3& arg3, - const ARG4& arg4) - : dest_func(func), obj(obj), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) {} - virtual void run() { (obj->*dest_func)(arg1, arg2, arg3, arg4); } - virtual ITask_impl* fork() { return new lambda(dest_func, obj, arg1, arg2, arg3, arg4); } - }; - return Task(new lambda(func, obj, arg1, arg2, arg3, arg4)); - } - - template - static Task gen(RET (T::*func)(FARG1, FARG2, FARG3, FARG4, FARG5), - T* obj, - ARG1 arg1, - ARG2 arg2, - ARG3 arg3, - ARG4 arg4, - ARG5 arg5) { - struct lambda : public ITask_impl { - RET (T::*dest_func)(FARG1, FARG2, FARG3, FARG4, FARG5); - T* obj; - ARG1 arg1; - ARG2 arg2; - ARG3 arg3; - ARG4 arg4; - ARG5 arg5; - lambda(RET (T::*func)(FARG1, FARG2, FARG3, FARG4, FARG5), - T* obj, - const ARG1& arg1, - const ARG2& arg2, - const ARG3& arg3, - const ARG4& arg4, - const ARG5& arg5) - : dest_func(func), obj(obj), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) {} - virtual void run() { (obj->*dest_func)(arg1, arg2, arg3, arg4, arg5); } - virtual ITask_impl* fork() { return new lambda(dest_func, obj, arg1, arg2, arg3, arg4, arg5); } - }; - return Task(new lambda(func, obj, arg1, arg2, arg3, arg4, arg5)); - } - - template - static Task gen(RET (T::*func)(FARG1, FARG2, FARG3, FARG4, FARG5, FARG6), - T* obj, - ARG1 arg1, - ARG2 arg2, - ARG3 arg3, - ARG4 arg4, - ARG5 arg5, - ARG6 arg6) { - struct lambda : public ITask_impl { - RET (T::*dest_func)(FARG1, FARG2, FARG3, FARG4, FARG5, FARG6); - T* obj; - ARG1 arg1; - ARG2 arg2; - ARG3 arg3; - ARG4 arg4; - ARG5 arg5; - ARG6 arg6; - lambda(RET (T::*func)(FARG1, FARG2, FARG3, FARG4, FARG5, FARG6), - T* obj, - const ARG1& arg1, - const ARG2& arg2, - const ARG3& arg3, - const ARG4& arg4, - const ARG5& arg5, - const ARG6& arg6) - : dest_func(func), obj(obj), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5), arg6(arg6) {} - virtual void run() { (obj->*dest_func)(arg1, arg2, arg3, arg4, arg5, arg6); } - virtual ITask_impl* fork() { return new lambda(dest_func, obj, arg1, arg2, arg3, arg4, arg5, arg6); } - }; - return Task(new lambda(func, obj, arg1, arg2, arg3, arg4, arg5, arg6)); - } - - template - static Task gen(RET (T::*func)(FARG1, FARG2, FARG3, FARG4, FARG5, FARG6, FARG7), - T* obj, - ARG1 arg1, - ARG2 arg2, - ARG3 arg3, - ARG4 arg4, - ARG5 arg5, - ARG6 arg6, - ARG7 arg7) { - struct lambda : public ITask_impl { - RET (T::*dest_func)(FARG1, FARG2, FARG3, FARG4, FARG5, FARG6, FARG7); - T* obj; - ARG1 arg1; - ARG2 arg2; - ARG3 arg3; - ARG4 arg4; - ARG5 arg5; - ARG6 arg6; - ARG7 arg7; - lambda(RET (T::*func)(FARG1, FARG2, FARG3, FARG4, FARG5, FARG6, FARG7), - T* obj, - const ARG1& arg1, - const ARG2& arg2, - const ARG3& arg3, - const ARG4& arg4, - const ARG5& arg5, - const ARG6& arg6, - const ARG7& arg7) - : dest_func(func), - obj(obj), - arg1(arg1), - arg2(arg2), - arg3(arg3), - arg4(arg4), - arg5(arg5), - arg6(arg6), - arg7(arg7) {} - virtual void run() { (obj->*dest_func)(arg1, arg2, arg3, arg4, arg5, arg6, arg7); } - virtual ITask_impl* fork() { return new lambda(dest_func, obj, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } - }; - return Task(new lambda(func, obj, arg1, arg2, arg3, arg4, arg5, arg6, arg7)); - } - - template - static Task gen(RET (T::*func)(FARG1, FARG2, FARG3, FARG4, FARG5, FARG6, FARG7, FARG8), - T* obj, - ARG1 arg1, - ARG2 arg2, - ARG3 arg3, - ARG4 arg4, - ARG5 arg5, - ARG6 arg6, - ARG7 arg7, - ARG8 arg8) { - struct lambda : public ITask_impl { - RET(T::*dest_func) - (FARG1, FARG2, FARG3, FARG4, FARG5, FARG6, FARG7, FARG8); - T* obj; - ARG1 arg1; - ARG2 arg2; - ARG3 arg3; - ARG4 arg4; - ARG5 arg5; - ARG6 arg6; - ARG7 arg7; - ARG8 arg8; - lambda(RET (T::*func)(FARG1, FARG2, FARG3, FARG4, FARG5, FARG6, FARG7, FARG8), - T* obj, - const ARG1& arg1, - const ARG2& arg2, - const ARG3& arg3, - const ARG4& arg4, - const ARG5& arg5, - const ARG6& arg6, - const ARG7& arg7, - const ARG8& arg8) - : dest_func(func), - obj(obj), - arg1(arg1), - arg2(arg2), - arg3(arg3), - arg4(arg4), - arg5(arg5), - arg6(arg6), - arg7(arg7), - arg8(arg8) {} - virtual void run() { (obj->*dest_func)(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } - virtual ITask_impl* fork() { return new lambda(dest_func, obj, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } - }; - return Task(new lambda(func, obj, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); - } - - template - static Task gen(RET (T::*func)(FARG1, FARG2, FARG3, FARG4, FARG5, FARG6, FARG7, FARG8, FARG9), - T* obj, - ARG1 arg1, - ARG2 arg2, - ARG3 arg3, - ARG4 arg4, - ARG5 arg5, - ARG6 arg6, - ARG7 arg7, - ARG8 arg8, - ARG9 arg9) { - struct lambda : public ITask_impl { - RET(T::*dest_func) - (FARG1, FARG2, FARG3, FARG4, FARG5, FARG6, FARG7, FARG8, FARG9); - T* obj; - ARG1 arg1; - ARG2 arg2; - ARG3 arg3; - ARG4 arg4; - ARG5 arg5; - ARG6 arg6; - ARG7 arg7; - ARG8 arg8; - ARG9 arg9; - lambda(RET (T::*func)(FARG1, FARG2, FARG3, FARG4, FARG5, FARG6, FARG7, FARG8, FARG9), - T* obj, - const ARG1& arg1, - const ARG2& arg2, - const ARG3& arg3, - const ARG4& arg4, - const ARG5& arg5, - const ARG6& arg6, - const ARG7& arg7, - const ARG8& arg8, - const ARG9& arg9) - : dest_func(func), - obj(obj), - arg1(arg1), - arg2(arg2), - arg3(arg3), - arg4(arg4), - arg5(arg5), - arg6(arg6), - arg7(arg7), - arg8(arg8), - arg9(arg9) {} - virtual void run() { (obj->*dest_func)(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } - virtual ITask_impl* fork() { - return new lambda(dest_func, obj, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); - } - }; - return Task(new lambda(func, obj, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)); - } -}; - -// m_flag; - disruptorLFQ* m_disruptorLFQ; - boost::mutex m_publishLock; -}; - -// -#include -#include "DefaultMQPushConsumerImpl.h" - -namespace rocketmq { -ConsumeMessageContext::ConsumeMessageContext() { - m_defaultMQPushConsumer = NULL; - // m_traceContext = NULL; -} -ConsumeMessageContext::~ConsumeMessageContext() { - m_traceContext.reset(); -} -std::string ConsumeMessageContext::getConsumerGroup() { - return m_consumerGroup; -} - -void ConsumeMessageContext::setConsumerGroup(const std::string& mConsumerGroup) { - m_consumerGroup = mConsumerGroup; -} - -bool ConsumeMessageContext::getSuccess() { - return m_success; -} - -void ConsumeMessageContext::setSuccess(bool mSuccess) { - m_success = mSuccess; -} - -std::vector ConsumeMessageContext::getMsgList() { - return m_msgList; -} - -void ConsumeMessageContext::setMsgList(std::vector mMsgList) { - m_msgList = mMsgList; -} - -std::string ConsumeMessageContext::getStatus() { - return m_status; -} - -void ConsumeMessageContext::setStatus(const std::string& mStatus) { - m_status = mStatus; -} - -int ConsumeMessageContext::getMsgIndex() { - return m_msgIndex; -} - -void ConsumeMessageContext::setMsgIndex(int mMsgIndex) { - m_msgIndex = mMsgIndex; -} - -MQMessageQueue ConsumeMessageContext::getMessageQueue() { - return m_messageQueue; -} - -void ConsumeMessageContext::setMessageQueue(const MQMessageQueue& mMessageQueue) { - m_messageQueue = mMessageQueue; -} - -DefaultMQPushConsumerImpl* ConsumeMessageContext::getDefaultMQPushConsumer() { - return m_defaultMQPushConsumer; -} - -void ConsumeMessageContext::setDefaultMQPushConsumer(DefaultMQPushConsumerImpl* mDefaultMqPushConsumer) { - m_defaultMQPushConsumer = mDefaultMqPushConsumer; -} - -std::shared_ptr ConsumeMessageContext::getTraceContext() { - return m_traceContext; -} - -void ConsumeMessageContext::setTraceContext(TraceContext* mTraceContext) { - m_traceContext.reset(mTraceContext); -} - -std::string ConsumeMessageContext::getNameSpace() { - return m_nameSpace; -} - -void ConsumeMessageContext::setNameSpace(const std::string& mNameSpace) { - m_nameSpace = mNameSpace; -} -} // namespace rocketmq diff --git a/src/trace/ConsumeMessageContext.h b/src/trace/ConsumeMessageContext.h deleted file mode 100644 index 109b08d7c..000000000 --- a/src/trace/ConsumeMessageContext.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __ROCKETMQ_CONSUME_MESSAGE_CONTEXT_H__ -#define __ROCKETMQ_CONSUME_MESSAGE_CONTEXT_H__ - -#include -#include -#include -#include "MQMessageExt.h" -#include "MQMessageQueue.h" -#include "TraceBean.h" -#include "TraceConstant.h" -#include "TraceContext.h" - -namespace rocketmq { -class DefaultMQPushConsumerImpl; -class ConsumeMessageContext { - public: - ConsumeMessageContext(); - - virtual ~ConsumeMessageContext(); - - std::string getConsumerGroup(); - - void setConsumerGroup(const std::string& mConsumerGroup); - - bool getSuccess(); - - void setSuccess(bool mSuccess); - - std::vector getMsgList(); - - void setMsgList(std::vector mMsgList); - - std::string getStatus(); - - void setStatus(const std::string& mStatus); - - int getMsgIndex(); - - void setMsgIndex(int mMsgIndex); - - MQMessageQueue getMessageQueue(); - - void setMessageQueue(const MQMessageQueue& mMessageQueue); - - DefaultMQPushConsumerImpl* getDefaultMQPushConsumer(); - - void setDefaultMQPushConsumer(DefaultMQPushConsumerImpl* mDefaultMqPushConsumer); - - std::shared_ptr getTraceContext(); - - void setTraceContext(TraceContext* mTraceContext); - - std::string getNameSpace(); - - void setNameSpace(const std::string& mNameSpace); - - private: - std::string m_consumerGroup; - bool m_success; - std::vector m_msgList; - std::string m_status; - int m_msgIndex; - MQMessageQueue m_messageQueue; - DefaultMQPushConsumerImpl* m_defaultMQPushConsumer; - // TraceContext* m_traceContext; - std::shared_ptr m_traceContext; - std::string m_nameSpace; -}; -} // namespace rocketmq -#endif \ No newline at end of file diff --git a/src/trace/ConsumeMessageHook.h b/src/trace/ConsumeMessageHook.h deleted file mode 100644 index d6317fb11..000000000 --- a/src/trace/ConsumeMessageHook.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __ROCKETMQ_COUNSUME_MESSAGE_RPC_HOOK_H__ -#define __ROCKETMQ_COUNSUME_MESSAGE_RPC_HOOK_H__ - -#include -#include "ConsumeMessageContext.h" -namespace rocketmq { -class ConsumeMessageHook { - public: - virtual ~ConsumeMessageHook() {} - virtual std::string getHookName() = 0; - virtual void executeHookBefore(ConsumeMessageContext* context) = 0; - virtual void executeHookAfter(ConsumeMessageContext* context) = 0; -}; -} // namespace rocketmq -#endif \ No newline at end of file diff --git a/src/trace/SendMessageContext.cpp b/src/trace/SendMessageContext.cpp deleted file mode 100644 index 9cf076627..000000000 --- a/src/trace/SendMessageContext.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "SendMessageContext.h" -#include - -namespace rocketmq { -SendMessageContext::SendMessageContext() {} - -SendMessageContext::~SendMessageContext() { - m_defaultMQProducer = NULL; -} - -std::string SendMessageContext::getProducerGroup() { - return m_producerGroup; -} - -void SendMessageContext::setProducerGroup(const std::string& mProducerGroup) { - m_producerGroup = mProducerGroup; -} - -MQMessage* SendMessageContext::getMessage() { - return &m_message; -} - -void SendMessageContext::setMessage(const MQMessage& mMessage) { - m_message = mMessage; -} - -TraceMessageType SendMessageContext::getMsgType() { - return m_msgType; -} - -void SendMessageContext::setMsgType(TraceMessageType mMsgType) { - m_msgType = mMsgType; -} - -MQMessageQueue* SendMessageContext::getMessageQueue() { - return &m_messageQueue; -} - -void SendMessageContext::setMessageQueue(const MQMessageQueue& mMq) { - m_messageQueue = mMq; -} - -std::string SendMessageContext::getBrokerAddr() { - return m_brokerAddr; -} - -void SendMessageContext::setBrokerAddr(const std::string& mBrokerAddr) { - m_brokerAddr = mBrokerAddr; -} - -std::string SendMessageContext::getBornHost() { - return m_bornHost; -} - -void SendMessageContext::setBornHost(const std::string& mBornHost) { - m_bornHost = mBornHost; -} - -CommunicationMode SendMessageContext::getCommunicationMode() { - return m_communicationMode; -} - -void SendMessageContext::setCommunicationMode(CommunicationMode mCommunicationMode) { - m_communicationMode = mCommunicationMode; -} - -DefaultMQProducerImpl* SendMessageContext::getDefaultMqProducer() { - return m_defaultMQProducer; -} - -void SendMessageContext::setDefaultMqProducer(DefaultMQProducerImpl* mDefaultMqProducer) { - m_defaultMQProducer = mDefaultMqProducer; -} - -SendResult* SendMessageContext::getSendResult() { - return &m_sendResult; -} - -void SendMessageContext::setSendResult(const SendResult& mSendResult) { - m_sendResult = mSendResult; -} - -TraceContext* SendMessageContext::getTraceContext() { - return m_traceContext; -} - -void SendMessageContext::setTraceContext(TraceContext* mTraceContext) { - m_traceContext = mTraceContext; -} - -std::string SendMessageContext::getNameSpace() { - return m_nameSpace; -} - -void SendMessageContext::setNameSpace(const std::string& mNameSpace) { - m_nameSpace = mNameSpace; -} -} // namespace rocketmq diff --git a/src/trace/SendMessageContext.h b/src/trace/SendMessageContext.h deleted file mode 100644 index ca7a52256..000000000 --- a/src/trace/SendMessageContext.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __ROCKETMQ_SEND_MESSAGE_CONTEXT_H__ -#define __ROCKETMQ_SEND_MESSAGE_CONTEXT_H__ - -#include -#include "CommunicationMode.h" -#include "MQMessage.h" -#include "MQMessageQueue.h" -#include "SendResult.h" -#include "TraceBean.h" -#include "TraceConstant.h" -#include "TraceContext.h" - -namespace rocketmq { -class DefaultMQProducerImpl; -class SendMessageContext { - public: - SendMessageContext(); - - virtual ~SendMessageContext(); - - std::string getProducerGroup(); - - void setProducerGroup(const std::string& mProducerGroup); - - MQMessage* getMessage(); - - void setMessage(const MQMessage& mMessage); - - TraceMessageType getMsgType(); - - void setMsgType(TraceMessageType mMsgType); - - MQMessageQueue* getMessageQueue(); - - void setMessageQueue(const MQMessageQueue& mMq); - - std::string getBrokerAddr(); - - void setBrokerAddr(const std::string& mBrokerAddr); - - std::string getBornHost(); - - void setBornHost(const std::string& mBornHost); - - CommunicationMode getCommunicationMode(); - - void setCommunicationMode(CommunicationMode mCommunicationMode); - - DefaultMQProducerImpl* getDefaultMqProducer(); - - void setDefaultMqProducer(DefaultMQProducerImpl* mDefaultMqProducer); - - SendResult* getSendResult(); - - void setSendResult(const SendResult& mSendResult); - - TraceContext* getTraceContext(); - - void setTraceContext(TraceContext* mTraceContext); - - std::string getNameSpace(); - - void setNameSpace(const std::string& mNameSpace); - - private: - std::string m_producerGroup; - MQMessage m_message; - TraceMessageType m_msgType; - MQMessageQueue m_messageQueue; - std::string m_brokerAddr; - std::string m_bornHost; - CommunicationMode m_communicationMode; - DefaultMQProducerImpl* m_defaultMQProducer; - SendResult m_sendResult; - TraceContext* m_traceContext; - std::string m_nameSpace; -}; - -} // namespace rocketmq -#endif \ No newline at end of file diff --git a/src/trace/SendMessageHook.h b/src/trace/SendMessageHook.h deleted file mode 100644 index 70c39277a..000000000 --- a/src/trace/SendMessageHook.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __ROCKETMQ_SEND_MESSAGE_RPC_HOOK_H__ -#define __ROCKETMQ_SEND_MESSAGE_RPC_HOOK_H__ - -#include -#include "SendMessageContext.h" -namespace rocketmq { -class SendMessageHook { - public: - virtual ~SendMessageHook() {} - virtual std::string getHookName() = 0; - virtual void executeHookBefore(SendMessageContext* context) = 0; - virtual void executeHookAfter(SendMessageContext* context) = 0; -}; -} // namespace rocketmq -#endif \ No newline at end of file diff --git a/src/trace/TraceBean.cpp b/src/trace/TraceBean.cpp deleted file mode 100644 index cf7275b86..000000000 --- a/src/trace/TraceBean.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "TraceBean.h" -#include -#include - -namespace rocketmq { -TraceBean::TraceBean() - : m_topic("null"), - m_msgId("null"), - m_offsetMsgId("null"), - m_tags("null"), - m_keys("null"), - m_storeHost("null"), - m_clientHost("null") {} - -TraceBean::~TraceBean() {} - -const std::string& TraceBean::getTopic() const { - return m_topic; -} - -void TraceBean::setTopic(const std::string& topic) { - m_topic = topic; -} - -const std::string& TraceBean::getMsgId() const { - return m_msgId; -} - -void TraceBean::setMsgId(const std::string& msgId) { - m_msgId = msgId; -} - -const std::string& TraceBean::getOffsetMsgId() const { - return m_offsetMsgId; -} - -void TraceBean::setOffsetMsgId(const std::string& offsetMsgId) { - m_offsetMsgId = offsetMsgId; -} - -const std::string& TraceBean::getTags() const { - return m_tags; -} - -void TraceBean::setTags(const std::string& tags) { - m_tags = tags; -} - -const std::string& TraceBean::getKeys() const { - return m_keys; -} - -void TraceBean::setKeys(const std::string& keys) { - m_keys = keys; -} - -const std::string& TraceBean::getStoreHost() const { - return m_storeHost; -} - -void TraceBean::setStoreHost(const std::string& storeHost) { - m_storeHost = storeHost; -} - -const std::string& TraceBean::getClientHost() const { - return m_clientHost; -} - -void TraceBean::setClientHost(const std::string& clientHost) { - m_clientHost = clientHost; -} - -TraceMessageType TraceBean::getMsgType() const { - return m_msgType; -} - -void TraceBean::setMsgType(TraceMessageType msgType) { - m_msgType = msgType; -} - -long long int TraceBean::getStoreTime() const { - return m_storeTime; -} - -void TraceBean::setStoreTime(long long int storeTime) { - m_storeTime = storeTime; -} - -int TraceBean::getRetryTimes() const { - return m_retryTimes; -} - -void TraceBean::setRetryTimes(int retryTimes) { - m_retryTimes = retryTimes; -} - -int TraceBean::getBodyLength() const { - return m_bodyLength; -} - -void TraceBean::setBodyLength(int bodyLength) { - m_bodyLength = bodyLength; -} -} // namespace rocketmq \ No newline at end of file diff --git a/src/trace/TraceBean.h b/src/trace/TraceBean.h deleted file mode 100644 index a5fedc9f1..000000000 --- a/src/trace/TraceBean.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __ROCKETMQ_TRACE_BEAN_H__ -#define __ROCKETMQ_TRACE_BEAN_H__ - -#include -#include -#include "TraceConstant.h" - -namespace rocketmq { -class TraceBean { - public: - TraceBean(); - virtual ~TraceBean(); - - const std::string& getTopic() const; - - void setTopic(const std::string& topic); - - const std::string& getMsgId() const; - - void setMsgId(const std::string& msgId); - - const std::string& getOffsetMsgId() const; - - void setOffsetMsgId(const std::string& offsetMsgId); - - const std::string& getTags() const; - - void setTags(const std::string& tags); - - const std::string& getKeys() const; - - void setKeys(const std::string& keys); - - const std::string& getStoreHost() const; - - void setStoreHost(const std::string& storeHost); - - const std::string& getClientHost() const; - - void setClientHost(const std::string& clientHost); - - TraceMessageType getMsgType() const; - - void setMsgType(TraceMessageType msgType); - - long long int getStoreTime() const; - - void setStoreTime(long long int storeTime); - - int getRetryTimes() const; - - void setRetryTimes(int retryTimes); - - int getBodyLength() const; - - void setBodyLength(int bodyLength); - - private: - std::string m_topic; - std::string m_msgId; - std::string m_offsetMsgId; - std::string m_tags; - std::string m_keys; - std::string m_storeHost; - std::string m_clientHost; - TraceMessageType m_msgType; - long long m_storeTime; - int m_retryTimes; - int m_bodyLength; -}; -} // namespace rocketmq -#endif \ No newline at end of file diff --git a/src/trace/TraceConstant.cpp b/src/trace/TraceConstant.cpp deleted file mode 100644 index 5e2c5ec75..000000000 --- a/src/trace/TraceConstant.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "TraceConstant.h" -#include - -namespace rocketmq { -std::string TraceConstant::GROUP_NAME = "_INNER_TRACE_PRODUCER"; -std::string TraceConstant::TRACE_TOPIC = "rmq_sys_TRACE_DATA_"; -std::string TraceConstant::DEFAULT_REDION = "DEFAULT_REGION"; -char TraceConstant::CONTENT_SPLITOR = 1; -char TraceConstant::FIELD_SPLITOR = 2; -std::string TraceConstant::TRACE_TYPE_PUB = "Pub"; -std::string TraceConstant::TRACE_TYPE_BEFORE = "SubBefore"; -std::string TraceConstant::TRACE_TYPE_AFTER = "SubAfter"; -} // namespace rocketmq diff --git a/src/trace/TraceConstant.h b/src/trace/TraceConstant.h deleted file mode 100644 index bf41e69ff..000000000 --- a/src/trace/TraceConstant.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __ROCKETMQ_TRACE_CONTANT_H_ -#define __ROCKETMQ_TRACE_CONTANT_H_ - -#include - -namespace rocketmq { -class TraceConstant { - public: - static std::string GROUP_NAME; - static std::string TRACE_TOPIC; - static std::string DEFAULT_REDION; - static char CONTENT_SPLITOR; - static char FIELD_SPLITOR; - static std::string TRACE_TYPE_PUB; - static std::string TRACE_TYPE_BEFORE; - static std::string TRACE_TYPE_AFTER; -}; -enum TraceMessageType { - TRACE_NORMAL_MSG = 0, - TRACE_TRANS_HALF_MSG, - TRACE_TRANS_COMMIT_MSG, - TRACE_DELAY_MSG, -}; -enum TraceType { - Pub, // for send message - SubBefore, // for consume message before - SubAfter, // for consum message after -}; -} // namespace rocketmq -#endif // diff --git a/src/trace/TraceContext.cpp b/src/trace/TraceContext.cpp deleted file mode 100644 index 6696f069b..000000000 --- a/src/trace/TraceContext.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "TraceContext.h" -#include -#include - -#include "StringIdMaker.h" -#include "UtilAll.h" - -namespace rocketmq { -TraceContext::TraceContext() : m_timeStamp(UtilAll::currentTimeMillis()) { - m_requestId = StringIdMaker::getInstance().createUniqID(); -} - -TraceContext::TraceContext(const std::string& mGroupName) : m_groupName(mGroupName) {} - -TraceContext::~TraceContext() {} - -TraceMessageType TraceContext::getMsgType() const { - return m_msgType; -} - -void TraceContext::setMsgType(TraceMessageType msgType) { - m_msgType = msgType; -} - -TraceType TraceContext::getTraceType() const { - return m_traceType; -} - -void TraceContext::setTraceType(TraceType traceType) { - m_traceType = traceType; -} - -long long int TraceContext::getTimeStamp() const { - return m_timeStamp; -} - -void TraceContext::setTimeStamp(long long int timeStamp) { - m_timeStamp = timeStamp; -} - -const string& TraceContext::getRegionId() const { - return m_regionId; -} - -void TraceContext::setRegionId(const string& regionId) { - m_regionId = regionId; -} - -const string& TraceContext::getGroupName() const { - return m_groupName; -} - -void TraceContext::setGroupName(const string& groupName) { - m_groupName = groupName; -} - -int TraceContext::getCostTime() const { - return m_costTime; -} - -void TraceContext::setCostTime(int costTime) { - m_costTime = costTime; -} - -bool TraceContext::getStatus() const { - return m_status; -} - -void TraceContext::setStatus(bool isSuccess) { - m_status = isSuccess; -} - -const string& TraceContext::getRequestId() const { - return m_requestId; -} - -void TraceContext::setRequestId(const string& requestId) { - m_requestId = requestId; -} - -int TraceContext::getTraceBeanIndex() const { - return m_traceBeanIndex; -} - -void TraceContext::setTraceBeanIndex(int traceBeanIndex) { - m_traceBeanIndex = traceBeanIndex; -} - -const vector& TraceContext::getTraceBeans() const { - return m_traceBeans; -} - -void TraceContext::setTraceBean(const TraceBean& traceBean) { - m_traceBeans.push_back(traceBean); -} -} // namespace rocketmq \ No newline at end of file diff --git a/src/trace/TraceContext.h b/src/trace/TraceContext.h deleted file mode 100644 index 93237d406..000000000 --- a/src/trace/TraceContext.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __ROCKETMQ_TRACE_CONTEXT_H__ -#define __ROCKETMQ_TRACE_CONTEXT_H__ - -#include -#include -#include "TraceBean.h" -#include "TraceConstant.h" - -namespace rocketmq { -class TraceContext { - public: - TraceContext(); - - TraceContext(const std::string& mGroupName); - - virtual ~TraceContext(); - - TraceMessageType getMsgType() const; - - void setMsgType(TraceMessageType msgType); - - TraceType getTraceType() const; - - void setTraceType(TraceType traceType); - - long long int getTimeStamp() const; - - void setTimeStamp(long long int timeStamp); - - const std::string& getRegionId() const; - - void setRegionId(const std::string& regionId); - - const std::string& getGroupName() const; - - void setGroupName(const std::string& groupName); - - int getCostTime() const; - - void setCostTime(int costTime); - - bool getStatus() const; - - void setStatus(bool isSuccess); - - const std::string& getRequestId() const; - - void setRequestId(const std::string& requestId); - - int getTraceBeanIndex() const; - - void setTraceBeanIndex(int traceBeanIndex); - - const std::vector& getTraceBeans() const; - - void setTraceBean(const TraceBean& traceBean); - - private: - TraceMessageType m_msgType; - TraceType m_traceType; - long long m_timeStamp; - std::string m_regionId; - std::string m_groupName; - int m_costTime; - bool m_status; - std::string m_requestId; - int m_traceBeanIndex; - std::vector m_traceBeans; -}; -} // namespace rocketmq -#endif \ No newline at end of file diff --git a/src/trace/TraceUtil.cpp b/src/trace/TraceUtil.cpp deleted file mode 100644 index 980b8c3ab..000000000 --- a/src/trace/TraceUtil.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "TraceUtil.h" -#include -#include -#include "TraceConstant.h" - -namespace rocketmq { -std::string TraceUtil::CovertTraceTypeToString(TraceType type) { - switch (type) { - case Pub: - return TraceConstant::TRACE_TYPE_PUB; - case SubBefore: - return TraceConstant::TRACE_TYPE_BEFORE; - case SubAfter: - return TraceConstant::TRACE_TYPE_AFTER; - default: - return TraceConstant::TRACE_TYPE_PUB; - } -} - -TraceTransferBean TraceUtil::CovertTraceContextToTransferBean(TraceContext* ctx) { - std::ostringstream ss; - std::vector beans = ctx->getTraceBeans(); - switch (ctx->getTraceType()) { - case Pub: { - std::vector::iterator it = beans.begin(); - ss << TraceUtil::CovertTraceTypeToString(ctx->getTraceType()) << TraceConstant::CONTENT_SPLITOR; - ss << ctx->getTimeStamp() << TraceConstant::CONTENT_SPLITOR; - ss << ctx->getRegionId() << TraceConstant::CONTENT_SPLITOR; - ss << ctx->getGroupName() << TraceConstant::CONTENT_SPLITOR; - ss << it->getTopic() << TraceConstant::CONTENT_SPLITOR; - ss << it->getMsgId() << TraceConstant::CONTENT_SPLITOR; - ss << it->getTags() << TraceConstant::CONTENT_SPLITOR; - ss << it->getKeys() << TraceConstant::CONTENT_SPLITOR; - ss << it->getStoreHost() << TraceConstant::CONTENT_SPLITOR; - ss << it->getBodyLength() << TraceConstant::CONTENT_SPLITOR; - ss << ctx->getCostTime() << TraceConstant::CONTENT_SPLITOR; - ss << it->getMsgType() << TraceConstant::CONTENT_SPLITOR; - ss << it->getOffsetMsgId() << TraceConstant::CONTENT_SPLITOR; - ss << (ctx->getStatus() ? "true" : "false") << TraceConstant::FIELD_SPLITOR; - } break; - - case SubBefore: { - std::vector::iterator it = beans.begin(); - for (; it != beans.end(); ++it) { - ss << TraceUtil::CovertTraceTypeToString(ctx->getTraceType()) << TraceConstant::CONTENT_SPLITOR; - ss << ctx->getTimeStamp() << TraceConstant::CONTENT_SPLITOR; - ss << ctx->getRegionId() << TraceConstant::CONTENT_SPLITOR; - ss << ctx->getGroupName() << TraceConstant::CONTENT_SPLITOR; - ss << ctx->getRequestId() << TraceConstant::CONTENT_SPLITOR; - ss << it->getMsgId() << TraceConstant::CONTENT_SPLITOR; - ss << it->getRetryTimes() << TraceConstant::CONTENT_SPLITOR; - // this is a bug caused by broker. - std::string defaultKey = "dKey"; - if (!it->getKeys().empty()) { - defaultKey = it->getKeys(); - } - ss << defaultKey << TraceConstant::FIELD_SPLITOR; - } - } break; - - case SubAfter: { - std::vector::iterator it = beans.begin(); - ss << TraceUtil::CovertTraceTypeToString(ctx->getTraceType()) << TraceConstant::CONTENT_SPLITOR; - ss << ctx->getRequestId() << TraceConstant::CONTENT_SPLITOR; - ss << it->getMsgId() << TraceConstant::CONTENT_SPLITOR; - ss << ctx->getCostTime() << TraceConstant::CONTENT_SPLITOR; - ss << (ctx->getStatus() ? "true" : "false") << TraceConstant::CONTENT_SPLITOR; - // this is a bug caused by broker. - std::string defaultKey = "dKey"; - if (!it->getKeys().empty()) { - defaultKey = it->getKeys(); - } - ss << defaultKey << TraceConstant::FIELD_SPLITOR; - } break; - - default: - break; - } - - TraceTransferBean transferBean; - transferBean.setTransData(ss.str()); - - switch (ctx->getTraceType()) { - case Pub: - case SubAfter: { - std::vector::iterator it = beans.begin(); - transferBean.setTransKey(it->getMsgId()); - if (it->getKeys() != "") { - transferBean.setTransKey(it->getKeys()); - } - } break; - case SubBefore: { - std::vector::iterator it = beans.begin(); - for (; it != beans.end(); ++it) { - transferBean.setTransKey((*it).getMsgId()); - if ((*it).getKeys() != "") { - transferBean.setTransKey((*it).getKeys()); - } - } - } break; - default: - break; - } - - return transferBean; -} -} // namespace rocketmq diff --git a/src/trace/TraceUtil.h b/src/trace/TraceUtil.h deleted file mode 100644 index 5a7c502e2..000000000 --- a/src/trace/TraceUtil.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __ROCKETMQ_TRACE_UTIL_H_ -#define __ROCKETMQ_TRACE_UTIL_H_ - -#include -#include "TraceConstant.h" -#include "TraceContext.h" -#include "TraceTransferBean.h" - -namespace rocketmq { -class TraceUtil { - public: - static std::string CovertTraceTypeToString(TraceType type); - static TraceTransferBean CovertTraceContextToTransferBean(TraceContext* ctx); -}; -} // namespace rocketmq -#endif // diff --git a/src/transport/ClientRemotingProcessor.cpp b/src/transport/ClientRemotingProcessor.cpp deleted file mode 100644 index a98d9abd0..000000000 --- a/src/transport/ClientRemotingProcessor.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "ClientRemotingProcessor.h" -#include "ClientRPCHook.h" -#include "ConsumerRunningInfo.h" -#include "MQClientFactory.h" -#include "UtilAll.h" - -namespace rocketmq { - -ClientRemotingProcessor::ClientRemotingProcessor(MQClientFactory* mqClientFactory) - : m_mqClientFactory(mqClientFactory) {} - -ClientRemotingProcessor::~ClientRemotingProcessor() {} - -RemotingCommand* ClientRemotingProcessor::processRequest(const string& addr, RemotingCommand* request) { - LOG_INFO("request Command received:processRequest, addr:%s, code:%d", addr.data(), request->getCode()); - switch (request->getCode()) { - case CHECK_TRANSACTION_STATE: - return checkTransactionState(addr, request); - break; - case NOTIFY_CONSUMER_IDS_CHANGED: - return notifyConsumerIdsChanged(request); - break; - case RESET_CONSUMER_CLIENT_OFFSET: // oneWayRPC - return resetOffset(request); - case GET_CONSUMER_STATUS_FROM_CLIENT: - // return getConsumeStatus( request); - break; - case GET_CONSUMER_RUNNING_INFO: - return getConsumerRunningInfo(addr, request); - break; - case CONSUME_MESSAGE_DIRECTLY: - // return consumeMessageDirectly( request); - break; - default: - break; - } - return NULL; -} - -RemotingCommand* ClientRemotingProcessor::resetOffset(RemotingCommand* request) { - request->SetExtHeader(request->getCode()); - const MemoryBlock* pbody = request->GetBody(); - if (pbody->getSize()) { - ResetOffsetBody* offsetBody = ResetOffsetBody::Decode(pbody); - ResetOffsetRequestHeader* offsetHeader = (ResetOffsetRequestHeader*)request->getCommandHeader(); - if (offsetBody) { - m_mqClientFactory->resetOffset(offsetHeader->getGroup(), offsetHeader->getTopic(), offsetBody->getOffsetTable()); - delete offsetBody; - offsetBody = nullptr; - } else { - LOG_ERROR("resetOffset failed as received data could not be unserialized"); - } - } - return NULL; // as resetOffset is oneWayRPC, do not need return any response -} - -std::map ResetOffsetBody::getOffsetTable() { - return m_offsetTable; -} - -void ResetOffsetBody::setOffsetTable(const MQMessageQueue& mq, int64 offset) { - m_offsetTable[mq] = offset; -} - -ResetOffsetBody* ResetOffsetBody::Decode(const MemoryBlock* mem) { - const char* const pData = static_cast(mem->getData()); - Json::Reader reader; - Json::Value root; - const char* begin = pData; - const char* end = pData + mem->getSize(); - - if (!reader.parse(begin, end, root, true)) { - LOG_ERROR("ResetOffsetBody::Decode fail"); - return NULL; - } - - ResetOffsetBody* rfb = new ResetOffsetBody(); - Json::Value qds = root["offsetTable"]; - for (unsigned int i = 0; i < qds.size(); i++) { - MQMessageQueue mq; - Json::Value qd = qds[i]; - mq.setBrokerName(qd["brokerName"].asString()); - mq.setQueueId(qd["queueId"].asInt()); - mq.setTopic(qd["topic"].asString()); - int64 offset = qd["offset"].asInt64(); - LOG_INFO("ResetOffsetBody brokerName:%s, queueID:%d, topic:%s, offset:%lld", mq.getBrokerName().c_str(), - mq.getQueueId(), mq.getTopic().c_str(), offset); - rfb->setOffsetTable(mq, offset); - } - return rfb; -} - -RemotingCommand* ClientRemotingProcessor::getConsumerRunningInfo(const string& addr, RemotingCommand* request) { - request->SetExtHeader(request->getCode()); - GetConsumerRunningInfoRequestHeader* requestHeader = - (GetConsumerRunningInfoRequestHeader*)request->getCommandHeader(); - LOG_INFO("getConsumerRunningInfo:%s", requestHeader->getConsumerGroup().c_str()); - - RemotingCommand* pResponse = - new RemotingCommand(request->getCode(), "CPP", request->getVersion(), request->getOpaque(), request->getFlag(), - request->getRemark(), NULL); - - unique_ptr runningInfo( - m_mqClientFactory->consumerRunningInfo(requestHeader->getConsumerGroup())); - if (runningInfo) { - if (requestHeader->isJstackEnable()) { - /*string jstack = UtilAll::jstack(); - consumerRunningInfo->setJstack(jstack);*/ - } - pResponse->setCode(SUCCESS_VALUE); - string body = runningInfo->encode(); - pResponse->SetBody(body.c_str(), body.length()); - pResponse->setMsgBody(body); - } else { - pResponse->setCode(SYSTEM_ERROR); - pResponse->setRemark("The Consumer Group not exist in this consumer"); - } - - SessionCredentials sessionCredentials; - m_mqClientFactory->getSessionCredentialFromConsumer(requestHeader->getConsumerGroup(), sessionCredentials); - ClientRPCHook rpcHook(sessionCredentials); - rpcHook.doBeforeRequest(addr, *pResponse); - pResponse->Encode(); - return pResponse; -} - -RemotingCommand* ClientRemotingProcessor::notifyConsumerIdsChanged(RemotingCommand* request) { - request->SetExtHeader(request->getCode()); - NotifyConsumerIdsChangedRequestHeader* requestHeader = - (NotifyConsumerIdsChangedRequestHeader*)request->getCommandHeader(); - if (requestHeader == nullptr) { - LOG_ERROR("notifyConsumerIdsChanged requestHeader null"); - return NULL; - } - string group = requestHeader->getGroup(); - LOG_INFO("notifyConsumerIdsChanged:%s", group.c_str()); - m_mqClientFactory->doRebalanceByConsumerGroup(requestHeader->getGroup()); - return NULL; -} - -RemotingCommand* ClientRemotingProcessor::checkTransactionState(const std::string& addr, RemotingCommand* request) { - if (!request) { - LOG_ERROR("checkTransactionState request null"); - return nullptr; - } - - LOG_INFO("checkTransactionState addr:%s, request: %s", addr.data(), request->ToString().data()); - - request->SetExtHeader(request->getCode()); - CheckTransactionStateRequestHeader* requestHeader = (CheckTransactionStateRequestHeader*)request->getCommandHeader(); - if (!requestHeader) { - LOG_ERROR("checkTransactionState CheckTransactionStateRequestHeader requestHeader null"); - return nullptr; - } - LOG_INFO("checkTransactionState request: %s", requestHeader->toString().data()); - - const MemoryBlock* block = request->GetBody(); - if (block && block->getSize() > 0) { - std::vector mqvec; - MQDecoder::decodes(block, mqvec); - if (mqvec.size() == 0) { - LOG_ERROR("checkTransactionState decodes MQMessageExt fail, request:%s", requestHeader->toString().data()); - return nullptr; - } - - MQMessageExt& messageExt = mqvec[0]; - string transactionId = messageExt.getProperty(MQMessage::PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX); - if (transactionId != "") { - messageExt.setTransactionId(transactionId); - } - - m_mqClientFactory->checkTransactionState(addr, messageExt, *requestHeader); - } else { - LOG_ERROR("checkTransactionState getbody null or size 0, request Header:%s", requestHeader->toString().data()); - } - return nullptr; -} - -} // namespace rocketmq diff --git a/src/transport/ClientRemotingProcessor.h b/src/transport/ClientRemotingProcessor.h deleted file mode 100644 index 5d79be428..000000000 --- a/src/transport/ClientRemotingProcessor.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __CLIENTREMOTINGPROCESSOR_H__ -#define __CLIENTREMOTINGPROCESSOR_H__ - -#include "MQMessageQueue.h" -#include "MQProtos.h" -#include "RemotingCommand.h" - -namespace rocketmq { - -class MQClientFactory; -class ClientRemotingProcessor { - public: - ClientRemotingProcessor(MQClientFactory* mqClientFactory); - virtual ~ClientRemotingProcessor(); - - RemotingCommand* processRequest(const string& addr, RemotingCommand* request); - RemotingCommand* resetOffset(RemotingCommand* request); - RemotingCommand* getConsumerRunningInfo(const string& addr, RemotingCommand* request); - RemotingCommand* notifyConsumerIdsChanged(RemotingCommand* request); - RemotingCommand* checkTransactionState(const string& addr, RemotingCommand* request); - - private: - MQClientFactory* m_mqClientFactory; -}; - -class ResetOffsetBody { - public: - ResetOffsetBody() {} - virtual ~ResetOffsetBody() { m_offsetTable.clear(); } - void setOffsetTable(const MQMessageQueue& mq, int64 offset); - std::map getOffsetTable(); - static ResetOffsetBody* Decode(const MemoryBlock* mem); - - private: - std::map m_offsetTable; -}; - -class CheckTransactionStateBody { - public: - CheckTransactionStateBody() {} - virtual ~CheckTransactionStateBody() { m_offsetTable.clear(); } - void setOffsetTable(MQMessageQueue mq, int64 offset); - std::map getOffsetTable(); - static ResetOffsetBody* Decode(const MemoryBlock* mem); - - private: - std::map m_offsetTable; -}; -} // namespace rocketmq - -#endif diff --git a/src/transport/EventLoop.cpp b/src/transport/EventLoop.cpp deleted file mode 100644 index 7c6eee4fe..000000000 --- a/src/transport/EventLoop.cpp +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "EventLoop.h" - -#if !defined(WIN32) && !defined(__APPLE__) -#include -#endif - -#include - -#include - -#include "Logging.h" - -namespace rocketmq { - -EventLoop* EventLoop::GetDefaultEventLoop() { - static EventLoop defaultEventLoop; - return &defaultEventLoop; -} - -EventLoop::EventLoop(const struct event_config* config, bool run_immediately) { -#ifdef WIN32 - evthread_use_windows_threads(); -#else - evthread_use_pthreads(); -#endif - - if (config == nullptr) { - m_eventBase = event_base_new(); - } else { - m_eventBase = event_base_new_with_config(config); - } - - if (m_eventBase == nullptr) { - // failure... - LOG_ERROR("Failed to create event base!"); - return; - } - - evthread_make_base_notifiable(m_eventBase); - - if (run_immediately) { - start(); - } -} - -EventLoop::~EventLoop() { - stop(); - - if (m_eventBase != nullptr) { - event_base_free(m_eventBase); - m_eventBase = nullptr; - } -} - -void EventLoop::start() { - if (m_loopThread == nullptr) { - // start event loop -#if !defined(WIN32) && !defined(__APPLE__) - string taskName = UtilAll::getProcessName(); - prctl(PR_SET_NAME, "EventLoop", 0, 0, 0); -#endif - m_loopThread = new std::thread(&EventLoop::runLoop, this); -#if !defined(WIN32) && !defined(__APPLE__) - prctl(PR_SET_NAME, taskName.c_str(), 0, 0, 0); -#endif - } -} - -void EventLoop::stop() { - if (m_loopThread != nullptr /*&& m_loopThread.joinable()*/) { - m_isRuning = false; - m_loopThread->join(); - - delete m_loopThread; - m_loopThread = nullptr; - } -} - -void EventLoop::runLoop() { - m_isRuning = true; - - while (m_isRuning) { - int ret; - - ret = event_base_dispatch(m_eventBase); - // ret = event_base_loop(m_eventBase, EVLOOP_NONBLOCK); - - if (ret == 1) { - // no event - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - } -} - -bool EventLoop::CreateSslContext(const std::string& ssl_property_file) { - ERR_load_crypto_strings(); - SSL_load_error_strings(); - SSL_library_init(); - OpenSSL_add_all_algorithms(); - - m_sslCtx.reset(SSL_CTX_new(SSLv23_client_method())); - if (!m_sslCtx) { - LOG_ERROR("Failed to create ssl context!"); - return false; - } - - std::string client_key_file = DEFAULT_CLIENT_KEY_FILE; - std::string client_key_passwd = DEFAULT_CLIENT_KEY_PASSWD; - std::string client_cert_file = DEFAULT_CLIENT_CERT_FILE; - std::string ca_cert_file = DEFAULT_CA_CERT_FILE; - std::string verify = "true"; - auto properties = UtilAll::ReadProperties(ssl_property_file); - if (!properties.empty()) { - if (properties.find("tls.client.keyPath") != properties.end()) { - client_key_file = properties["tls.client.keyPath"]; - } - if (properties.find("tls.client.keyPassword") != properties.end()) { - client_key_passwd = properties["tls.client.keyPassword"]; - } - if (properties.find("tls.client.certPath") != properties.end()) { - client_cert_file = properties["tls.client.certPath"]; - } - if (properties.find("tls.client.trustCertPath") != properties.end()) { - ca_cert_file = properties["tls.client.trustCertPath"]; - } - if (properties.find("tls.client.authServer") != properties.end()) { - verify = properties["tls.client.authServer"]; - boost::algorithm::trim(verify); - boost::algorithm::to_lower(verify); - } - } else { - LOG_WARN( - "The tls properties file is not specified or empty. " - "Set it by modifying the api of setTlsPropertyFile and fill the configuration content."); - } - - if (verify == "false") { - SSL_CTX_set_verify(m_sslCtx.get(), SSL_VERIFY_NONE, NULL); - } else { - SSL_CTX_set_verify(m_sslCtx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); - } - SSL_CTX_set_mode(m_sslCtx.get(), SSL_MODE_AUTO_RETRY); - - if (client_key_passwd.empty()) { - LOG_WARN( - "The pass phrase is not specified. " - "Set it by adding the 'tls.client.keyPassword' property in configuration file."); - } else { - SSL_CTX_set_default_passwd_cb_userdata(m_sslCtx.get(), (void*)client_key_passwd.c_str()); - } - - bool check_flag{true}; - if (!boost::filesystem::exists(ca_cert_file.c_str())) { - check_flag = false; - LOG_WARN( - "'%s' does not exist. Please make sure the 'tls.client.trustCertPath' property " - "in the configuration file is configured correctly.", - ca_cert_file.c_str()); - } else if (SSL_CTX_load_verify_locations(m_sslCtx.get(), ca_cert_file.c_str(), NULL) <= 0) { - LOG_ERROR("SSL_CTX_load_verify_locations error!"); - ERR_print_errors_fp(stderr); - return false; - } - - if (!boost::filesystem::exists(client_cert_file.c_str())) { - check_flag = false; - LOG_WARN( - "'%s' does not exist. Please make sure the 'tls.client.certPath' property " - "in the configuration file is configured correctly.", - client_cert_file.c_str()); - } else if (SSL_CTX_use_certificate_file(m_sslCtx.get(), client_cert_file.c_str(), SSL_FILETYPE_PEM) <= 0) { - LOG_ERROR("SSL_CTX_use_certificate_file error!"); - ERR_print_errors_fp(stderr); - return false; - } - - if (!boost::filesystem::exists(client_key_file.c_str())) { - check_flag = false; - LOG_WARN( - "'%s' does not exist. Please make sure the 'tls.client.keyPath' property " - "in the configuration file is configured correctly.", - client_key_file.c_str()); - } else if (SSL_CTX_use_PrivateKey_file(m_sslCtx.get(), client_key_file.c_str(), SSL_FILETYPE_PEM) <= 0) { - LOG_ERROR("SSL_CTX_use_PrivateKey_file error!"); - ERR_print_errors_fp(stderr); - return false; - } - - if (check_flag && SSL_CTX_check_private_key(m_sslCtx.get()) <= 0) { - LOG_ERROR("SSL_CTX_check_private_key error!"); - ERR_print_errors_fp(stderr); - return false; - } - - return true; -} - -#define OPT_UNLOCK_CALLBACKS (BEV_OPT_DEFER_CALLBACKS | BEV_OPT_UNLOCK_CALLBACKS) - -BufferEvent* EventLoop::createBufferEvent(socket_t fd, - int options, - bool enable_ssl, - const std::string& ssl_property_file) { - struct bufferevent* event{nullptr}; - - if (enable_ssl) { - if (!m_sslCtx && !CreateSslContext(ssl_property_file)) { - LOG_ERROR("Failed to create ssl context!"); - return nullptr; - } - - SSL* ssl = SSL_new(m_sslCtx.get()); - if (ssl == nullptr) { - LOG_ERROR("Failed to create ssl handle!"); - return nullptr; - } - - // create ssl bufferevent - event = bufferevent_openssl_socket_new(m_eventBase, fd, ssl, BUFFEREVENT_SSL_CONNECTING, options); - - /* create filter ssl bufferevent - struct bufferevent *bev = bufferevent_socket_new(m_eventBase, fd, options); - event = bufferevent_openssl_filter_new(m_eventBase, bev, ssl, - BUFFEREVENT_SSL_CONNECTING, options); - */ - } else { - event = bufferevent_socket_new(m_eventBase, fd, options); - } - - if (event == nullptr) { - LOG_ERROR("Failed to create bufferevent!"); - return nullptr; - } - - bool unlock = (options & OPT_UNLOCK_CALLBACKS) == OPT_UNLOCK_CALLBACKS; - - return new BufferEvent(event, unlock); -} - -BufferEvent::BufferEvent(struct bufferevent* event, bool unlockCallbacks) - : m_bufferEvent(event), - m_unlockCallbacks(unlockCallbacks), - m_readCallback(nullptr), - m_writeCallback(nullptr), - m_eventCallback(nullptr), - m_callbackTransport() { -#ifdef ROCKETMQ_BUFFEREVENT_PROXY_ALL_CALLBACK - if (m_bufferEvent != nullptr) { - bufferevent_setcb(m_bufferEvent, read_callback, write_callback, event_callback, this); - } -#endif // ROCKETMQ_BUFFEREVENT_PROXY_ALL_CALLBACK -} - -BufferEvent::~BufferEvent() { - if (m_bufferEvent != nullptr) { - // free function will set all callbacks to NULL first. - bufferevent_free(m_bufferEvent); - m_bufferEvent = nullptr; - } -} - -void BufferEvent::setCallback(BufferEventDataCallback readCallback, - BufferEventDataCallback writeCallback, - BufferEventEventCallback eventCallback, - std::shared_ptr transport) { - // use lock in bufferevent - bufferevent_lock(m_bufferEvent); - - // wrap callback - m_readCallback = readCallback; - m_writeCallback = writeCallback; - m_eventCallback = eventCallback; - m_callbackTransport = transport; - -#ifndef ROCKETMQ_BUFFEREVENT_PROXY_ALL_CALLBACK - bufferevent_data_cb readcb = readCallback != nullptr ? read_callback : nullptr; - bufferevent_data_cb writecb = writeCallback != nullptr ? write_callback : nullptr; - bufferevent_event_cb eventcb = eventCallback != nullptr ? event_callback : nullptr; - - bufferevent_setcb(m_bufferEvent, readcb, writecb, eventcb, this); -#endif // ROCKETMQ_BUFFEREVENT_PROXY_ALL_CALLBACK - - bufferevent_unlock(m_bufferEvent); -} - -void BufferEvent::read_callback(struct bufferevent* bev, void* ctx) { - auto event = static_cast(ctx); - - if (event->m_unlockCallbacks) - bufferevent_lock(event->m_bufferEvent); - - BufferEventDataCallback callback = event->m_readCallback; - std::shared_ptr transport = event->m_callbackTransport.lock(); - - if (event->m_unlockCallbacks) - bufferevent_unlock(event->m_bufferEvent); - - if (callback) { - callback(event, transport.get()); - } -} - -void BufferEvent::write_callback(struct bufferevent* bev, void* ctx) { - auto event = static_cast(ctx); - - if (event->m_unlockCallbacks) - bufferevent_lock(event->m_bufferEvent); - - BufferEventDataCallback callback = event->m_writeCallback; - std::shared_ptr transport = event->m_callbackTransport.lock(); - - if (event->m_unlockCallbacks) - bufferevent_unlock(event->m_bufferEvent); - - if (callback) { - callback(event, transport.get()); - } -} - -static std::string buildPeerAddrPort(socket_t fd) { - sockaddr_in addr; - socklen_t len = sizeof(addr); - - getpeername(fd, (struct sockaddr*)&addr, &len); - - LOG_DEBUG("socket: %d, addr: %s, port: %d", fd, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); - std::string addrPort(inet_ntoa(addr.sin_addr)); - addrPort.append(":"); - addrPort.append(UtilAll::to_string(ntohs(addr.sin_port))); - - return addrPort; -} - -void BufferEvent::event_callback(struct bufferevent* bev, short what, void* ctx) { - auto event = static_cast(ctx); - - if (what & BEV_EVENT_CONNECTED) { - socket_t fd = event->getfd(); - event->m_peerAddrPort = buildPeerAddrPort(fd); - } - - if (event->m_unlockCallbacks) - bufferevent_lock(event->m_bufferEvent); - - BufferEventEventCallback callback = event->m_eventCallback; - std::shared_ptr transport = event->m_callbackTransport.lock(); - - if (event->m_unlockCallbacks) - bufferevent_unlock(event->m_bufferEvent); - - if (callback) { - callback(event, what, transport.get()); - } -} - -} // namespace rocketmq diff --git a/src/transport/EventLoop.h b/src/transport/EventLoop.h deleted file mode 100644 index 24eb9bafb..000000000 --- a/src/transport/EventLoop.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __EVENTLOOP_H__ -#define __EVENTLOOP_H__ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "UtilAll.h" -#include "noncopyable.h" - -using socket_t = evutil_socket_t; - -namespace rocketmq { - -class BufferEvent; - -class EventLoop : public noncopyable { - public: - static EventLoop* GetDefaultEventLoop(); - - public: - explicit EventLoop(const struct event_config* config = nullptr, bool run_immediately = true); - virtual ~EventLoop(); - - void start(); - void stop(); - - BufferEvent* createBufferEvent(socket_t fd, int options, bool enable_ssl, const std::string& ssl_property_file); - - private: - void runLoop(); - bool CreateSslContext(const std::string& ssl_property_file); - - private: - struct event_base* m_eventBase{nullptr}; - std::thread* m_loopThread{nullptr}; - using SSL_CTX_ptr = std::unique_ptr; - SSL_CTX_ptr m_sslCtx{nullptr, ::SSL_CTX_free}; - bool m_isRuning{false}; // aotmic is unnecessary -}; - -class TcpTransport; - -using BufferEventDataCallback = void (*)(BufferEvent* event, TcpTransport* transport); -using BufferEventEventCallback = void (*)(BufferEvent* event, short what, TcpTransport* transport); - -class BufferEvent : public noncopyable { - public: - virtual ~BufferEvent(); - - void setCallback(BufferEventDataCallback readCallback, - BufferEventDataCallback writeCallback, - BufferEventEventCallback eventCallback, - std::shared_ptr transport); - - void setWatermark(short events, size_t lowmark, size_t highmark) { - bufferevent_setwatermark(m_bufferEvent, events, lowmark, highmark); - } - - int enable(short event) { return bufferevent_enable(m_bufferEvent, event); } - - int connect(const struct sockaddr* addr, int socklen) { - return bufferevent_socket_connect(m_bufferEvent, (struct sockaddr*)addr, socklen); - } - - int write(const void* data, size_t size) { return bufferevent_write(m_bufferEvent, data, size); } - - size_t read(void* data, size_t size) { return bufferevent_read(m_bufferEvent, data, size); } - - struct evbuffer* getInput() { - return bufferevent_get_input(m_bufferEvent); - } - - socket_t getfd() const { return bufferevent_getfd(m_bufferEvent); } - - std::string getPeerAddrPort() const { return m_peerAddrPort; } - - private: - BufferEvent(struct bufferevent* event, bool unlockCallbacks); - friend EventLoop; - - static void read_callback(struct bufferevent* bev, void* ctx); - static void write_callback(struct bufferevent* bev, void* ctx); - static void event_callback(struct bufferevent* bev, short what, void* ctx); - - private: - struct bufferevent* m_bufferEvent; - const bool m_unlockCallbacks; - - BufferEventDataCallback m_readCallback; - BufferEventDataCallback m_writeCallback; - BufferEventEventCallback m_eventCallback; - std::weak_ptr m_callbackTransport; // avoid reference cycle - - // cache properties - std::string m_peerAddrPort; -}; - -} // namespace rocketmq - -#endif //__EVENTLOOP_H__ diff --git a/src/transport/ResponseFuture.cpp b/src/transport/ResponseFuture.cpp deleted file mode 100644 index 8ac926bb2..000000000 --- a/src/transport/ResponseFuture.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "ResponseFuture.h" - -#include - -#include "Logging.h" -#include "TcpRemotingClient.h" - -namespace rocketmq { - -// pCallback) - : m_requestCode(requestCode), - m_opaque(opaque), - m_timeout(timeout), - m_bAsync(bAsync), - m_pCallbackWrap(pCallback), - m_asyncCallbackStatus(ASYNC_CALLBACK_STATUS_INIT), - m_haveResponse(false), - m_sendRequestOK(false), - m_pResponseCommand(nullptr), - m_maxRetrySendTimes(1), - m_retrySendTimes(1) { - m_brokerAddr = ""; - m_beginTimestamp = UtilAll::currentTimeMillis(); -} - -ResponseFuture::~ResponseFuture() {} - -void ResponseFuture::releaseThreadCondition() { - m_defaultEvent.notify_all(); -} - -RemotingCommand* ResponseFuture::waitResponse(int timeoutMillis) { - std::unique_lock eventLock(m_defaultEventLock); - if (!m_haveResponse) { - if (timeoutMillis <= 0) { - timeoutMillis = m_timeout; - } - if (m_defaultEvent.wait_for(eventLock, std::chrono::milliseconds(timeoutMillis)) == std::cv_status::timeout) { - LOG_WARN("waitResponse of code:%d with opaque:%d timeout", m_requestCode, m_opaque); - m_haveResponse = true; - } - } - return m_pResponseCommand; -} - -bool ResponseFuture::setResponse(RemotingCommand* pResponseCommand) { - std::unique_lock eventLock(m_defaultEventLock); - - if (m_haveResponse) { - return false; - } - - m_pResponseCommand = pResponseCommand; - m_haveResponse = true; - - if (!getAsyncFlag()) { - m_defaultEvent.notify_all(); - } - - return true; -} - -const bool ResponseFuture::getAsyncFlag() { - return m_bAsync; -} - -bool ResponseFuture::isSendRequestOK() const { - return m_sendRequestOK; -} - -void ResponseFuture::setSendRequestOK(bool sendRequestOK) { - m_sendRequestOK = sendRequestOK; -} - -int ResponseFuture::getOpaque() const { - return m_opaque; -} - -int ResponseFuture::getRequestCode() const { - return m_requestCode; -} - -void ResponseFuture::invokeCompleteCallback() { - if (m_pCallbackWrap == nullptr) { - deleteAndZero(m_pResponseCommand); - return; - } else { - m_pCallbackWrap->operationComplete(this, true); - } -} - -void ResponseFuture::invokeExceptionCallback() { - if (m_pCallbackWrap == nullptr) { - LOG_ERROR("m_pCallbackWrap is NULL, critical error"); - return; - } else { - // here no need retrySendTimes process because of it have timeout - LOG_ERROR("send msg, callback timeout, opaque:%d, sendTimes:%d, maxRetryTimes:%d", getOpaque(), getRetrySendTimes(), - getMaxRetrySendTimes()); - - m_pCallbackWrap->onException(); - } -} - -bool ResponseFuture::isTimeOut() const { - int64 diff = UtilAll::currentTimeMillis() - m_beginTimestamp; - // m_timeout; -} - -int ResponseFuture::getMaxRetrySendTimes() const { - return m_maxRetrySendTimes; -} -int ResponseFuture::getRetrySendTimes() const { - return m_retrySendTimes; -} - -void ResponseFuture::setMaxRetrySendTimes(int maxRetryTimes) { - m_maxRetrySendTimes = maxRetryTimes; -} -void ResponseFuture::setRetrySendTimes(int retryTimes) { - m_retrySendTimes = retryTimes; -} - -void ResponseFuture::setBrokerAddr(const std::string& brokerAddr) { - m_brokerAddr = brokerAddr; -} - -std::string ResponseFuture::getBrokerAddr() const { - return m_brokerAddr; -} - -void ResponseFuture::setRequestCommand(const RemotingCommand& requestCommand) { - m_requestCommand = requestCommand; -} -const RemotingCommand& ResponseFuture::getRequestCommand() { - return m_requestCommand; -} - -int64 ResponseFuture::leftTime() const { - int64 diff = UtilAll::currentTimeMillis() - m_beginTimestamp; - return m_timeout - diff; -} - -RemotingCommand* ResponseFuture::getCommand() const { - return m_pResponseCommand; -} - -std::shared_ptr ResponseFuture::getAsyncCallbackWrap() { - return m_pCallbackWrap; -} - -// -#include - -#include "AsyncCallbackWrap.h" -#include "RemotingCommand.h" -#include "UtilAll.h" - -namespace rocketmq { - -typedef enum AsyncCallbackStatus { - ASYNC_CALLBACK_STATUS_INIT = 0, - ASYNC_CALLBACK_STATUS_RESPONSE = 1, - ASYNC_CALLBACK_STATUS_TIMEOUT = 2 -} AsyncCallbAackStatus; - -class TcpRemotingClient; -// pCallback = std::shared_ptr()); - virtual ~ResponseFuture(); - - void releaseThreadCondition(); - RemotingCommand* waitResponse(int timeoutMillis = 0); - RemotingCommand* getCommand() const; - - bool setResponse(RemotingCommand* pResponseCommand); - - bool isSendRequestOK() const; - void setSendRequestOK(bool sendRequestOK); - int getRequestCode() const; - int getOpaque() const; - - // getAsyncCallbackWrap(); - - void setMaxRetrySendTimes(int maxRetryTimes); - void setRetrySendTimes(int retryTimes); - void setBrokerAddr(const std::string& brokerAddr); - void setRequestCommand(const RemotingCommand& requestCommand); - const RemotingCommand& getRequestCommand(); - std::string getBrokerAddr() const; - - private: - int m_requestCode; - int m_opaque; - int64 m_timeout; // ms - - const bool m_bAsync; - std::shared_ptr m_pCallbackWrap; - - AsyncCallbackStatus m_asyncCallbackStatus; - std::mutex m_asyncCallbackLock; - - bool m_haveResponse; - std::mutex m_defaultEventLock; - std::condition_variable m_defaultEvent; - - int64 m_beginTimestamp; - bool m_sendRequestOK; - RemotingCommand* m_pResponseCommand; //h_aliases; - if (*alias != 0) { - return *alias; - } else { - return inet_ntoa(in.sin_addr); - } -} - -uint64 swapll(uint64 v) { -#ifdef ENDIANMODE_BIG - return v; -#else - uint64 ret = ((v << 56) | ((v & 0xff00) << 40) | ((v & 0xff0000) << 24) | ((v & 0xff000000) << 8) | - ((v >> 8) & 0xff000000) | ((v >> 24) & 0xff0000) | ((v >> 40) & 0xff00) | (v >> 56)); - - return ret; -#endif -} - -uint64 h2nll(uint64 v) { - return swapll(v); -} - -uint64 n2hll(uint64 v) { - return swapll(v); -} -} // namespace rocketmq diff --git a/src/transport/SocketUtil.h b/src/transport/SocketUtil.h deleted file mode 100644 index 55cb5a2d1..000000000 --- a/src/transport/SocketUtil.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __SOCKETUTIL_H__ -#define __SOCKETUTIL_H__ - -#ifdef WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#include -#include -#pragma comment(lib, "ws2_32.lib") -#else -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#include "UtilAll.h" - -namespace rocketmq { -// -#if !defined(WIN32) && !defined(__APPLE__) -#include -#endif - -#include "Logging.h" -#include "MemoryOutputStream.h" -#include "TopAddressing.h" -#include "UtilAll.h" -#include -#include - -namespace rocketmq { - -//interrupt(); - m_timerServiceThread->join(); - removeAllTimerCallback(); - - { - std::lock_guard lock(m_tcpTableLock); - for (const auto& trans : m_tcpTable) { - trans.second->disconnect(trans.first); - } - m_tcpTable.clear(); - } - - m_handleService.stop(); - m_handleThreadPool.join_all(); - - m_dispatchService.stop(); - m_dispatchThreadPool.join_all(); - - { - std::lock_guard lock(m_futureTableLock); - for (const auto& future : m_futureTable) { - if (future.second) { - if (!future.second->getAsyncFlag()) { - future.second->releaseThreadCondition(); - } - } - } - } - - LOG_ERROR("TcpRemotingClient::stopAllTcpTransportThread End, m_tcpTable:%lu", m_tcpTable.size()); -} - -void TcpRemotingClient::updateNameServerAddressList(const string& addrs) { - LOG_INFO("updateNameServerAddressList: [%s]", addrs.c_str()); - - if (addrs.empty()) { - return; - } - - std::unique_lock lock(m_namesrvLock, std::try_to_lock); - if (!lock.owns_lock()) { - if (!lock.try_lock_for(std::chrono::seconds(10))) { - LOG_ERROR("updateNameServerAddressList get timed_mutex timeout"); - return; - } - } - - // clear first; - m_namesrvAddrList.clear(); - - vector out; - UtilAll::Split(out, addrs, ";"); - - std::random_device rd; - std::mt19937 g(rd()); - std::shuffle(out.begin(), out.end(), g); - - for (auto addr : out) { - UtilAll::Trim(addr); - - string hostName; - short portNumber; - if (UtilAll::SplitURL(addr, hostName, portNumber)) { - LOG_INFO("update Namesrv:%s", addr.c_str()); - m_namesrvAddrList.push_back(addr); - } else { - LOG_INFO("This may be invalid namer server: [%s]", addr.c_str()); - } - } - out.clear(); -} - -bool TcpRemotingClient::invokeHeartBeat(const string& addr, RemotingCommand& request, int timeoutMillis) { - std::shared_ptr pTcp = GetTransport(addr, true); - if (pTcp != nullptr) { - int code = request.getCode(); - int opaque = request.getOpaque(); - std::shared_ptr cbw; - std::shared_ptr responseFuture(new ResponseFuture(code, opaque, this, timeoutMillis, false, cbw)); - addResponseFuture(opaque, responseFuture); - - if (SendCommand(pTcp, request)) { - responseFuture->setSendRequestOK(true); - unique_ptr pRsp(responseFuture->waitResponse()); - if (pRsp == nullptr) { - LOG_ERROR("wait response timeout of heartbeat, so closeTransport of addr:%s", addr.c_str()); - // avoid responseFuture leak; - findAndDeleteResponseFuture(opaque); - CloseTransport(addr, pTcp); - return false; - } else if (pRsp->getCode() == SUCCESS_VALUE) { - return true; - } else { - LOG_WARN("get error response:%d of heartbeat to addr:%s", pRsp->getCode(), addr.c_str()); - return false; - } - } else { - // avoid responseFuture leak; - findAndDeleteResponseFuture(opaque); - CloseTransport(addr, pTcp); - } - } - return false; -} - -RemotingCommand* TcpRemotingClient::invokeSync(const string& addr, RemotingCommand& request, int timeoutMillis) { - LOG_DEBUG("InvokeSync:", addr.c_str()); - std::shared_ptr pTcp = GetTransport(addr, true); - if (pTcp != nullptr) { - int code = request.getCode(); - int opaque = request.getOpaque(); - std::shared_ptr cbw; - std::shared_ptr responseFuture(new ResponseFuture(code, opaque, this, timeoutMillis, false, cbw)); - addResponseFuture(opaque, responseFuture); - - if (SendCommand(pTcp, request)) { - responseFuture->setSendRequestOK(true); - RemotingCommand* pRsp = responseFuture->waitResponse(); - if (pRsp == nullptr) { - if (code != GET_CONSUMER_LIST_BY_GROUP) { - LOG_WARN("wait response timeout or get NULL response of code:%d, so closeTransport of addr:%s", code, - addr.c_str()); - CloseTransport(addr, pTcp); - } - // avoid responseFuture leak; - findAndDeleteResponseFuture(opaque); - return nullptr; - } else { - return pRsp; - } - } else { - // avoid responseFuture leak; - findAndDeleteResponseFuture(opaque); - CloseTransport(addr, pTcp); - } - } - LOG_DEBUG("InvokeSync [%s] Failed: Cannot Get Transport.", addr.c_str()); - return nullptr; -} - -bool TcpRemotingClient::invokeAsync(const string& addr, - RemotingCommand& request, - std::shared_ptr callback, - int64 timeoutMillis, - int maxRetrySendTimes, - int retrySendTimes) { - std::shared_ptr pTcp = GetTransport(addr, true); - if (pTcp != nullptr) { - int code = request.getCode(); - int opaque = request.getOpaque(); - - // delete in callback - std::shared_ptr responseFuture( - new ResponseFuture(code, opaque, this, timeoutMillis, true, callback)); - responseFuture->setMaxRetrySendTimes(maxRetrySendTimes); - responseFuture->setRetrySendTimes(retrySendTimes); - responseFuture->setBrokerAddr(addr); - responseFuture->setRequestCommand(request); - addResponseFuture(opaque, responseFuture); - - // timeout monitor - boost::asio::deadline_timer* t = - new boost::asio::deadline_timer(m_timerService, boost::posix_time::milliseconds(timeoutMillis)); - addTimerCallback(t, opaque); - t->async_wait( - boost::bind(&TcpRemotingClient::handleAsyncRequestTimeout, this, boost::asio::placeholders::error, opaque)); - - // even if send failed, asyncTimerThread will trigger next pull request or report send msg failed - if (SendCommand(pTcp, request)) { - LOG_DEBUG("invokeAsync success, addr:%s, code:%d, opaque:%d", addr.c_str(), code, opaque); - responseFuture->setSendRequestOK(true); - } - return true; - } - - LOG_ERROR("invokeAsync failed of addr:%s", addr.c_str()); - return false; -} - -void TcpRemotingClient::invokeOneway(const string& addr, RemotingCommand& request) { - // pTcp = GetTransport(addr, true); - if (pTcp != nullptr) { - request.markOnewayRPC(); - if (SendCommand(pTcp, request)) { - LOG_DEBUG("invokeOneway success. addr:%s, code:%d", addr.c_str(), request.getCode()); - } else { - LOG_WARN("invokeOneway failed. addr:%s, code:%d", addr.c_str(), request.getCode()); - } - } else { - LOG_WARN("invokeOneway failed: NULL transport. addr:%s, code:%d", addr.c_str(), request.getCode()); - } -} - -std::shared_ptr TcpRemotingClient::GetTransport(const string& addr, bool needResponse) { - if (addr.empty()) { - LOG_DEBUG("GetTransport of NameServer"); - return CreateNameServerTransport(needResponse); - } - return CreateTransport(addr, needResponse); -} - -std::shared_ptr TcpRemotingClient::CreateTransport(const string& addr, bool needResponse) { - std::shared_ptr tts; - - { - // try get m_tcpLock util m_tcpTransportTryLockTimeout to avoid blocking - // long time, if could not get m_tcpLock, return NULL - std::unique_lock lock(m_tcpTableLock, std::try_to_lock); - if (!lock.owns_lock()) { - if (!lock.try_lock_for(std::chrono::seconds(m_tcpTransportTryLockTimeout))) { - LOG_ERROR("GetTransport of:%s get timed_mutex timeout", addr.c_str()); - std::shared_ptr pTcp; - return pTcp; - } - } - - // check for reuse - if (m_tcpTable.find(addr) != m_tcpTable.end()) { - std::shared_ptr tcp = m_tcpTable[addr]; - - if (tcp) { - TcpConnectStatus connectStatus = tcp->getTcpConnectStatus(); - if (connectStatus == TCP_CONNECT_STATUS_SUCCESS) { - return tcp; - } else if (connectStatus == TCP_CONNECT_STATUS_WAIT) { - tts = tcp; - } else if (connectStatus == TCP_CONNECT_STATUS_FAILED) { - LOG_ERROR("tcpTransport with server disconnected, erase server:%s", addr.c_str()); - tcp->disconnect(addr); // avoid coredump when connection with broker was broken - m_tcpTable.erase(addr); - } else { - LOG_ERROR("go to fault state, erase:%s from tcpMap, and reconnect it", addr.c_str()); - m_tcpTable.erase(addr); - } - } - } - - //connect(addr, 0); // use non-block - if (connectStatus != TCP_CONNECT_STATUS_WAIT) { - LOG_WARN("can not connect to:%s", addr.c_str()); - tts->disconnect(addr); - std::shared_ptr pTcp; - return pTcp; - } else { - // even if connecting failed finally, this server transport will be erased by next CreateTransport - m_tcpTable[addr] = tts; - } - } - } - - TcpConnectStatus connectStatus = tts->waitTcpConnectEvent(static_cast(m_tcpConnectTimeout)); - if (connectStatus != TCP_CONNECT_STATUS_SUCCESS) { - LOG_WARN("can not connect to server:%s", addr.c_str()); - tts->disconnect(addr); - std::shared_ptr pTcp; - return pTcp; - } else { - LOG_INFO("connect server with addr:%s success", addr.c_str()); - return tts; - } -} - -std::shared_ptr TcpRemotingClient::CreateNameServerTransport(bool needResponse) { - // m_namesrvLock was added to avoid operation of nameServer was blocked by - // m_tcpLock, it was used by single Thread mostly, so no performance impact - // try get m_tcpLock until m_tcpTransportTryLockTimeout to avoid blocking long - // time, if could not get m_namesrvlock, return NULL - LOG_DEBUG("--CreateNameserverTransport--"); - std::unique_lock lock(m_namesrvLock, std::try_to_lock); - if (!lock.owns_lock()) { - if (!lock.try_lock_for(std::chrono::seconds(m_tcpTransportTryLockTimeout))) { - LOG_ERROR("CreateNameserverTransport get timed_mutex timeout"); - std::shared_ptr pTcp; - return pTcp; - } - } - - if (!m_namesrvAddrChoosed.empty()) { - std::shared_ptr pTcp = CreateTransport(m_namesrvAddrChoosed, true); - if (pTcp) - return pTcp; - else - m_namesrvAddrChoosed.clear(); - } - - for (unsigned i = 0; i < m_namesrvAddrList.size(); i++) { - unsigned int index = m_namesrvIndex++ % m_namesrvAddrList.size(); - LOG_INFO("namesrvIndex is:%d, index:%d, namesrvaddrlist size:" SIZET_FMT "", m_namesrvIndex, index, - m_namesrvAddrList.size()); - std::shared_ptr pTcp = CreateTransport(m_namesrvAddrList[index], true); - if (pTcp) { - m_namesrvAddrChoosed = m_namesrvAddrList[index]; - return pTcp; - } - } - - std::shared_ptr pTcp; - return pTcp; -} - -bool TcpRemotingClient::CloseTransport(const string& addr, std::shared_ptr pTcp) { - if (addr.empty()) { - return CloseNameServerTransport(pTcp); - } - - std::unique_lock lock(m_tcpTableLock, std::try_to_lock); - if (!lock.owns_lock()) { - if (!lock.try_lock_for(std::chrono::seconds(m_tcpTransportTryLockTimeout))) { - LOG_ERROR("CloseTransport of:%s get timed_mutex timeout", addr.c_str()); - return false; - } - } - - LOG_ERROR("CloseTransport of:%s", addr.c_str()); - - bool removeItemFromTable = true; - if (m_tcpTable.find(addr) != m_tcpTable.end()) { - if (m_tcpTable[addr]->getStartTime() != pTcp->getStartTime()) { - LOG_INFO("tcpTransport with addr:%s has been closed before, and has been created again, nothing to do", - addr.c_str()); - removeItemFromTable = false; - } - } else { - LOG_INFO("tcpTransport with addr:%s had been removed from tcpTable before", addr.c_str()); - removeItemFromTable = false; - } - - if (removeItemFromTable) { - LOG_WARN("closeTransport: disconnect:%s with state:%d", addr.c_str(), m_tcpTable[addr]->getTcpConnectStatus()); - if (m_tcpTable[addr]->getTcpConnectStatus() == TCP_CONNECT_STATUS_SUCCESS) - m_tcpTable[addr]->disconnect(addr); // avoid coredump when connection with server was broken - LOG_WARN("closeTransport: erase broker: %s", addr.c_str()); - m_tcpTable.erase(addr); - } - - LOG_ERROR("CloseTransport of:%s end", addr.c_str()); - - return removeItemFromTable; -} - -bool TcpRemotingClient::CloseNameServerTransport(std::shared_ptr pTcp) { - std::unique_lock lock(m_namesrvLock, std::try_to_lock); - if (!lock.owns_lock()) { - if (!lock.try_lock_for(std::chrono::seconds(m_tcpTransportTryLockTimeout))) { - LOG_ERROR("CreateNameServerTransport get timed_mutex timeout"); - return false; - } - } - - string addr = m_namesrvAddrChoosed; - - bool removeItemFromTable = CloseTransport(addr, pTcp); - if (removeItemFromTable) { - m_namesrvAddrChoosed.clear(); - } - - return removeItemFromTable; -} - -bool TcpRemotingClient::SendCommand(std::shared_ptr pTts, RemotingCommand& msg) { - const MemoryBlock* pHead = msg.GetHead(); - const MemoryBlock* pBody = msg.GetBody(); - - unique_ptr buffer(new MemoryOutputStream(1024)); - if (pHead->getSize() > 0) { - buffer->write(pHead->getData(), static_cast(pHead->getSize())); - } - if (pBody->getSize() > 0) { - buffer->write(pBody->getData(), static_cast(pBody->getSize())); - } - - const char* pData = static_cast(buffer->getData()); - size_t len = buffer->getDataSize(); - return pTts->sendMessage(pData, len); -} - -void TcpRemotingClient::static_messageReceived(void* context, const MemoryBlock& mem, const string& addr) { - auto* pTcpRemotingClient = reinterpret_cast(context); - if (pTcpRemotingClient) - pTcpRemotingClient->messageReceived(mem, addr); -} - -void TcpRemotingClient::messageReceived(const MemoryBlock& mem, const string& addr) { - m_dispatchService.post(boost::bind(&TcpRemotingClient::ProcessData, this, mem, addr)); -} - -void TcpRemotingClient::ProcessData(const MemoryBlock& mem, const string& addr) { - RemotingCommand* pRespondCmd = nullptr; - try { - pRespondCmd = RemotingCommand::Decode(mem); - } catch (...) { - LOG_ERROR("processData error"); - return; - } - - int opaque = pRespondCmd->getOpaque(); - - //isResponseType()) { - std::shared_ptr pFuture = findAndDeleteResponseFuture(opaque); - if (!pFuture) { - LOG_DEBUG("responseFuture was deleted by timeout of opaque:%d", opaque); - deleteAndZero(pRespondCmd); - return; - } - - LOG_DEBUG("find_response opaque:%d", opaque); - processResponseCommand(pRespondCmd, pFuture); - } else { - m_handleService.post(boost::bind(&TcpRemotingClient::processRequestCommand, this, pRespondCmd, addr)); - } -} - -void TcpRemotingClient::processResponseCommand(RemotingCommand* pCmd, std::shared_ptr pFuture) { - int code = pFuture->getRequestCode(); - pCmd->SetExtHeader(code); // set head, for response use - - int opaque = pCmd->getOpaque(); - LOG_DEBUG("processResponseCommand, code:%d, opaque:%d, maxRetryTimes:%d, retrySendTimes:%d", code, opaque, - pFuture->getMaxRetrySendTimes(), pFuture->getRetrySendTimes()); - - if (!pFuture->setResponse(pCmd)) { - // this branch is unreachable normally. - LOG_WARN("response already timeout of opaque:%d", opaque); - deleteAndZero(pCmd); - return; - } - - if (pFuture->getAsyncFlag()) { - cancelTimerCallback(opaque); - - m_handleService.post(boost::bind(&ResponseFuture::invokeCompleteCallback, pFuture)); - } -} - -void TcpRemotingClient::handleAsyncRequestTimeout(const boost::system::error_code& e, int opaque) { - if (e == boost::asio::error::operation_aborted) { - LOG_DEBUG("handleAsyncRequestTimeout aborted opaque:%d, e_code:%d, msg:%s", opaque, e.value(), e.message().data()); - return; - } - - LOG_DEBUG("handleAsyncRequestTimeout opaque:%d, e_code:%d, msg:%s", opaque, e.value(), e.message().data()); - - std::shared_ptr pFuture(findAndDeleteResponseFuture(opaque)); - if (pFuture) { - LOG_ERROR("no response got for opaque:%d", opaque); - eraseTimerCallback(opaque); - if (pFuture->getAsyncCallbackWrap()) { - m_handleService.post(boost::bind(&ResponseFuture::invokeExceptionCallback, pFuture)); - } - } -} - -void TcpRemotingClient::processRequestCommand(RemotingCommand* pCmd, const string& addr) { - unique_ptr pRequestCommand(pCmd); - int requestCode = pRequestCommand->getCode(); - if (m_requestTable.find(requestCode) == m_requestTable.end()) { - LOG_ERROR("can_not_find request:%d processor", requestCode); - } else { - unique_ptr pResponse(m_requestTable[requestCode]->processRequest(addr, pRequestCommand.get())); - if (!pRequestCommand->isOnewayRPC()) { - if (pResponse) { - pResponse->setOpaque(pRequestCommand->getOpaque()); - pResponse->markResponseType(); - pResponse->Encode(); - - invokeOneway(addr, *pResponse); - } - } - } -} - -void TcpRemotingClient::addResponseFuture(int opaque, std::shared_ptr pFuture) { - std::lock_guard lock(m_futureTableLock); - m_futureTable[opaque] = pFuture; -} - -// Note: after call this function, shared_ptr of m_syncFutureTable[opaque] will -// be erased, so caller must ensure the life cycle of returned shared_ptr; -std::shared_ptr TcpRemotingClient::findAndDeleteResponseFuture(int opaque) { - std::lock_guard lock(m_futureTableLock); - std::shared_ptr pResponseFuture; - if (m_futureTable.find(opaque) != m_futureTable.end()) { - pResponseFuture = m_futureTable[opaque]; - m_futureTable.erase(opaque); - } - return pResponseFuture; -} - -void TcpRemotingClient::registerProcessor(MQRequestCode requestCode, ClientRemotingProcessor* clientRemotingProcessor) { - if (m_requestTable.find(requestCode) != m_requestTable.end()) - m_requestTable.erase(requestCode); - m_requestTable[requestCode] = clientRemotingProcessor; -} - -void TcpRemotingClient::addTimerCallback(boost::asio::deadline_timer* t, int opaque) { - std::lock_guard lock(m_asyncTimerTableLock); - if (m_asyncTimerTable.find(opaque) != m_asyncTimerTable.end()) { - LOG_DEBUG("addTimerCallback:erase timerCallback opaque:%lld", opaque); - boost::asio::deadline_timer* old_t = m_asyncTimerTable[opaque]; - m_asyncTimerTable.erase(opaque); - try { - old_t->cancel(); - } catch (const std::exception& ec) { - LOG_WARN("encounter exception when cancel old timer: %s", ec.what()); - } - delete old_t; - } - m_asyncTimerTable[opaque] = t; -} - -void TcpRemotingClient::eraseTimerCallback(int opaque) { - std::lock_guard lock(m_asyncTimerTableLock); - if (m_asyncTimerTable.find(opaque) != m_asyncTimerTable.end()) { - LOG_DEBUG("eraseTimerCallback: opaque:%lld", opaque); - boost::asio::deadline_timer* t = m_asyncTimerTable[opaque]; - m_asyncTimerTable.erase(opaque); - delete t; - } -} - -void TcpRemotingClient::cancelTimerCallback(int opaque) { - std::lock_guard lock(m_asyncTimerTableLock); - if (m_asyncTimerTable.find(opaque) != m_asyncTimerTable.end()) { - LOG_DEBUG("cancelTimerCallback: opaque:%lld", opaque); - boost::asio::deadline_timer* t = m_asyncTimerTable[opaque]; - m_asyncTimerTable.erase(opaque); - try { - t->cancel(); - } catch (const std::exception& ec) { - LOG_WARN("encounter exception when cancel timer: %s", ec.what()); - } - delete t; - } -} - -void TcpRemotingClient::removeAllTimerCallback() { - std::lock_guard lock(m_asyncTimerTableLock); - for (const auto& timer : m_asyncTimerTable) { - boost::asio::deadline_timer* t = timer.second; - try { - t->cancel(); - } catch (const std::exception& ec) { - LOG_WARN("encounter exception when cancel timer: %s", ec.what()); - } - delete t; - } - m_asyncTimerTable.clear(); -} - -// -#include - -#include -#include -#include -#include - -#include "ClientRemotingProcessor.h" -#include "RemotingCommand.h" -#include "ResponseFuture.h" -#include "SocketUtil.h" -#include "TcpTransport.h" - -namespace rocketmq { -// cbw, - int64 timeoutMilliseconds, - int maxRetrySendTimes = 1, - int retrySendTimes = 1); - - virtual void invokeOneway(const string& addr, RemotingCommand& request); - - virtual void registerProcessor(MQRequestCode requestCode, ClientRemotingProcessor* clientRemotingProcessor); - - private: - static void static_messageReceived(void* context, const MemoryBlock& mem, const string& addr); - - void messageReceived(const MemoryBlock& mem, const string& addr); - void ProcessData(const MemoryBlock& mem, const string& addr); - void processRequestCommand(RemotingCommand* pCmd, const string& addr); - void processResponseCommand(RemotingCommand* pCmd, std::shared_ptr pFuture); - void handleAsyncRequestTimeout(const boost::system::error_code& e, int opaque); - - std::shared_ptr GetTransport(const string& addr, bool needResponse); - std::shared_ptr CreateTransport(const string& addr, bool needResponse); - std::shared_ptr CreateNameServerTransport(bool needResponse); - - bool CloseTransport(const string& addr, std::shared_ptr pTcp); - bool CloseNameServerTransport(std::shared_ptr pTcp); - - bool SendCommand(std::shared_ptr pTts, RemotingCommand& msg); - - void addResponseFuture(int opaque, std::shared_ptr pFuture); - std::shared_ptr findAndDeleteResponseFuture(int opaque); - - void addTimerCallback(boost::asio::deadline_timer* t, int opaque); - void eraseTimerCallback(int opaque); - void cancelTimerCallback(int opaque); - void removeAllTimerCallback(); - - void boost_asio_work(); - - private: - using RequestMap = map; - using TcpMap = map>; - using ResMap = map>; - using AsyncTimerMap = map; - - RequestMap m_requestTable; - - TcpMap m_tcpTable; //tcp; - std::timed_mutex m_tcpTableLock; - - ResMap m_futureTable; //future; - std::mutex m_futureTableLock; - - AsyncTimerMap m_asyncTimerTable; - std::mutex m_asyncTimerTableLock; - - int m_dispatchThreadNum; - int m_pullThreadNum; - uint64_t m_tcpConnectTimeout; // ms - uint64_t m_tcpTransportTryLockTimeout; // s - - bool m_enableSsl; - std::string m_sslPropertyFile; - - // m_namesrvAddrList; - string m_namesrvAddrChoosed; - unsigned int m_namesrvIndex; - - boost::asio::io_service m_dispatchService; - boost::asio::io_service::work m_dispatchServiceWork; - boost::thread_group m_dispatchThreadPool; - - boost::asio::io_service m_handleService; - boost::asio::io_service::work m_handleServiceWork; - boost::thread_group m_handleThreadPool; - - boost::asio::io_service m_timerService; - unique_ptr m_timerServiceThread; -}; - -// - -#ifndef WIN32 -#include // for sockaddr_in and inet_ntoa... -#include -#include // for socket(), bind(), and connect()... -#endif - -#include "Logging.h" -#include "TcpRemotingClient.h" -#include "UtilAll.h" - -namespace rocketmq { - -//setCallback(nullptr, nullptr, nullptr, nullptr); - } - - // then, release BufferEvent - m_event.reset(); -} - -void TcpTransport::setTcpConnectStatus(TcpConnectStatus connectStatus) { - m_tcpConnectStatus = connectStatus; -} - -TcpConnectStatus TcpTransport::getTcpConnectStatus() { - return m_tcpConnectStatus; -} - -TcpConnectStatus TcpTransport::waitTcpConnectEvent(int timeoutMillis) { - if (m_tcpConnectStatus == TCP_CONNECT_STATUS_WAIT) { - std::unique_lock eventLock(m_connectEventLock); - if (!m_connectEvent.wait_for(eventLock, std::chrono::milliseconds(timeoutMillis), - [&] { return m_tcpConnectStatus != TCP_CONNECT_STATUS_WAIT; })) { - LOG_INFO("connect timeout"); - } - } - return m_tcpConnectStatus; -} - -// internal method -void TcpTransport::setTcpConnectEvent(TcpConnectStatus connectStatus) { - TcpConnectStatus baseStatus = m_tcpConnectStatus.exchange(connectStatus, std::memory_order_relaxed); - if (baseStatus == TCP_CONNECT_STATUS_WAIT) { - // awake waiting thread - m_connectEvent.notify_all(); - } -} - -u_long TcpTransport::getInetAddr(string& hostname) { - u_long addr = inet_addr(hostname.c_str()); - - if (INADDR_NONE == addr) { - constexpr size_t length = 128; - struct evutil_addrinfo hints; - struct evutil_addrinfo* answer = NULL; - /* Build the hints to tell getaddrinfo how to act. */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; /* v4 or v6 is fine. */ - // Look up the hostname. - int err = evutil_getaddrinfo(hostname.c_str(), NULL, &hints, &answer); - if (err != 0) { - string info = "Failed to resolve host name(" + hostname + "): " + evutil_gai_strerror(err); - THROW_MQEXCEPTION(MQClientException, info, -1); - } - - struct evutil_addrinfo* addressInfo; - for (addressInfo = answer; addressInfo; addressInfo = addressInfo->ai_next) { - char buf[length]; - const char* address = NULL; - if (addressInfo->ai_family == AF_INET) { - struct sockaddr_in* sin = (struct sockaddr_in*)addressInfo->ai_addr; - address = evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, length); - } else if (addressInfo->ai_family == AF_INET6) { - struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addressInfo->ai_addr; - address = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, length); - } - if (address) { - addr = inet_addr(address); - if (addr != INADDR_NONE) { - break; - } - } - } - evutil_freeaddrinfo(answer); - } - - return addr; -} - -void TcpTransport::disconnect(const string& addr) { - // disconnect is idempotent. - std::lock_guard lock(m_eventLock); - if (getTcpConnectStatus() != TCP_CONNECT_STATUS_INIT) { - LOG_INFO("disconnect:%s start. event:%p", addr.c_str(), m_event.get()); - freeBufferEvent(); - setTcpConnectEvent(TCP_CONNECT_STATUS_INIT); - LOG_INFO("disconnect:%s completely", addr.c_str()); - } -} - -TcpConnectStatus TcpTransport::connect(const string& strServerURL, int timeoutMillis) { - string hostname; - short port; - LOG_DEBUG("connect to [%s].", strServerURL.c_str()); - if (!UtilAll::SplitURL(strServerURL, hostname, port)) { - LOG_INFO("connect to [%s] failed, Invalid url.", strServerURL.c_str()); - return TCP_CONNECT_STATUS_FAILED; - } - - { - std::lock_guard lock(m_eventLock); - - struct sockaddr_in sin; - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - try { - sin.sin_addr.s_addr = getInetAddr(hostname); - } catch (const MQClientException& e) { - LOG_INFO("connect to %s failed, %s", strServerURL.c_str(), e.what()); - setTcpConnectStatus(TCP_CONNECT_STATUS_FAILED); - return TCP_CONNECT_STATUS_FAILED; - } - sin.sin_port = htons(port); - - m_event.reset(EventLoop::GetDefaultEventLoop()->createBufferEvent(-1, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE, - m_enableSsl, m_sslPropertyFile)); - m_event->setCallback(readNextMessageIntCallback, nullptr, eventCallback, shared_from_this()); - m_event->setWatermark(EV_READ, 4, 0); - m_event->enable(EV_READ | EV_WRITE); - - setTcpConnectStatus(TCP_CONNECT_STATUS_WAIT); - if (m_event->connect((struct sockaddr*)&sin, sizeof(sin)) < 0) { - LOG_INFO("connect to fd:%d failed", m_event->getfd()); - freeBufferEvent(); - setTcpConnectStatus(TCP_CONNECT_STATUS_FAILED); - return TCP_CONNECT_STATUS_FAILED; - } - } - - if (timeoutMillis <= 0) { - LOG_INFO("try to connect to fd:%d, addr:%s", m_event->getfd(), hostname.c_str()); - return TCP_CONNECT_STATUS_WAIT; - } - - TcpConnectStatus connectStatus = waitTcpConnectEvent(timeoutMillis); - if (connectStatus != TCP_CONNECT_STATUS_SUCCESS) { - LOG_WARN("can not connect to server:%s", strServerURL.c_str()); - - std::lock_guard lock(m_eventLock); - freeBufferEvent(); - setTcpConnectStatus(TCP_CONNECT_STATUS_FAILED); - return TCP_CONNECT_STATUS_FAILED; - } - - return TCP_CONNECT_STATUS_SUCCESS; -} - -void TcpTransport::eventCallback(BufferEvent* event, short what, TcpTransport* transport) { - socket_t fd = event->getfd(); - LOG_INFO("eventcb: received event:%x on fd:%d", what, fd); - if (what & BEV_EVENT_CONNECTED) { - LOG_INFO("eventcb: connect to fd:%d successfully", fd); - - // disable Nagle - int val = 1; -#ifdef WIN32 - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&val), sizeof(val)); -#else - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&val), sizeof(val)); -#endif - transport->setTcpConnectEvent(TCP_CONNECT_STATUS_SUCCESS); - } else if (what & (BEV_EVENT_ERROR | BEV_EVENT_EOF | BEV_EVENT_READING | BEV_EVENT_WRITING)) { - LOG_INFO("eventcb: received error event cb:%x on fd:%d", what, fd); - // if error, stop callback. - event->setCallback(nullptr, nullptr, nullptr, nullptr); - transport->setTcpConnectEvent(TCP_CONNECT_STATUS_FAILED); - } else { - LOG_ERROR("eventcb: received error event:%d on fd:%d", what, fd); - } -} - -void TcpTransport::readNextMessageIntCallback(BufferEvent* event, TcpTransport* transport) { - /* This callback is invoked when there is data to read on bev. */ - - // protocol:
- // 1 2 3 4 - // rocketmq protocol contains 4 parts as following: - // 1, big endian 4 bytes int, its length is sum of 2,3 and 4 - // 2, big endian 4 bytes int, its length is 3 - // 3, use json to serialization data - // 4, application could self-defined binary data - - struct evbuffer* input = event->getInput(); - while (1) { - struct evbuffer_iovec v[4]; - int n = evbuffer_peek(input, 4, NULL, v, sizeof(v) / sizeof(v[0])); - - char hdr[4]; - char* p = hdr; - size_t needed = 4; - - for (int idx = 0; idx < n; idx++) { - if (needed > 0) { - size_t tmp = needed < v[idx].iov_len ? needed : v[idx].iov_len; - memcpy(p, v[idx].iov_base, tmp); - p += tmp; - needed -= tmp; - } else { - break; - } - } - - if (needed > 0) { - LOG_DEBUG("too little data received with sum = %d", 4 - needed); - /** - * reset read water mark to 4 - */ - event->setWatermark(EV_READ, 4, 0); - return; - } - - uint32 totalLenOfOneMsg = *(uint32*)hdr; // first 4 bytes, which indicates 1st part of protocol - uint32 msgLen = ntohl(totalLenOfOneMsg); - size_t recvLen = evbuffer_get_length(input); - if (recvLen >= msgLen + 4) { - LOG_DEBUG("had received all data. msgLen:%d, from:%d, recvLen:%d", msgLen, event->getfd(), recvLen); - } else { - LOG_DEBUG("didn't received whole. msgLen:%d, from:%d, recvLen:%d", msgLen, event->getfd(), recvLen); - /** - * set read water mark to msgLen + 4,wait for receiving whole data - */ - event->setWatermark(EV_READ, msgLen + 4, 0); - return; // consider large data which was not received completely by now - } - - if (msgLen > 0) { - MemoryBlock msg(msgLen, true); - - event->read(hdr, 4); // skip length field - event->read(msg.getData(), msgLen); - - transport->messageReceived(msg, event->getPeerAddrPort()); - } - } -} - -void TcpTransport::messageReceived(const MemoryBlock& mem, const std::string& addr) { - if (m_readCallback != nullptr) { - m_readCallback(m_tcpRemotingClient, mem, addr); - } -} - -bool TcpTransport::sendMessage(const char* pData, size_t len) { - std::lock_guard lock(m_eventLock); - if (getTcpConnectStatus() != TCP_CONNECT_STATUS_SUCCESS) { - return false; - } - - /* NOTE: - do not need to consider large data which could not send by once, as - bufferevent could handle this case; - */ - return m_event != nullptr && m_event->write(pData, len) == 0; -} - -const string TcpTransport::getPeerAddrAndPort() { - std::lock_guard lock(m_eventLock); - return m_event ? m_event->getPeerAddrPort() : ""; -} - -const uint64_t TcpTransport::getStartTime() const { - return m_startTime; -} - -} // namespace rocketmq diff --git a/src/transport/TcpTransport.h b/src/transport/TcpTransport.h deleted file mode 100644 index 79b14d799..000000000 --- a/src/transport/TcpTransport.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef __TCPTRANSPORT_H__ -#define __TCPTRANSPORT_H__ - -#include -#include -#include - -#include "EventLoop.h" -#include "dataBlock.h" - -namespace rocketmq { - -// { - public: - static std::shared_ptr CreateTransport(TcpRemotingClient* pTcpRemotingClient, - bool enableSsl, - const std::string& sslPropertyFile, - TcpTransportReadCallback handle = nullptr) { - // transport must be managed by smart pointer - std::shared_ptr transport(new TcpTransport(pTcpRemotingClient, enableSsl, sslPropertyFile, handle)); - return transport; - } - - virtual ~TcpTransport(); - - void disconnect(const std::string& addr); - TcpConnectStatus connect(const std::string& strServerURL, int timeoutMillis = 3000); - TcpConnectStatus waitTcpConnectEvent(int timeoutMillis = 3000); - TcpConnectStatus getTcpConnectStatus(); - - bool sendMessage(const char* pData, size_t len); - const std::string getPeerAddrAndPort(); - const uint64_t getStartTime() const; - - private: - TcpTransport(TcpRemotingClient* pTcpRemotingClient, - bool enableSsl, - const std::string& sslPropertyFile, - TcpTransportReadCallback handle = nullptr); - - static void readNextMessageIntCallback(BufferEvent* event, TcpTransport* transport); - static void eventCallback(BufferEvent* event, short what, TcpTransport* transport); - - void messageReceived(const MemoryBlock& mem, const std::string& addr); - void freeBufferEvent(); // not thread-safe - - void setTcpConnectEvent(TcpConnectStatus connectStatus); - void setTcpConnectStatus(TcpConnectStatus connectStatus); - - u_long getInetAddr(std::string& hostname); - - private: - uint64_t m_startTime; - - std::shared_ptr m_event; // NOTE: use m_event in callback is unsafe. - std::mutex m_eventLock; - std::atomic m_tcpConnectStatus; - - std::mutex m_connectEventLock; - std::condition_variable m_connectEvent; - - //, int64, int, int)); -}; -class MockMQClientAPIImpl : public MQClientAPIImpl { - public: - MockMQClientAPIImpl(const string& mqClientId, - ClientRemotingProcessor* clientRemotingProcessor, - int pullThreadNum, - uint64_t tcpConnectTimeout, - uint64_t tcpTransportTryLockTimeout, - string unitName) - : MQClientAPIImpl(mqClientId, true, DEFAULT_SSL_PROPERTY_FILE) {} - void reInitRemoteClient(TcpRemotingClient* client) { m_pRemotingClient.reset(client); } -}; - -TEST(MQClientAPIImplTest, getMaxOffset) { - SessionCredentials sc; - MockMQClientAPIImpl* impl = new MockMQClientAPIImpl("testMockAPIImpl", nullptr, 1, 2, 3, "testUnit"); - Mock::AllowLeak(impl); - MockTcpRemotingClient* pClient = new MockTcpRemotingClient(); - Mock::AllowLeak(pClient); - impl->reInitRemoteClient(pClient); - GetMaxOffsetResponseHeader* pHead = new GetMaxOffsetResponseHeader(); - pHead->offset = 4096; - RemotingCommand* pCommandFailed = new RemotingCommand(SYSTEM_ERROR, nullptr); - RemotingCommand* pCommandSuccuss = new RemotingCommand(SUCCESS_VALUE, pHead); - EXPECT_CALL(*pClient, invokeSync(_, _, _)) - .Times(3) - .WillOnce(Return(nullptr)) - .WillOnce(Return(pCommandFailed)) - .WillOnce(Return(pCommandSuccuss)); - EXPECT_ANY_THROW(impl->getMaxOffset("127.0.0.0:10911", "testTopic", 0, 1000, sc)); - EXPECT_ANY_THROW(impl->getMaxOffset("127.0.0.0:10911", "testTopic", 0, 1000, sc)); - int64 offset = impl->getMaxOffset("127.0.0.0:10911", "testTopic", 0, 1000, sc); - EXPECT_EQ(4096, offset); -} - -TEST(MQClientAPIImplTest, getMinOffset) { - SessionCredentials sc; - MockMQClientAPIImpl* impl = new MockMQClientAPIImpl("testMockAPIImpl", nullptr, 1, 2, 3, "testUnit"); - Mock::AllowLeak(impl); - MockTcpRemotingClient* pClient = new MockTcpRemotingClient(); - Mock::AllowLeak(pClient); - impl->reInitRemoteClient(pClient); - GetMinOffsetResponseHeader* pHead = new GetMinOffsetResponseHeader(); - pHead->offset = 2048; - RemotingCommand* pCommandFailed = new RemotingCommand(SYSTEM_ERROR, nullptr); - RemotingCommand* pCommandSuccuss = new RemotingCommand(SUCCESS_VALUE, pHead); - EXPECT_CALL(*pClient, invokeSync(_, _, _)) - .Times(3) - .WillOnce(Return(nullptr)) - .WillOnce(Return(pCommandFailed)) - .WillOnce(Return(pCommandSuccuss)); - EXPECT_ANY_THROW(impl->getMinOffset("127.0.0.0:10911", "testTopic", 0, 1000, sc)); - EXPECT_ANY_THROW(impl->getMinOffset("127.0.0.0:10911", "testTopic", 0, 1000, sc)); - int64 offset = impl->getMinOffset("127.0.0.0:10911", "testTopic", 0, 1000, sc); - EXPECT_EQ(2048, offset); -} -class MyMockAutoDeleteSendCallback : public AutoDeleteSendCallBack { - public: - virtual ~MyMockAutoDeleteSendCallback() {} - virtual void onSuccess(SendResult& sendResult) { - std::cout << "send Success" << std::endl; - return; - } - virtual void onException(MQException& e) { - std::cout << "send Exception" << e << std::endl; - return; - } -}; - -TEST(MQClientAPIImplTest, sendMessage) { - string cid = "testClientId"; - SessionCredentials sc; - MockMQClientAPIImpl* impl = new MockMQClientAPIImpl("testMockAPIImpl", nullptr, 1, 2, 3, "testUnit"); - Mock::AllowLeak(impl); - MockTcpRemotingClient* pClient = new MockTcpRemotingClient(); - Mock::AllowLeak(pClient); - impl->reInitRemoteClient(pClient); - SendMessageResponseHeader* pHead = new SendMessageResponseHeader(); - pHead->msgId = "MessageID"; - pHead->queueId = 1; - pHead->queueOffset = 409600; - RemotingCommand* pCommandSync = new RemotingCommand(SUCCESS_VALUE, pHead); - EXPECT_CALL(*pClient, invokeSync(_, _, _)).Times(1).WillOnce(Return(pCommandSync)); - MQMessage message("testTopic", "Hello, RocketMQ"); - string unique_msgId = "UniqMessageID"; - message.setProperty(MQMessage::PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, unique_msgId); - SendMessageRequestHeader* requestHeader = new SendMessageRequestHeader(); - requestHeader->producerGroup = cid; - requestHeader->topic = (message.getTopic()); - requestHeader->defaultTopic = DEFAULT_TOPIC; - requestHeader->defaultTopicQueueNums = 4; - requestHeader->bornTimestamp = UtilAll::currentTimeMillis(); - SendResult result = - impl->sendMessage("127.0.0.0:10911", "testBroker", message, *requestHeader, 100, 1, ComMode_SYNC, nullptr, sc); - EXPECT_EQ(result.getSendStatus(), SEND_OK); - EXPECT_EQ(result.getMsgId(), unique_msgId); - EXPECT_EQ(result.getQueueOffset(), 409600); - EXPECT_EQ(result.getOffsetMsgId(), "MessageID"); - EXPECT_EQ(result.getMessageQueue().getBrokerName(), "testBroker"); - EXPECT_EQ(result.getMessageQueue().getTopic(), "testTopic"); - - // Try to test Async send - - EXPECT_CALL(*pClient, invokeAsync(_, _, _, _, _, _)) - .Times(7) - .WillOnce(Return(false)) - .WillOnce(Return(true)) - .WillOnce(Return(false)) - .WillOnce(Return(true)) - .WillOnce(Return(false)) - .WillOnce(Return(false)) - .WillOnce(Return(false)); - - SendMessageRequestHeader* requestHeader2 = new SendMessageRequestHeader(); - requestHeader2->producerGroup = cid; - requestHeader2->topic = (message.getTopic()); - requestHeader2->defaultTopic = DEFAULT_TOPIC; - requestHeader2->defaultTopicQueueNums = 4; - requestHeader2->bornTimestamp = UtilAll::currentTimeMillis(); - EXPECT_ANY_THROW( - impl->sendMessage("127.0.0.0:10911", "testBroker", message, *requestHeader2, 100, 1, ComMode_ASYNC, nullptr, sc)); - - SendMessageRequestHeader* requestHeader3 = new SendMessageRequestHeader(); - requestHeader3->producerGroup = cid; - requestHeader3->topic = (message.getTopic()); - requestHeader3->defaultTopic = DEFAULT_TOPIC; - requestHeader3->defaultTopicQueueNums = 4; - requestHeader3->bornTimestamp = UtilAll::currentTimeMillis(); - SendCallback* pSendCallback = new MyMockAutoDeleteSendCallback(); - EXPECT_NO_THROW(impl->sendMessage("127.0.0.0:10911", "testBroker", message, *requestHeader3, 100, 1, ComMode_ASYNC, - pSendCallback, sc)); - - SendMessageRequestHeader* requestHeader4 = new SendMessageRequestHeader(); - requestHeader4->producerGroup = cid; - requestHeader4->topic = (message.getTopic()); - requestHeader4->defaultTopic = DEFAULT_TOPIC; - requestHeader4->defaultTopicQueueNums = 4; - requestHeader4->bornTimestamp = UtilAll::currentTimeMillis(); - SendCallback* pSendCallback2 = new MyMockAutoDeleteSendCallback(); - EXPECT_NO_THROW(impl->sendMessage("127.0.0.0:10911", "testBroker", message, *requestHeader4, 1000, 2, ComMode_ASYNC, - pSendCallback2, sc)); - - SendMessageRequestHeader* requestHeader5 = new SendMessageRequestHeader(); - requestHeader5->producerGroup = cid; - requestHeader5->topic = (message.getTopic()); - requestHeader5->defaultTopic = DEFAULT_TOPIC; - requestHeader5->defaultTopicQueueNums = 4; - requestHeader5->bornTimestamp = UtilAll::currentTimeMillis(); - SendCallback* pSendCallback3 = new MyMockAutoDeleteSendCallback(); - EXPECT_NO_THROW(impl->sendMessage("127.0.0.0:10911", "testBroker", message, *requestHeader5, 1000, 3, ComMode_ASYNC, - pSendCallback3, sc)); -} - -TEST(MQClientAPIImplTest, consumerSendMessageBack) { - SessionCredentials sc; - MQMessageExt msg; - MockMQClientAPIImpl* impl = new MockMQClientAPIImpl("testMockAPIImpl", nullptr, 1, 2, 3, "testUnit"); - Mock::AllowLeak(impl); - MockTcpRemotingClient* pClient = new MockTcpRemotingClient(); - Mock::AllowLeak(pClient); - impl->reInitRemoteClient(pClient); - RemotingCommand* pCommandFailed = new RemotingCommand(SYSTEM_ERROR, nullptr); - RemotingCommand* pCommandSuccuss = new RemotingCommand(SUCCESS_VALUE, nullptr); - EXPECT_CALL(*pClient, invokeSync(_, _, _)) - .Times(3) - .WillOnce(Return(nullptr)) - .WillOnce(Return(pCommandFailed)) - .WillOnce(Return(pCommandSuccuss)); - EXPECT_ANY_THROW(impl->consumerSendMessageBack("127.0.0.0:10911", msg, "testGroup", 0, 1000, 16, sc)); - EXPECT_ANY_THROW(impl->consumerSendMessageBack("127.0.0.0:10911", msg, "testGroup", 0, 1000, 16, sc)); - EXPECT_NO_THROW(impl->consumerSendMessageBack("127.0.0.0:10911", msg, "testGroup", 0, 1000, 16, sc)); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(filter) = "MQClientAPIImplTest.*"; - return RUN_ALL_TESTS(); -} diff --git a/test/src/MQClientFactoryTest.cpp b/test/src/MQClientFactoryTest.cpp deleted file mode 100644 index cab4f32e7..000000000 --- a/test/src/MQClientFactoryTest.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "ConsumerRunningInfo.h" -#include "DefaultMQPushConsumerImpl.h" -#include "MQClientFactory.h" - -using namespace std; -using namespace rocketmq; -using rocketmq::ConsumerRunningInfo; -using rocketmq::DefaultMQPushConsumerImpl; -using rocketmq::MQClientFactory; -using rocketmq::TopicRouteData; -using testing::_; -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Mock; -using testing::Return; - -class MockPushConsumerImpl : public DefaultMQPushConsumerImpl { - public: - MockPushConsumerImpl(const std::string& groupname) : DefaultMQPushConsumerImpl() {} - MOCK_METHOD0(getConsumerRunningInfo, ConsumerRunningInfo*()); -}; - -class MockMQClientAPIImpl : public MQClientAPIImpl { - public: - MockMQClientAPIImpl(const string& mqClientId, - ClientRemotingProcessor* clientRemotingProcessor, - int pullThreadNum, - uint64_t tcpConnectTimeout, - uint64_t tcpTransportTryLockTimeout, - string unitName) - : MQClientAPIImpl(mqClientId, true, DEFAULT_SSL_PROPERTY_FILE) {} - - MOCK_METHOD5(getMinOffset, int64(const string&, const string&, int, int, const SessionCredentials&)); - MOCK_METHOD3(getTopicRouteInfoFromNameServer, TopicRouteData*(const string&, int, const SessionCredentials&)); -}; -class MockMQClientFactory : public MQClientFactory { - public: - MockMQClientFactory(const string& mqClientId, - int pullThreadNum, - uint64_t tcpConnectTimeout, - uint64_t tcpTransportTryLockTimeout, - string unitName) - : MQClientFactory(mqClientId, true, DEFAULT_SSL_PROPERTY_FILE) {} - void reInitClientImpl(MQClientAPIImpl* pImpl) { m_pClientAPIImpl.reset(pImpl); } - void addTestConsumer(const string& consumerName, MQConsumer* pMQConsumer) { - addConsumerToTable(consumerName, pMQConsumer); - } -}; - -TEST(MQClientFactoryTest, minOffset) { - string clientId = "testClientId"; - int pullThreadNum = 1; - uint64_t tcpConnectTimeout = 3000; - uint64_t tcpTransportTryLockTimeout = 3000; - string unitName = "central"; - MockMQClientFactory* factory = - new MockMQClientFactory(clientId, pullThreadNum, tcpConnectTimeout, tcpTransportTryLockTimeout, unitName); - MockMQClientAPIImpl* pImpl = new MockMQClientAPIImpl(clientId, nullptr, pullThreadNum, tcpConnectTimeout, - tcpTransportTryLockTimeout, unitName); - factory->reInitClientImpl(pImpl); - MQMessageQueue mq; - mq.setTopic("testTopic"); - mq.setBrokerName("testBroker"); - mq.setQueueId(1); - SessionCredentials session_credentials; - - TopicRouteData* pData = new TopicRouteData(); - pData->setOrderTopicConf("OrderTopicConf"); - QueueData qd; - qd.brokerName = "testBroker"; - qd.readQueueNums = 8; - qd.writeQueueNums = 8; - qd.perm = 1; - pData->getQueueDatas().push_back(qd); - BrokerData bd; - bd.brokerName = "testBroker"; - bd.brokerAddrs[0] = "127.0.0.1:10091"; - bd.brokerAddrs[1] = "127.0.0.2:10092"; - pData->getBrokerDatas().push_back(bd); - - EXPECT_CALL(*pImpl, getMinOffset(_, _, _, _, _)).Times(1).WillOnce(Return(1024)); - EXPECT_CALL(*pImpl, getTopicRouteInfoFromNameServer(_, _, _)).Times(1).WillOnce(Return(pData)); - int64 offset = factory->minOffset(mq, session_credentials); - EXPECT_EQ(1024, offset); - delete factory; -} - -TEST(MQClientFactoryTest, consumerRunningInfo) { - string clientId = "testClientId"; - int pullThreadNum = 1; - uint64_t tcpConnectTimeout = 3000; - uint64_t tcpTransportTryLockTimeout = 3000; - string unitName = "central"; - MockMQClientFactory* factory = - new MockMQClientFactory(clientId, pullThreadNum, tcpConnectTimeout, tcpTransportTryLockTimeout, unitName); - MockPushConsumerImpl* mockPushConsumer = new MockPushConsumerImpl(clientId); - Mock::AllowLeak(mockPushConsumer); - factory->addTestConsumer(clientId, mockPushConsumer); - ConsumerRunningInfo* info = new ConsumerRunningInfo(); - info->setJstack("Hello,JStack"); - EXPECT_CALL(*mockPushConsumer, getConsumerRunningInfo()).Times(1).WillOnce(Return(info)); - ConsumerRunningInfo* info2 = factory->consumerRunningInfo(clientId); - EXPECT_EQ(info2->getJstack(), "Hello,JStack"); - delete factory; -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/test/src/MQClientManagerTest.cpp b/test/src/MQClientManagerTest.cpp deleted file mode 100644 index 208770e69..000000000 --- a/test/src/MQClientManagerTest.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "MQClientManager.h" - -using namespace std; -using namespace rocketmq; -using rocketmq::MQClientFactory; -using rocketmq::MQClientManager; -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -TEST(MQClientManagerTest, getClientFactory) { - string clientId = "testClientId"; - string unitName = "central"; - MQClientFactory* factory = MQClientManager::getInstance()->getMQClientFactory(clientId, 1, 1000, 3000, unitName, true, - DEFAULT_SSL_PROPERTY_FILE); - MQClientFactory* factory2 = MQClientManager::getInstance()->getMQClientFactory(clientId, 1, 1000, 3000, unitName, - true, DEFAULT_SSL_PROPERTY_FILE); - EXPECT_EQ(factory, factory2); - factory->shutdown(); - - MQClientManager::getInstance()->removeClientFactory(clientId); -} -TEST(MQClientManagerTest, removeClientFactory) { - string clientId = "testClientId"; - MQClientManager::getInstance()->removeClientFactory(clientId); -} -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/test/src/common/ClientRPCHookTest.cpp b/test/src/common/ClientRPCHookTest.cpp deleted file mode 100644 index 6fd48b631..000000000 --- a/test/src/common/ClientRPCHookTest.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "ClientRPCHook.h" -#include "CommandHeader.h" -#include "RemotingCommand.h" -#include "SessionCredentials.h" - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::RemotingCommand; -using rocketmq::SendMessageRequestHeader; -using rocketmq::SessionCredentials; - -using rocketmq::ClientRPCHook; - -TEST(clientRPCHook, doBeforeRequest) { - SessionCredentials sessionCredentials; - sessionCredentials.setAccessKey("accessKey"); - sessionCredentials.setSecretKey("secretKey"); - sessionCredentials.setAuthChannel("onsChannel"); - - ClientRPCHook clientRPCHook(sessionCredentials); - - RemotingCommand remotingCommand; - clientRPCHook.doBeforeRequest("127.0.0.1:9876", remotingCommand); - - SendMessageRequestHeader* sendMessageRequestHeader = new SendMessageRequestHeader(); - RemotingCommand headeRremotingCommand(17, sendMessageRequestHeader); - clientRPCHook.doBeforeRequest("127.0.0.1:9876", headeRremotingCommand); - - headeRremotingCommand.setMsgBody("1231231"); - clientRPCHook.doBeforeRequest("127.0.0.1:9876", headeRremotingCommand); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "clientRPCHook.doBeforeRequest"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/common/MQVersionTest.cpp b/test/src/common/MQVersionTest.cpp deleted file mode 100644 index 587339bef..000000000 --- a/test/src/common/MQVersionTest.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "MQVersion.h" - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::MQVersion; -using rocketmq::RocketMQCPPClientVersion; - -TEST(MQVersionTest, Version2String) { - for (int v = MQVersion::V3_0_0_SNAPSHOT; v <= MQVersion::HIGHER_VERSION; v++) { - EXPECT_STREQ(MQVersion::GetVersionDesc(v), RocketMQCPPClientVersion[v]); - } - EXPECT_STREQ(MQVersion::GetVersionDesc(-100), MQVersion::GetVersionDesc(MQVersion::V3_0_0_SNAPSHOT)); - EXPECT_STREQ(MQVersion::GetVersionDesc(MQVersion::V4_6_0), "V4_6_0"); - EXPECT_STREQ(MQVersion::GetVersionDesc(MQVersion::HIGHER_VERSION + 100), - MQVersion::GetVersionDesc(MQVersion::HIGHER_VERSION)); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "MQVersionTest.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/common/MemoryBlockTest.cpp b/test/src/common/MemoryBlockTest.cpp deleted file mode 100644 index 4b72d6cd2..000000000 --- a/test/src/common/MemoryBlockTest.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "dataBlock.h" - -using std::string; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::MemoryBlock; - -TEST(memoryBlock, init) { - MemoryBlock memoryBlock; - EXPECT_EQ(memoryBlock.getSize(), 0); - EXPECT_TRUE(memoryBlock.getData() == nullptr); - - MemoryBlock twoMemoryBlock(-1, true); - EXPECT_EQ(twoMemoryBlock.getSize(), 0); - EXPECT_TRUE(twoMemoryBlock.getData() == nullptr); - - MemoryBlock threeMemoryBlock(10, true); - EXPECT_EQ(threeMemoryBlock.getSize(), 10); - EXPECT_TRUE(threeMemoryBlock.getData() != nullptr); - - MemoryBlock frouMemoryBlock(12, false); - EXPECT_EQ(frouMemoryBlock.getSize(), 12); - EXPECT_TRUE(frouMemoryBlock.getData() != nullptr); - - char* buf = (char*)malloc(sizeof(char) * 9); - strcpy(buf, "RocketMQ"); - MemoryBlock fiveMemoryBlock(buf, 0); - EXPECT_EQ(fiveMemoryBlock.getSize(), 0); - EXPECT_TRUE(fiveMemoryBlock.getData() == nullptr); - - char* bufNull = NULL; - MemoryBlock sixMemoryBlock(bufNull, 16); - EXPECT_EQ(sixMemoryBlock.getSize(), 16); - EXPECT_TRUE(sixMemoryBlock.getData() != nullptr); - - buf = (char*)realloc(buf, 20); - MemoryBlock sevenMemoryBlock(buf, 20); - EXPECT_EQ(sevenMemoryBlock.getSize(), 20); - sevenMemoryBlock.getData(); - EXPECT_EQ(string(sevenMemoryBlock.getData()), string(buf)); - - MemoryBlock nineMemoryBlock(sevenMemoryBlock); - EXPECT_EQ(nineMemoryBlock.getSize(), sevenMemoryBlock.getSize()); - EXPECT_EQ(string(nineMemoryBlock.getData()), string(sevenMemoryBlock.getData())); - - MemoryBlock eightMemoryBlock(fiveMemoryBlock); - EXPECT_EQ(eightMemoryBlock.getSize(), fiveMemoryBlock.getSize()); - EXPECT_TRUE(eightMemoryBlock.getData() == nullptr); - - free(buf); -} - -TEST(memoryBlock, operators) { - MemoryBlock memoryBlock(12, false); - - MemoryBlock operaterMemoryBlock = memoryBlock; - - EXPECT_TRUE(operaterMemoryBlock == memoryBlock); - - char* buf = (char*)malloc(sizeof(char) * 16); - memset(buf, 0, 16); - strcpy(buf, "RocketMQ"); - MemoryBlock twoMemoryBlock(buf, 12); - EXPECT_FALSE(memoryBlock == twoMemoryBlock); - - MemoryBlock threeMemoryBlock(buf, 16); - EXPECT_FALSE(memoryBlock == threeMemoryBlock); - EXPECT_TRUE(twoMemoryBlock != threeMemoryBlock); - - threeMemoryBlock.fillWith(49); - EXPECT_EQ(string(threeMemoryBlock.getData(), 16), "1111111111111111"); - - threeMemoryBlock.reset(); - EXPECT_EQ(threeMemoryBlock.getSize(), 0); - EXPECT_TRUE(threeMemoryBlock.getData() == nullptr); - - threeMemoryBlock.setSize(16, 0); - EXPECT_EQ(threeMemoryBlock.getSize(), 16); - // EXPECT_EQ(threeMemoryBlock.getData() , buf); - - threeMemoryBlock.setSize(0, 0); - EXPECT_EQ(threeMemoryBlock.getSize(), 0); - EXPECT_TRUE(threeMemoryBlock.getData() == nullptr); - - MemoryBlock appendMemoryBlock; - EXPECT_EQ(appendMemoryBlock.getSize(), 0); - EXPECT_TRUE(appendMemoryBlock.getData() == nullptr); - - appendMemoryBlock.append(buf, -1); - EXPECT_EQ(appendMemoryBlock.getSize(), 0); - EXPECT_TRUE(appendMemoryBlock.getData() == nullptr); - - appendMemoryBlock.append(buf, 8); - EXPECT_EQ(appendMemoryBlock.getSize(), 8); - - MemoryBlock replaceWithMemoryBlock; - replaceWithMemoryBlock.append(buf, 8); - - char* aliyunBuf = (char*)malloc(sizeof(char) * 8); - memset(aliyunBuf, 0, 8); - strcpy(aliyunBuf, "aliyun"); - replaceWithMemoryBlock.replaceWith(aliyunBuf, 0); - EXPECT_EQ(replaceWithMemoryBlock.getSize(), 8); - EXPECT_EQ(string(replaceWithMemoryBlock.getData(), 8), "RocketMQ"); - - replaceWithMemoryBlock.replaceWith(aliyunBuf, 6); - EXPECT_EQ(replaceWithMemoryBlock.getSize(), 6); - EXPECT_EQ(string(replaceWithMemoryBlock.getData(), strlen(aliyunBuf)), "aliyun"); - - MemoryBlock insertMemoryBlock; - insertMemoryBlock.append(buf, 8); - insertMemoryBlock.insert(aliyunBuf, -1, -1); - EXPECT_EQ(string(insertMemoryBlock.getData(), 8), "RocketMQ"); - - /* MemoryBlock fourInsertMemoryBlock; - fourInsertMemoryBlock.append(buf , 8); - // 6+ (-1) - fourInsertMemoryBlock.insert(aliyunBuf , 8 , -1); - string fourStr( fourInsertMemoryBlock.getData()); - EXPECT_TRUE( fourStr == "liyun");*/ - - MemoryBlock twoInsertMemoryBlock; - twoInsertMemoryBlock.append(buf, 8); - twoInsertMemoryBlock.insert(aliyunBuf, strlen(aliyunBuf), 0); - EXPECT_EQ(string(twoInsertMemoryBlock.getData(), 8 + strlen(aliyunBuf)), "aliyunRocketMQ"); - - MemoryBlock threeInsertMemoryBlock; - threeInsertMemoryBlock.append(buf, 8); - threeInsertMemoryBlock.insert(aliyunBuf, 6, 100); - EXPECT_EQ(string(threeInsertMemoryBlock.getData(), 8 + strlen(aliyunBuf)), "RocketMQaliyun"); - - MemoryBlock removeSectionMemoryBlock(buf, 8); - removeSectionMemoryBlock.removeSection(8, -1); - EXPECT_EQ(string(removeSectionMemoryBlock.getData(), 8), "RocketMQ"); - - MemoryBlock twoRemoveSectionMemoryBlock(buf, 8); - twoRemoveSectionMemoryBlock.removeSection(1, 4); - string str(twoRemoveSectionMemoryBlock.getData(), 4); - EXPECT_TRUE(str == "RtMQ"); - - free(buf); - free(aliyunBuf); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "memoryBlock.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/common/MemoryOutputStreamTest.cpp b/test/src/common/MemoryOutputStreamTest.cpp deleted file mode 100644 index 05af181e0..000000000 --- a/test/src/common/MemoryOutputStreamTest.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "string.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "MemoryInputStream.h" -#include "MemoryOutputStream.h" -#include "dataBlock.h" - -using std::string; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::MemoryBlock; -using rocketmq::MemoryInputStream; -using rocketmq::MemoryOutputStream; - -TEST(memoryOutputStream, init) { - MemoryOutputStream memoryOutput; - EXPECT_EQ(memoryOutput.getMemoryBlock().getSize(), 0); - EXPECT_TRUE(memoryOutput.getData() != nullptr); - - EXPECT_EQ(memoryOutput.getPosition(), 0); - EXPECT_EQ(memoryOutput.getDataSize(), 0); - - MemoryOutputStream twoMemoryOutput(512); - EXPECT_EQ(memoryOutput.getMemoryBlock().getSize(), 0); - - MemoryBlock memoryBlock(12, false); - MemoryOutputStream threeMemoryOutput(memoryBlock, false); - EXPECT_EQ(threeMemoryOutput.getPosition(), 0); - EXPECT_EQ(threeMemoryOutput.getDataSize(), 0); - - MemoryOutputStream frouMemoryOutput(memoryBlock, true); - EXPECT_EQ(frouMemoryOutput.getPosition(), memoryBlock.getSize()); - EXPECT_EQ(frouMemoryOutput.getDataSize(), memoryBlock.getSize()); - - char* buf = (char*)malloc(sizeof(char) * 9); - strcpy(buf, "RocketMQ"); - MemoryOutputStream fiveMemoryOutputStream(buf, 8); - EXPECT_EQ(fiveMemoryOutputStream.getData(), buf); - - fiveMemoryOutputStream.reset(); - EXPECT_EQ(memoryOutput.getPosition(), 0); - EXPECT_EQ(memoryOutput.getDataSize(), 0); - free(buf); -} - -TEST(memoryOutputStream, flush) { - char* buf = (char*)malloc(sizeof(char) * 9); - strcpy(buf, "RocketMQ"); - MemoryOutputStream memoryOutput; - memoryOutput.write(buf, 9); - memoryOutput.flush(); - EXPECT_FALSE(memoryOutput.getData() == buf); - free(buf); -} - -TEST(memoryOutputStream, preallocate) { - MemoryOutputStream memoryOutput; - memoryOutput.preallocate(250); - - memoryOutput.preallocate(256); -} - -TEST(memoryOutputStream, getMemoryBlock) { - char* buf = (char*)malloc(sizeof(char) * 9); - strcpy(buf, "RocketMQ"); - MemoryOutputStream memoryOutput; - memoryOutput.write(buf, 9); - MemoryBlock memoryBlock = memoryOutput.getMemoryBlock(); - EXPECT_EQ(memoryBlock.getSize(), memoryOutput.getDataSize()); - free(buf); -} - -TEST(memoryOutputStream, prepareToWriteAndGetData) { - char* buf = (char*)malloc(sizeof(char) * 9); - strcpy(buf, "RocketMQ"); - MemoryOutputStream memoryOutput(buf, 9); - EXPECT_EQ(memoryOutput.getData(), buf); - - // prepareToWrite - // EXPECT_TRUE(memoryOutput.writeIntBigEndian(123)); - EXPECT_TRUE(memoryOutput.writeByte('r')); - const char* data = static_cast(memoryOutput.getData()); - EXPECT_EQ(string(data), "rocketMQ"); - - MemoryOutputStream blockMmoryOutput(8); - char* memoryData = (char*)blockMmoryOutput.getData(); - - EXPECT_EQ(memoryData[blockMmoryOutput.getDataSize()], 0); - - blockMmoryOutput.write(buf, 8); - blockMmoryOutput.write(buf, 8); - data = static_cast(blockMmoryOutput.getData()); - EXPECT_EQ(string(data), "rocketMQrocketMQ"); - free(buf); -} - -TEST(memoryOutputStream, position) { - char* buf = (char*)malloc(sizeof(char) * 9); - strcpy(buf, "RocketMQ"); - - MemoryOutputStream memoryOutput; - EXPECT_EQ(memoryOutput.getPosition(), 0); - - memoryOutput.write(buf, 8); - EXPECT_EQ(memoryOutput.getPosition(), 8); - - EXPECT_FALSE(memoryOutput.setPosition(9)); - - EXPECT_TRUE(memoryOutput.setPosition(-1)); - EXPECT_EQ(memoryOutput.getPosition(), 0); - - EXPECT_TRUE(memoryOutput.setPosition(8)); - EXPECT_EQ(memoryOutput.getPosition(), 8); - - EXPECT_TRUE(memoryOutput.setPosition(7)); - EXPECT_EQ(memoryOutput.getPosition(), 7); - free(buf); -} - -TEST(memoryOutputStream, write) { - MemoryOutputStream memoryOutput; - MemoryInputStream memoryInput(memoryOutput.getData(), 256, false); - - EXPECT_TRUE(memoryOutput.writeBool(true)); - EXPECT_TRUE(memoryInput.readBool()); - - EXPECT_TRUE(memoryOutput.writeBool(false)); - EXPECT_FALSE(memoryInput.readBool()); - - EXPECT_TRUE(memoryOutput.writeByte('a')); - EXPECT_EQ(memoryInput.readByte(), 'a'); - - EXPECT_TRUE(memoryOutput.writeShortBigEndian(128)); - EXPECT_EQ(memoryInput.readShortBigEndian(), 128); - - EXPECT_TRUE(memoryOutput.writeIntBigEndian(123)); - EXPECT_EQ(memoryInput.readIntBigEndian(), 123); - - EXPECT_TRUE(memoryOutput.writeInt64BigEndian(123123)); - EXPECT_EQ(memoryInput.readInt64BigEndian(), 123123); - - EXPECT_TRUE(memoryOutput.writeDoubleBigEndian(12.71)); - EXPECT_EQ(memoryInput.readDoubleBigEndian(), 12.71); - - EXPECT_TRUE(memoryOutput.writeFloatBigEndian(12.1)); - float f = 12.1; - EXPECT_EQ(memoryInput.readFloatBigEndian(), f); - - // EXPECT_TRUE(memoryOutput.writeRepeatedByte(8 , 8)); -} - -TEST(memoryInputStream, info) { - char* buf = (char*)malloc(sizeof(char) * 9); - strcpy(buf, "RocketMQ"); - - MemoryInputStream memoryInput(buf, 8, false); - - char* memoryData = (char*)memoryInput.getData(); - EXPECT_EQ(memoryData, buf); - - EXPECT_EQ(memoryInput.getTotalLength(), 8); - - MemoryInputStream twoMemoryInput(buf, 8, true); - EXPECT_NE(twoMemoryInput.getData(), buf); - - memoryData = (char*)twoMemoryInput.getData(); - EXPECT_NE(&memoryData, &buf); - - MemoryBlock memoryBlock(buf, 8); - MemoryInputStream threeMemoryInput(memoryBlock, false); - memoryData = (char*)threeMemoryInput.getData(); - EXPECT_EQ(memoryData, threeMemoryInput.getData()); - EXPECT_EQ(threeMemoryInput.getTotalLength(), 8); - - MemoryInputStream frouMemoryInput(memoryBlock, true); - EXPECT_NE(frouMemoryInput.getData(), memoryBlock.getData()); - free(buf); -} - -TEST(memoryInputStream, position) { - char* buf = (char*)malloc(sizeof(char) * 9); - strcpy(buf, "RocketMQ"); - - MemoryInputStream memoryInput(buf, 8, false); - EXPECT_EQ(memoryInput.getPosition(), 0); - EXPECT_FALSE(memoryInput.isExhausted()); - - memoryInput.setPosition(9); - EXPECT_EQ(memoryInput.getPosition(), 8); - EXPECT_TRUE(memoryInput.isExhausted()); - - memoryInput.setPosition(-1); - EXPECT_EQ(memoryInput.getPosition(), 0); - free(buf); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "*.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/common/NameSpaceUtilTest.cpp b/test/src/common/NameSpaceUtilTest.cpp deleted file mode 100644 index 08873b5f7..000000000 --- a/test/src/common/NameSpaceUtilTest.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "NameSpaceUtil.h" - -using std::string; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::NameSpaceUtil; - -TEST(NameSpaceUtil, isEndPointURL) { - const string url = "http://rocketmq.nameserver.com"; - EXPECT_TRUE(NameSpaceUtil::isEndPointURL(url)); - EXPECT_FALSE(NameSpaceUtil::isEndPointURL("rocketmq.nameserver.com")); - EXPECT_FALSE(NameSpaceUtil::isEndPointURL("127.0.0.1")); -} -TEST(NameSpaceUtil, formatNameServerURL) { - string url = "http://rocketmq.nameserver.com"; - string urlFormatted = "rocketmq.nameserver.com"; - EXPECT_EQ(NameSpaceUtil::formatNameServerURL(url), urlFormatted); - EXPECT_EQ(NameSpaceUtil::formatNameServerURL(urlFormatted), urlFormatted); -} -TEST(NameSpaceUtil, getNameSpaceFromNsURL) { - string url = "http://MQ_INST_UNITTEST.rocketmq.nameserver.com"; - string url2 = "MQ_INST_UNITTEST.rocketmq.nameserver.com"; - string noInstUrl = "http://rocketmq.nameserver.com"; - string inst = "MQ_INST_UNITTEST"; - EXPECT_EQ(NameSpaceUtil::getNameSpaceFromNsURL(url), inst); - EXPECT_EQ(NameSpaceUtil::getNameSpaceFromNsURL(url2), inst); - EXPECT_EQ(NameSpaceUtil::getNameSpaceFromNsURL(noInstUrl), ""); -} -TEST(NameSpaceUtil, checkNameSpaceExistInNsURL) { - string url = "http://MQ_INST_UNITTEST.rocketmq.nameserver.com"; - string url2 = "MQ_INST_UNITTEST.rocketmq.nameserver.com"; - string noInstUrl = "http://rocketmq.nameserver.com"; - EXPECT_TRUE(NameSpaceUtil::checkNameSpaceExistInNsURL(url)); - EXPECT_FALSE(NameSpaceUtil::checkNameSpaceExistInNsURL(url2)); - EXPECT_FALSE(NameSpaceUtil::checkNameSpaceExistInNsURL(noInstUrl)); -} -TEST(NameSpaceUtil, checkNameSpaceExistInNameServer) { - string url = "http://MQ_INST_UNITTEST.rocketmq.nameserver.com"; - string url2 = "MQ_INST_UNITTEST.rocketmq.nameserver.com"; - string noInstUrl = "rocketmq.nameserver.com"; - string nsIP = "127.0.0.1"; - EXPECT_TRUE(NameSpaceUtil::checkNameSpaceExistInNameServer(url)); - EXPECT_TRUE(NameSpaceUtil::checkNameSpaceExistInNameServer(url2)); - EXPECT_FALSE(NameSpaceUtil::checkNameSpaceExistInNameServer(noInstUrl)); - EXPECT_FALSE(NameSpaceUtil::checkNameSpaceExistInNameServer(nsIP)); -} -TEST(NameSpaceUtil, withNameSpace) { - string source = "testTopic"; - string ns = "MQ_INST_UNITTEST"; - string nsSource = "MQ_INST_UNITTEST%testTopic"; - EXPECT_EQ(NameSpaceUtil::withNameSpace(source, ns), nsSource); - EXPECT_EQ(NameSpaceUtil::withNameSpace(source, ""), source); -} -TEST(NameSpaceUtil, hasNameSpace) { - string source = "testTopic"; - string ns = "MQ_INST_UNITTEST"; - string nsSource = "MQ_INST_UNITTEST%testTopic"; - string nsTraceSource = "rmq_sys_TRACE_DATA_Region"; - EXPECT_TRUE(NameSpaceUtil::hasNameSpace(nsSource, ns)); - EXPECT_FALSE(NameSpaceUtil::hasNameSpace(source, ns)); - EXPECT_FALSE(NameSpaceUtil::hasNameSpace(source, "")); - EXPECT_TRUE(NameSpaceUtil::hasNameSpace(nsTraceSource, ns)); -} -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "NameSpaceUtil.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/common/PermNametTest.cpp b/test/src/common/PermNametTest.cpp deleted file mode 100644 index 3296b84d7..000000000 --- a/test/src/common/PermNametTest.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "PermName.h" - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::PermName; - -TEST(permName, perm2String) { - EXPECT_EQ(PermName::perm2String(0), "---"); - EXPECT_EQ(PermName::perm2String(1), "--X"); - EXPECT_EQ(PermName::perm2String(2), "-W"); - EXPECT_EQ(PermName::perm2String(3), "-WX"); - EXPECT_EQ(PermName::perm2String(4), "R--"); - EXPECT_EQ(PermName::perm2String(5), "R-X"); - EXPECT_EQ(PermName::perm2String(6), "RW"); - EXPECT_EQ(PermName::perm2String(7), "RWX"); - EXPECT_EQ(PermName::perm2String(8), "---"); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "permName.perm2String"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/common/PullSysFlagTest.cpp b/test/src/common/PullSysFlagTest.cpp deleted file mode 100644 index 7b7c9db95..000000000 --- a/test/src/common/PullSysFlagTest.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "PullSysFlag.h" - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::PullSysFlag; - -TEST(pullSysFlag, flag) { - EXPECT_EQ(PullSysFlag::buildSysFlag(false, false, false, false), 0); - - EXPECT_EQ(PullSysFlag::buildSysFlag(true, false, false, false), 1); - EXPECT_EQ(PullSysFlag::buildSysFlag(true, true, false, false), 3); - EXPECT_EQ(PullSysFlag::buildSysFlag(true, true, true, false), 7); - EXPECT_EQ(PullSysFlag::buildSysFlag(true, true, true, true), 15); - - EXPECT_EQ(PullSysFlag::buildSysFlag(false, true, false, false), 2); - EXPECT_EQ(PullSysFlag::buildSysFlag(false, true, true, false), 6); - EXPECT_EQ(PullSysFlag::buildSysFlag(false, true, true, true), 14); - - EXPECT_EQ(PullSysFlag::buildSysFlag(false, false, true, false), 4); - EXPECT_EQ(PullSysFlag::buildSysFlag(false, false, true, true), 12); - - EXPECT_EQ(PullSysFlag::buildSysFlag(false, false, false, true), 8); - - int FLAG_COMMIT_OFFSET = 0x1 << 0; - int FLAG_SUSPEND = 0x1 << 1; - int FLAG_SUBSCRIPTION = 0x1 << 2; - int FLAG_CLASS_FILTER = 0x1 << 3; - - for (int i = 0; i < 16; i++) { - if ((i & FLAG_COMMIT_OFFSET) == FLAG_COMMIT_OFFSET) { - EXPECT_TRUE(PullSysFlag::hasCommitOffsetFlag(i)); - } else { - EXPECT_FALSE(PullSysFlag::hasCommitOffsetFlag(i)); - } - - if ((i & FLAG_SUSPEND) == FLAG_SUSPEND) { - EXPECT_TRUE(PullSysFlag::hasSuspendFlag(i)); - } else { - EXPECT_FALSE(PullSysFlag::hasSuspendFlag(i)); - } - - if ((i & FLAG_SUBSCRIPTION) == FLAG_SUBSCRIPTION) { - EXPECT_TRUE(PullSysFlag::hasSubscriptionFlag(i)); - } else { - EXPECT_FALSE(PullSysFlag::hasSubscriptionFlag(i)); - } - - if ((i & FLAG_CLASS_FILTER) == FLAG_CLASS_FILTER) { - EXPECT_TRUE(PullSysFlag::hasClassFilterFlag(i)); - } else { - EXPECT_FALSE(PullSysFlag::hasClassFilterFlag(i)); - } - - if ((i & FLAG_COMMIT_OFFSET) == FLAG_COMMIT_OFFSET) { - EXPECT_TRUE(PullSysFlag::hasCommitOffsetFlag(i)); - } else { - EXPECT_FALSE(PullSysFlag::hasCommitOffsetFlag(i)); - } - - if (i == 0 || i == 1) { - EXPECT_EQ(PullSysFlag::clearCommitOffsetFlag(i), 0); - } else { - EXPECT_TRUE(PullSysFlag::clearCommitOffsetFlag(i) > 0); - } - } -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "pullSysFlag.flag"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/common/TopicConfigTest.cpp b/test/src/common/TopicConfigTest.cpp deleted file mode 100644 index 8c163942c..000000000 --- a/test/src/common/TopicConfigTest.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "string.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "PermName.h" -#include "TopicConfig.h" -#include "TopicFilterType.h" - -using std::string; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::PermName; -using rocketmq::TopicConfig; -using rocketmq::TopicFilterType; - -TEST(topicConfig, encodeAndDecode) { - TopicConfig topicConfig("testTopic", 4, 4, PermName::PERM_READ); - string str = topicConfig.encode(); - - TopicConfig topicDecodeConfig; - topicDecodeConfig.decode(str); - EXPECT_EQ(str, topicDecodeConfig.encode()); -} - -TEST(topicConfig, info) { - TopicConfig topicConfig; - - topicConfig.setTopicName("testTopic"); - EXPECT_EQ(topicConfig.getTopicName(), "testTopic"); - - topicConfig.setReadQueueNums(4); - EXPECT_EQ(topicConfig.getReadQueueNums(), 4); - - topicConfig.setWriteQueueNums(4); - EXPECT_EQ(topicConfig.getWriteQueueNums(), 4); - - topicConfig.setPerm(PermName::PERM_READ); - EXPECT_EQ(topicConfig.getPerm(), PermName::PERM_READ); - - topicConfig.setTopicFilterType(TopicFilterType::MULTI_TAG); - EXPECT_EQ(topicConfig.getTopicFilterType(), TopicFilterType::MULTI_TAG); -} - -TEST(topicConfig, init) { - TopicConfig topicConfig; - EXPECT_TRUE(topicConfig.getTopicName() == ""); - EXPECT_EQ(topicConfig.getReadQueueNums(), TopicConfig::DefaultReadQueueNums); - EXPECT_EQ(topicConfig.getWriteQueueNums(), TopicConfig::DefaultWriteQueueNums); - EXPECT_EQ(topicConfig.getPerm(), PermName::PERM_READ | PermName::PERM_WRITE); - EXPECT_EQ(topicConfig.getTopicFilterType(), TopicFilterType::SINGLE_TAG); - - TopicConfig twoTopicConfig("testTopic"); - EXPECT_EQ(twoTopicConfig.getTopicName(), "testTopic"); - EXPECT_EQ(twoTopicConfig.getReadQueueNums(), TopicConfig::DefaultReadQueueNums); - EXPECT_EQ(twoTopicConfig.getWriteQueueNums(), TopicConfig::DefaultWriteQueueNums); - EXPECT_EQ(twoTopicConfig.getPerm(), PermName::PERM_READ | PermName::PERM_WRITE); - EXPECT_EQ(twoTopicConfig.getTopicFilterType(), TopicFilterType::SINGLE_TAG); - - TopicConfig threeTopicConfig("testTopic", 4, 4, PermName::PERM_READ); - EXPECT_EQ(threeTopicConfig.getTopicName(), "testTopic"); - EXPECT_EQ(threeTopicConfig.getReadQueueNums(), 4); - EXPECT_EQ(threeTopicConfig.getWriteQueueNums(), 4); - EXPECT_EQ(threeTopicConfig.getPerm(), PermName::PERM_READ); - EXPECT_EQ(threeTopicConfig.getTopicFilterType(), TopicFilterType::SINGLE_TAG); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "topicConfig.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/common/UrlTest.cpp b/test/src/common/UrlTest.cpp deleted file mode 100644 index 636c2dee2..000000000 --- a/test/src/common/UrlTest.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include "CCommon.h" -#include "CMQException.h" -#include "CMessage.h" -#include "CProducer.h" -#include "CSendResult.h" -#include "TopicConfig.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "url.h" - -#include - -#include -#include "CCommon.h" -#include "CMQException.h" -#include "CMessage.h" -#include "CProducer.h" -#include "CSendResult.h" - -using namespace std; -using rocketmq::TopicConfig; -using rocketmq::Url; -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -class MockTopicConfig : public TopicConfig { - public: - MOCK_METHOD0(getReadQueueNums, int()); -}; - -TEST(Url, Url) { - Url url_s("172.17.0.2:9876"); - EXPECT_EQ(url_s.protocol_, "172.17.0.2:9876"); - - Url url_z("https://www.aliyun.com/RocketMQ?5.0"); - EXPECT_EQ(url_z.protocol_, "https"); - EXPECT_EQ(url_z.host_, "www.aliyun.com"); - EXPECT_EQ(url_z.port_, "80"); - EXPECT_EQ(url_z.path_, "/RocketMQ"); - EXPECT_EQ(url_z.query_, "5.0"); - - Url url_path("https://www.aliyun.com:9876/RocketMQ?5.0"); - EXPECT_EQ(url_path.port_, "9876"); - MockTopicConfig topicConfig; - EXPECT_CALL(topicConfig, getReadQueueNums()).WillRepeatedly(Return(-1)); - int nums = topicConfig.getReadQueueNums(); - cout << nums << endl; -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(filter) = "Url.Url"; - int itestts = RUN_ALL_TESTS(); - ; - return itestts; -} diff --git a/test/src/common/UtilAllTest.cpp b/test/src/common/UtilAllTest.cpp deleted file mode 100644 index 86e1130fb..000000000 --- a/test/src/common/UtilAllTest.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "UtilAll.h" - -using std::string; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::UtilAll; - -TEST(UtilAll, startsWith_retry) { - string source = "testTopic"; - string retrySource = "%RETRY%testTopic"; - string noRetrySource = "%DLQ%testTopic"; - EXPECT_TRUE(UtilAll::startsWith_retry(retrySource)); - EXPECT_FALSE(UtilAll::startsWith_retry(source)); - EXPECT_FALSE(UtilAll::startsWith_retry(noRetrySource)); -} -TEST(UtilAll, getRetryTopic) { - string source = "testTopic"; - string retrySource = "%RETRY%testTopic"; - EXPECT_EQ(UtilAll::getRetryTopic(source), retrySource); -} -TEST(UtilAll, Trim) { - string source = "testTopic"; - string preSource = " testTopic"; - string surSource = "testTopic "; - string allSource = " testTopic "; - UtilAll::Trim(preSource); - UtilAll::Trim(surSource); - UtilAll::Trim(allSource); - EXPECT_EQ(preSource, source); - EXPECT_EQ(surSource, source); - EXPECT_EQ(allSource, source); -} -TEST(UtilAll, hexstr2ull) { - const char* a = "1"; - const char* b = "FF"; - const char* c = "1a"; - const char* d = "101"; - EXPECT_EQ(UtilAll::hexstr2ull(a), 1); - EXPECT_EQ(UtilAll::hexstr2ull(b), 255); - EXPECT_EQ(UtilAll::hexstr2ull(c), 26); - EXPECT_EQ(UtilAll::hexstr2ull(d), 257); -} -TEST(UtilAll, SplitURL) { - string source = "127.0.0.1"; - string source1 = "127.0.0.1:0"; - string source2 = "127.0.0.1:9876"; - string addr; - string addr1; - string addr2; - short port; - EXPECT_FALSE(UtilAll::SplitURL(source, addr, port)); - EXPECT_FALSE(UtilAll::SplitURL(source1, addr1, port)); - EXPECT_TRUE(UtilAll::SplitURL(source2, addr2, port)); - EXPECT_EQ(addr2, "127.0.0.1"); - EXPECT_EQ(port, 9876); -} -TEST(UtilAll, SplitOne) { - string source = "127.0.0.1:9876"; - vector ret; - EXPECT_EQ(UtilAll::Split(ret, source, '.'), 4); - EXPECT_EQ(ret[0], "127"); -} -TEST(UtilAll, SplitStr) { - string source = "11AA222AA3333AA44444AA5"; - vector ret; - EXPECT_EQ(UtilAll::Split(ret, source, "AA"), 5); - EXPECT_EQ(ret[0], "11"); -} -TEST(UtilAll, StringToInt32) { - string source = "123"; - int value; - EXPECT_TRUE(UtilAll::StringToInt32(source, value)); - EXPECT_EQ(123, value); - EXPECT_FALSE(UtilAll::StringToInt32("123456789X123456789", value)); - EXPECT_FALSE(UtilAll::StringToInt32("-1234567890123456789", value)); - EXPECT_FALSE(UtilAll::StringToInt32("1234567890123456789", value)); -} -TEST(UtilAll, StringToInt64) { - string source = "123"; - int64_t value; - EXPECT_TRUE(UtilAll::StringToInt64(source, value)); - EXPECT_EQ(123, value); - EXPECT_FALSE(UtilAll::StringToInt64("XXXXXXXXXXX", value)); - EXPECT_FALSE(UtilAll::StringToInt64("123456789X123456789", value)); - EXPECT_EQ(123456789, value); - EXPECT_FALSE(UtilAll::StringToInt64("-123456789012345678901234567890123456789012345678901234567890", value)); - EXPECT_FALSE(UtilAll::StringToInt64("123456789012345678901234567890123456789012345678901234567890", value)); -} -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "UtilAll.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/common/ValidatorsTest.cpp b/test/src/common/ValidatorsTest.cpp deleted file mode 100644 index 23594cdd3..000000000 --- a/test/src/common/ValidatorsTest.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "string.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "MQClientException.h" -#include "MQMessage.h" -#include "Validators.h" - -using std::string; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::MQClientException; -using rocketmq::MQMessage; -using rocketmq::Validators; - -TEST(validators, regularExpressionMatcher) { - EXPECT_FALSE(Validators::regularExpressionMatcher(string(), string())); - - EXPECT_TRUE(Validators::regularExpressionMatcher(string("123456"), string())); - - EXPECT_TRUE(Validators::regularExpressionMatcher(string("123456"), string("123"))); -} - -TEST(validators, getGroupWithRegularExpression) { - EXPECT_EQ(Validators::getGroupWithRegularExpression(string(), string()), ""); -} - -TEST(validators, checkTopic) { - EXPECT_THROW(Validators::checkTopic(string()), MQClientException); - string exceptionTopic = "1234567890"; - for (int i = 0; i < 25; i++) { - exceptionTopic.append("1234567890"); - } - EXPECT_THROW(Validators::checkTopic(exceptionTopic), MQClientException); - - EXPECT_THROW(Validators::checkTopic("TBW102"), MQClientException); -} - -TEST(validators, checkGroup) { - EXPECT_THROW(Validators::checkGroup(string()), MQClientException); - string exceptionTopic = "1234567890"; - for (int i = 0; i < 25; i++) { - exceptionTopic.append("1234567890"); - } - EXPECT_THROW(Validators::checkGroup(exceptionTopic), MQClientException); -} - -TEST(validators, checkMessage) { - MQMessage message("testTopic", string()); - - EXPECT_THROW(Validators::checkMessage(MQMessage("testTopic", string()), 1), MQClientException); - - EXPECT_THROW(Validators::checkMessage(MQMessage("testTopic", string("123")), 2), MQClientException); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "validators.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/common/VirtualEnvUtilTest.cpp b/test/src/common/VirtualEnvUtilTest.cpp deleted file mode 100644 index 1300c90d5..000000000 --- a/test/src/common/VirtualEnvUtilTest.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "string.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "VirtualEnvUtil.h" - -using std::string; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::VirtualEnvUtil; - -TEST(virtualEnvUtil, buildWithProjectGroup) { - string origin = "origin"; - string originWithGroupA = "origin%PROJECT_testGroupA%"; - string originWithGroupB = "origin%PROJECT_testGroupB%"; - string originWithGroupAB = "origin%PROJECT_testGroupA%%PROJECT_testGroupB%"; - string projectGroupA = "testGroupA"; - string projectGroupB = "testGroupB"; - EXPECT_EQ(VirtualEnvUtil::buildWithProjectGroup(origin, string()), origin); - EXPECT_EQ(VirtualEnvUtil::buildWithProjectGroup(origin, projectGroupA), originWithGroupA); - EXPECT_EQ(VirtualEnvUtil::buildWithProjectGroup(originWithGroupA, projectGroupA), originWithGroupA); - EXPECT_EQ(VirtualEnvUtil::buildWithProjectGroup(originWithGroupA, projectGroupB), originWithGroupAB); -} - -TEST(virtualEnvUtil, clearProjectGroup) { - string origin = "origin"; - string originWithGroup = "origin%PROJECT_testGroup%"; - string projectGroup = "testGroup"; - string projectGroupB = "testGroupB"; - EXPECT_EQ(VirtualEnvUtil::clearProjectGroup(origin, string()), origin); - EXPECT_EQ(VirtualEnvUtil::clearProjectGroup(originWithGroup, string()), originWithGroup); - EXPECT_EQ(VirtualEnvUtil::clearProjectGroup(originWithGroup, projectGroupB), originWithGroup); - EXPECT_EQ(VirtualEnvUtil::clearProjectGroup(origin, projectGroup), origin); - EXPECT_EQ(VirtualEnvUtil::clearProjectGroup(originWithGroup, projectGroup), origin); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "virtualEnvUtil.*"; - int iTest = RUN_ALL_TESTS(); - return iTest; -} diff --git a/test/src/common/big_endianTest.cpp b/test/src/common/big_endianTest.cpp deleted file mode 100644 index 06432d2b0..000000000 --- a/test/src/common/big_endianTest.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "big_endian.h" - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::BigEndianReader; -using rocketmq::BigEndianWriter; - -TEST(big_endian, bigEndianObject) { - char* buf = (char*)malloc(sizeof(char) * 32); - - BigEndianWriter writer(buf, 32); - BigEndianReader reader(buf, 32); - - uint8_t* unit8 = (uint8_t*)malloc(sizeof(uint8_t)); - EXPECT_TRUE(writer.WriteU8((uint8_t)12)); - EXPECT_TRUE(reader.ReadU8(unit8)); - EXPECT_EQ(*unit8, 12); - free(unit8); - - uint16_t* unit16 = (uint16_t*)malloc(sizeof(uint16_t)); - EXPECT_TRUE(writer.WriteU16((uint16_t)1200)); - EXPECT_TRUE(reader.ReadU16(unit16)); - EXPECT_EQ(*unit16, 1200); - free(unit16); - - uint32_t* unit32 = (uint32_t*)malloc(sizeof(uint32_t)); - - EXPECT_TRUE(writer.WriteU32((uint32_t)120000)); - EXPECT_TRUE(reader.ReadU32(unit32)); - EXPECT_EQ(*unit32, 120000); - free(unit32); - - uint64_t* unit64 = (uint64_t*)malloc(sizeof(uint64_t)); - - EXPECT_TRUE(writer.WriteU64((uint64_t)120000)); - EXPECT_TRUE(reader.ReadU64(unit64)); - EXPECT_EQ(*unit64, 120000); - free(unit64); - - char* newBuf = (char*)malloc(sizeof(char) * 8); - char* writeBuf = (char*)malloc(sizeof(char) * 8); - strncpy(writeBuf, "RocketMQ", 8); - EXPECT_TRUE(writer.WriteBytes(writeBuf, (size_t)8)); - EXPECT_TRUE(reader.ReadBytes(newBuf, (size_t)8)); - EXPECT_EQ(*writeBuf, *newBuf); - - free(newBuf); - free(writeBuf); -} - -TEST(big_endian, bigEndian) { - char writeBuf[8]; - - /*TODO - char *newBuf = (char *) malloc(sizeof(char) * 8); - strncpy(newBuf, "RocketMQ", 8); - - char readBuf[8]; - rocketmq::WriteBigEndian(writeBuf, newBuf); - rocketmq::ReadBigEndian(writeBuf, readBuf); - EXPECT_EQ(writeBuf, readBuf); - */ - - rocketmq::WriteBigEndian(writeBuf, (uint8_t)12); - uint8_t* out = (uint8_t*)malloc(sizeof(uint8_t)); - rocketmq::ReadBigEndian(writeBuf, out); - EXPECT_EQ(*out, 12); - free(out); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "big_endian.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/consumer/DefaultMQPushConsumerImplTest.cpp b/test/src/consumer/DefaultMQPushConsumerImplTest.cpp deleted file mode 100644 index cfdc95fc6..000000000 --- a/test/src/consumer/DefaultMQPushConsumerImplTest.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "ConsumeMessageContext.h" -#include "ConsumeMessageHookImpl.h" -#include "DefaultMQProducerImpl.h" -#include "DefaultMQPushConsumerImpl.h" -#include "MQMessageExt.h" -#include "MQMessageQueue.h" - -using namespace std; -using namespace rocketmq; -using rocketmq::DefaultMQProducerImpl; -using rocketmq::DefaultMQPushConsumerImpl; -using testing::_; -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -class MockDefaultMQProducerImpl : public DefaultMQProducerImpl { - public: - MockDefaultMQProducerImpl(const string& groupId) : DefaultMQProducerImpl(groupId) {} - MOCK_METHOD3(send, void(MQMessage&, SendCallback*, bool)); -}; -TEST(DefaultMQPushConsumerImplTest, init) { - DefaultMQPushConsumerImpl* impl = new DefaultMQPushConsumerImpl("testMQConsumerGroup"); - EXPECT_EQ(impl->getGroupName(), "testMQConsumerGroup"); - impl->setUnitName("testUnit"); - EXPECT_EQ(impl->getUnitName(), "testUnit"); - impl->setTcpTransportPullThreadNum(64); - EXPECT_EQ(impl->getTcpTransportPullThreadNum(), 64); - impl->setTcpTransportConnectTimeout(2000); - EXPECT_EQ(impl->getTcpTransportConnectTimeout(), 2000); - impl->setTcpTransportTryLockTimeout(3000); - EXPECT_EQ(impl->getTcpTransportTryLockTimeout(), 3); - impl->setNamesrvAddr("http://rocketmq.nameserver.com"); - EXPECT_EQ(impl->getNamesrvAddr(), "rocketmq.nameserver.com"); - impl->setNameSpace("MQ_INST_NAMESPACE_TEST"); - EXPECT_EQ(impl->getNameSpace(), "MQ_INST_NAMESPACE_TEST"); - impl->setMessageTrace(true); - EXPECT_TRUE(impl->getMessageTrace()); - impl->setAsyncPull(true); - - impl->setConsumeMessageBatchMaxSize(3000); - EXPECT_EQ(impl->getConsumeMessageBatchMaxSize(), 3000); - - impl->setConsumeThreadCount(3); - EXPECT_EQ(impl->getConsumeThreadCount(), 3); - - impl->setMaxReconsumeTimes(30); - EXPECT_EQ(impl->getMaxReconsumeTimes(), 30); - - impl->setMaxCacheMsgSizePerQueue(3000); - EXPECT_EQ(impl->getMaxCacheMsgSizePerQueue(), 3000); - - impl->setPullMsgThreadPoolCount(10); - EXPECT_EQ(impl->getPullMsgThreadPoolCount(), 10); -} - -TEST(DefaultMQPushConsumerImpl, Trace) { - DefaultMQPushConsumerImpl* impl = new DefaultMQPushConsumerImpl(); - MockDefaultMQProducerImpl* implProducer = new MockDefaultMQProducerImpl("testMockProducerTraceGroup"); - std::shared_ptr hook(new ConsumeMessageHookImpl()); - impl->setMessageTrace(true); - impl->setDefaultMqProducerImpl(implProducer); - impl->registerConsumeMessageHook(hook); - EXPECT_CALL(*implProducer, send(_, _, _)).WillRepeatedly(Return()); - - ConsumeMessageContext consumeMessageContext; - MQMessageQueue messageQueue("TestTopic", "BrokerA", 0); - MQMessageExt messageExt; - messageExt.setMsgId("MessageID"); - messageExt.setKeys("MessageKey"); - vector msgs; - consumeMessageContext.setDefaultMQPushConsumer(impl); - consumeMessageContext.setConsumerGroup("testMockProducerTraceGroup"); - consumeMessageContext.setMessageQueue(messageQueue); - consumeMessageContext.setMsgList(msgs); - consumeMessageContext.setSuccess(false); - consumeMessageContext.setNameSpace("NameSpace"); - impl->executeConsumeMessageHookBefore(&consumeMessageContext); - impl->executeConsumeMessageHookAfter(&consumeMessageContext); - - msgs.push_back(messageExt); - consumeMessageContext.setMsgList(msgs); - - impl->executeConsumeMessageHookBefore(&consumeMessageContext); - - consumeMessageContext.setMsgIndex(0); - consumeMessageContext.setStatus("CONSUME_SUCCESS"); - consumeMessageContext.setSuccess(true); - impl->executeConsumeMessageHookAfter(&consumeMessageContext); - EXPECT_TRUE(impl->hasConsumeMessageHook()); - delete implProducer; -} -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/test/src/extern/CMessageExtTest.cpp b/test/src/extern/CMessageExtTest.cpp deleted file mode 100644 index 386054a54..000000000 --- a/test/src/extern/CMessageExtTest.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "CCommon.h" -#include "CMessageExt.h" -#include "MQMessageExt.h" - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::MQMessageExt; - -TEST(cmessageExt, info) { - MQMessageExt* mqMessageExt = new MQMessageExt(); - CMessageExt* messageExt = (CMessageExt*)mqMessageExt; - - mqMessageExt->setTopic("testTopic"); - EXPECT_EQ(GetMessageTopic(messageExt), mqMessageExt->getTopic()); - - mqMessageExt->setTags("testTags"); - EXPECT_EQ(GetMessageTags(messageExt), mqMessageExt->getTags()); - - mqMessageExt->setKeys("testKeys"); - EXPECT_EQ(GetMessageKeys(messageExt), mqMessageExt->getKeys()); - - std::string body("testBody"); - body.append(3, '\0'); - mqMessageExt->setBody(body.c_str(), body.length()); - std::string retrieved_body(GetMessageBody(messageExt), GetMessageBodyLength(messageExt)); - EXPECT_TRUE(body == retrieved_body); - - mqMessageExt->setProperty("testKey", "testValues"); - EXPECT_EQ(GetMessageProperty(messageExt, "testKey"), mqMessageExt->getProperty("testKey")); - - mqMessageExt->setMsgId("msgId123456"); - EXPECT_EQ(GetMessageId(messageExt), mqMessageExt->getMsgId()); - - mqMessageExt->setDelayTimeLevel(1); - EXPECT_EQ(GetMessageDelayTimeLevel(messageExt), mqMessageExt->getDelayTimeLevel()); - - mqMessageExt->setQueueId(4); - EXPECT_EQ(GetMessageQueueId(messageExt), mqMessageExt->getQueueId()); - - mqMessageExt->setReconsumeTimes(1234567); - EXPECT_EQ(GetMessageReconsumeTimes(messageExt), mqMessageExt->getReconsumeTimes()); - - mqMessageExt->setStoreSize(127); - EXPECT_EQ(GetMessageStoreSize(messageExt), mqMessageExt->getStoreSize()); - - mqMessageExt->setBornTimestamp(9876543); - EXPECT_EQ(GetMessageBornTimestamp(messageExt), mqMessageExt->getBornTimestamp()); - - mqMessageExt->setStoreTimestamp(123123); - EXPECT_EQ(GetMessageStoreTimestamp(messageExt), mqMessageExt->getStoreTimestamp()); - - mqMessageExt->setQueueOffset(1024); - EXPECT_EQ(GetMessageQueueOffset(messageExt), mqMessageExt->getQueueOffset()); - - mqMessageExt->setCommitLogOffset(2048); - EXPECT_EQ(GetMessageCommitLogOffset(messageExt), mqMessageExt->getCommitLogOffset()); - - mqMessageExt->setPreparedTransactionOffset(4096); - EXPECT_EQ(GetMessagePreparedTransactionOffset(messageExt), mqMessageExt->getPreparedTransactionOffset()); - - delete mqMessageExt; -} - -TEST(cmessageExt, null) { - EXPECT_TRUE(GetMessageTopic(NULL) == NULL); - EXPECT_TRUE(GetMessageTags(NULL) == NULL); - EXPECT_TRUE(GetMessageKeys(NULL) == NULL); - EXPECT_TRUE(GetMessageBody(NULL) == NULL); - EXPECT_TRUE(GetMessageProperty(NULL, NULL) == NULL); - EXPECT_TRUE(GetMessageId(NULL) == NULL); - EXPECT_EQ(GetMessageDelayTimeLevel(NULL), NULL_POINTER); - EXPECT_EQ(GetMessageQueueId(NULL), NULL_POINTER); - EXPECT_EQ(GetMessageReconsumeTimes(NULL), NULL_POINTER); - EXPECT_EQ(GetMessageStoreSize(NULL), NULL_POINTER); - EXPECT_EQ(GetMessageBornTimestamp(NULL), NULL_POINTER); - EXPECT_EQ(GetMessageStoreTimestamp(NULL), NULL_POINTER); - EXPECT_EQ(GetMessageQueueOffset(NULL), NULL_POINTER); - EXPECT_EQ(GetMessageCommitLogOffset(NULL), NULL_POINTER); - EXPECT_EQ(GetMessagePreparedTransactionOffset(NULL), NULL_POINTER); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(filter) = "cmessageExt.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/extern/CMessageTest.cpp b/test/src/extern/CMessageTest.cpp deleted file mode 100644 index 4ac24f1bc..000000000 --- a/test/src/extern/CMessageTest.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "CCommon.h" -#include "CMessage.h" -#include "MQMessage.h" - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::MQMessage; - -TEST(cmessages, originMessage) { - CMessage* message = CreateMessage(NULL); - EXPECT_STREQ(GetOriginMessageTopic(message), ""); - - SetMessageTopic(message, "testTopic"); - EXPECT_STREQ(GetOriginMessageTopic(message), "testTopic"); - - SetMessageTags(message, "testTags"); - EXPECT_STREQ(GetOriginMessageTags(message), "testTags"); - - SetMessageKeys(message, "testKeys"); - EXPECT_STREQ(GetOriginMessageKeys(message), "testKeys"); - - std::string body("test_body"); - body.append(3, '\0'); - SetByteMessageBody(message, body.c_str(), body.length()); - std::string retrieved_body(GetOriginMessageBody(message), GetOriginMessageBodyLength(message)); - EXPECT_TRUE(body == retrieved_body); - - SetMessageProperty(message, "testKey", "testValue"); - EXPECT_STREQ(GetOriginMessageProperty(message, "testKey"), "testValue"); - - SetDelayTimeLevel(message, 1); - EXPECT_EQ(GetOriginDelayTimeLevel(message), 1); - - EXPECT_EQ(DestroyMessage(message), OK); - - CMessage* message2 = CreateMessage("testTwoTopic"); - EXPECT_STREQ(GetOriginMessageTopic(message2), "testTwoTopic"); - - EXPECT_EQ(DestroyMessage(message2), OK); -} - -TEST(cmessages, info) { - CMessage* message = CreateMessage(NULL); - MQMessage* mqMessage = (MQMessage*)message; - EXPECT_EQ(mqMessage->getTopic(), ""); - - SetMessageTopic(message, "testTopic"); - EXPECT_EQ(mqMessage->getTopic(), "testTopic"); - - SetMessageTags(message, "testTags"); - EXPECT_EQ(mqMessage->getTags(), "testTags"); - - SetMessageKeys(message, "testKeys"); - EXPECT_EQ(mqMessage->getKeys(), "testKeys"); - - SetMessageBody(message, "testBody"); - EXPECT_EQ(mqMessage->getBody(), "testBody"); - - SetByteMessageBody(message, "testBody", 5); - EXPECT_EQ(mqMessage->getBody(), "testB"); - - SetMessageProperty(message, "testKey", "testValue"); - EXPECT_EQ(mqMessage->getProperty("testKey"), "testValue"); - - SetDelayTimeLevel(message, 1); - EXPECT_EQ(mqMessage->getDelayTimeLevel(), 1); - - EXPECT_EQ(DestroyMessage(message), OK); - - CMessage* twomessage = CreateMessage("testTwoTopic"); - MQMessage* twoMqMessage = (MQMessage*)twomessage; - EXPECT_EQ(twoMqMessage->getTopic(), "testTwoTopic"); - - EXPECT_EQ(DestroyMessage(twomessage), OK); -} - -TEST(cmessages, null) { - EXPECT_EQ(SetMessageTopic(NULL, NULL), NULL_POINTER); - EXPECT_EQ(SetMessageTags(NULL, NULL), NULL_POINTER); - EXPECT_EQ(SetMessageKeys(NULL, NULL), NULL_POINTER); - EXPECT_EQ(SetMessageBody(NULL, NULL), NULL_POINTER); - EXPECT_EQ(SetByteMessageBody(NULL, NULL, 0), NULL_POINTER); - EXPECT_EQ(SetMessageProperty(NULL, NULL, NULL), NULL_POINTER); - EXPECT_EQ(SetDelayTimeLevel(NULL, 0), NULL_POINTER); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - - // testing::GTEST_FLAG(filter) = "cmessages.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/extern/CProducerTest.cpp b/test/src/extern/CProducerTest.cpp deleted file mode 100644 index 9a5156fea..000000000 --- a/test/src/extern/CProducerTest.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "string.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "CMessage.h" -#include "CProducer.h" -#include "CSendResult.h" - -#include "AsyncCallback.h" -#include "DefaultMQProducer.h" -#include "MQMessage.h" -#include "MQMessageQueue.h" -#include "MQSelector.h" -#include "SendResult.h" -#include "SessionCredentials.h" - -using std::string; - -using ::testing::_; -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Mock; -using testing::Return; - -using rocketmq::DefaultMQProducer; -using rocketmq::elogLevel; -using rocketmq::MessageQueueSelector; -using rocketmq::MQMessage; -using rocketmq::MQMessageQueue; -using rocketmq::SendCallback; -using rocketmq::SendResult; -using rocketmq::SendStatus; -using rocketmq::SessionCredentials; - -class MockDefaultMQProducer : public DefaultMQProducer { - public: - MockDefaultMQProducer(const string& groupname) : DefaultMQProducer(groupname) {} - MOCK_METHOD0(start, void()); - MOCK_METHOD0(shutdown, void()); - MOCK_METHOD2(setLogFileSizeAndNum, void(int, long)); - MOCK_METHOD1(SetProducerLogLevel, void(elogLevel)); - MOCK_METHOD2(send, SendResult(MQMessage&, bool)); - MOCK_METHOD3(send, void(MQMessage&, SendCallback*, bool)); - MOCK_METHOD2(sendOneway, void(MQMessage&, bool)); - MOCK_METHOD5(send, SendResult(MQMessage&, MessageQueueSelector*, void*, int, bool)); -}; - -void CSendSuccessCallbackFunc(CSendResult result) {} -void cSendExceptionCallbackFunc(CMQException e) {} - -TEST(cProducer, SendMessageAsync) { - MockDefaultMQProducer* mockProducer = new MockDefaultMQProducer("testGroup"); - CProducer* cProducer = CreateProducer("testGroup"); - // cProducer= mockProducer; - DefaultMQProducer** aProducer = (DefaultMQProducer**)cProducer; - aProducer[0] = mockProducer; - CMessage* msg = (CMessage*)new MQMessage(); - - EXPECT_EQ(SendMessageAsync(NULL, NULL, NULL, NULL), NULL_POINTER); - EXPECT_EQ(SendMessageAsync(cProducer, NULL, NULL, NULL), NULL_POINTER); - EXPECT_EQ(SendMessageAsync(cProducer, msg, CSendSuccessCallbackFunc, NULL), NULL_POINTER); - - // EXPECT_CALL(*mockProducer, send(_, _)).Times(1); - EXPECT_EQ(SendMessageAsync(cProducer, msg, CSendSuccessCallbackFunc, cSendExceptionCallbackFunc), OK); - Mock::AllowLeak(mockProducer); - DestroyMessage(msg); -} - -int QueueSelectorCallbackFunc(int size, CMessage* msg, void* arg) { - return 0; -} - -TEST(cProducer, sendMessageOrderly) { - MockDefaultMQProducer* mockProducer = new MockDefaultMQProducer("testGroup"); - // CProducer* cProducer = (CProducer*)mockProducer; - CProducer* cProducer = CreateOrderlyProducer("testGroup"); - // cProducer= mockProducer; - DefaultMQProducer** aProducer = (DefaultMQProducer**)cProducer; - aProducer[0] = mockProducer; - CMessage* msg = (CMessage*)new MQMessage(); - MQMessageQueue messageQueue; - - EXPECT_EQ(SendMessageOrderly(NULL, NULL, NULL, msg, 1, NULL), NULL_POINTER); - EXPECT_EQ(SendMessageOrderly(cProducer, NULL, NULL, msg, 1, NULL), NULL_POINTER); - EXPECT_EQ(SendMessageOrderly(cProducer, msg, NULL, msg, 1, NULL), NULL_POINTER); - EXPECT_EQ(SendMessageOrderly(cProducer, msg, QueueSelectorCallbackFunc, NULL, 1, NULL), NULL_POINTER); - EXPECT_EQ(SendMessageOrderly(cProducer, msg, QueueSelectorCallbackFunc, msg, 1, NULL), NULL_POINTER); - - EXPECT_CALL(*mockProducer, send(_, _, _, _, _)) - .WillOnce(Return(SendResult(SendStatus::SEND_OK, "3", "offset1", messageQueue, 14))); - // EXPECT_EQ(SendMessageOrderly(cProducer, msg, callback, msg, 1, result), OK); - Mock::AllowLeak(mockProducer); - DestroyMessage(msg); - // free(result); -} - -TEST(cProducer, sendOneway) { - MockDefaultMQProducer* mockProducer = new MockDefaultMQProducer("testGroup"); - // CProducer* cProducer = (CProducer*)mockProducer; - CProducer* cProducer = CreateProducer("testGroup"); - // cProducer= mockProducer; - DefaultMQProducer** aProducer = (DefaultMQProducer**)cProducer; - aProducer[0] = mockProducer; - CMessage* msg = (CMessage*)new MQMessage(); - - EXPECT_EQ(SendMessageOneway(NULL, NULL), NULL_POINTER); - EXPECT_EQ(SendMessageOneway(cProducer, NULL), NULL_POINTER); - - EXPECT_CALL(*mockProducer, sendOneway(_, _)).Times(1); - EXPECT_EQ(SendMessageOneway(cProducer, msg), OK); - Mock::AllowLeak(mockProducer); - DestroyMessage(msg); -} - -TEST(cProducer, sendMessageSync) { - MockDefaultMQProducer* mockProducer = new MockDefaultMQProducer("testGroup"); - // CProducer* cProducer = (CProducer*)mockProducer; - CProducer* cProducer = CreateProducer("testGroup"); - // cProducer= mockProducer; - DefaultMQProducer** aProducer = (DefaultMQProducer**)cProducer; - aProducer[0] = mockProducer; - MQMessage* mqMessage = new MQMessage(); - CMessage* msg = (CMessage*)mqMessage; - CSendResult* result; - MQMessageQueue messageQueue; - EXPECT_EQ(SendMessageSync(NULL, NULL, NULL), NULL_POINTER); - EXPECT_EQ(SendMessageSync(cProducer, NULL, NULL), NULL_POINTER); - - EXPECT_EQ(SendMessageSync(cProducer, msg, NULL), NULL_POINTER); - - result = (CSendResult*)malloc(sizeof(CSendResult)); - - EXPECT_CALL(*mockProducer, send(_, _)) - .Times(5) - .WillOnce(Return(SendResult(SendStatus::SEND_FLUSH_DISK_TIMEOUT, "1", "offset1", messageQueue, 14))) - .WillOnce(Return(SendResult(SendStatus::SEND_FLUSH_SLAVE_TIMEOUT, "2", "offset1", messageQueue, 14))) - .WillOnce(Return(SendResult(SendStatus::SEND_SLAVE_NOT_AVAILABLE, "3", "offset1", messageQueue, 14))) - .WillOnce(Return(SendResult(SendStatus::SEND_OK, "3", "offset1", messageQueue, 14))) - .WillOnce(Return(SendResult((SendStatus)-1, "4", "offset1", messageQueue, 14))); - - EXPECT_EQ(SendMessageSync(cProducer, msg, result), OK); - EXPECT_EQ(result->sendStatus, E_SEND_FLUSH_DISK_TIMEOUT); - - EXPECT_EQ(SendMessageSync(cProducer, msg, result), OK); - EXPECT_EQ(result->sendStatus, E_SEND_FLUSH_SLAVE_TIMEOUT); - - EXPECT_EQ(SendMessageSync(cProducer, msg, result), OK); - EXPECT_EQ(result->sendStatus, E_SEND_SLAVE_NOT_AVAILABLE); - - EXPECT_EQ(SendMessageSync(cProducer, msg, result), OK); - EXPECT_EQ(result->sendStatus, E_SEND_OK); - - EXPECT_EQ(SendMessageSync(cProducer, msg, result), OK); - EXPECT_EQ(result->sendStatus, E_SEND_OK); - Mock::AllowLeak(mockProducer); - DestroyMessage(msg); - free(result); -} - -TEST(cProducer, infoMock) { - MockDefaultMQProducer* mockProducer = new MockDefaultMQProducer("testGroup"); - // CProducer* cProducer = (CProducer*)mockProducer; - CProducer* cProducer = CreateProducer("testGroup"); - // cProducer= mockProducer; - DefaultMQProducer** aProducer = (DefaultMQProducer**)cProducer; - aProducer[0] = mockProducer; - EXPECT_CALL(*mockProducer, start()).Times(1); - EXPECT_EQ(StartProducer(cProducer), OK); - - EXPECT_CALL(*mockProducer, shutdown()).Times(1); - EXPECT_EQ(ShutdownProducer(cProducer), OK); - - EXPECT_CALL(*mockProducer, setLogFileSizeAndNum(_, _)).Times(1); - EXPECT_EQ(SetProducerLogFileNumAndSize(cProducer, 1, 1), OK); - - EXPECT_CALL(*mockProducer, SetProducerLogLevel(_)).Times(1); - EXPECT_EQ(SetProducerLogLevel(cProducer, E_LOG_LEVEL_FATAL), OK); - Mock::AllowLeak(mockProducer); -} - -TEST(cProducer, info) { - CProducer* cProducer = CreateProducer("groupTest"); - // DefaultMQProducer* defaultMQProducer = (DefaultMQProducer*)cProducer; - DefaultMQProducer** aProducer = (DefaultMQProducer**)cProducer; - DefaultMQProducer* defaultMQProducer = aProducer[0]; - EXPECT_TRUE(cProducer != NULL); - EXPECT_EQ(defaultMQProducer->getGroupName(), "groupTest"); - - EXPECT_EQ(SetProducerNameServerAddress(cProducer, "127.0.0.1:9876"), OK); - EXPECT_EQ(defaultMQProducer->getNamesrvAddr(), "127.0.0.1:9876"); - - EXPECT_EQ(SetProducerNameServerDomain(cProducer, "domain"), OK); - EXPECT_EQ(defaultMQProducer->getNamesrvDomain(), "domain"); - - EXPECT_EQ(SetProducerGroupName(cProducer, "testGroup"), OK); - EXPECT_EQ(defaultMQProducer->getGroupName(), "testGroup"); - - EXPECT_EQ(SetProducerInstanceName(cProducer, "instance"), OK); - EXPECT_EQ(defaultMQProducer->getInstanceName(), "instance"); - - EXPECT_EQ(SetProducerSendMsgTimeout(cProducer, 1), OK); - EXPECT_EQ(defaultMQProducer->getSendMsgTimeout(), 1); - - EXPECT_EQ(SetProducerMaxMessageSize(cProducer, 2), OK); - EXPECT_EQ(defaultMQProducer->getMaxMessageSize(), 2); - - EXPECT_EQ(SetProducerCompressLevel(cProducer, 1), OK); - EXPECT_EQ(defaultMQProducer->getCompressLevel(), 1); - - EXPECT_EQ(SetProducerSessionCredentials(NULL, NULL, NULL, NULL), NULL_POINTER); - EXPECT_EQ(SetProducerSessionCredentials(cProducer, "accessKey", "secretKey", "channel"), OK); - SessionCredentials sessionCredentials = defaultMQProducer->getSessionCredentials(); - EXPECT_EQ(sessionCredentials.getAccessKey(), "accessKey"); - - EXPECT_EQ(SetProducerMessageTrace(cProducer, OPEN), OK); - EXPECT_EQ(defaultMQProducer->getMessageTrace(), true); - - Mock::AllowLeak(defaultMQProducer); -} - -TEST(cProducer, null) { - EXPECT_TRUE(CreateProducer(NULL) == NULL); - EXPECT_EQ(StartProducer(NULL), NULL_POINTER); - EXPECT_EQ(ShutdownProducer(NULL), NULL_POINTER); - EXPECT_EQ(SetProducerNameServerAddress(NULL, NULL), NULL_POINTER); - EXPECT_EQ(SetProducerNameServerDomain(NULL, NULL), NULL_POINTER); - EXPECT_EQ(SetProducerGroupName(NULL, NULL), NULL_POINTER); - EXPECT_EQ(SetProducerInstanceName(NULL, NULL), NULL_POINTER); - EXPECT_EQ(SetProducerSessionCredentials(NULL, NULL, NULL, NULL), NULL_POINTER); - EXPECT_EQ(SetProducerLogLevel(NULL, E_LOG_LEVEL_FATAL), NULL_POINTER); - EXPECT_EQ(SetProducerSendMsgTimeout(NULL, 1), NULL_POINTER); - EXPECT_EQ(SetProducerCompressLevel(NULL, 1), NULL_POINTER); - EXPECT_EQ(SetProducerMaxMessageSize(NULL, 2), NULL_POINTER); - EXPECT_EQ(SetProducerLogLevel(NULL, E_LOG_LEVEL_FATAL), NULL_POINTER); - EXPECT_EQ(DestroyProducer(NULL), NULL_POINTER); -} -TEST(cProducer, version) { - CProducer* cProducer = CreateProducer("groupTestVersion"); - EXPECT_TRUE(cProducer != NULL); - string version(ShowProducerVersion(cProducer)); - EXPECT_GT(version.length(), 0); - CProducer* cProducer2 = CreateOrderlyProducer("orderGroupTestVersion"); - EXPECT_TRUE(cProducer2 != NULL); - string version2(ShowProducerVersion(cProducer2)); - EXPECT_GT(version2.length(), 0); - - CProducer* cProducer3 = CreateTransactionProducer("tranGroupTestVersion", NULL, NULL); - EXPECT_TRUE(cProducer3 != NULL); - string version3(ShowProducerVersion(cProducer3)); - EXPECT_GT(version3.length(), 0); -} -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "cProducer.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/extern/CPullConsumerTest.cpp b/test/src/extern/CPullConsumerTest.cpp deleted file mode 100644 index a5459d9c3..000000000 --- a/test/src/extern/CPullConsumerTest.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "CCommon.h" -#include "CPullConsumer.h" - -#include "DefaultMQPullConsumer.h" -#include "MQClient.h" -#include "MQMessageExt.h" -#include "MQMessageQueue.h" -#include "PullResult.h" -#include "SessionCredentials.h" - -using std::string; -using std::vector; - -using ::testing::_; -using testing::Expectation; -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; -using testing::SetArgReferee; - -using rocketmq::DefaultMQPullConsumer; -using rocketmq::elogLevel; -using rocketmq::MessageModel; -using rocketmq::MQMessageExt; -using rocketmq::MQMessageQueue; -using rocketmq::PullResult; -using rocketmq::PullStatus; -using rocketmq::SessionCredentials; - -class MockDefaultMQPullConsumer : public DefaultMQPullConsumer { - public: - MockDefaultMQPullConsumer(const string& groupname) : DefaultMQPullConsumer(groupname) {} - MOCK_METHOD0(start, void()); - MOCK_METHOD0(shutdown, void()); - MOCK_METHOD2(setLogFileSizeAndNum, void(int, long)); - MOCK_METHOD1(setLogLevel, void(elogLevel)); - MOCK_METHOD2(fetchSubscribeMessageQueues, void(const string&, vector&)); - MOCK_METHOD4(pull, PullResult(const MQMessageQueue&, const string&, int64, int)); -}; - -TEST(cpullConsumer, pull) { - MockDefaultMQPullConsumer* mqPullConsumer = new MockDefaultMQPullConsumer("groudId"); - CPullConsumer* pullConsumer = (CPullConsumer*)mqPullConsumer; - - CMessageQueue cMessageQueue; - strncpy(cMessageQueue.topic, "testTopic", 8); - strncpy(cMessageQueue.brokerName, "testBroker", 9); - cMessageQueue.queueId = 1; - - PullResult timeOutPullResult(PullStatus::BROKER_TIMEOUT, 1, 2, 3); - - PullResult noNewMsgPullResult(PullStatus::NO_NEW_MSG, 1, 2, 3); - - PullResult noMatchedMsgPullResult(PullStatus::NO_MATCHED_MSG, 1, 2, 3); - - PullResult offsetIllegalPullResult(PullStatus::OFFSET_ILLEGAL, 1, 2, 3); - - PullResult defaultPullResult((PullStatus)-1, 1, 2, 3); - - vector src; - for (int i = 0; i < 5; i++) { - MQMessageExt ext; - src.push_back(ext); - } - - PullResult foundPullResult(PullStatus::FOUND, 1, 2, 3, src); - EXPECT_CALL(*mqPullConsumer, pull(_, _, _, _)) - .WillOnce(Return(timeOutPullResult)) - .WillOnce(Return(noNewMsgPullResult)) - .WillOnce(Return(noMatchedMsgPullResult)) - .WillOnce(Return(offsetIllegalPullResult)) - .WillOnce(Return(defaultPullResult)) - //.WillOnce(Return(timeOutPullResult)) //will not called - .WillOnce(Return(foundPullResult)); - CPullResult timeOutcPullResult = Pull(pullConsumer, &cMessageQueue, "123123", 0, 0); - EXPECT_EQ(timeOutcPullResult.pullStatus, E_BROKER_TIMEOUT); - CPullResult noNewMsgcPullResult = Pull(pullConsumer, &cMessageQueue, "123123", 0, 0); - EXPECT_EQ(noNewMsgcPullResult.pullStatus, E_NO_NEW_MSG); - - CPullResult noMatchedMsgcPullResult = Pull(pullConsumer, &cMessageQueue, "123123", 0, 0); - EXPECT_EQ(noMatchedMsgcPullResult.pullStatus, E_NO_MATCHED_MSG); - - CPullResult offsetIllegalcPullResult = Pull(pullConsumer, &cMessageQueue, "123123", 0, 0); - EXPECT_EQ(offsetIllegalcPullResult.pullStatus, E_OFFSET_ILLEGAL); - - CPullResult defaultcPullResult = Pull(pullConsumer, &cMessageQueue, "123123", 0, 0); - EXPECT_EQ(defaultcPullResult.pullStatus, E_NO_NEW_MSG); - CPullResult exceptionPullResult = Pull(pullConsumer, &cMessageQueue, NULL, 0, 0); - EXPECT_EQ(exceptionPullResult.pullStatus, E_BROKER_TIMEOUT); - CPullResult foundcPullResult = Pull(pullConsumer, &cMessageQueue, "123123", 0, 0); - EXPECT_EQ(foundcPullResult.pullStatus, E_FOUND); - - delete mqPullConsumer; -} - -TEST(cpullConsumer, infoMock) { - MockDefaultMQPullConsumer* mqPullConsumer = new MockDefaultMQPullConsumer("groudId"); - CPullConsumer* pullConsumer = (CPullConsumer*)mqPullConsumer; - - Expectation exp = EXPECT_CALL(*mqPullConsumer, start()).Times(1); - EXPECT_EQ(StartPullConsumer(pullConsumer), OK); - - EXPECT_CALL(*mqPullConsumer, shutdown()).Times(1); - EXPECT_EQ(ShutdownPullConsumer(pullConsumer), OK); - - // EXPECT_CALL(*mqPullConsumer,setLogFileSizeAndNum(_,_)).Times(1); - EXPECT_EQ(SetPullConsumerLogFileNumAndSize(pullConsumer, 1, 2), OK); - - // EXPECT_CALL(*mqPullConsumer,setLogLevel(_)).Times(1); - EXPECT_EQ(SetPullConsumerLogLevel(pullConsumer, E_LOG_LEVEL_INFO), OK); - - std::vector fullMQ; - for (int i = 0; i < 5; i++) { - MQMessageQueue queue("testTopic", "testsBroker", i); - fullMQ.push_back(queue); - } - - EXPECT_CALL(*mqPullConsumer, fetchSubscribeMessageQueues(_, _)).Times(1).WillOnce(SetArgReferee<1>(fullMQ)); - CMessageQueue* mqs = NULL; - int size = 0; - FetchSubscriptionMessageQueues(pullConsumer, "testTopic", &mqs, &size); - EXPECT_EQ(size, 5); - - delete mqPullConsumer; -} - -TEST(cpullConsumer, init) { - CPullConsumer* pullConsumer = CreatePullConsumer("testGroupId"); - DefaultMQPullConsumer* defaultMQPullConsumer = (DefaultMQPullConsumer*)pullConsumer; - EXPECT_FALSE(pullConsumer == NULL); - - EXPECT_EQ(SetPullConsumerGroupID(pullConsumer, "groupId"), OK); - EXPECT_EQ(GetPullConsumerGroupID(pullConsumer), defaultMQPullConsumer->getGroupName().c_str()); - - EXPECT_EQ(SetPullConsumerNameServerAddress(pullConsumer, "127.0.0.1:10091"), OK); - EXPECT_EQ(defaultMQPullConsumer->getNamesrvAddr(), "127.0.0.1:10091"); - - EXPECT_EQ(SetPullConsumerNameServerDomain(pullConsumer, "domain"), OK); - EXPECT_EQ(defaultMQPullConsumer->getNamesrvDomain(), "domain"); - - EXPECT_EQ(SetPullConsumerSessionCredentials(pullConsumer, "accessKey", "secretKey", "channel"), OK); - SessionCredentials sessionCredentials = defaultMQPullConsumer->getSessionCredentials(); - EXPECT_EQ(sessionCredentials.getAccessKey(), "accessKey"); - - EXPECT_EQ(SetPullConsumerLogPath(pullConsumer, ""), OK); - - // EXPECT_EQ(SetPullConsumerLogFileNumAndSize(pullConsumer,NULL,NULL),NULL_POINTER); - EXPECT_EQ(SetPullConsumerLogLevel(pullConsumer, E_LOG_LEVEL_DEBUG), OK); -} - -TEST(cpullConsumer, null) { - CPullConsumer* pullConsumer = CreatePullConsumer("testGroupId"); - DefaultMQPullConsumer* defaultMQPullConsumer = (DefaultMQPullConsumer*)pullConsumer; - EXPECT_FALSE(pullConsumer == NULL); - - EXPECT_EQ(SetPullConsumerGroupID(pullConsumer, "groupId"), OK); - EXPECT_EQ(GetPullConsumerGroupID(pullConsumer), defaultMQPullConsumer->getGroupName().c_str()); - - EXPECT_EQ(SetPullConsumerNameServerAddress(pullConsumer, "127.0.0.1:10091"), OK); - EXPECT_EQ(defaultMQPullConsumer->getNamesrvAddr(), "127.0.0.1:10091"); - - EXPECT_EQ(SetPullConsumerNameServerDomain(pullConsumer, "domain"), OK); - EXPECT_EQ(defaultMQPullConsumer->getNamesrvDomain(), "domain"); - - EXPECT_EQ(SetPullConsumerSessionCredentials(pullConsumer, "accessKey", "secretKey", "channel"), OK); - SessionCredentials sessionCredentials = defaultMQPullConsumer->getSessionCredentials(); - EXPECT_EQ(sessionCredentials.getAccessKey(), "accessKey"); - - EXPECT_EQ(SetPullConsumerLogPath(pullConsumer, ""), OK); - // EXPECT_EQ(SetPullConsumerLogFileNumAndSize(pullConsumer,NULL,NULL),NULL_POINTER); - EXPECT_EQ(SetPullConsumerLogLevel(pullConsumer, E_LOG_LEVEL_DEBUG), OK); - EXPECT_EQ(DestroyPullConsumer(pullConsumer), OK); - EXPECT_EQ(StartPullConsumer(NULL), NULL_POINTER); - EXPECT_EQ(ShutdownPullConsumer(NULL), NULL_POINTER); -} -TEST(cpullConsumer, version) { - CPullConsumer* pullConsumer = CreatePullConsumer("groupTestVersion"); - EXPECT_TRUE(pullConsumer != NULL); - string version(ShowPullConsumerVersion(pullConsumer)); - EXPECT_GT(version.length(), 0); -} -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "cpullConsumer.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/extern/CPushConsumerTest.cpp b/test/src/extern/CPushConsumerTest.cpp deleted file mode 100644 index 6b516ab84..000000000 --- a/test/src/extern/CPushConsumerTest.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "string.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "CPushConsumer.h" - -#include "ConsumeType.h" -#include "DefaultMQPushConsumer.h" -#include "MQMessageListener.h" -#include "SessionCredentials.h" - -using std::string; - -using ::testing::_; -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Mock; -using testing::Return; - -using rocketmq::DefaultMQPushConsumer; -using rocketmq::elogLevel; -using rocketmq::MessageListenerType; -using rocketmq::MessageModel; -using rocketmq::SessionCredentials; - -class MockDefaultMQPushConsumer : public DefaultMQPushConsumer { - public: - MockDefaultMQPushConsumer(const string& groupname) : DefaultMQPushConsumer(groupname) {} - - MOCK_METHOD0(start, void()); - MOCK_METHOD0(shutdown, void()); - MOCK_METHOD2(setLogFileSizeAndNum, void(int, long)); - MOCK_METHOD1(setLogLevel, void(elogLevel)); -}; - -TEST(cPushComsumer, infomock) { - MockDefaultMQPushConsumer* pushComsumer = new MockDefaultMQPushConsumer("testGroup"); - CPushConsumer* consumer = (CPushConsumer*)pushComsumer; - - EXPECT_CALL(*pushComsumer, start()).Times(1); - EXPECT_EQ(StartPushConsumer(consumer), OK); - - EXPECT_CALL(*pushComsumer, shutdown()).Times(1); - EXPECT_EQ(ShutdownPushConsumer(consumer), OK); - - EXPECT_CALL(*pushComsumer, setLogFileSizeAndNum(1, 1)).Times(1); - pushComsumer->setLogFileSizeAndNum(1, 1); - EXPECT_EQ(SetPushConsumerLogFileNumAndSize(consumer, 1, 1), OK); - - // EXPECT_CALL(*pushComsumer,setLogLevel(_)).Times(1); - EXPECT_EQ(SetPushConsumerLogLevel(consumer, E_LOG_LEVEL_FATAL), OK); - - Mock::AllowLeak(pushComsumer); -} - -int MessageCallBackFunc(CPushConsumer* consumer, CMessageExt* msg) { - return 0; -} - -TEST(cPushComsumer, info) { - CPushConsumer* cpushConsumer = CreatePushConsumer("testGroup"); - DefaultMQPushConsumer* mqPushConsumer = (DefaultMQPushConsumer*)cpushConsumer; - - EXPECT_TRUE(cpushConsumer != NULL); - EXPECT_EQ(string(GetPushConsumerGroupID(cpushConsumer)), "testGroup"); - - EXPECT_EQ(SetPushConsumerGroupID(cpushConsumer, "testGroupTwo"), OK); - EXPECT_EQ(string(GetPushConsumerGroupID(cpushConsumer)), "testGroupTwo"); - - EXPECT_EQ(SetPushConsumerNameServerAddress(cpushConsumer, "127.0.0.1:9876"), OK); - EXPECT_EQ(mqPushConsumer->getNamesrvAddr(), "127.0.0.1:9876"); - - EXPECT_EQ(SetPushConsumerNameServerDomain(cpushConsumer, "domain"), OK); - EXPECT_EQ(mqPushConsumer->getNamesrvDomain(), "domain"); - - EXPECT_EQ(Subscribe(cpushConsumer, "testTopic", "testSub"), OK); - - EXPECT_EQ(RegisterMessageCallbackOrderly(cpushConsumer, MessageCallBackFunc), OK); - EXPECT_EQ(mqPushConsumer->getMessageListenerType(), MessageListenerType::messageListenerOrderly); - - EXPECT_EQ(RegisterMessageCallback(cpushConsumer, MessageCallBackFunc), OK); - EXPECT_EQ(mqPushConsumer->getMessageListenerType(), MessageListenerType::messageListenerConcurrently); - - EXPECT_EQ(UnregisterMessageCallbackOrderly(cpushConsumer), OK); - EXPECT_EQ(UnregisterMessageCallback(cpushConsumer), OK); - - EXPECT_EQ(SetPushConsumerThreadCount(cpushConsumer, 10), OK); - EXPECT_EQ(mqPushConsumer->getConsumeThreadCount(), 10); - - EXPECT_EQ(SetPushConsumerMessageBatchMaxSize(cpushConsumer, 1024), OK); - EXPECT_EQ(mqPushConsumer->getConsumeMessageBatchMaxSize(), 1024); - - EXPECT_EQ(SetPushConsumerInstanceName(cpushConsumer, "instance"), OK); - EXPECT_EQ(mqPushConsumer->getInstanceName(), "instance"); - - EXPECT_EQ(SetPushConsumerSessionCredentials(cpushConsumer, "accessKey", "secretKey", "channel"), OK); - SessionCredentials sessionCredentials = mqPushConsumer->getSessionCredentials(); - EXPECT_EQ(sessionCredentials.getAccessKey(), "accessKey"); - - EXPECT_EQ(SetPushConsumerMessageModel(cpushConsumer, BROADCASTING), OK); - EXPECT_EQ(mqPushConsumer->getMessageModel(), MessageModel::BROADCASTING); - - EXPECT_EQ(SetPushConsumerMessageTrace(cpushConsumer, CLOSE), OK); - EXPECT_EQ(mqPushConsumer->getMessageTrace(), false); - Mock::AllowLeak(mqPushConsumer); -} - -TEST(cPushComsumer, null) { - CPushConsumer* cpushConsumer = CreatePushConsumer("testGroup"); - - EXPECT_TRUE(CreatePushConsumer(NULL) == NULL); - EXPECT_EQ(DestroyPushConsumer(NULL), NULL_POINTER); - EXPECT_EQ(StartPushConsumer(NULL), NULL_POINTER); - EXPECT_EQ(ShutdownPushConsumer(NULL), NULL_POINTER); - EXPECT_EQ(SetPushConsumerGroupID(NULL, "testGroup"), NULL_POINTER); - EXPECT_TRUE(GetPushConsumerGroupID(NULL) == NULL); - EXPECT_EQ(SetPushConsumerNameServerAddress(NULL, NULL), NULL_POINTER); - EXPECT_EQ(SetPushConsumerNameServerDomain(NULL, NULL), NULL_POINTER); - EXPECT_EQ(Subscribe(NULL, NULL, NULL), NULL_POINTER); - EXPECT_EQ(RegisterMessageCallbackOrderly(NULL, NULL), NULL_POINTER); - EXPECT_EQ(RegisterMessageCallbackOrderly(cpushConsumer, NULL), NULL_POINTER); - EXPECT_EQ(RegisterMessageCallback(NULL, NULL), NULL_POINTER); - EXPECT_EQ(UnregisterMessageCallbackOrderly(NULL), NULL_POINTER); - EXPECT_EQ(UnregisterMessageCallback(NULL), NULL_POINTER); - EXPECT_EQ(SetPushConsumerThreadCount(NULL, 0), NULL_POINTER); - EXPECT_EQ(SetPushConsumerMessageBatchMaxSize(NULL, 0), NULL_POINTER); - EXPECT_EQ(SetPushConsumerInstanceName(NULL, NULL), NULL_POINTER); - EXPECT_EQ(SetPushConsumerSessionCredentials(NULL, NULL, NULL, NULL), NULL_POINTER); - EXPECT_EQ(SetPushConsumerLogPath(NULL, NULL), NULL_POINTER); - EXPECT_EQ(SetPushConsumerLogFileNumAndSize(NULL, 1, 1), NULL_POINTER); - EXPECT_EQ(SetPushConsumerLogLevel(NULL, E_LOG_LEVEL_LEVEL_NUM), NULL_POINTER); - EXPECT_EQ(SetPushConsumerMessageModel(NULL, BROADCASTING), NULL_POINTER); -} -TEST(cPushComsumer, version) { - CPushConsumer* pushConsumer = CreatePushConsumer("groupTestVersion"); - EXPECT_TRUE(pushConsumer != NULL); - string version(ShowPushConsumerVersion(pushConsumer)); - EXPECT_GT(version.length(), 0); -} -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(filter) = "cPushComsumer.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/message/BatchMessageTest.cpp b/test/src/message/BatchMessageTest.cpp deleted file mode 100644 index 789e09bfe..000000000 --- a/test/src/message/BatchMessageTest.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "gtest/gtest.h" -#include "gmock/gmock.h" -#include -#include -#include -#include "BatchMessage.h" -#include "MQMessage.h" -#include - -using namespace std; -using namespace rocketmq; -using ::testing::InitGoogleTest; -using ::testing::InitGoogleMock; -using testing::Return; - -TEST(BatchMessageEncodeTest, encodeMQMessage) { - MQMessage msg1("topic", "*", "test"); - // const map& properties = msg1.getProperties(); - // for (auto& pair : properties) { - // std::cout << pair.first << " : " << pair.second << std::endl; - //} - - EXPECT_EQ(msg1.getProperties().size(), 2); - EXPECT_EQ(msg1.getBody().size(), 4); - // 20 + bodyLen + 2 + propertiesLength; - string encodeMessage = BatchMessage::encode(msg1); - EXPECT_EQ(encodeMessage.size(), 43); - - msg1.setProperty(MQMessage::PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX, "1"); - encodeMessage = BatchMessage::encode(msg1); - EXPECT_EQ(encodeMessage.size(), 54); -} - -TEST(BatchMessageEncodeTest, encodeMQMessages) { - std::vector msgs; - MQMessage msg1("topic", "*", "test1"); - // const map& properties = msg1.getProperties(); - // for (auto& pair : properties) { - // std::cout << pair.first << " : " << pair.second << std::endl; - //} - msgs.push_back(msg1); - // 20 + bodyLen + 2 + propertiesLength; - string encodeMessage = BatchMessage::encode(msgs); - EXPECT_EQ(encodeMessage.size(), 86); - MQMessage msg2("topic", "*", "test2"); - MQMessage msg3("topic", "*", "test3"); - msgs.push_back(msg2); - msgs.push_back(msg3); - encodeMessage = BatchMessage::encode(msgs); - EXPECT_EQ(encodeMessage.size(), 258); // 86*3 -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/test/src/message/MQDecoderTest.cpp b/test/src/message/MQDecoderTest.cpp deleted file mode 100644 index a92ba10fb..000000000 --- a/test/src/message/MQDecoderTest.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "MemoryInputStream.h" -#include "MemoryOutputStream.h" - -#include "CommandHeader.h" -#include "MQDecoder.h" -#include "MQMessage.h" -#include "MQMessageExt.h" -#include "MQMessageId.h" -#include "MessageSysFlag.h" -#include "RemotingCommand.h" -#include "UtilAll.h" - -using namespace std; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::MemoryBlock; -using rocketmq::MemoryInputStream; -using rocketmq::MemoryOutputStream; -using rocketmq::MessageSysFlag; -using rocketmq::MQDecoder; -using rocketmq::MQMessage; -using rocketmq::MQMessageExt; -using rocketmq::MQMessageId; -using rocketmq::RemotingCommand; -using rocketmq::SendMessageRequestHeader; -using rocketmq::UtilAll; - -// TODO -TEST(decoder, messageId) { - int host; - int port; - int64 offset = 1234567890; - string msgIdStr = - MQDecoder::createMessageId(rocketmq::IPPort2socketAddress(ntohl(inet_addr("127.0.0.1")), 10091), offset); - MQMessageId msgId = MQDecoder::decodeMessageId(msgIdStr); - - EXPECT_EQ(msgId.getOffset(), offset); - - rocketmq::socketAddress2IPPort(msgId.getAddress(), host, port); - EXPECT_EQ(host, ntohl(inet_addr("127.0.0.1"))); - EXPECT_EQ(port, 10091); -} - -TEST(decoder, decoder) { - MQMessageExt mext; - MemoryOutputStream* memoryOut = new MemoryOutputStream(1024); - - // 1 TOTALSIZE 4 - memoryOut->writeIntBigEndian(107); - mext.setStoreSize(107); - - // 2 MAGICCODE sizeof(int) 8=4+4 - memoryOut->writeIntBigEndian(14); - - // 3 BODYCRC 12=8+4 - memoryOut->writeIntBigEndian(24); - mext.setBodyCRC(24); - // 4 QUEUEID 16=12+4 - memoryOut->writeIntBigEndian(4); - mext.setQueueId(4); - // 5 FLAG 20=16+4 - memoryOut->writeIntBigEndian(4); - mext.setFlag(4); - // 6 QUEUEOFFSET 28 = 20+8 - memoryOut->writeInt64BigEndian((int64)1024); - mext.setQueueOffset(1024); - // 7 PHYSICALOFFSET 36=28+8 - memoryOut->writeInt64BigEndian((int64)2048); - mext.setCommitLogOffset(2048); - // 8 SYSFLAG 40=36+4 - memoryOut->writeIntBigEndian(0); - mext.setSysFlag(0); - // 9 BORNTIMESTAMP 48 = 40+8 - memoryOut->writeInt64BigEndian((int64)4096); - mext.setBornTimestamp(4096); - // 10 BORNHOST 56= 48+8 - memoryOut->writeIntBigEndian(ntohl(inet_addr("127.0.0.1"))); - memoryOut->writeIntBigEndian(10091); - mext.setBornHost(rocketmq::IPPort2socketAddress(ntohl(inet_addr("127.0.0.1")), 10091)); - // 11 STORETIMESTAMP 64 =56+8 - memoryOut->writeInt64BigEndian((int64)4096); - mext.setStoreTimestamp(4096); - // 12 STOREHOST 72 = 64+8 - memoryOut->writeIntBigEndian(ntohl(inet_addr("127.0.0.2"))); - memoryOut->writeIntBigEndian(10092); - mext.setStoreHost(rocketmq::IPPort2socketAddress(ntohl(inet_addr("127.0.0.2")), 10092)); - // 13 RECONSUMETIMES 76 = 72+4 - mext.setReconsumeTimes(111111); - memoryOut->writeIntBigEndian(mext.getReconsumeTimes()); - // 14 Prepared Transaction Offset 84 = 76+8 - memoryOut->writeInt64BigEndian((int64)12); - mext.setPreparedTransactionOffset(12); - // 15 BODY 88 = 84+4 10 - string* body = new string("1234567890"); - mext.setBody(body->c_str()); - memoryOut->writeIntBigEndian(10); - memoryOut->write(body->c_str(), body->size()); - - // 16 TOPIC - memoryOut->writeByte(10); - memoryOut->write(body->c_str(), body->size()); - mext.setTopic(body->c_str()); - - // 17 PROPERTIES - memoryOut->writeShortBigEndian(0); - - mext.setMsgId(MQDecoder::createMessageId(mext.getStoreHost(), (int64)mext.getCommitLogOffset())); - - vector mqvec; - MemoryBlock block = memoryOut->getMemoryBlock(); - MQDecoder::decodes(&block, mqvec); - EXPECT_EQ(mqvec.size(), 1); - std::cout << mext.toString() << "\n"; - std::cout << mqvec[0].toString() << "\n"; - EXPECT_EQ(mqvec[0].toString(), mext.toString()); - - mqvec.clear(); - MQDecoder::decodes(&block, mqvec, false); - EXPECT_FALSE(mqvec[0].getBody().size()); - - //=============================================================== - // 8 SYSFLAG 40=36+4 - mext.setSysFlag(0 | MessageSysFlag::CompressedFlag); - memoryOut->setPosition(36); - memoryOut->writeIntBigEndian(mext.getSysFlag()); - - // 15 Body 84 - string outBody; - string boody("123123123"); - UtilAll::deflate(boody, outBody, 5); - mext.setBody(outBody); - - memoryOut->setPosition(84); - memoryOut->writeIntBigEndian(outBody.size()); - memoryOut->write(outBody.c_str(), outBody.size()); - - // 16 TOPIC - memoryOut->writeByte(10); - memoryOut->write(body->c_str(), body->size()); - mext.setTopic(body->c_str()); - - // 17 PROPERTIES - map properties; - properties["RocketMQ"] = "cpp-client"; - properties[MQMessage::PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX] = "123456"; - mext.setProperties(properties); - mext.setMsgId("123456"); - - string proString = MQDecoder::messageProperties2String(properties); - - memoryOut->writeShortBigEndian(proString.size()); - memoryOut->write(proString.c_str(), proString.size()); - - mext.setStoreSize(memoryOut->getDataSize()); - memoryOut->setPosition(0); - memoryOut->writeIntBigEndian(mext.getStoreSize()); - - block = memoryOut->getMemoryBlock(); - MQDecoder::decodes(&block, mqvec); - EXPECT_EQ(mqvec[0].toString(), mext.toString()); -} - -TEST(decoder, messagePropertiesAndToString) { - map properties; - properties["RocketMQ"] = "cpp-client"; - string proString = MQDecoder::messageProperties2String(properties); - - map newProperties; - MQDecoder::string2messageProperties(proString, newProperties); - EXPECT_EQ(properties, newProperties); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - - testing::GTEST_FLAG(filter) = "decoder.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/message/MQMessageExtTest.cpp b/test/src/message/MQMessageExtTest.cpp deleted file mode 100644 index a1f989afa..000000000 --- a/test/src/message/MQMessageExtTest.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "MQMessageExt.h" -#include "MessageSysFlag.h" -#include "SocketUtil.h" -#include "TopicFilterType.h" - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::MessageSysFlag; -using rocketmq::MQMessageExt; -using rocketmq::TopicFilterType; - -TEST(messageExt, init) { - MQMessageExt messageExt; - EXPECT_EQ(messageExt.getQueueOffset(), 0); - EXPECT_EQ(messageExt.getCommitLogOffset(), 0); - EXPECT_EQ(messageExt.getBornTimestamp(), 0); - EXPECT_EQ(messageExt.getStoreTimestamp(), 0); - EXPECT_EQ(messageExt.getPreparedTransactionOffset(), 0); - EXPECT_EQ(messageExt.getQueueId(), 0); - EXPECT_EQ(messageExt.getStoreSize(), 0); - EXPECT_EQ(messageExt.getReconsumeTimes(), 3); - EXPECT_EQ(messageExt.getBodyCRC(), 0); - EXPECT_EQ(messageExt.getMsgId(), ""); - EXPECT_EQ(messageExt.getOffsetMsgId(), ""); - - messageExt.setQueueOffset(1); - EXPECT_EQ(messageExt.getQueueOffset(), 1); - - messageExt.setCommitLogOffset(1024); - EXPECT_EQ(messageExt.getCommitLogOffset(), 1024); - - messageExt.setBornTimestamp(1024); - EXPECT_EQ(messageExt.getBornTimestamp(), 1024); - - messageExt.setStoreTimestamp(2048); - EXPECT_EQ(messageExt.getStoreTimestamp(), 2048); - - messageExt.setPreparedTransactionOffset(4096); - EXPECT_EQ(messageExt.getPreparedTransactionOffset(), 4096); - - messageExt.setQueueId(2); - EXPECT_EQ(messageExt.getQueueId(), 2); - - messageExt.setStoreSize(12); - EXPECT_EQ(messageExt.getStoreSize(), 12); - - messageExt.setReconsumeTimes(48); - EXPECT_EQ(messageExt.getReconsumeTimes(), 48); - - messageExt.setBodyCRC(32); - EXPECT_EQ(messageExt.getBodyCRC(), 32); - - messageExt.setMsgId("MsgId"); - EXPECT_EQ(messageExt.getMsgId(), "MsgId"); - - messageExt.setOffsetMsgId("offsetMsgId"); - EXPECT_EQ(messageExt.getOffsetMsgId(), "offsetMsgId"); - - messageExt.setBornTimestamp(1111); - EXPECT_EQ(messageExt.getBornTimestamp(), 1111); - - messageExt.setStoreTimestamp(2222); - EXPECT_EQ(messageExt.getStoreTimestamp(), 2222); - - struct sockaddr_in sa; - sa.sin_family = AF_INET; - sa.sin_port = htons(10091); - sa.sin_addr.s_addr = inet_addr("127.0.0.1"); - - sockaddr bornHost; - memcpy(&bornHost, &sa, sizeof(sockaddr)); - - messageExt.setBornHost(bornHost); - EXPECT_EQ(messageExt.getBornHostNameString(), rocketmq::getHostName(bornHost)); - EXPECT_EQ(messageExt.getBornHostString(), rocketmq::socketAddress2String(bornHost)); - - struct sockaddr_in storeSa; - storeSa.sin_family = AF_INET; - storeSa.sin_port = htons(10092); - storeSa.sin_addr.s_addr = inet_addr("127.0.0.2"); - - sockaddr storeHost; - memcpy(&storeHost, &storeSa, sizeof(sockaddr)); - messageExt.setStoreHost(storeHost); - EXPECT_EQ(messageExt.getStoreHostString(), rocketmq::socketAddress2String(storeHost)); - - MQMessageExt twoMessageExt(2, 1024, bornHost, 2048, storeHost, "msgId"); - EXPECT_EQ(twoMessageExt.getQueueOffset(), 0); - EXPECT_EQ(twoMessageExt.getCommitLogOffset(), 0); - EXPECT_EQ(twoMessageExt.getBornTimestamp(), 1024); - EXPECT_EQ(twoMessageExt.getStoreTimestamp(), 2048); - EXPECT_EQ(twoMessageExt.getPreparedTransactionOffset(), 0); - EXPECT_EQ(twoMessageExt.getQueueId(), 2); - EXPECT_EQ(twoMessageExt.getStoreSize(), 0); - EXPECT_EQ(twoMessageExt.getReconsumeTimes(), 3); - EXPECT_EQ(twoMessageExt.getBodyCRC(), 0); - EXPECT_EQ(twoMessageExt.getMsgId(), "msgId"); - EXPECT_EQ(twoMessageExt.getOffsetMsgId(), ""); - - EXPECT_EQ(twoMessageExt.getBornHostNameString(), rocketmq::getHostName(bornHost)); - EXPECT_EQ(twoMessageExt.getBornHostString(), rocketmq::socketAddress2String(bornHost)); - - EXPECT_EQ(twoMessageExt.getStoreHostString(), rocketmq::socketAddress2String(storeHost)); - - EXPECT_EQ(MQMessageExt::parseTopicFilterType(MessageSysFlag::MultiTagsFlag), TopicFilterType::MULTI_TAG); - - EXPECT_EQ(MQMessageExt::parseTopicFilterType(0), TopicFilterType::SINGLE_TAG); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - - testing::GTEST_FLAG(filter) = "messageExt.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/message/MQMessageIdTest.cpp b/test/src/message/MQMessageIdTest.cpp deleted file mode 100644 index 6e97480f8..000000000 --- a/test/src/message/MQMessageIdTest.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include - -#include "MQMessageId.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -using namespace std; -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::MQMessageId; - -TEST(messageId, id) { - int host; - int port; - sockaddr addr = rocketmq::IPPort2socketAddress(inet_addr("127.0.0.1"), 10091); - MQMessageId id(addr, 1024); - - rocketmq::socketAddress2IPPort(id.getAddress(), host, port); - EXPECT_EQ(host, inet_addr("127.0.0.1")); - EXPECT_EQ(port, 10091); - EXPECT_EQ(id.getOffset(), 1024); - - id.setAddress(rocketmq::IPPort2socketAddress(inet_addr("127.0.0.2"), 10092)); - id.setOffset(2048); - - rocketmq::socketAddress2IPPort(id.getAddress(), host, port); - EXPECT_EQ(host, inet_addr("127.0.0.2")); - EXPECT_EQ(port, 10092); - EXPECT_EQ(id.getOffset(), 2048); - - MQMessageId id2 = id; - EXPECT_EQ(id2.getOffset(), 2048); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - - testing::GTEST_FLAG(filter) = "messageId.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/message/MQMessageQueueTest.cpp b/test/src/message/MQMessageQueueTest.cpp deleted file mode 100644 index c1c542dd7..000000000 --- a/test/src/message/MQMessageQueueTest.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "MQMessageQueue.h" - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::MQMessageQueue; - -TEST(messageQueue, init) { - MQMessageQueue messageQueue; - EXPECT_EQ(messageQueue.getBrokerName(), ""); - EXPECT_EQ(messageQueue.getTopic(), ""); - EXPECT_EQ(messageQueue.getQueueId(), -1); - - MQMessageQueue twoMessageQueue("testTopic", "testBroker", 1); - EXPECT_EQ(twoMessageQueue.getBrokerName(), "testBroker"); - EXPECT_EQ(twoMessageQueue.getTopic(), "testTopic"); - EXPECT_EQ(twoMessageQueue.getQueueId(), 1); - - MQMessageQueue threeMessageQueue("threeTestTopic", "threeTestBroker", 2); - MQMessageQueue frouMessageQueue(threeMessageQueue); - EXPECT_EQ(frouMessageQueue.getBrokerName(), "threeTestBroker"); - EXPECT_EQ(frouMessageQueue.getTopic(), "threeTestTopic"); - EXPECT_EQ(frouMessageQueue.getQueueId(), 2); - - frouMessageQueue = twoMessageQueue; - EXPECT_EQ(frouMessageQueue.getBrokerName(), "testBroker"); - EXPECT_EQ(frouMessageQueue.getTopic(), "testTopic"); - EXPECT_EQ(frouMessageQueue.getQueueId(), 1); - - frouMessageQueue.setBrokerName("frouTestBroker"); - frouMessageQueue.setTopic("frouTestTopic"); - frouMessageQueue.setQueueId(4); - EXPECT_EQ(frouMessageQueue.getBrokerName(), "frouTestBroker"); - EXPECT_EQ(frouMessageQueue.getTopic(), "frouTestTopic"); - EXPECT_EQ(frouMessageQueue.getQueueId(), 4); -} - -TEST(messageQueue, operators) { - MQMessageQueue messageQueue; - EXPECT_EQ(messageQueue, messageQueue); - EXPECT_EQ(messageQueue.compareTo(messageQueue), 0); - - MQMessageQueue twoMessageQueue; - EXPECT_EQ(messageQueue, twoMessageQueue); - EXPECT_EQ(messageQueue.compareTo(twoMessageQueue), 0); - - twoMessageQueue.setTopic("testTopic"); - EXPECT_FALSE(messageQueue == twoMessageQueue); - EXPECT_FALSE(messageQueue.compareTo(twoMessageQueue) == 0); - - twoMessageQueue.setQueueId(1); - EXPECT_FALSE(messageQueue == twoMessageQueue); - EXPECT_FALSE(messageQueue.compareTo(twoMessageQueue) == 0); - - twoMessageQueue.setBrokerName("testBroker"); - EXPECT_FALSE(messageQueue == twoMessageQueue); - EXPECT_FALSE(messageQueue.compareTo(twoMessageQueue) == 0); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - - testing::GTEST_FLAG(filter) = "messageQueue.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/message/MQMessageTest.cpp b/test/src/message/MQMessageTest.cpp deleted file mode 100644 index 0f55cbb29..000000000 --- a/test/src/message/MQMessageTest.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include - -#include -#include - -#include "MQMessage.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -using namespace std; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::MQMessage; - -TEST(message, Init) { - MQMessage messageOne; - EXPECT_EQ(messageOne.getTopic(), ""); - EXPECT_EQ(messageOne.getBody(), ""); - EXPECT_EQ(messageOne.getTags(), ""); - EXPECT_EQ(messageOne.getFlag(), 0); - - MQMessage messageTwo("test", "testBody"); - EXPECT_EQ(messageTwo.getTopic(), "test"); - EXPECT_EQ(messageTwo.getBody(), "testBody"); - EXPECT_EQ(messageTwo.getTags(), ""); - EXPECT_EQ(messageTwo.getFlag(), 0); - - MQMessage messageThree("test", "tagTest", "testBody"); - EXPECT_EQ(messageThree.getTopic(), "test"); - EXPECT_EQ(messageThree.getBody(), "testBody"); - EXPECT_EQ(messageThree.getTags(), "tagTest"); - EXPECT_EQ(messageThree.getFlag(), 0); - - MQMessage messageFour("test", "tagTest", "testKey", "testBody"); - EXPECT_EQ(messageFour.getTopic(), "test"); - EXPECT_EQ(messageFour.getBody(), "testBody"); - EXPECT_EQ(messageFour.getTags(), "tagTest"); - EXPECT_EQ(messageFour.getKeys(), "testKey"); - EXPECT_EQ(messageFour.getFlag(), 0); - - MQMessage messageFive("test", "tagTest", "testKey", 1, "testBody", 2); - EXPECT_EQ(messageFive.getTopic(), "test"); - EXPECT_EQ(messageFive.getBody(), "testBody"); - EXPECT_EQ(messageFive.getTags(), "tagTest"); - EXPECT_EQ(messageFive.getKeys(), "testKey"); - EXPECT_EQ(messageFive.getFlag(), 1); - - MQMessage messageSix(messageFive); - EXPECT_EQ(messageSix.getTopic(), "test"); - EXPECT_EQ(messageSix.getBody(), "testBody"); - EXPECT_EQ(messageSix.getTags(), "tagTest"); - EXPECT_EQ(messageSix.getKeys(), "testKey"); - EXPECT_EQ(messageSix.getFlag(), 1); - - MQMessage messageSeven = messageSix; - EXPECT_EQ(messageSeven.getTopic(), "test"); - EXPECT_EQ(messageSeven.getBody(), "testBody"); - EXPECT_EQ(messageSeven.getTags(), "tagTest"); - EXPECT_EQ(messageSeven.getKeys(), "testKey"); - EXPECT_EQ(messageSeven.getFlag(), 1); -} - -TEST(message, info) { - MQMessage message; - - EXPECT_EQ(message.getTopic(), ""); - message.setTopic("testTopic"); - EXPECT_EQ(message.getTopic(), "testTopic"); - string topic = "testTopic"; - const char* ctopic = topic.c_str(); - message.setTopic(ctopic, 5); - EXPECT_EQ(message.getTopic(), "testT"); - - EXPECT_EQ(message.getBody(), ""); - message.setBody("testBody"); - EXPECT_EQ(message.getBody(), "testBody"); - - string body = "testBody"; - const char* b = body.c_str(); - message.setBody(b, 5); - EXPECT_EQ(message.getBody(), "testB"); - - string tags(message.getTags()); - EXPECT_EQ(tags, ""); - EXPECT_EQ(message.getFlag(), 0); - message.setFlag(2); - EXPECT_EQ(message.getFlag(), 2); - - EXPECT_EQ(message.isWaitStoreMsgOK(), true); - message.setWaitStoreMsgOK(false); - EXPECT_EQ(message.isWaitStoreMsgOK(), false); - message.setWaitStoreMsgOK(true); - EXPECT_EQ(message.isWaitStoreMsgOK(), true); - - string keys(message.getTags()); - EXPECT_EQ(keys, ""); - message.setKeys("testKeys"); - EXPECT_EQ(message.getKeys(), "testKeys"); - - EXPECT_EQ(message.getDelayTimeLevel(), 0); - message.setDelayTimeLevel(1); - EXPECT_EQ(message.getDelayTimeLevel(), 1); - - message.setSysFlag(1); - EXPECT_EQ(message.getSysFlag(), 1); -} - -TEST(message, properties) { - MQMessage message; - EXPECT_EQ(message.getProperties().size(), 1); - EXPECT_STREQ(message.getProperty(MQMessage::PROPERTY_TRANSACTION_PREPARED).c_str(), ""); - - message.setProperty(MQMessage::PROPERTY_TRANSACTION_PREPARED, "true"); - EXPECT_EQ(message.getProperties().size(), 2); - EXPECT_EQ(message.getSysFlag(), 4); - EXPECT_EQ(message.getProperty(MQMessage::PROPERTY_TRANSACTION_PREPARED), "true"); - - message.setProperty(MQMessage::PROPERTY_TRANSACTION_PREPARED, "false"); - EXPECT_EQ(message.getProperties().size(), 2); - EXPECT_EQ(message.getSysFlag(), 0); - EXPECT_EQ(message.getProperty(MQMessage::PROPERTY_TRANSACTION_PREPARED), "false"); - - map newProperties; - - newProperties[MQMessage::PROPERTY_TRANSACTION_PREPARED] = "true"; - message.setProperties(newProperties); - EXPECT_EQ(message.getSysFlag(), 4); - EXPECT_EQ(message.getProperty(MQMessage::PROPERTY_TRANSACTION_PREPARED), "true"); - - newProperties[MQMessage::PROPERTY_TRANSACTION_PREPARED] = "false"; - message.setProperties(newProperties); - EXPECT_EQ(message.getSysFlag(), 0); - EXPECT_EQ(message.getProperty(MQMessage::PROPERTY_TRANSACTION_PREPARED), "false"); -} - -TEST(message, Keys) { - MQMessage message; - vector keys; - keys.push_back("abc"); - keys.push_back("efg"); - keys.push_back("hij"); - message.setKeys(keys); - EXPECT_EQ(message.getKeys(), "abc efg hij"); -} -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - - // testing::GTEST_FLAG(filter) = "message.info"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/producer/DefaultMQProducerImplTest.cpp b/test/src/producer/DefaultMQProducerImplTest.cpp deleted file mode 100644 index b54ec67cd..000000000 --- a/test/src/producer/DefaultMQProducerImplTest.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "DefaultMQProducerImpl.h" -#include "MQClientFactory.h" -#include "TopicPublishInfo.h" - -using namespace std; -using namespace rocketmq; -using rocketmq::DefaultMQProducerImpl; -using rocketmq::MQClientAPIImpl; -using rocketmq::MQClientFactory; -using rocketmq::TopicPublishInfo; -using testing::_; -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -class MySendCallback : public SendCallback { - virtual void onSuccess(SendResult& sendResult) {} - virtual void onException(MQException& e) {} -}; - -class MyMessageQueueSelector : public MessageQueueSelector { - virtual MQMessageQueue select(const std::vector& mqs, const MQMessage& msg, void* arg) { - return MQMessageQueue("TestTopic", "BrokerA", 0); - } -}; -class MockMQClientFactory : public MQClientFactory { - public: - MockMQClientFactory(const string& mqClientId) : MQClientFactory(mqClientId, true, DEFAULT_SSL_PROPERTY_FILE) {} - MOCK_METHOD0(start, void()); - MOCK_METHOD0(shutdown, void()); - MOCK_METHOD0(sendHeartbeatToAllBroker, void()); - MOCK_METHOD0(getMQClientAPIImpl, MQClientAPIImpl*()); - MOCK_METHOD1(registerProducer, bool(MQProducer*)); - MOCK_METHOD1(unregisterProducer, void(MQProducer*)); - MOCK_METHOD1(findBrokerAddressInPublish, string(const string&)); - MOCK_METHOD2(tryToFindTopicPublishInfo, - boost::shared_ptr(const string&, const SessionCredentials&)); -}; -class MockMQClientAPIImpl : public MQClientAPIImpl { - public: - MockMQClientAPIImpl() : MQClientAPIImpl("testMockMQClientAPIImpl", true, DEFAULT_SSL_PROPERTY_FILE) {} - - MOCK_METHOD9(sendMessage, - SendResult(const string&, - const string&, - const MQMessage&, - const SendMessageRequestHeader&, - int, - int, - int, - SendCallback*, - const SessionCredentials&)); -}; -TEST(DefaultMQProducerImplTest, init) { - DefaultMQProducerImpl* impl = new DefaultMQProducerImpl("testMQProducerGroup"); - EXPECT_EQ(impl->getGroupName(), "testMQProducerGroup"); - impl->setUnitName("testUnit"); - EXPECT_EQ(impl->getUnitName(), "testUnit"); - impl->setTcpTransportPullThreadNum(64); - EXPECT_EQ(impl->getTcpTransportPullThreadNum(), 64); - impl->setTcpTransportConnectTimeout(2000); - EXPECT_EQ(impl->getTcpTransportConnectTimeout(), 2000); - impl->setTcpTransportTryLockTimeout(3000); - // need fix the unit - EXPECT_EQ(impl->getTcpTransportTryLockTimeout(), 3); - impl->setRetryTimes4Async(4); - EXPECT_EQ(impl->getRetryTimes4Async(), 4); - impl->setRetryTimes(2); - EXPECT_EQ(impl->getRetryTimes(), 2); - impl->setSendMsgTimeout(1000); - EXPECT_EQ(impl->getSendMsgTimeout(), 1000); - impl->setCompressMsgBodyOverHowmuch(1024); - EXPECT_EQ(impl->getCompressMsgBodyOverHowmuch(), 1024); - impl->setCompressLevel(2); - EXPECT_EQ(impl->getCompressLevel(), 2); - impl->setMaxMessageSize(2048); - EXPECT_EQ(impl->getMaxMessageSize(), 2048); - - impl->setNamesrvAddr("http://rocketmq.nameserver.com"); - EXPECT_EQ(impl->getNamesrvAddr(), "rocketmq.nameserver.com"); - impl->setNameSpace("MQ_INST_NAMESPACE_TEST"); - EXPECT_EQ(impl->getNameSpace(), "MQ_INST_NAMESPACE_TEST"); - impl->setMessageTrace(true); - EXPECT_TRUE(impl->getMessageTrace()); -} -TEST(DefaultMQProducerImplTest, Sends) { - DefaultMQProducerImpl* impl = new DefaultMQProducerImpl("testMockSendMQProducerGroup"); - MockMQClientFactory* mockFactory = new MockMQClientFactory("testClientId"); - MockMQClientAPIImpl* apiImpl = new MockMQClientAPIImpl(); - - impl->setFactory(mockFactory); - impl->setNamesrvAddr("http://rocketmq.nameserver.com"); - - // prepare send - boost::shared_ptr topicPublishInfo = boost::make_shared(); - MQMessageQueue mqA("TestTopic", "BrokerA", 0); - MQMessageQueue mqB("TestTopic", "BrokerB", 0); - topicPublishInfo->updateMessageQueueList(mqA); - topicPublishInfo->updateMessageQueueList(mqB); - - SendResult okMQAResult(SEND_OK, "MSSAGEID", "OFFSETID", mqA, 1024, "DEFAULT_REGION", false); - SendResult okMQBResult(SEND_OK, "MSSAGEID", "OFFSETID", mqB, 2048); - okMQBResult.setRegionId("DEFAULT_REGION"); - okMQBResult.toString(); - SendResult errorMQBResult(SEND_SLAVE_NOT_AVAILABLE, "MSSAGEID", "OFFSETID", mqB, 2048); - - EXPECT_CALL(*mockFactory, start()).Times(1).WillOnce(Return()); - EXPECT_CALL(*mockFactory, shutdown()).Times(1).WillOnce(Return()); - EXPECT_CALL(*mockFactory, registerProducer(_)).Times(1).WillOnce(Return(true)); - EXPECT_CALL(*mockFactory, unregisterProducer(_)).Times(1).WillOnce(Return()); - EXPECT_CALL(*mockFactory, sendHeartbeatToAllBroker()).Times(1).WillOnce(Return()); - EXPECT_CALL(*mockFactory, tryToFindTopicPublishInfo(_, _)).WillRepeatedly(Return(topicPublishInfo)); - EXPECT_CALL(*mockFactory, findBrokerAddressInPublish(_)).WillRepeatedly(Return("BrokerA")); - EXPECT_CALL(*mockFactory, getMQClientAPIImpl()).WillRepeatedly(Return(apiImpl)); - - EXPECT_CALL(*apiImpl, sendMessage(_, _, _, _, _, _, _, _, _)) - .WillOnce(Return(okMQAResult)) - .WillOnce(Return(okMQBResult)) - .WillOnce(Return(errorMQBResult)) - .WillOnce(Return(okMQAResult)) - .WillOnce(Return(okMQAResult)) - .WillRepeatedly(Return(okMQAResult)); - - // Start Producer. - impl->start(); - - MQMessage msg("testTopic", "testTag", "testKey", "testBodysA"); - SendResult s1 = impl->send(msg); - EXPECT_EQ(s1.getSendStatus(), SEND_OK); - EXPECT_EQ(s1.getQueueOffset(), 1024); - SendResult s2 = impl->send(msg, mqB); - EXPECT_EQ(s2.getSendStatus(), SEND_OK); - EXPECT_EQ(s2.getQueueOffset(), 2048); - MessageQueueSelector* pSelect = new MyMessageQueueSelector(); - SendResult s3 = impl->send(msg, pSelect, nullptr, 3, true); - EXPECT_EQ(s3.getSendStatus(), SEND_OK); - EXPECT_EQ(s3.getQueueOffset(), 1024); - SendResult s33 = impl->send(msg, pSelect, nullptr); - EXPECT_EQ(s33.getSendStatus(), SEND_OK); - EXPECT_EQ(s33.getQueueOffset(), 1024); - - SendCallback* pCallback = new MySendCallback(); - EXPECT_NO_THROW(impl->send(msg, pCallback, true)); - EXPECT_NO_THROW(impl->send(msg, pSelect, nullptr, pCallback)); - EXPECT_NO_THROW(impl->send(msg, mqA, pCallback)); - - EXPECT_NO_THROW(impl->sendOneway(msg)); - EXPECT_NO_THROW(impl->sendOneway(msg, mqA)); - EXPECT_NO_THROW(impl->sendOneway(msg, pSelect, nullptr)); - - MQMessage msgB("testTopic", "testTag", "testKey", "testBodysB"); - vector msgs; - msgs.push_back(msg); - msgs.push_back(msgB); - SendResult s4 = impl->send(msgs); - EXPECT_EQ(s4.getSendStatus(), SEND_OK); - EXPECT_EQ(s4.getQueueOffset(), 1024); - SendResult s5 = impl->send(msgs, mqA); - EXPECT_EQ(s5.getSendStatus(), SEND_OK); - EXPECT_EQ(s5.getQueueOffset(), 1024); - - impl->shutdown(); - delete mockFactory; - delete apiImpl; -} -TEST(DefaultMQProducerImplTest, Trace) { - DefaultMQProducerImpl* impl = new DefaultMQProducerImpl("testMockProducerTraceGroup"); - MockMQClientFactory* mockFactory = new MockMQClientFactory("testTraceClientId"); - MockMQClientAPIImpl* apiImpl = new MockMQClientAPIImpl(); - - impl->setFactory(mockFactory); - impl->setNamesrvAddr("http://rocketmq.nameserver.com"); - impl->setMessageTrace(true); - - // prepare send - boost::shared_ptr topicPublishInfo = boost::make_shared(); - MQMessageQueue mqA("TestTraceTopic", "BrokerA", 0); - MQMessageQueue mqB("TestTraceTopic", "BrokerB", 0); - topicPublishInfo->updateMessageQueueList(mqA); - topicPublishInfo->updateMessageQueueList(mqB); - - SendResult okMQAResult(SEND_OK, "MSSAGEID", "OFFSETID", mqA, 1024, "DEFAULT_REGION", false); - - EXPECT_CALL(*mockFactory, start()).Times(1).WillOnce(Return()); - EXPECT_CALL(*mockFactory, shutdown()).Times(1).WillOnce(Return()); - EXPECT_CALL(*mockFactory, registerProducer(_)).Times(1).WillOnce(Return(true)); - EXPECT_CALL(*mockFactory, unregisterProducer(_)).Times(1).WillOnce(Return()); - EXPECT_CALL(*mockFactory, sendHeartbeatToAllBroker()).Times(1).WillOnce(Return()); - EXPECT_CALL(*mockFactory, tryToFindTopicPublishInfo(_, _)).WillRepeatedly(Return(topicPublishInfo)); - EXPECT_CALL(*mockFactory, findBrokerAddressInPublish(_)).WillRepeatedly(Return("BrokerA")); - EXPECT_CALL(*mockFactory, getMQClientAPIImpl()).WillRepeatedly(Return(apiImpl)); - - EXPECT_CALL(*apiImpl, sendMessage(_, _, _, _, _, _, _, _, _)).WillRepeatedly(Return(okMQAResult)); - - // Start Producer. - impl->start(); - - MQMessage msg("TestTraceTopic", "testTag", "testKey", "testBodysA"); - SendResult s1 = impl->send(msg); - EXPECT_EQ(s1.getSendStatus(), SEND_OK); - - impl->shutdown(); - delete mockFactory; - delete apiImpl; -} -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/test/src/producer/TopicPublishInfoTest.cpp b/test/src/producer/TopicPublishInfoTest.cpp deleted file mode 100644 index d1548a425..000000000 --- a/test/src/producer/TopicPublishInfoTest.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "MQMessageQueue.h" -#include "TopicPublishInfo.h" - -using namespace std; -using namespace rocketmq; -using rocketmq::MQMessageQueue; -using rocketmq::TopicPublishInfo; -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -TEST(TopicPublishInfoTest, testAll) { - TopicPublishInfo* info = new TopicPublishInfo(); - - MQMessageQueue mqA("TestTopicA", "BrokerA", 0); - MQMessageQueue mqB("TestTopicA", "BrokerB", 0); - int index = -1; - EXPECT_EQ(info->getWhichQueue(), 0); - EXPECT_FALSE(info->ok()); - EXPECT_EQ(info->selectOneMessageQueue(mqA, index), MQMessageQueue()); - EXPECT_EQ(info->selectOneActiveMessageQueue(mqA, index), MQMessageQueue()); - info->updateMessageQueueList(mqA); - info->updateMessageQueueList(mqB); - EXPECT_TRUE(info->ok()); - EXPECT_EQ(info->getMessageQueueList().size(), 2); - - EXPECT_EQ(info->selectOneMessageQueue(mqA, index), MQMessageQueue()); - EXPECT_EQ(info->selectOneActiveMessageQueue(mqA, index), MQMessageQueue()); - index = 0; - MQMessageQueue mqSelect1 = info->selectOneMessageQueue(MQMessageQueue(), index); - EXPECT_EQ(index, 0); - EXPECT_EQ(mqSelect1, mqA); - EXPECT_EQ(info->getWhichQueue(), 1); - MQMessageQueue mqSelect2 = info->selectOneMessageQueue(mqSelect1, index); - EXPECT_EQ(index, 1); - EXPECT_EQ(mqSelect2, mqB); - EXPECT_EQ(info->getWhichQueue(), 3); - index = 0; - MQMessageQueue mqActiveSelect1 = info->selectOneActiveMessageQueue(MQMessageQueue(), index); - EXPECT_EQ(index, 0); - EXPECT_EQ(mqActiveSelect1, mqA); - MQMessageQueue mqActiveSelect2 = info->selectOneActiveMessageQueue(mqActiveSelect1, index); - EXPECT_EQ(index, 1); - EXPECT_EQ(mqActiveSelect2, mqB); - EXPECT_EQ(info->getWhichQueue(), 6); - info->updateNonServiceMessageQueue(mqA, 1000); - info->updateNonServiceMessageQueue(mqA, 1000); - index = 0; - MQMessageQueue mqActiveSelect3 = info->selectOneActiveMessageQueue(mqActiveSelect1, index); - EXPECT_EQ(index, 1); - EXPECT_EQ(mqActiveSelect3, mqB); - MQMessageQueue mqActiveSelect4 = info->selectOneActiveMessageQueue(mqActiveSelect2, index); - EXPECT_EQ(index, 1); - EXPECT_EQ(mqActiveSelect4, mqA); - info->updateNonServiceMessageQueue(mqB, 1000); - index = 0; - MQMessageQueue mqSelect3 = info->selectOneMessageQueue(MQMessageQueue(), index); - EXPECT_EQ(index, 0); - EXPECT_EQ(mqSelect3, mqA); - index = 0; - MQMessageQueue mqActiveSelect5 = info->selectOneActiveMessageQueue(MQMessageQueue(), index); - EXPECT_EQ(index, 1); - EXPECT_EQ(mqActiveSelect5, mqA); - index = 0; - MQMessageQueue mqActiveSelect6 = info->selectOneActiveMessageQueue(mqB, index); - EXPECT_EQ(index, 0); - EXPECT_EQ(mqActiveSelect6, mqA); - info->updateMessageQueueList(mqSelect3); - info->resumeNonServiceMessageQueueList(); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/test/src/protocol/CommandHeaderTest.cpp b/test/src/protocol/CommandHeaderTest.cpp deleted file mode 100644 index 8ce2d591d..000000000 --- a/test/src/protocol/CommandHeaderTest.cpp +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "json/value.h" -#include "json/writer.h" - -#include "CommandHeader.h" -#include "dataBlock.h" - -using std::shared_ptr; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using Json::FastWriter; -using Json::Value; - -using rocketmq::CheckTransactionStateRequestHeader; -using rocketmq::CommandHeader; -using rocketmq::ConsumerSendMsgBackRequestHeader; -using rocketmq::CreateTopicRequestHeader; -using rocketmq::EndTransactionRequestHeader; -using rocketmq::GetConsumerListByGroupRequestHeader; -using rocketmq::GetConsumerListByGroupResponseBody; -using rocketmq::GetConsumerListByGroupResponseHeader; -using rocketmq::GetConsumerRunningInfoRequestHeader; -using rocketmq::GetEarliestMsgStoretimeRequestHeader; -using rocketmq::GetEarliestMsgStoretimeResponseHeader; -using rocketmq::GetMaxOffsetRequestHeader; -using rocketmq::GetMaxOffsetResponseHeader; -using rocketmq::GetMinOffsetRequestHeader; -using rocketmq::GetMinOffsetResponseHeader; -using rocketmq::GetRouteInfoRequestHeader; -using rocketmq::MemoryBlock; -using rocketmq::NotifyConsumerIdsChangedRequestHeader; -using rocketmq::PullMessageRequestHeader; -using rocketmq::PullMessageResponseHeader; -using rocketmq::QueryConsumerOffsetRequestHeader; -using rocketmq::QueryConsumerOffsetResponseHeader; -using rocketmq::ResetOffsetRequestHeader; -using rocketmq::SearchOffsetRequestHeader; -using rocketmq::SearchOffsetResponseHeader; -using rocketmq::SendMessageRequestHeader; -using rocketmq::SendMessageRequestHeaderV2; -using rocketmq::SendMessageResponseHeader; -using rocketmq::UnregisterClientRequestHeader; -using rocketmq::UpdateConsumerOffsetRequestHeader; -using rocketmq::ViewMessageRequestHeader; - -TEST(commandHeader, ConsumerSendMsgBackRequestHeader) { - string group = "testGroup"; - int delayLevel = 2; - int64 offset = 3027; - bool unitMode = true; - string originMsgId = "testOriginMsgId"; - string originTopic = "testTopic"; - int maxReconsumeTimes = 12; - ConsumerSendMsgBackRequestHeader header; - header.group = group; - header.delayLevel = delayLevel; - header.offset = offset; - header.unitMode = unitMode; - header.originMsgId = originMsgId; - header.originTopic = originTopic; - header.maxReconsumeTimes = maxReconsumeTimes; - map requestMap; - header.SetDeclaredFieldOfCommandHeader(requestMap); - EXPECT_EQ(requestMap["group"], group); - EXPECT_EQ(requestMap["delayLevel"], "2"); - EXPECT_EQ(requestMap["offset"], "3027"); - EXPECT_EQ(requestMap["unitMode"], "true"); - EXPECT_EQ(requestMap["originMsgId"], originMsgId); - EXPECT_EQ(requestMap["originTopic"], originTopic); - EXPECT_EQ(requestMap["maxReconsumeTimes"], "12"); - - Value outData; - header.Encode(outData); - EXPECT_EQ(outData["group"], group); - EXPECT_EQ(outData["delayLevel"], 2); - EXPECT_EQ(outData["offset"], "3027"); - EXPECT_EQ(outData["unitMode"], "true"); - EXPECT_EQ(outData["originMsgId"], originMsgId); - EXPECT_EQ(outData["originTopic"], originTopic); - EXPECT_EQ(outData["maxReconsumeTimes"], 12); -} - -TEST(commandHeader, GetRouteInfoRequestHeader) { - GetRouteInfoRequestHeader header("testTopic"); - map requestMap; - header.SetDeclaredFieldOfCommandHeader(requestMap); - EXPECT_EQ(requestMap["topic"], "testTopic"); - - Value outData; - header.Encode(outData); - EXPECT_EQ(outData["topic"], "testTopic"); -} - -TEST(commandHeader, UnregisterClientRequestHeader) { - UnregisterClientRequestHeader header("testGroup", "testProducer", "testConsumer"); - map requestMap; - header.SetDeclaredFieldOfCommandHeader(requestMap); - EXPECT_EQ(requestMap["clientID"], "testGroup"); - EXPECT_EQ(requestMap["producerGroup"], "testProducer"); - EXPECT_EQ(requestMap["consumerGroup"], "testConsumer"); - - Value outData; - header.Encode(outData); - EXPECT_EQ(outData["clientID"], "testGroup"); - EXPECT_EQ(outData["producerGroup"], "testProducer"); - EXPECT_EQ(outData["consumerGroup"], "testConsumer"); -} - -TEST(commandHeader, CreateTopicRequestHeader) { - string topic = "testTopic"; - string defaultTopic = "defaultTopic"; - int readQueueNums = 4; - int writeQueueNums = 6; - int perm = 8; - string topicFilterType = "filterType"; - CreateTopicRequestHeader header; - header.topic = topic; - header.defaultTopic = defaultTopic; - header.readQueueNums = readQueueNums; - header.writeQueueNums = writeQueueNums; - header.perm = perm; - header.topicFilterType = topicFilterType; - map requestMap; - header.SetDeclaredFieldOfCommandHeader(requestMap); - EXPECT_EQ(requestMap["topic"], topic); - EXPECT_EQ(requestMap["defaultTopic"], defaultTopic); - EXPECT_EQ(requestMap["readQueueNums"], "4"); - EXPECT_EQ(requestMap["writeQueueNums"], "6"); - EXPECT_EQ(requestMap["perm"], "8"); - EXPECT_EQ(requestMap["topicFilterType"], topicFilterType); - - Value outData; - header.Encode(outData); - EXPECT_EQ(outData["topic"], topic); - EXPECT_EQ(outData["defaultTopic"], defaultTopic); - EXPECT_EQ(outData["readQueueNums"], readQueueNums); - EXPECT_EQ(outData["writeQueueNums"], writeQueueNums); - EXPECT_EQ(outData["perm"], perm); - EXPECT_EQ(outData["topicFilterType"], topicFilterType); -} - -TEST(commandHeader, CheckTransactionStateRequestHeader) { - CheckTransactionStateRequestHeader header(2000, 1000, "ABC", "DEF", "GHI"); - map requestMap; - header.SetDeclaredFieldOfCommandHeader(requestMap); - EXPECT_EQ(requestMap["msgId"], "ABC"); - EXPECT_EQ(requestMap["transactionId"], "DEF"); - EXPECT_EQ(requestMap["offsetMsgId"], "GHI"); - EXPECT_EQ(requestMap["commitLogOffset"], "1000"); - EXPECT_EQ(requestMap["tranStateTableOffset"], "2000"); - - Value value; - value["msgId"] = "ABC"; - value["transactionId"] = "DEF"; - value["offsetMsgId"] = "GHI"; - value["commitLogOffset"] = "1000"; - value["tranStateTableOffset"] = "2000"; - shared_ptr headerDecode( - static_cast(CheckTransactionStateRequestHeader::Decode(value))); - EXPECT_EQ(headerDecode->m_msgId, "ABC"); - EXPECT_EQ(headerDecode->m_commitLogOffset, 1000); - EXPECT_EQ(headerDecode->m_tranStateTableOffset, 2000); - EXPECT_EQ(headerDecode->toString(), header.toString()); -} - -TEST(commandHeader, EndTransactionRequestHeader) { - EndTransactionRequestHeader header("testProducer", 1000, 2000, 3000, true, "ABC", "DEF"); - map requestMap; - header.SetDeclaredFieldOfCommandHeader(requestMap); - EXPECT_EQ(requestMap["msgId"], "ABC"); - EXPECT_EQ(requestMap["transactionId"], "DEF"); - EXPECT_EQ(requestMap["producerGroup"], "testProducer"); - EXPECT_EQ(requestMap["tranStateTableOffset"], "1000"); - EXPECT_EQ(requestMap["commitLogOffset"], "2000"); - EXPECT_EQ(requestMap["commitOrRollback"], "3000"); - EXPECT_EQ(requestMap["fromTransactionCheck"], "true"); - - Value outData; - header.Encode(outData); - EXPECT_EQ(outData["msgId"], "ABC"); - EXPECT_EQ(outData["transactionId"], "DEF"); - EXPECT_EQ(outData["producerGroup"], "testProducer"); - EXPECT_EQ(outData["tranStateTableOffset"], "1000"); - EXPECT_EQ(outData["commitLogOffset"], "2000"); - EXPECT_EQ(outData["commitOrRollback"], "3000"); - EXPECT_EQ(outData["fromTransactionCheck"], "true"); - - EXPECT_NO_THROW(header.toString()); -} - -TEST(commandHeader, SendMessageRequestHeader) { - string producerGroup = "testProducer"; - string topic = "testTopic"; - string defaultTopic = "defaultTopic"; - int defaultTopicQueueNums = 1; - int queueId = 2; - int sysFlag = 3; - int64 bornTimestamp = 4; - int flag = 5; - string properties = "testProperty"; - int reconsumeTimes = 6; - bool unitMode = true; - bool batch = false; - - SendMessageRequestHeader header; - header.producerGroup = producerGroup; - header.topic = topic; - header.defaultTopic = defaultTopic; - header.defaultTopicQueueNums = defaultTopicQueueNums; - header.queueId = queueId; - header.sysFlag = sysFlag; - header.bornTimestamp = bornTimestamp; - header.flag = flag; - header.properties = properties; - header.reconsumeTimes = reconsumeTimes; - header.unitMode = unitMode; - header.batch = batch; - map requestMap; - header.SetDeclaredFieldOfCommandHeader(requestMap); - EXPECT_EQ(requestMap["topic"], topic); - EXPECT_EQ(requestMap["producerGroup"], producerGroup); - EXPECT_EQ(requestMap["defaultTopic"], defaultTopic); - EXPECT_EQ(requestMap["defaultTopicQueueNums"], "1"); - EXPECT_EQ(requestMap["queueId"], "2"); - EXPECT_EQ(requestMap["sysFlag"], "3"); - EXPECT_EQ(requestMap["bornTimestamp"], "4"); - EXPECT_EQ(requestMap["flag"], "5"); - EXPECT_EQ(requestMap["properties"], properties); - EXPECT_EQ(requestMap["reconsumeTimes"], "6"); - EXPECT_EQ(requestMap["unitMode"], "true"); - EXPECT_EQ(requestMap["batch"], "false"); - - Value outData; - header.Encode(outData); - EXPECT_EQ(outData["topic"], topic); - EXPECT_EQ(outData["producerGroup"], producerGroup); - EXPECT_EQ(outData["defaultTopic"], defaultTopic); - EXPECT_EQ(outData["defaultTopicQueueNums"], defaultTopicQueueNums); - EXPECT_EQ(outData["queueId"], queueId); - EXPECT_EQ(outData["sysFlag"], sysFlag); - EXPECT_EQ(outData["bornTimestamp"], "4"); - EXPECT_EQ(outData["flag"], flag); - EXPECT_EQ(outData["properties"], properties); - EXPECT_EQ(outData["reconsumeTimes"], "6"); - EXPECT_EQ(outData["unitMode"], "true"); - EXPECT_EQ(outData["batch"], "false"); -} - -TEST(commandHeader, SendMessageRequestHeaderV2) { - string producerGroup = "testProducer"; - string topic = "testTopic"; - string defaultTopic = "defaultTopic"; - int defaultTopicQueueNums = 1; - int queueId = 2; - int sysFlag = 3; - int64 bornTimestamp = 4; - int flag = 5; - string properties = "testProperty"; - int reconsumeTimes = 6; - bool unitMode = true; - bool batch = false; - - SendMessageRequestHeaderV2 header; - header.a = producerGroup; - header.b = topic; - header.c = defaultTopic; - header.d = defaultTopicQueueNums; - header.e = queueId; - header.f = sysFlag; - header.g = bornTimestamp; - header.h = flag; - header.i = properties; - header.j = reconsumeTimes; - header.k = unitMode; - header.m = batch; - map requestMap; - header.SetDeclaredFieldOfCommandHeader(requestMap); - EXPECT_EQ(requestMap["a"], producerGroup); - EXPECT_EQ(requestMap["b"], topic); - EXPECT_EQ(requestMap["c"], defaultTopic); - EXPECT_EQ(requestMap["d"], "1"); - EXPECT_EQ(requestMap["e"], "2"); - EXPECT_EQ(requestMap["f"], "3"); - EXPECT_EQ(requestMap["g"], "4"); - EXPECT_EQ(requestMap["h"], "5"); - EXPECT_EQ(requestMap["i"], properties); - EXPECT_EQ(requestMap["j"], "6"); - EXPECT_EQ(requestMap["k"], "true"); - EXPECT_EQ(requestMap["m"], "false"); - - Value outData; - header.Encode(outData); - EXPECT_EQ(outData["a"], producerGroup); - EXPECT_EQ(outData["b"], topic); - EXPECT_EQ(outData["c"], defaultTopic); - EXPECT_EQ(outData["d"], defaultTopicQueueNums); - EXPECT_EQ(outData["e"], queueId); - EXPECT_EQ(outData["f"], sysFlag); - EXPECT_EQ(outData["g"], "4"); - EXPECT_EQ(outData["h"], flag); - EXPECT_EQ(outData["i"], properties); - EXPECT_EQ(outData["j"], "6"); - EXPECT_EQ(outData["k"], "true"); - EXPECT_EQ(outData["m"], "false"); - - SendMessageRequestHeader v1; - header.CreateSendMessageRequestHeaderV1(v1); - EXPECT_EQ(v1.producerGroup, producerGroup); - EXPECT_EQ(v1.queueId, queueId); - EXPECT_EQ(v1.batch, batch); - - SendMessageRequestHeaderV2 v2(v1); - EXPECT_EQ(header.a, v2.a); - EXPECT_EQ(header.e, v2.e); - EXPECT_EQ(header.m, v2.m); - EXPECT_EQ(header.g, v2.g); -} - -TEST(commandHeader, SendMessageResponseHeader) { - SendMessageResponseHeader header; - header.msgId = "ABCDEFG"; - header.queueId = 1; - header.queueOffset = 2; - header.transactionId = "ID"; - header.regionId = "public"; - map requestMap; - header.SetDeclaredFieldOfCommandHeader(requestMap); - EXPECT_EQ(requestMap["msgId"], "ABCDEFG"); - EXPECT_EQ(requestMap["queueId"], "1"); - EXPECT_EQ(requestMap["queueOffset"], "2"); - EXPECT_EQ(requestMap["transactionId"], "ID"); - EXPECT_EQ(requestMap["MSG_REGION"], "public"); - - Value value; - value["msgId"] = "EFGHIJK"; - value["queueId"] = "3"; - value["queueOffset"] = "4"; - value["transactionId"] = "transactionId"; - value["MSG_REGION"] = "MSG_REGION"; - shared_ptr headerDecode( - static_cast(SendMessageResponseHeader::Decode(value))); - EXPECT_EQ(headerDecode->msgId, "EFGHIJK"); - EXPECT_EQ(headerDecode->queueId, 3); - EXPECT_EQ(headerDecode->queueOffset, 4); - EXPECT_EQ(headerDecode->transactionId, "transactionId"); - EXPECT_EQ(headerDecode->regionId, "MSG_REGION"); -} - -TEST(commandHeader, PullMessageRequestHeader) { - PullMessageRequestHeader header; - header.consumerGroup = "testConsumer"; - header.topic = "testTopic"; - header.queueId = 1; - header.maxMsgNums = 2; - header.sysFlag = 3; - header.subscription = "testSub"; - header.queueOffset = 4; - header.commitOffset = 5; - header.suspendTimeoutMillis = 6; - header.subVersion = 7; - map requestMap; - header.SetDeclaredFieldOfCommandHeader(requestMap); - EXPECT_EQ(requestMap["consumerGroup"], "testConsumer"); - EXPECT_EQ(requestMap["topic"], "testTopic"); - EXPECT_EQ(requestMap["queueId"], "1"); - EXPECT_EQ(requestMap["maxMsgNums"], "2"); - EXPECT_EQ(requestMap["sysFlag"], "3"); - EXPECT_EQ(requestMap["subscription"], "testSub"); - EXPECT_EQ(requestMap["queueOffset"], "4"); - EXPECT_EQ(requestMap["commitOffset"], "5"); - EXPECT_EQ(requestMap["suspendTimeoutMillis"], "6"); - EXPECT_EQ(requestMap["subVersion"], "7"); - - Value outData; - header.Encode(outData); - EXPECT_EQ(outData["consumerGroup"], "testConsumer"); - EXPECT_EQ(outData["topic"], "testTopic"); - EXPECT_EQ(outData["queueId"], 1); - EXPECT_EQ(outData["maxMsgNums"], 2); - EXPECT_EQ(outData["sysFlag"], 3); - EXPECT_EQ(outData["subscription"], "testSub"); - EXPECT_EQ(outData["queueOffset"], "4"); - EXPECT_EQ(outData["commitOffset"], "5"); - EXPECT_EQ(outData["suspendTimeoutMillis"], "6"); - EXPECT_EQ(outData["subVersion"], "7"); -} - -TEST(commandHeader, PullMessageResponseHeader) { - PullMessageResponseHeader header; - header.suggestWhichBrokerId = 100; - header.nextBeginOffset = 200; - header.minOffset = 3000; - header.maxOffset = 5000; - map requestMap; - header.SetDeclaredFieldOfCommandHeader(requestMap); - EXPECT_EQ(requestMap["suggestWhichBrokerId"], "100"); - EXPECT_EQ(requestMap["nextBeginOffset"], "200"); - EXPECT_EQ(requestMap["minOffset"], "3000"); - EXPECT_EQ(requestMap["maxOffset"], "5000"); - - Value value; - value["suggestWhichBrokerId"] = "5"; - value["nextBeginOffset"] = "102400"; - value["minOffset"] = "1"; - value["maxOffset"] = "123456789"; - shared_ptr headerDecode( - static_cast(PullMessageResponseHeader::Decode(value))); - EXPECT_EQ(headerDecode->suggestWhichBrokerId, 5); - EXPECT_EQ(headerDecode->nextBeginOffset, 102400); - EXPECT_EQ(headerDecode->minOffset, 1); - EXPECT_EQ(headerDecode->maxOffset, 123456789); -} - -TEST(commandHeader, GetConsumerListByGroupResponseBody) { - Value value; - value[0] = "body"; - value[1] = 1; - - Value root; - root["consumerIdList"] = value; - - FastWriter writer; - string data = writer.write(root); - - MemoryBlock* mem = new MemoryBlock(data.c_str(), data.size()); - vector cids; - GetConsumerListByGroupResponseBody::Decode(mem, cids); - - EXPECT_EQ(cids.size(), 1); - - delete mem; -} - -TEST(commandHeader, ResetOffsetRequestHeader) { - ResetOffsetRequestHeader header; - - header.setTopic("testTopic"); - EXPECT_EQ(header.getTopic(), "testTopic"); - - header.setGroup("testGroup"); - EXPECT_EQ(header.getGroup(), "testGroup"); - - header.setTimeStamp(123); - EXPECT_EQ(header.getTimeStamp(), 123); - - header.setForceFlag(true); - EXPECT_TRUE(header.getForceFlag()); - - Value value; - value["isForce"] = "false"; - shared_ptr headersh( - static_cast(ResetOffsetRequestHeader::Decode(value))); - EXPECT_EQ(headersh->getTopic(), ""); - EXPECT_EQ(headersh->getGroup(), ""); - // EXPECT_EQ(headersh->getTimeStamp(), 0); - EXPECT_FALSE(headersh->getForceFlag()); - value["topic"] = "testTopic"; - headersh.reset(static_cast(ResetOffsetRequestHeader::Decode(value))); - EXPECT_EQ(headersh->getTopic(), "testTopic"); - EXPECT_EQ(headersh->getGroup(), ""); - // EXPECT_EQ(headersh->getTimeStamp(), 0); - EXPECT_FALSE(headersh->getForceFlag()); - - value["topic"] = "testTopic"; - value["group"] = "testGroup"; - headersh.reset(static_cast(ResetOffsetRequestHeader::Decode(value))); - EXPECT_EQ(headersh->getTopic(), "testTopic"); - EXPECT_EQ(headersh->getGroup(), "testGroup"); - // EXPECT_EQ(headersh->getTimeStamp(), 0); - EXPECT_FALSE(headersh->getForceFlag()); - - value["topic"] = "testTopic"; - value["group"] = "testGroup"; - value["timestamp"] = "123"; - headersh.reset(static_cast(ResetOffsetRequestHeader::Decode(value))); - EXPECT_EQ(headersh->getTopic(), "testTopic"); - EXPECT_EQ(headersh->getGroup(), "testGroup"); - EXPECT_EQ(headersh->getTimeStamp(), 123); - EXPECT_FALSE(headersh->getForceFlag()); - - value["topic"] = "testTopic"; - value["group"] = "testGroup"; - value["timestamp"] = "123"; - value["isForce"] = "1"; - headersh.reset(static_cast(ResetOffsetRequestHeader::Decode(value))); - EXPECT_EQ(headersh->getTopic(), "testTopic"); - EXPECT_EQ(headersh->getGroup(), "testGroup"); - EXPECT_EQ(headersh->getTimeStamp(), 123); - EXPECT_TRUE(headersh->getForceFlag()); -} - -TEST(commandHeader, GetConsumerRunningInfoRequestHeader) { - GetConsumerRunningInfoRequestHeader header; - header.setClientId("testClientId"); - header.setConsumerGroup("testConsumer"); - header.setJstackEnable(true); - - map requestMap; - header.SetDeclaredFieldOfCommandHeader(requestMap); - EXPECT_EQ(requestMap["clientId"], "testClientId"); - EXPECT_EQ(requestMap["consumerGroup"], "testConsumer"); - EXPECT_EQ(requestMap["jstackEnable"], "true"); - - Value outData; - header.Encode(outData); - EXPECT_EQ(outData["clientId"], "testClientId"); - EXPECT_EQ(outData["consumerGroup"], "testConsumer"); - EXPECT_TRUE(outData["jstackEnable"].asBool()); - - shared_ptr decodeHeader( - static_cast(GetConsumerRunningInfoRequestHeader::Decode(outData))); - EXPECT_EQ(decodeHeader->getClientId(), "testClientId"); - EXPECT_EQ(decodeHeader->getConsumerGroup(), "testConsumer"); - EXPECT_TRUE(decodeHeader->isJstackEnable()); -} - -TEST(commandHeader, NotifyConsumerIdsChangedRequestHeader) { - Json::Value ext; - shared_ptr header( - static_cast(NotifyConsumerIdsChangedRequestHeader::Decode(ext))); - EXPECT_EQ(header->getGroup(), ""); - - ext["consumerGroup"] = "testGroup"; - header.reset(static_cast(NotifyConsumerIdsChangedRequestHeader::Decode(ext))); - EXPECT_EQ(header->getGroup(), "testGroup"); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "commandHeader.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/protocol/ConsumerRunningInfoTest.cpp b/test/src/protocol/ConsumerRunningInfoTest.cpp deleted file mode 100644 index 44604ec4b..000000000 --- a/test/src/protocol/ConsumerRunningInfoTest.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include "map" -#include "string" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "json/reader.h" -#include "json/value.h" - -#include "ConsumeStats.h" -#include "ConsumerRunningInfo.h" -#include "MessageQueue.h" -#include "ProcessQueueInfo.h" -#include "SubscriptionData.h" - -using std::map; -using std::string; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using Json::Reader; -using Json::Value; - -using rocketmq::ConsumerRunningInfo; -using rocketmq::ConsumeStats; -using rocketmq::MessageQueue; -using rocketmq::ProcessQueueInfo; -using rocketmq::SubscriptionData; - -TEST(ConsumerRunningInfo, init) { - ConsumerRunningInfo info; - - // jstack - info.setJstack("jstack"); - EXPECT_EQ(info.getJstack(), "jstack"); - - // property - EXPECT_TRUE(info.getProperties().empty()); - info.setProperty("testKey", "testValue"); - map properties = info.getProperties(); - EXPECT_EQ(properties["testKey"], "testValue"); - info.setProperties(map()); - EXPECT_TRUE(info.getProperties().empty()); - info.setProperty("testKey", "testValue"); - map properties2 = info.getProperties(); - EXPECT_EQ(properties2["testKey"], "testValue"); - - // subscription - EXPECT_TRUE(info.getSubscriptionSet().empty()); - vector subscriptionSet; - SubscriptionData sData1("testTopic", "testSub"); - sData1.putTagsSet("testTag"); - sData1.putCodeSet("11234"); - subscriptionSet.push_back(sData1); - SubscriptionData sData2("testTopic2", "testSub2"); - sData2.putTagsSet("testTag2"); - sData2.putCodeSet("21234"); - subscriptionSet.push_back(sData2); - info.setSubscriptionSet(subscriptionSet); - EXPECT_EQ(info.getSubscriptionSet().size(), 2); - - // mqtable - EXPECT_TRUE(info.getMqTable().empty()); - - MessageQueue messageQueue1("testTopic", "testBrokerA", 3); - ProcessQueueInfo processQueueInfo1; - processQueueInfo1.commitOffset = 1024; - info.setMqTable(messageQueue1, processQueueInfo1); - MessageQueue messageQueue2("testTopic", "testBrokerB", 4); - ProcessQueueInfo processQueueInfo2; - processQueueInfo2.cachedMsgCount = 1023; - info.setMqTable(messageQueue2, processQueueInfo2); - map mqTable = info.getMqTable(); - EXPECT_EQ(mqTable.size(), 2); - EXPECT_EQ(mqTable[messageQueue1].commitOffset, 1024); - EXPECT_EQ(mqTable[messageQueue2].cachedMsgCount, 1023); - // consumeStats - EXPECT_TRUE(info.getStatusTable().empty()); - - ConsumeStats consumeStats; - consumeStats.pullTPS = 22.5; - ConsumeStats consumeStats2; - consumeStats2.consumeOKTPS = 3.168; - info.setStatusTable("TopicA", consumeStats); - info.setStatusTable("TopicB", consumeStats2); - map statsTable = info.getStatusTable(); - EXPECT_EQ(statsTable.size(), 2); - EXPECT_EQ(statsTable["TopicA"].pullTPS, 22.5); - EXPECT_EQ(statsTable["TopicB"].consumeOKTPS, 3.168); - - // encode start - info.setProperty(ConsumerRunningInfo::PROP_NAMESERVER_ADDR, "127.0.0.1:9876"); - info.setProperty(ConsumerRunningInfo::PROP_THREADPOOL_CORE_SIZE, "core_size"); - info.setProperty(ConsumerRunningInfo::PROP_CONSUME_ORDERLY, "consume_orderly"); - info.setProperty(ConsumerRunningInfo::PROP_CONSUME_TYPE, "consume_type"); - info.setProperty(ConsumerRunningInfo::PROP_CLIENT_VERSION, "client_version"); - info.setProperty(ConsumerRunningInfo::PROP_CONSUMER_START_TIMESTAMP, "127"); - info.setProperty(ConsumerRunningInfo::PROP_CLIENT_SDK_VERSION, "sdk_version"); - - // encode - string outStr = info.encode(); - EXPECT_GT(outStr.length(), 1); - EXPECT_NE(outStr.find("testTopic"), string::npos); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "ConsumerRunningInfo.*"; - int iTests = RUN_ALL_TESTS(); - return iTests; -} diff --git a/test/src/protocol/HeartbeatDataTest.cpp b/test/src/protocol/HeartbeatDataTest.cpp deleted file mode 100644 index c153ed58a..000000000 --- a/test/src/protocol/HeartbeatDataTest.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "vector" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "ConsumeType.h" -#include "HeartbeatData.h" -#include "SubscriptionData.h" - -using std::vector; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::ConsumeFromWhere; -using rocketmq::ConsumerData; -using rocketmq::ConsumeType; -using rocketmq::HeartbeatData; -using rocketmq::MessageModel; -using rocketmq::ProducerData; -using rocketmq::SubscriptionData; - -TEST(heartbeatData, ProducerData) { - ProducerData producerData; - producerData.groupName = "testGroup"; - - Json::Value outJson = producerData.toJson(); - EXPECT_EQ(outJson["groupName"], "testGroup"); -} - -TEST(heartbeatData, ConsumerData) { - ConsumerData consumerData; - consumerData.groupName = "testGroup"; - consumerData.consumeType = ConsumeType::CONSUME_ACTIVELY; - consumerData.messageModel = MessageModel::BROADCASTING; - consumerData.consumeFromWhere = ConsumeFromWhere::CONSUME_FROM_TIMESTAMP; - - vector subs; - subs.push_back(SubscriptionData("testTopic", "sub")); - - consumerData.subscriptionDataSet = subs; - - Json::Value outJson = consumerData.toJson(); - - EXPECT_EQ(outJson["groupName"], "testGroup"); - - EXPECT_EQ(outJson["consumeType"].asInt(), ConsumeType::CONSUME_ACTIVELY); - EXPECT_EQ(outJson["messageModel"].asInt(), MessageModel::BROADCASTING); - EXPECT_EQ(outJson["consumeFromWhere"].asInt(), ConsumeFromWhere::CONSUME_FROM_TIMESTAMP); - - Json::Value subsValue = outJson["subscriptionDataSet"]; - EXPECT_EQ(subsValue[0]["topic"], "testTopic"); - EXPECT_EQ(subsValue[0]["subString"], "sub"); -} - -TEST(heartbeatData, HeartbeatData) { - HeartbeatData heartbeatData; - heartbeatData.setClientID("testClientId"); - - ProducerData producerData; - producerData.groupName = "testGroup"; - - EXPECT_TRUE(heartbeatData.isProducerDataSetEmpty()); - heartbeatData.insertDataToProducerDataSet(producerData); - EXPECT_FALSE(heartbeatData.isProducerDataSetEmpty()); - - ConsumerData consumerData; - consumerData.groupName = "testGroup"; - consumerData.consumeType = ConsumeType::CONSUME_ACTIVELY; - consumerData.messageModel = MessageModel::BROADCASTING; - consumerData.consumeFromWhere = ConsumeFromWhere::CONSUME_FROM_TIMESTAMP; - - vector subs; - subs.push_back(SubscriptionData("testTopic", "sub")); - - consumerData.subscriptionDataSet = subs; - EXPECT_TRUE(heartbeatData.isConsumerDataSetEmpty()); - heartbeatData.insertDataToConsumerDataSet(consumerData); - EXPECT_FALSE(heartbeatData.isConsumerDataSetEmpty()); - - string outData; - heartbeatData.Encode(outData); - - Json::Value root; - Json::Reader reader; - reader.parse(outData, root); - - EXPECT_EQ(root["clientID"], "testClientId"); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "heartbeatData.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/protocol/LockBatchBodyTest.cpp b/test/src/protocol/LockBatchBodyTest.cpp deleted file mode 100644 index 81f5e4f9a..000000000 --- a/test/src/protocol/LockBatchBodyTest.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "vector" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "LockBatchBody.h" -#include "MQMessageQueue.h" -#include "dataBlock.h" - -using std::vector; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::LockBatchRequestBody; -using rocketmq::LockBatchResponseBody; -using rocketmq::MemoryBlock; -using rocketmq::MQMessageQueue; -using rocketmq::UnlockBatchRequestBody; - -TEST(lockBatchBody, LockBatchRequestBody) { - LockBatchRequestBody lockBatchRequestBody; - - lockBatchRequestBody.setClientId("testClientId"); - EXPECT_EQ(lockBatchRequestBody.getClientId(), "testClientId"); - - lockBatchRequestBody.setConsumerGroup("testGroup"); - EXPECT_EQ(lockBatchRequestBody.getConsumerGroup(), "testGroup"); - - vector vectorMessageQueue; - vectorMessageQueue.push_back(MQMessageQueue()); - vectorMessageQueue.push_back(MQMessageQueue()); - - lockBatchRequestBody.setMqSet(vectorMessageQueue); - EXPECT_EQ(lockBatchRequestBody.getMqSet(), vectorMessageQueue); - - Json::Value outJson = lockBatchRequestBody.toJson(MQMessageQueue("topicTest", "testBroker", 10)); - EXPECT_EQ(outJson["topic"], "topicTest"); - EXPECT_EQ(outJson["brokerName"], "testBroker"); - EXPECT_EQ(outJson["queueId"], 10); - - string outData; - lockBatchRequestBody.Encode(outData); - - Json::Value root; - Json::Reader reader; - reader.parse(outData, root); - EXPECT_EQ(root["clientId"], "testClientId"); - EXPECT_EQ(root["consumerGroup"], "testGroup"); -} - -TEST(lockBatchBody, UnlockBatchRequestBody) { - UnlockBatchRequestBody uRB; - uRB.setClientId("testClient"); - EXPECT_EQ(uRB.getClientId(), "testClient"); - uRB.setConsumerGroup("testGroup"); - EXPECT_EQ(uRB.getConsumerGroup(), "testGroup"); - - // message queue - EXPECT_TRUE(uRB.getMqSet().empty()); - vector mqs; - MQMessageQueue mqA("testTopic", "testBrokerA", 1); - mqs.push_back(mqA); - MQMessageQueue mqB("testTopic", "testBrokerB", 2); - mqs.push_back(mqB); - uRB.setMqSet(mqs); - EXPECT_EQ(uRB.getMqSet().size(), 2); - string outData; - uRB.Encode(outData); - EXPECT_GT(outData.length(), 1); - EXPECT_NE(outData.find("testTopic"), string::npos); -} - -TEST(lockBatchBody, LockBatchResponseBody) { - Json::Value root; - Json::Value mqs; - - Json::Value mq; - mq["topic"] = "testTopic"; - mq["brokerName"] = "testBroker"; - mq["queueId"] = 1; - mqs[0] = mq; - root["lockOKMQSet"] = mqs; - - Json::FastWriter fastwrite; - string outData = fastwrite.write(root); - - MemoryBlock* mem = new MemoryBlock(outData.c_str(), outData.size()); - - LockBatchResponseBody lockBatchResponseBody; - - vector messageQueues; - LockBatchResponseBody::Decode(mem, messageQueues); - - MQMessageQueue messageQueue("testTopic", "testBroker", 1); - EXPECT_EQ(messageQueue, messageQueues[0]); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "lockBatchBody.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/protocol/MessageQueueTest.cpp b/test/src/protocol/MessageQueueTest.cpp deleted file mode 100644 index eb943d206..000000000 --- a/test/src/protocol/MessageQueueTest.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/*" - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "MessageQueue.h" - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::MessageQueue; - -TEST(messageExt, init) { - MessageQueue messageQueue; - EXPECT_EQ(messageQueue.getQueueId(), -1); - - MessageQueue twoMessageQueue("testTopic", "testBroker", 1); - EXPECT_EQ(twoMessageQueue.getQueueId(), 1); - EXPECT_EQ(twoMessageQueue.getTopic(), "testTopic"); - EXPECT_EQ(twoMessageQueue.getBrokerName(), "testBroker"); - - MessageQueue threeMessageQueue(twoMessageQueue); - EXPECT_EQ(threeMessageQueue.getQueueId(), 1); - EXPECT_EQ(threeMessageQueue.getTopic(), "testTopic"); - EXPECT_EQ(threeMessageQueue.getBrokerName(), "testBroker"); - - Json::Value outJson = twoMessageQueue.toJson(); - EXPECT_EQ(outJson["queueId"], 1); - EXPECT_EQ(outJson["topic"], "testTopic"); - EXPECT_EQ(outJson["brokerName"], "testBroker"); - - MessageQueue fiveMessageQueue = threeMessageQueue; - EXPECT_EQ(fiveMessageQueue.getQueueId(), 1); - EXPECT_EQ(fiveMessageQueue.getTopic(), "testTopic"); - EXPECT_EQ(fiveMessageQueue.getBrokerName(), "testBroker"); -} - -TEST(messageExt, info) { - MessageQueue messageQueue; - - messageQueue.setQueueId(11); - EXPECT_EQ(messageQueue.getQueueId(), 11); - - messageQueue.setTopic("testTopic"); - EXPECT_EQ(messageQueue.getTopic(), "testTopic"); - - messageQueue.setBrokerName("testBroker"); - EXPECT_EQ(messageQueue.getBrokerName(), "testBroker"); -} - -TEST(messageExt, operators) { - MessageQueue messageQueue; - EXPECT_TRUE(messageQueue == messageQueue); - - MessageQueue twoMessageQueue; - EXPECT_TRUE(messageQueue == twoMessageQueue); - - twoMessageQueue.setTopic("testTopic"); - EXPECT_FALSE(messageQueue == twoMessageQueue); - - messageQueue.setQueueId(11); - EXPECT_FALSE(messageQueue == twoMessageQueue); - - messageQueue.setBrokerName("testBroker"); - EXPECT_FALSE(messageQueue == twoMessageQueue); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "messageExt.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/protocol/ProcessQueueInfoTest.cpp b/test/src/protocol/ProcessQueueInfoTest.cpp deleted file mode 100644 index bb5e7141e..000000000 --- a/test/src/protocol/ProcessQueueInfoTest.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "MQMessageExt.h" -#include "ProcessQueueInfo.h" - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::MQMessageExt; -using rocketmq::ProcessQueueInfo; - -TEST(processQueueInfo, init) { - ProcessQueueInfo processQueueInfo; - EXPECT_EQ(processQueueInfo.commitOffset, 0); - EXPECT_EQ(processQueueInfo.cachedMsgMinOffset, 0); - EXPECT_EQ(processQueueInfo.cachedMsgMaxOffset, 0); - EXPECT_EQ(processQueueInfo.cachedMsgCount, 0); - EXPECT_EQ(processQueueInfo.transactionMsgMinOffset, 0); - EXPECT_EQ(processQueueInfo.transactionMsgMaxOffset, 0); - EXPECT_EQ(processQueueInfo.transactionMsgCount, 0); - EXPECT_EQ(processQueueInfo.locked, false); - EXPECT_EQ(processQueueInfo.tryUnlockTimes, 0); - EXPECT_EQ(processQueueInfo.lastLockTimestamp, 123); - EXPECT_EQ(processQueueInfo.droped, false); - EXPECT_EQ(processQueueInfo.lastPullTimestamp, 0); - EXPECT_EQ(processQueueInfo.lastConsumeTimestamp, 0); - - processQueueInfo.setLocked(true); - EXPECT_EQ(processQueueInfo.isLocked(), true); - - processQueueInfo.setDroped(true); - EXPECT_EQ(processQueueInfo.isDroped(), true); - - processQueueInfo.setCommitOffset(456); - EXPECT_EQ(processQueueInfo.getCommitOffset(), 456); - - Json::Value outJson = processQueueInfo.toJson(); - - EXPECT_EQ(outJson["commitOffset"], "456"); - EXPECT_EQ(outJson["cachedMsgMinOffset"], "0"); - EXPECT_EQ(outJson["cachedMsgMaxOffset"], "0"); - EXPECT_EQ(outJson["cachedMsgCount"].asInt(), 0); - EXPECT_EQ(outJson["transactionMsgMinOffset"], "0"); - EXPECT_EQ(outJson["transactionMsgMaxOffset"], "0"); - EXPECT_EQ(outJson["transactionMsgCount"].asInt(), 0); - EXPECT_EQ(outJson["locked"].asBool(), true); - EXPECT_EQ(outJson["tryUnlockTimes"].asInt(), 0); - EXPECT_EQ(outJson["lastLockTimestamp"], "123"); - EXPECT_EQ(outJson["droped"].asBool(), true); - EXPECT_EQ(outJson["lastPullTimestamp"], "0"); - EXPECT_EQ(outJson["lastConsumeTimestamp"], "0"); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "processQueueInfo.init"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/protocol/RemotingCommandTest.cpp b/test/src/protocol/RemotingCommandTest.cpp deleted file mode 100644 index ca28aa3f4..000000000 --- a/test/src/protocol/RemotingCommandTest.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "CommandHeader.h" -#include "MQProtos.h" -#include "MQVersion.h" -#include "MemoryOutputStream.h" -#include "RemotingCommand.h" -#include "dataBlock.h" - -using std::shared_ptr; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::CommandHeader; -using rocketmq::GetConsumerRunningInfoRequestHeader; -using rocketmq::GetEarliestMsgStoretimeResponseHeader; -using rocketmq::GetMaxOffsetResponseHeader; -using rocketmq::GetMinOffsetResponseHeader; -using rocketmq::GetRouteInfoRequestHeader; -using rocketmq::MemoryBlock; -using rocketmq::MemoryOutputStream; -using rocketmq::MQRequestCode; -using rocketmq::MQVersion; -using rocketmq::NotifyConsumerIdsChangedRequestHeader; -using rocketmq::PullMessageResponseHeader; -using rocketmq::QueryConsumerOffsetResponseHeader; -using rocketmq::RemotingCommand; -using rocketmq::ResetOffsetRequestHeader; -using rocketmq::SearchOffsetResponseHeader; -using rocketmq::SendMessageResponseHeader; - -TEST(remotingCommand, init) { - RemotingCommand remotingCommand; - EXPECT_EQ(remotingCommand.getCode(), 0); - - RemotingCommand twoRemotingCommand(13); - EXPECT_EQ(twoRemotingCommand.getCode(), 13); - EXPECT_EQ(twoRemotingCommand.getOpaque(), 0); - EXPECT_EQ(twoRemotingCommand.getRemark(), ""); - EXPECT_EQ(twoRemotingCommand.getVersion(), MQVersion::s_CurrentVersion); - // EXPECT_EQ(twoRemotingCommand.getFlag() , 0); - EXPECT_EQ(twoRemotingCommand.getMsgBody(), ""); - EXPECT_TRUE(twoRemotingCommand.getCommandHeader() == nullptr); - - RemotingCommand threeRemotingCommand(13, new GetRouteInfoRequestHeader("topic")); - EXPECT_FALSE(threeRemotingCommand.getCommandHeader() == nullptr); - - RemotingCommand frouRemotingCommand(13, "CPP", MQVersion::s_CurrentVersion, 12, 3, "remark", - new GetRouteInfoRequestHeader("topic")); - EXPECT_EQ(frouRemotingCommand.getCode(), 13); - EXPECT_EQ(frouRemotingCommand.getOpaque(), 12); - EXPECT_EQ(frouRemotingCommand.getRemark(), "remark"); - EXPECT_EQ(frouRemotingCommand.getVersion(), MQVersion::s_CurrentVersion); - EXPECT_EQ(frouRemotingCommand.getFlag(), 3); - EXPECT_EQ(frouRemotingCommand.getMsgBody(), ""); - EXPECT_FALSE(frouRemotingCommand.getCommandHeader() == nullptr); - - RemotingCommand sixRemotingCommand(frouRemotingCommand); - EXPECT_EQ(sixRemotingCommand.getCode(), 13); - EXPECT_EQ(sixRemotingCommand.getOpaque(), 12); - EXPECT_EQ(sixRemotingCommand.getRemark(), "remark"); - EXPECT_EQ(sixRemotingCommand.getVersion(), MQVersion::s_CurrentVersion); - EXPECT_EQ(sixRemotingCommand.getFlag(), 3); - EXPECT_EQ(sixRemotingCommand.getMsgBody(), ""); - EXPECT_TRUE(sixRemotingCommand.getCommandHeader() == nullptr); - - RemotingCommand* sevenRemotingCommand = &sixRemotingCommand; - EXPECT_EQ(sevenRemotingCommand->getCode(), 13); - EXPECT_EQ(sevenRemotingCommand->getOpaque(), 12); - EXPECT_EQ(sevenRemotingCommand->getRemark(), "remark"); - EXPECT_EQ(sevenRemotingCommand->getVersion(), MQVersion::s_CurrentVersion); - EXPECT_EQ(sevenRemotingCommand->getFlag(), 3); - EXPECT_EQ(sevenRemotingCommand->getMsgBody(), ""); - EXPECT_TRUE(sevenRemotingCommand->getCommandHeader() == nullptr); -} - -TEST(remotingCommand, info) { - RemotingCommand remotingCommand; - - remotingCommand.setCode(13); - EXPECT_EQ(remotingCommand.getCode(), 13); - - remotingCommand.setOpaque(12); - EXPECT_EQ(remotingCommand.getOpaque(), 12); - - remotingCommand.setRemark("123"); - EXPECT_EQ(remotingCommand.getRemark(), "123"); - - remotingCommand.setMsgBody("msgBody"); - EXPECT_EQ(remotingCommand.getMsgBody(), "msgBody"); - - remotingCommand.addExtField("key", "value"); -} - -TEST(remotingCommand, flag) { - RemotingCommand remotingCommand(13, "CPP", MQVersion::s_CurrentVersion, 12, 0, "remark", - new GetRouteInfoRequestHeader("topic")); - ; - EXPECT_EQ(remotingCommand.getFlag(), 0); - - remotingCommand.markResponseType(); - int bits = 1 << 0; - int flag = 0; - flag |= bits; - EXPECT_EQ(remotingCommand.getFlag(), flag); - EXPECT_TRUE(remotingCommand.isResponseType()); - - bits = 1 << 1; - flag |= bits; - remotingCommand.markOnewayRPC(); - EXPECT_EQ(remotingCommand.getFlag(), flag); - EXPECT_TRUE(remotingCommand.isOnewayRPC()); -} - -TEST(remotingCommand, encodeAndDecode) { - RemotingCommand remotingCommand(13, "CPP", MQVersion::s_CurrentVersion, 12, 3, "remark", NULL); - remotingCommand.SetBody("123123", 6); - remotingCommand.Encode(); - // no delete - const MemoryBlock* head = remotingCommand.GetHead(); - const MemoryBlock* body = remotingCommand.GetBody(); - - unique_ptr result(new MemoryOutputStream(1024)); - result->write(head->getData() + 4, head->getSize() - 4); - result->write(body->getData(), body->getSize()); - - shared_ptr decodeRemtingCommand(RemotingCommand::Decode(result->getMemoryBlock())); - EXPECT_EQ(remotingCommand.getCode(), decodeRemtingCommand->getCode()); - EXPECT_EQ(remotingCommand.getOpaque(), decodeRemtingCommand->getOpaque()); - EXPECT_EQ(remotingCommand.getRemark(), decodeRemtingCommand->getRemark()); - EXPECT_EQ(remotingCommand.getVersion(), decodeRemtingCommand->getVersion()); - EXPECT_EQ(remotingCommand.getFlag(), decodeRemtingCommand->getFlag()); - EXPECT_TRUE(decodeRemtingCommand->getCommandHeader() == NULL); - - // ~RemotingCommand delete - GetConsumerRunningInfoRequestHeader* requestHeader = new GetConsumerRunningInfoRequestHeader(); - requestHeader->setClientId("client"); - requestHeader->setConsumerGroup("consumerGroup"); - requestHeader->setJstackEnable(false); - - RemotingCommand encodeRemotingCommand(307, "CPP", MQVersion::s_CurrentVersion, 12, 3, "remark", requestHeader); - encodeRemotingCommand.SetBody("123123", 6); - encodeRemotingCommand.Encode(); - - // no delete - const MemoryBlock* phead = encodeRemotingCommand.GetHead(); - const MemoryBlock* pbody = encodeRemotingCommand.GetBody(); - - unique_ptr results(new MemoryOutputStream(1024)); - results->write(phead->getData() + 4, phead->getSize() - 4); - results->write(pbody->getData(), pbody->getSize()); - - shared_ptr decodeRemtingCommandTwo(RemotingCommand::Decode(results->getMemoryBlock())); - - decodeRemtingCommandTwo->SetExtHeader(encodeRemotingCommand.getCode()); - GetConsumerRunningInfoRequestHeader* header = - reinterpret_cast(decodeRemtingCommandTwo->getCommandHeader()); - EXPECT_EQ(requestHeader->getClientId(), header->getClientId()); - EXPECT_EQ(requestHeader->getConsumerGroup(), header->getConsumerGroup()); -} - -TEST(remotingCommand, SetExtHeader) { - shared_ptr remotingCommand(new RemotingCommand()); - - remotingCommand->SetExtHeader(-1); - EXPECT_TRUE(remotingCommand->getCommandHeader() == NULL); - - Json::Value object; - Json::Value extFields; - extFields["id"] = 1; - object["extFields"] = extFields; - remotingCommand->setParsedJson(object); - - remotingCommand->SetExtHeader(MQRequestCode::SEND_MESSAGE); - SendMessageResponseHeader* sendMessageResponseHeader = - reinterpret_cast(remotingCommand->getCommandHeader()); - EXPECT_EQ(sendMessageResponseHeader->msgId, ""); - - remotingCommand->SetExtHeader(MQRequestCode::PULL_MESSAGE); - PullMessageResponseHeader* pullMessageResponseHeader = - reinterpret_cast(remotingCommand->getCommandHeader()); - EXPECT_EQ(pullMessageResponseHeader->suggestWhichBrokerId, 0); - - remotingCommand->SetExtHeader(MQRequestCode::GET_MIN_OFFSET); - GetMinOffsetResponseHeader* getMinOffsetResponseHeader = - reinterpret_cast(remotingCommand->getCommandHeader()); - EXPECT_EQ(getMinOffsetResponseHeader->offset, 0); - - remotingCommand->SetExtHeader(MQRequestCode::GET_MAX_OFFSET); - GetMaxOffsetResponseHeader* getMaxOffsetResponseHeader = - reinterpret_cast(remotingCommand->getCommandHeader()); - EXPECT_EQ(getMaxOffsetResponseHeader->offset, 0); - - remotingCommand->SetExtHeader(MQRequestCode::SEARCH_OFFSET_BY_TIMESTAMP); - SearchOffsetResponseHeader* searchOffsetResponseHeader = - reinterpret_cast(remotingCommand->getCommandHeader()); - EXPECT_EQ(searchOffsetResponseHeader->offset, 0); - - remotingCommand->SetExtHeader(MQRequestCode::GET_EARLIEST_MSG_STORETIME); - GetEarliestMsgStoretimeResponseHeader* getEarliestMsgStoretimeResponseHeader = - reinterpret_cast(remotingCommand->getCommandHeader()); - EXPECT_EQ(getEarliestMsgStoretimeResponseHeader->timestamp, 0); - - remotingCommand->SetExtHeader(MQRequestCode::QUERY_CONSUMER_OFFSET); - QueryConsumerOffsetResponseHeader* queryConsumerOffsetResponseHeader = - reinterpret_cast(remotingCommand->getCommandHeader()); - EXPECT_EQ(queryConsumerOffsetResponseHeader->offset, 0); - - extFields["isForce"] = "true"; - object["extFields"] = extFields; - remotingCommand->setParsedJson(object); - remotingCommand->SetExtHeader(MQRequestCode::RESET_CONSUMER_CLIENT_OFFSET); - ResetOffsetRequestHeader* resetOffsetRequestHeader = - reinterpret_cast(remotingCommand->getCommandHeader()); - resetOffsetRequestHeader->setGroup("group"); - - remotingCommand->SetExtHeader(MQRequestCode::GET_CONSUMER_RUNNING_INFO); - GetConsumerRunningInfoRequestHeader* getConsumerRunningInfoRequestHeader = - reinterpret_cast(remotingCommand->getCommandHeader()); - getConsumerRunningInfoRequestHeader->setClientId("id"); - - remotingCommand->SetExtHeader(MQRequestCode::NOTIFY_CONSUMER_IDS_CHANGED); - NotifyConsumerIdsChangedRequestHeader* notifyConsumerIdsChangedRequestHeader = - reinterpret_cast(remotingCommand->getCommandHeader()); - notifyConsumerIdsChangedRequestHeader->setGroup("group"); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "remotingCommand.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/protocol/TopicRouteDataTest.cpp b/test/src/protocol/TopicRouteDataTest.cpp deleted file mode 100644 index cf88ac106..000000000 --- a/test/src/protocol/TopicRouteDataTest.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "TopicRouteData.h" -#include "dataBlock.h" - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::BrokerData; -using rocketmq::MemoryBlock; -using rocketmq::QueueData; -using rocketmq::TopicRouteData; - -TEST(topicRouteData, topicRouteData) { - Json::Value root; - root["orderTopicConf"] = "orderTopicConf"; - - Json::Value queueDatas; - Json::Value queueData; - - queueData["brokerName"] = "brokerTest"; - queueData["readQueueNums"] = 8; - queueData["writeQueueNums"] = 8; - queueData["perm"] = 7; - queueDatas[0] = queueData; - - root["queueDatas"] = queueDatas; - - Json::Value brokerDatas; - Json::Value brokerData; - brokerData["brokerName"] = "testBroker"; - - Json::Value brokerAddrs; - brokerAddrs["0"] = "127.0.0.1:10091"; - brokerAddrs["1"] = "127.0.0.2:10092"; - brokerData["brokerAddrs"] = brokerAddrs; - - brokerDatas[0] = brokerData; - - root["brokerDatas"] = brokerDatas; - string out = root.toStyledString(); - - MemoryBlock* block = new MemoryBlock(out.c_str(), out.size()); - TopicRouteData* topicRouteData = TopicRouteData::Decode(block); - EXPECT_EQ(root["orderTopicConf"], topicRouteData->getOrderTopicConf()); - - BrokerData broker; - broker.brokerName = "testBroker"; - broker.brokerAddrs[0] = "127.0.0.1:10091"; - broker.brokerAddrs[1] = "127.0.0.2:10092"; - - vector brokerDataSt = topicRouteData->getBrokerDatas(); - EXPECT_EQ(broker, brokerDataSt[0]); - - QueueData queue; - queue.brokerName = "brokerTest"; - queue.readQueueNums = 8; - queue.writeQueueNums = 8; - queue.perm = 7; - vector queueDataSt = topicRouteData->getQueueDatas(); - EXPECT_EQ(queue, queueDataSt[0]); - - EXPECT_EQ(topicRouteData->selectBrokerAddr(), "127.0.0.1:10091"); - - delete block; - delete topicRouteData; -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "topicRouteData.topicRouteData"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/trace/TraceBeanTest.cpp b/test/src/trace/TraceBeanTest.cpp deleted file mode 100644 index 7fcbe32c0..000000000 --- a/test/src/trace/TraceBeanTest.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "TraceBean.h" - -using std::string; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::TraceBean; -using rocketmq::TraceMessageType; - -TEST(TraceBean, Init) { - std::string m_topic("topic"); - std::string m_msgId("msgid"); - std::string m_offsetMsgId("offsetmsgid"); - std::string m_tags("tag"); - std::string m_keys("ksy"); - std::string m_storeHost("storehost"); - std::string m_clientHost("clienthost"); - TraceMessageType m_msgType = TraceMessageType::TRACE_NORMAL_MSG; - long long m_storeTime = 100; - int m_retryTimes = 2; - int m_bodyLength = 1024; - TraceBean bean; - bean.setTopic(m_topic); - bean.setMsgId(m_msgId); - bean.setOffsetMsgId(m_offsetMsgId); - bean.setTags(m_tags); - bean.setKeys(m_keys); - bean.setStoreHost(m_storeHost); - bean.setClientHost(m_clientHost); - bean.setMsgType(m_msgType); - bean.setStoreTime(m_storeTime); - bean.setRetryTimes(m_retryTimes); - bean.setBodyLength(m_bodyLength); - EXPECT_EQ(bean.getTopic(), m_topic); - EXPECT_EQ(bean.getMsgId(), m_msgId); - EXPECT_EQ(bean.getOffsetMsgId(), m_offsetMsgId); - EXPECT_EQ(bean.getTags(), m_tags); - EXPECT_EQ(bean.getKeys(), m_keys); - EXPECT_EQ(bean.getStoreHost(), m_storeHost); - EXPECT_EQ(bean.getClientHost(), m_clientHost); - EXPECT_EQ(bean.getMsgType(), m_msgType); - EXPECT_EQ(bean.getStoreTime(), m_storeTime); - EXPECT_EQ(bean.getRetryTimes(), m_retryTimes); - EXPECT_EQ(bean.getBodyLength(), m_bodyLength); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "TraceBean.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/trace/TraceUtilTest.cpp b/test/src/trace/TraceUtilTest.cpp deleted file mode 100644 index 8fa6cff41..000000000 --- a/test/src/trace/TraceUtilTest.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "TraceConstant.h" -#include "TraceUtil.h" - -using std::string; - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::TraceBean; -using rocketmq::TraceConstant; -using rocketmq::TraceContext; -using rocketmq::TraceMessageType; -using rocketmq::TraceTransferBean; -using rocketmq::TraceType; -using rocketmq::TraceUtil; - -TEST(TraceUtil, CovertTraceTypeToString) { - EXPECT_EQ(TraceUtil::CovertTraceTypeToString(TraceType::Pub), TraceConstant::TRACE_TYPE_PUB); - EXPECT_EQ(TraceUtil::CovertTraceTypeToString(TraceType::SubBefore), TraceConstant::TRACE_TYPE_BEFORE); - EXPECT_EQ(TraceUtil::CovertTraceTypeToString(TraceType::SubAfter), TraceConstant::TRACE_TYPE_AFTER); - EXPECT_EQ(TraceUtil::CovertTraceTypeToString((TraceType)5), TraceConstant::TRACE_TYPE_PUB); -} -TEST(TraceUtil, CovertTraceContextToTransferBean) { - TraceContext context; - TraceBean bean; - bean.setMsgType(TraceMessageType::TRACE_NORMAL_MSG); - bean.setMsgId("MessageID"); - bean.setKeys("MessageKey"); - context.setRegionId("region"); - context.setMsgType(TraceMessageType::TRACE_TRANS_COMMIT_MSG); - context.setTraceType(TraceType::Pub); - context.setGroupName("PubGroup"); - context.setCostTime(50); - context.setStatus(true); - context.setTraceBean(bean); - context.setTraceBeanIndex(1); - TraceTransferBean beanPub = TraceUtil::CovertTraceContextToTransferBean(&context); - EXPECT_GT(beanPub.getTransKey().size(), 0); - context.setTraceType(TraceType::SubBefore); - TraceTransferBean beanBefore = TraceUtil::CovertTraceContextToTransferBean(&context); - EXPECT_GT(beanBefore.getTransKey().size(), 0); - - context.setTraceType(TraceType::SubAfter); - TraceTransferBean beanAfter = TraceUtil::CovertTraceContextToTransferBean(&context); - EXPECT_GT(beanAfter.getTransKey().size(), 0); - - TraceContext contextFailed("testGroup"); - contextFailed.setMsgType(context.getMsgType()); - contextFailed.setTraceType((TraceType)5); - contextFailed.setRequestId(context.getRegionId()); - contextFailed.setTimeStamp(context.getTimeStamp()); - contextFailed.setTraceBeanIndex(context.getTraceBeanIndex()); - TraceTransferBean beanWrong = TraceUtil::CovertTraceContextToTransferBean(&contextFailed); - EXPECT_EQ(beanWrong.getTransKey().size(), 0); -} -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "TraceUtil.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/transport/ClientRemotingProcessorTest.cpp b/test/src/transport/ClientRemotingProcessorTest.cpp deleted file mode 100644 index 716150d1c..000000000 --- a/test/src/transport/ClientRemotingProcessorTest.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "map" -#include "string.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "json/value.h" -#include "json/writer.h" - -#include "ClientRPCHook.h" -#include "ClientRemotingProcessor.h" -#include "ConsumerRunningInfo.h" -#include "MQClientFactory.h" -#include "MQMessageQueue.h" -#include "MQProtos.h" -#include "RemotingCommand.h" -#include "SessionCredentials.h" -#include "UtilAll.h" -#include "dataBlock.h" - -using std::map; -using std::string; - -using ::testing::_; -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Mock; -using testing::Return; -using testing::SetArgReferee; - -using Json::FastWriter; -using Json::Value; - -using rocketmq::ClientRemotingProcessor; -using rocketmq::ClientRPCHook; -using rocketmq::ConsumerRunningInfo; -using rocketmq::GetConsumerRunningInfoRequestHeader; -using rocketmq::MemoryBlock; -using rocketmq::MQClientFactory; -using rocketmq::MQMessageQueue; -using rocketmq::MQRequestCode; -using rocketmq::MQResponseCode; -using rocketmq::NotifyConsumerIdsChangedRequestHeader; -using rocketmq::RemotingCommand; -using rocketmq::ResetOffsetBody; -using rocketmq::ResetOffsetRequestHeader; -using rocketmq::SessionCredentials; -using rocketmq::UtilAll; - -class MockClientRemotingProcessor : public ClientRemotingProcessor { - public: - MockClientRemotingProcessor(MQClientFactory* factrory) : ClientRemotingProcessor(factrory) {} - MOCK_METHOD1(resetOffset, RemotingCommand*(RemotingCommand* request)); - MOCK_METHOD1(getConsumerRunningInfo, RemotingCommand*(RemotingCommand* request)); - MOCK_METHOD1(notifyConsumerIdsChanged, RemotingCommand*(RemotingCommand* request)); -}; - -class MockMQClientFactory : public MQClientFactory { - public: - MockMQClientFactory(const string& clientID, - int pullThreadNum, - uint64_t tcpConnectTimeout, - uint64_t tcpTransportTryLockTimeout, - string unitName) - : MQClientFactory(clientID, - pullThreadNum, - tcpConnectTimeout, - tcpTransportTryLockTimeout, - unitName, - true, - rocketmq::DEFAULT_SSL_PROPERTY_FILE) {} - - MOCK_METHOD3(resetOffset, - void(const string& group, const string& topic, const map& offsetTable)); - MOCK_METHOD1(consumerRunningInfo, ConsumerRunningInfo*(const string& consumerGroup)); - MOCK_METHOD2(getSessionCredentialFromConsumer, - bool(const string& consumerGroup, SessionCredentials& sessionCredentials)); - MOCK_METHOD1(doRebalanceByConsumerGroup, void(const string& consumerGroup)); -}; - -TEST(clientRemotingProcessor, processRequest) { - MockMQClientFactory* factory = new MockMQClientFactory("testClientId", 4, 3000, 4000, "a"); - ClientRemotingProcessor clientRemotingProcessor(factory); - - string addr = "127.0.0.1:9876"; - RemotingCommand* command = new RemotingCommand(); - RemotingCommand* pResponse = new RemotingCommand(13); - - pResponse->setCode(MQRequestCode::RESET_CONSUMER_CLIENT_OFFSET); - command->setCode(MQRequestCode::RESET_CONSUMER_CLIENT_OFFSET); - EXPECT_TRUE(clientRemotingProcessor.processRequest(addr, command) == nullptr); - EXPECT_EQ(nullptr, clientRemotingProcessor.processRequest(addr, command)); - - NotifyConsumerIdsChangedRequestHeader* header = new NotifyConsumerIdsChangedRequestHeader(); - header->setGroup("testGroup"); - RemotingCommand* twoCommand = new RemotingCommand(MQRequestCode::NOTIFY_CONSUMER_IDS_CHANGED, header); - - EXPECT_EQ(NULL, clientRemotingProcessor.processRequest(addr, twoCommand)); - - command->setCode(MQRequestCode::GET_CONSUMER_RUNNING_INFO); - // EXPECT_EQ(NULL , clientRemotingProcessor.processRequest(addr, command)); - - command->setCode(MQRequestCode::CHECK_TRANSACTION_STATE); - EXPECT_TRUE(clientRemotingProcessor.processRequest(addr, command) == nullptr); - - command->setCode(MQRequestCode::GET_CONSUMER_STATUS_FROM_CLIENT); - EXPECT_TRUE(clientRemotingProcessor.processRequest(addr, command) == nullptr); - - command->setCode(MQRequestCode::CONSUME_MESSAGE_DIRECTLY); - EXPECT_TRUE(clientRemotingProcessor.processRequest(addr, command) == nullptr); - - command->setCode(1); - EXPECT_TRUE(clientRemotingProcessor.processRequest(addr, command) == nullptr); - - delete twoCommand; - delete command; - delete pResponse; -} - -TEST(clientRemotingProcessor, resetOffset) { - MockMQClientFactory* factory = new MockMQClientFactory("testClientId", 4, 3000, 4000, "a"); - Mock::AllowLeak(factory); - ClientRemotingProcessor clientRemotingProcessor(factory); - Value root; - Value messageQueues; - Value messageQueue; - messageQueue["brokerName"] = "testBroker"; - messageQueue["queueId"] = 4; - messageQueue["topic"] = "testTopic"; - messageQueue["offset"] = 1024; - - messageQueues.append(messageQueue); - root["offsetTable"] = messageQueues; - - FastWriter wrtier; - string strData = wrtier.write(root); - - ResetOffsetRequestHeader* header = new ResetOffsetRequestHeader(); - RemotingCommand* request = new RemotingCommand(13, header); - - EXPECT_CALL(*factory, resetOffset(_, _, _)).Times(1); - clientRemotingProcessor.resetOffset(request); - - request->SetBody(strData.c_str(), strData.size() - 2); - clientRemotingProcessor.resetOffset(request); - - request->SetBody(strData.c_str(), strData.size()); - clientRemotingProcessor.resetOffset(request); - - // here header no need delete, it will managered by RemotingCommand - // delete header; - delete request; -} - -TEST(clientRemotingProcessor, getConsumerRunningInfoFailed) { - MockMQClientFactory* factory = new MockMQClientFactory("testClientId", 4, 3000, 4000, "a"); - Mock::AllowLeak(factory); - ConsumerRunningInfo* info = new ConsumerRunningInfo(); - EXPECT_CALL(*factory, consumerRunningInfo(_)).Times(2).WillOnce(Return(info)).WillOnce(Return(info)); - EXPECT_CALL(*factory, getSessionCredentialFromConsumer(_, _)) - .Times(2); //.WillRepeatedly(SetArgReferee<1>(sessionCredentials)); - ClientRemotingProcessor clientRemotingProcessor(factory); - - GetConsumerRunningInfoRequestHeader* header = new GetConsumerRunningInfoRequestHeader(); - header->setConsumerGroup("testGroup"); - header->setClientId("testClientId"); - header->setJstackEnable(false); - - RemotingCommand* request = new RemotingCommand(14, header); - - RemotingCommand* command = clientRemotingProcessor.getConsumerRunningInfo("127.0.0.1:9876", request); - EXPECT_EQ(command->getCode(), MQResponseCode::SYSTEM_ERROR); - EXPECT_EQ(command->getRemark(), "The Consumer Group not exist in this consumer"); - delete command; - delete request; -} - -TEST(clientRemotingProcessor, notifyConsumerIdsChanged) { - MockMQClientFactory* factory = new MockMQClientFactory("testClientId", 4, 3000, 4000, "a"); - Mock::AllowLeak(factory); - ClientRemotingProcessor clientRemotingProcessor(factory); - NotifyConsumerIdsChangedRequestHeader* header = new NotifyConsumerIdsChangedRequestHeader(); - header->setGroup("testGroup"); - RemotingCommand* request = new RemotingCommand(14, header); - - EXPECT_CALL(*factory, doRebalanceByConsumerGroup(_)).Times(1); - clientRemotingProcessor.notifyConsumerIdsChanged(request); - - delete request; -} - -TEST(clientRemotingProcessor, resetOffsetBody) { - MockMQClientFactory* factory = new MockMQClientFactory("testClientId", 4, 3000, 4000, "a"); - ClientRemotingProcessor clientRemotingProcessor(factory); - - Value root; - Value messageQueues; - Value messageQueue; - messageQueue["brokerName"] = "testBroker"; - messageQueue["queueId"] = 4; - messageQueue["topic"] = "testTopic"; - messageQueue["offset"] = 1024; - - messageQueues.append(messageQueue); - root["offsetTable"] = messageQueues; - - FastWriter wrtier; - string strData = wrtier.write(root); - - MemoryBlock* mem = new MemoryBlock(strData.c_str(), strData.size()); - - ResetOffsetBody* resetOffset = ResetOffsetBody::Decode(mem); - - map map = resetOffset->getOffsetTable(); - MQMessageQueue mqmq("testTopic", "testBroker", 4); - EXPECT_EQ(map[mqmq], 1024); - Mock::AllowLeak(factory); - delete resetOffset; - delete mem; -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "clientRemotingProcessor.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/transport/ResponseFutureTest.cpp b/test/src/transport/ResponseFutureTest.cpp deleted file mode 100644 index 058dbe7cd..000000000 --- a/test/src/transport/ResponseFutureTest.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "AsyncCallback.h" -#include "AsyncCallbackWrap.h" -#include "MQClientAPIImpl.h" -#include "MQMessage.h" -#include "RemotingCommand.h" -#include "ResponseFuture.h" -#include "TcpRemotingClient.h" -#include "UtilAll.h" - -using ::testing::_; -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -using rocketmq::AsyncCallback; -using rocketmq::AsyncCallbackStatus; -using rocketmq::asyncCallBackType; -using rocketmq::AsyncCallbackWrap; -using rocketmq::MQClientAPIImpl; -using rocketmq::MQMessage; -using rocketmq::RemotingCommand; -using rocketmq::ResponseFuture; -using rocketmq::SendCallbackWrap; -using rocketmq::TcpRemotingClient; -using rocketmq::UtilAll; - -class MockAsyncCallbackWrap : public SendCallbackWrap { - public: - MockAsyncCallbackWrap(AsyncCallback* pAsyncCallback, MQClientAPIImpl* pclientAPI) - : SendCallbackWrap("", MQMessage(), pAsyncCallback, pclientAPI) {} - - MOCK_METHOD2(operationComplete, void(ResponseFuture*, bool)); - MOCK_METHOD0(onException, void()); - asyncCallBackType getCallbackType() { return asyncCallBackType::sendCallbackWrap; } -}; - -TEST(responseFuture, init) { - ResponseFuture responseFuture(13, 4, NULL, 1000); - EXPECT_EQ(responseFuture.getRequestCode(), 13); - EXPECT_EQ(responseFuture.getOpaque(), 4); - - EXPECT_EQ(responseFuture.getRequestCommand().getCode(), 0); - EXPECT_FALSE(responseFuture.isSendRequestOK()); - EXPECT_EQ(responseFuture.getMaxRetrySendTimes(), 1); - EXPECT_EQ(responseFuture.getRetrySendTimes(), 1); - EXPECT_EQ(responseFuture.getBrokerAddr(), ""); - - EXPECT_FALSE(responseFuture.getAsyncFlag()); - EXPECT_TRUE(responseFuture.getAsyncCallbackWrap() == nullptr); - - // ~ResponseFuture delete pcall - std::shared_ptr callBack = std::make_shared("", MQMessage(), nullptr, nullptr); - ResponseFuture twoResponseFuture(13, 4, nullptr, 1000, true, callBack); - EXPECT_TRUE(twoResponseFuture.getAsyncFlag()); - EXPECT_FALSE(twoResponseFuture.getAsyncCallbackWrap() == nullptr); -} - -TEST(responseFuture, info) { - ResponseFuture responseFuture(13, 4, NULL, 1000); - - responseFuture.setBrokerAddr("127.0.0.1:9876"); - EXPECT_EQ(responseFuture.getBrokerAddr(), "127.0.0.1:9876"); - - responseFuture.setMaxRetrySendTimes(3000); - EXPECT_EQ(responseFuture.getMaxRetrySendTimes(), 3000); - - responseFuture.setRetrySendTimes(3000); - EXPECT_EQ(responseFuture.getRetrySendTimes(), 3000); - - responseFuture.setSendRequestOK(true); - EXPECT_TRUE(responseFuture.isSendRequestOK()); -} - -TEST(responseFuture, response) { - // m_bAsync = false m_syncResponse - ResponseFuture responseFuture(13, 4, NULL, 1000); - - EXPECT_FALSE(responseFuture.getAsyncFlag()); - - RemotingCommand* pResponseCommand = NULL; - responseFuture.setResponse(pResponseCommand); - EXPECT_EQ(responseFuture.getRequestCommand().getCode(), 0); - - // m_bAsync = true m_syncResponse - ResponseFuture twoResponseFuture(13, 4, NULL, 1000, true); - EXPECT_TRUE(twoResponseFuture.getAsyncFlag()); - - ResponseFuture threeResponseFuture(13, 4, NULL, 1000); - - uint64_t millis = UtilAll::currentTimeMillis(); - RemotingCommand* remotingCommand = threeResponseFuture.waitResponse(10); - uint64_t useTime = UtilAll::currentTimeMillis() - millis; - EXPECT_LT(useTime, 30); - - EXPECT_EQ(NULL, remotingCommand); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "responseFuture.*"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/test/src/transport/SocketUtilTest.cpp b/test/src/transport/SocketUtilTest.cpp deleted file mode 100644 index 09560b241..000000000 --- a/test/src/transport/SocketUtilTest.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -#include "SocketUtil.h" - -using ::testing::InitGoogleMock; -using ::testing::InitGoogleTest; -using testing::Return; - -TEST(socketUtil, init) { - sockaddr addr = rocketmq::IPPort2socketAddress(inet_addr("127.0.0.1"), 10091); - - EXPECT_EQ(rocketmq::socketAddress2IPPort(addr), "1.0.0.127:10091"); - - int host; - int port; - - rocketmq::socketAddress2IPPort(addr, host, port); - EXPECT_EQ(host, inet_addr("127.0.0.1")); - EXPECT_EQ(port, 10091); - - EXPECT_EQ(rocketmq::socketAddress2String(addr), "1.0.0.127"); -} - -int main(int argc, char* argv[]) { - InitGoogleMock(&argc, argv); - testing::GTEST_FLAG(throw_on_failure) = true; - testing::GTEST_FLAG(filter) = "socketUtil.init"; - int itestts = RUN_ALL_TESTS(); - return itestts; -} diff --git a/third_party/BUILD.bazel b/third_party/BUILD.bazel new file mode 100644 index 000000000..28e0699af --- /dev/null +++ b/third_party/BUILD.bazel @@ -0,0 +1,16 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# diff --git a/third_party/ThreadPool.BUILD b/third_party/ThreadPool.BUILD new file mode 100644 index 000000000..616a34ee9 --- /dev/null +++ b/third_party/ThreadPool.BUILD @@ -0,0 +1,11 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +cc_library( + name = "ThreadPool", + hdrs = [ + "ThreadPool.h", + ], + visibility = [ + "//visibility:public" + ], +) \ No newline at end of file diff --git a/third_party/asio.BUILD b/third_party/asio.BUILD new file mode 100644 index 000000000..98f590dd0 --- /dev/null +++ b/third_party/asio.BUILD @@ -0,0 +1,17 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") +cc_library( + name = "asio", + hdrs = glob(["include/**/*.hpp", "include/**/*.ipp"]), + visibility = ["//visibility:public"], + includes = [ + "include", + ], + defines = [ + "ASIO_STANDALONE", + "ASIO_HAS_STD_ADDRESSOF", + "ASIO_HAS_STD_ARRAY", + "ASIO_HAS_CSTDINT", + "ASIO_HAS_STD_SHARED_PTR", + "ASIO_HAS_STD_TYPE_TRAITS", + ], +) \ No newline at end of file diff --git a/third_party/cpp_httplib.BUILD b/third_party/cpp_httplib.BUILD new file mode 100644 index 000000000..cf425f721 --- /dev/null +++ b/third_party/cpp_httplib.BUILD @@ -0,0 +1,17 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +cc_library( + name = "cpp_httplib", + hdrs = [ + "httplib.h", + ], + visibility = [ + "//visibility:public", + ], + deps = [ + "//external:madler_zlib", + ], + defines = [ + "CPPHTTPLIB_ZLIB_SUPPORT", + ], +) \ No newline at end of file diff --git a/third_party/curl.BUILD b/third_party/curl.BUILD new file mode 100644 index 000000000..4b3965794 --- /dev/null +++ b/third_party/curl.BUILD @@ -0,0 +1,35 @@ +load("@org_apache_rocketmq//bazel:curl.bzl", "CURL_COPTS") + +package(features = ["no_copts_tokenization"]) + +config_setting( + name = "windows", + values = {"cpu": "x64_windows"}, + visibility = ["//visibility:private"], +) + +config_setting( + name = "osx", + values = {"cpu": "darwin"}, + visibility = ["//visibility:private"], +) + +cc_library( + name = "curl", + srcs = glob([ + "lib/**/*.c", + ]), + hdrs = glob([ + "include/curl/*.h", + "lib/**/*.h", + ]), + copts = CURL_COPTS + [ + "-DOS=\"os\"", + "-DCURL_EXTERN_SYMBOL=__attribute__((__visibility__(\"default\")))", + ], + includes = [ + "include/", + "lib/", + ], + visibility = ["//visibility:public"], +) diff --git a/third_party/filesystem.BUILD b/third_party/filesystem.BUILD new file mode 100644 index 000000000..2556cada6 --- /dev/null +++ b/third_party/filesystem.BUILD @@ -0,0 +1,9 @@ +cc_library( + name = "filesystem", + hdrs = glob([ + "include/**/*.hpp", + ]), + includes = ["include"], + visibility = ["//visibility:public"], + deps = [], +) \ No newline at end of file diff --git a/third_party/fmtlib.BUILD b/third_party/fmtlib.BUILD new file mode 100644 index 000000000..14b965fb5 --- /dev/null +++ b/third_party/fmtlib.BUILD @@ -0,0 +1,12 @@ +cc_library( + name = "fmtlib", + srcs = glob([ + "fmt/*.cc", + ]), + hdrs = glob([ + "include/fmt/*.h", + ]), + defines = ["FMT_HEADER_ONLY"], + includes = ["include"], + visibility = ["//visibility:public"], +) \ No newline at end of file diff --git a/third_party/spdlog.BUILD b/third_party/spdlog.BUILD new file mode 100644 index 000000000..debd1ad44 --- /dev/null +++ b/third_party/spdlog.BUILD @@ -0,0 +1,21 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +cc_library( + name = "spdlog", + hdrs = glob([ + "include/**/*.cc", + "include/**/*.h", + ]), + defines = [ + "SPDLOG_FMT_EXTERNAL" + ], + includes = [ + "include" + ], + visibility = [ + "//visibility:public" + ], + deps = [ + "@com_github_fmtlib_fmt//:fmtlib" + ], +) \ No newline at end of file diff --git a/tools/copyright.txt b/tools/copyright.txt new file mode 100644 index 000000000..1745cfe66 --- /dev/null +++ b/tools/copyright.txt @@ -0,0 +1,14 @@ +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You 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. diff --git a/tools/coverage.sh b/tools/coverage.sh new file mode 100755 index 000000000..423bfef92 --- /dev/null +++ b/tools/coverage.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +TOOLS_DIR=$(dirname "$0") +WORKSPACE_DIR=$(dirname "$TOOLS_DIR") +cd $WORKSPACE_DIR + +if test "$#" -lt 1; then + echo "Use bazel cache for Development Environment" + bazel coverage --config=remote_cache //src/test/cpp/ut/... +elif test "$1" = "ci"; then + echo "Use bazel cache for CI" + bazel coverage --config=ci_remote_cache //src/test/cpp/ut/... +else + echo "Unknown argument $*. Use bazel cache for Development Environment" + bazel coverage --config=remote_cache //src/test/cpp/ut/... +fi + +genhtml bazel-out/_coverage/_coverage_report.dat --output-directory coverage \ No newline at end of file diff --git a/tools/fix_copyright.py b/tools/fix_copyright.py new file mode 100755 index 000000000..24bb8f59c --- /dev/null +++ b/tools/fix_copyright.py @@ -0,0 +1,59 @@ +#!/usr/bin/python +import os +import fnmatch + +def checkAndFixFileHeaderComment(fileName, template, bazel=False): + lines = [] + with open(fileName, 'r') as f: + lines = f.readlines() + + if len(lines) > 0: + if bazel: + if lines[0].startswith("#"): + return False + else: + if lines[0].startswith("/*"): + return False + + lines.insert(0, template) + + with open(fileName, 'w') as f: + for line in lines: + f.write(line) + return True + + +def main(): + bzl_template = "#" + os.linesep + template = "/*" + os.linesep + with open('tools/copyright.txt', 'r') as reader: + line = reader.readline() + while line != '': + template += " * " + line + bzl_template += "# " + line + line = reader.readline() + template += " */" + os.linesep + bzl_template += "#" + os.linesep + + cnt = 0 + for root, dir, files in os.walk(os.curdir): + if ".git/" in root: + continue + + for item in fnmatch.filter(files, "*.h"): + if(checkAndFixFileHeaderComment(root + os.sep + item, template)): + cnt = cnt +1 + + for item in fnmatch.filter(files, "*.cpp"): + if (checkAndFixFileHeaderComment(root + os.sep + item, template)): + cnt = cnt + 1 + + for item in fnmatch.filter(files, "*.bazel"): + if (checkAndFixFileHeaderComment(root + os.sep + item, bzl_template, bazel=True)): + cnt = cnt + 1 + + print("{} files fixed".format(cnt)) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/tools/format.sh b/tools/format.sh new file mode 100755 index 000000000..21d995625 --- /dev/null +++ b/tools/format.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +TOOLS_DIR=$(dirname "$0") +WORKSPACE_DIR=$(dirname "$TOOLS_DIR") +cd $WORKSPACE_DIR + +find . -iname *.h -o -iname *.cpp | xargs clang-format -i \ No newline at end of file diff --git a/tools/trouble_shooting.sh b/tools/trouble_shooting.sh new file mode 100644 index 000000000..738bd6b62 --- /dev/null +++ b/tools/trouble_shooting.sh @@ -0,0 +1,2 @@ +export GRPC_VERBOSITY=debug +export GRPC_TRACE=tcp,http,api \ No newline at end of file diff --git a/tools/use_clang.sh b/tools/use_clang.sh new file mode 100755 index 000000000..7725259c9 --- /dev/null +++ b/tools/use_clang.sh @@ -0,0 +1,2 @@ +export CC=/usr/bin/clang +export CXX=/usr/bin/clang++ \ No newline at end of file diff --git a/win32_build.bat b/win32_build.bat deleted file mode 100644 index 0095a05b1..000000000 --- a/win32_build.bat +++ /dev/null @@ -1,101 +0,0 @@ -:/* -: * Licensed to the Apache Software Foundation (ASF) under one or more -: * contributor license agreements. See the NOTICE file distributed with -: * this work for additional information regarding copyright ownership. -: * The ASF licenses this file to You 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. -: */ - -if "%1" == "build" ( - call:build -) -if "%1" == "build64" ( - call:build64 -) else ( - call:download - call:build64 -) -goto:eof - -:download --download dependency lib -@echo download start -rmdir thirdparty /S /Q -mkdir thirdparty -cd thirdparty -git clone https://github.com/jsj020122/jsoncpp-0.10.6.git -git clone https://github.com/jsj020122/boost_1_58_0.git -git clone https://github.com/jsj020122/libevent-release-2.0.22.git -git clone https://github.com/jsj020122/zlib-1.2.3-src.git -cd .. -@echo download end -goto:eof - -:build --build all project -@echo build start -cd thirdparty/boost_1_58_0 -@if "%programfiles%"=="" ("set programfiles=E:\Program Files (x86)") -call "%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\Common7\Tools\vsvars32.bat" -:: amd64 - -::call ""E:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"" amd64 - -set ZLIB_SOURCE="%cd%\zlib-1.2.3-src\src\zlib\1.2.3\zlib-1.2.3\" -::cd boost_1_58_0 -call bootstrap.bat -@echo build start..... -bjam.exe address-model=32 --with-serialization --with-atomic --with-log --with-locale --with-iostreams --with-system --with-regex --with-thread --with-date_time --with-chrono --with-filesystem link=static threading=multi variant=release runtime-link=shared -cd ../jsoncpp-0.10.6 -devenv ./jsoncpp_lib_static.vcxproj /Rebuild "Debug|x86" /out log.txt -cd ../libevent-release-2.0.22 -devenv ./libevent.vcxproj /Rebuild "Debug|x86" /out log.txt -cd ../../Win32 -::cd ./Win32 -::devenv ./rocketmq-client-cpp.sln /Rebuild "Release|x64" /out log.txt -::devenv ./rocketmq-client-cpp.vcxproj /Build "Release|x64" /out log.txt -devenv ./rocketmq-client-cpp.sln /Build "Debug|x86" /out log.txt -::devenv ./rocketmq-client-cpp.vcxproj /Rebuild "Release|x64" /out log.txt -::cd .. -@echo build end -goto:eof - - - -:build64 --build all project -@echo build start -cd thirdparty/boost_1_58_0 -@if "%programfiles%"=="" ("set programfiles=E:\Program Files (x86)") -call "%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\Common7\Tools\vsvars32.bat" -:: amd64 - -::call ""E:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"" amd64 - -set ZLIB_SOURCE="%cd%\zlib-1.2.3-src\src\zlib\1.2.3\zlib-1.2.3\" -set ZLIB_INCLUDE="%cd%\zlib-1.2.3-src\src\zlib\1.2.3\zlib-1.2.3\" - - -::cd boost_1_58_0 -call bootstrap.bat -@echo build start..... -.\b2 -j8 --with-serialization --with-atomic --with-log --with-locale --with-iostreams --with-system --with-regex --with-thread --with-date_time --with-chrono --with-filesystem --build-type=complete address-model=64 -cd ../jsoncpp-0.10.6 -devenv ./jsoncpp_lib_static.vcxproj /Build "Release|x64" /out log.txt -cd ../libevent-release-2.0.22 -devenv ./libevent.vcxproj /Build "Release|x64" /out log.txt -cd ../../Win32 -::cd ./Win32 -::devenv ./rocketmq-client-cpp.sln /Rebuild "Release|x64" /out log.txt -::devenv ./rocketmq-client-cpp.vcxproj /Build "Release|x64" /out log.txt -devenv ./rocketmq-client-cpp.sln /Build "Release|x64" /out log.txt -::devenv ./rocketmq-client-cpp.vcxproj /Rebuild "Release|x64" /out log.txt -::cd .. -@echo build end -goto:eof