Compare commits

...

No commits in common. 'master' and 'revert-106-v2' have entirely different histories.

100 changed files with 13315 additions and 5822 deletions
Unified View
  1. +0
    -42
      .asf.yaml
  2. +15
    -0
      .editorconfig
  3. +0
    -122
      .github/ISSUE_TEMPLATE/#0_bug_report_zh.yml
  4. +0
    -94
      .github/ISSUE_TEMPLATE/#1_feature_request_zh.yml
  5. +0
    -80
      .github/ISSUE_TEMPLATE/#2_question_zh.yml
  6. +0
    -47
      .github/ISSUE_TEMPLATE/#3_proposal_zh.yml
  7. +0
    -26
      .github/ISSUE_TEMPLATE/#4_discussion_zh.yml
  8. +0
    -122
      .github/ISSUE_TEMPLATE/0_bug_report.yml
  9. +0
    -60
      .github/ISSUE_TEMPLATE/1_feature_request.yml
  10. +0
    -80
      .github/ISSUE_TEMPLATE/2_question.yml
  11. +0
    -47
      .github/ISSUE_TEMPLATE/3_proposal.yml
  12. +0
    -26
      .github/ISSUE_TEMPLATE/4_discussion.yml
  13. +26
    -0
      .github/ISSUE_TEMPLATE/bug_report.md
  14. +17
    -0
      .github/ISSUE_TEMPLATE/feature_request.md
  15. +15
    -24
      .github/PULL_REQUEST_TEMPLATE.md
  16. +0
    -71
      .github/actions/labeler/labeler.yml
  17. +1
    -0
      .github/actions/review-dog
  18. +0
    -155
      .github/release-drafter.yml
  19. +0
    -75
      .github/workflows/build.yml
  20. +0
    -69
      .github/workflows/codeql.yml
  21. +0
    -62
      .github/workflows/golangci-lint.yml
  22. +0
    -83
      .github/workflows/integrate-test.yml
  23. +0
    -42
      .github/workflows/labeler.yml
  24. +0
    -71
      .github/workflows/license.yml
  25. +63
    -0
      .github/workflows/main.yml
  26. +0
    -23
      .github/workflows/release-drafter.yml
  27. +53
    -0
      .github/workflows/release.yml
  28. +35
    -0
      .github/workflows/reviewdog.yml
  29. +0
    -50
      .github/workflows/stale.yml
  30. +9
    -26
      .gitignore
  31. +3
    -0
      .gitmodules
  32. +12
    -86
      .golangci.yml
  33. +0
    -78
      .licenserc.yaml
  34. +0
    -24
      .pre-commit-config.yaml
  35. +6
    -0
      .reviewdog.yml
  36. +0
    -212
      CONTRIBUTING.md
  37. +0
    -210
      CONTRIBUTING_CN.md
  38. +0
    -10
      DISCLAIMER
  39. +45
    -0
      Makefile
  40. +0
    -5
      NOTICE
  41. +64
    -150
      README.md
  42. +0
    -164
      README_ZH.md
  43. +0
    -78
      changes/0.1.0.md
  44. +0
    -78
      changes/0.1.0_zh.md
  45. +0
    -156
      changes/1.0.2-RC1.md
  46. +0
    -157
      changes/1.0.2-RC1_zh.md
  47. +0
    -95
      changes/1.0.3.md
  48. +0
    -98
      changes/1.0.3_zh.md
  49. +0
    -91
      changes/1.1.0.md
  50. +0
    -92
      changes/1.1.0_zh.md
  51. +0
    -80
      changes/1.2.0.md
  52. +0
    -83
      changes/1.2.0_zh.md
  53. +0
    -173
      changes/2.0.0.md
  54. +0
    -169
      changes/2.0.0_zh.md
  55. +0
    -48
      changes/dev.md
  56. +0
    -50
      changes/dev_zh.md
  57. +50
    -0
      cmd/profiles/dev/config.yml
  58. +0
    -22
      cmd/start.go
  59. +138
    -0
      cmd/tc/main.go
  60. +17
    -0
      dist/Dockerfile
  61. +44
    -0
      dist/config.yml
  62. +74
    -0
      docs/README_ZH.md
  63. BIN
      docs/images/seata-flow.png
  64. +18
    -108
      go.mod
  65. +80
    -655
      go.sum
  66. +0
    -29
      goimports.sh
  67. +0
    -48
      integrate_test.sh
  68. +0
    -9
      licenses/LICENSE.tpl
  69. +0
    -80
      makefile
  70. +9636
    -0
      pkg/apis/seata.pb.go
  71. +413
    -0
      pkg/apis/seata.proto
  72. +468
    -0
      pkg/apis/seata_grpc.pb.go
  73. +11
    -0
      pkg/client/base/context/business_action_context.go
  74. +151
    -0
      pkg/client/base/context/root_context.go
  75. +56
    -0
      pkg/client/base/exception/transaction_exception.go
  76. +12
    -0
      pkg/client/base/model/resource.go
  77. +47
    -0
      pkg/client/base/model/transaction_info.go
  78. +27
    -95
      pkg/client/client.go
  79. +0
    -254
      pkg/client/config.go
  80. +151
    -0
      pkg/client/config/configuration.go
  81. +0
    -226
      pkg/client/config_test.go
  82. +169
    -0
      pkg/client/proxy/service.go
  83. +221
    -0
      pkg/client/proxy/service_test.go
  84. +257
    -0
      pkg/client/rm/resource_manager.go
  85. +179
    -0
      pkg/client/tcc/proxy.go
  86. +23
    -0
      pkg/client/tcc/tcc_resource.go
  87. +153
    -0
      pkg/client/tcc/tcc_resource_manager.go
  88. +261
    -0
      pkg/client/tm/global_transaction.go
  89. +151
    -0
      pkg/client/tm/proxy.go
  90. +125
    -0
      pkg/client/tm/transaction_manager.go
  91. +19
    -0
      pkg/common/message_future.go
  92. +0
    -18
      pkg/compressor/7z_compress.go
  93. +0
    -67
      pkg/compressor/bzip2_compress.go
  94. +0
    -40
      pkg/compressor/bzip2_compress_test.go
  95. +0
    -24
      pkg/compressor/compressor.go
  96. +0
    -53
      pkg/compressor/compressor_type.go
  97. +0
    -51
      pkg/compressor/deflate_compress.go
  98. +0
    -53
      pkg/compressor/deflate_compress_test.go
  99. +0
    -66
      pkg/compressor/gzip_compress.go
  100. +0
    -40
      pkg/compressor/gzip_compress_test.go

+ 0
- 42
.asf.yaml View File

@@ -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.
#
github:
description: "Go Implementation For Seata"
homepage: https://seata.apache.org/
labels:
- at
- tcc
- saga
- xa
enabled_merge_buttons:
squash: true
merge: false
rebase: false
dependabot_alerts: true
dependabot_updates: false
protected_branches:
master:
required_status_checks:
strict: true
required_pull_request_reviews:
dismiss_stale_reviews: true
required_approving_review_count: 1
notifications:
commits: notifications@seata.apache.org
issues: notifications@seata.apache.org
pullrequests: notifications@seata.apache.org
discussions: dev@seata.apache.org

+ 15
- 0
.editorconfig View File

@@ -0,0 +1,15 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = tab
indent_size = 4
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

[*.yml]
indent_size = 2

+ 0
- 122
.github/ISSUE_TEMPLATE/#0_bug_report_zh.yml View File

@@ -1,122 +0,0 @@
name: "🐞 Bug 报告"
description: "提交 Bug 帮助我们改进"
title: "[BUG] "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
## 👋 感谢您的反馈!
请填写以下信息帮助我们更好地理解和解决问题。

- type: checkboxes
id: duplicate-check
attributes:
label: "✅ 验证清单"
description: "请确认您已经完成以下操作:"
options:
- label: "🔍 我已经搜索过 [现有 Issues](https://github.com/apache/incubator-seata-go/issues),确信这不是重复问题"
required: true

- type: markdown
attributes:
value: |
---
## 🔧 环境信息

- type: input
id: go-version
attributes:
label: "🚀 Go 版本"
description: "请提供您使用的 Go 版本"
placeholder: "例如:1.23.0"
validations:
required: true

- type: input
id: seata-go-version
attributes:
label: "📦 Seata-go 版本"
description: "请提供您使用的 seata-go 版本"
placeholder: "例如:v1.2.0"
validations:
required: true

- type: dropdown
id: platform
attributes:
label: "💾 操作系统"
description: "您使用的操作系统平台"
options:
- "🪟 Windows"
- "🍎 macOS"
- "🐧 Linux"
validations:
required: true

- type: markdown
attributes:
value: |
---
## 🐛 问题详情

- type: textarea
id: bug-description
attributes:
label: "📝 Bug 描述"
description: "请清晰简洁地描述您遇到的问题"
placeholder: |
请详细描述您遇到的 bug,包括:
• 具体的问题现象
• 错误信息(如有)
• 影响范围
validations:
required: true

- type: textarea
id: reproduction-steps
attributes:
label: "🔄 重现步骤"
description: "请提供详细的步骤来重现这个问题"
placeholder: |
请按顺序列出重现步骤:
1. 第一步...
2. 第二步...
3. 第三步...
4. 看到错误

💡 如果可能,请提供 GitHub 仓库链接或最小重现代码
validations:
required: true

- type: textarea
id: expected-behavior
attributes:
label: "✅ 预期行为"
description: "请描述您期望应该发生什么"
placeholder: "详细描述正确的行为应该是什么样的..."
validations:
required: true

- type: textarea
id: actual-behavior
attributes:
label: "❌ 实际行为"
description: "请描述实际发生了什么"
placeholder: |
详细描述实际发生的情况,包括:
• 错误消息
• 异常堆栈
• 日志输出
validations:
required: true

- type: textarea
id: possible-solution
attributes:
label: "💡 可能的解决方案"
description: "如果您对解决这个问题有想法,请在此分享"
placeholder: "分享您的想法、建议或已尝试的解决方案..."
validations:
required: false

+ 0
- 94
.github/ISSUE_TEMPLATE/#1_feature_request_zh.yml View File

@@ -1,94 +0,0 @@
name: "✨ 功能请求"
description: "提出新想法或功能建议"
title: "[FEATURE] "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
## 🚀 功能请求
感谢您为项目提供新的想法和建议!

- type: checkboxes
id: verification
attributes:
label: "✅ 验证清单"
description: "请确认您已经完成以下操作:"
options:
- label: "🔍 我已经搜索过 [现有 Issues](https://github.com/apache/incubator-seata-go/issues),确信这不是重复请求"
required: true
- label: "📋 我已经查看了 [发布说明](https://github.com/apache/incubator-seata-go/releases),确信此功能尚未实现"
required: true

- type: markdown
attributes:
value: |
---
## 💡 功能详情

- type: textarea
id: solution-description
attributes:
label: "🎯 功能描述"
description: "清晰概述您建议的功能或方法"
placeholder: |
请详细描述您希望看到的功能,包括:
• 功能的核心作用
• 预期的使用方式
• 与现有功能的关系
validations:
required: true

- type: textarea
id: use-cases
attributes:
label: "📋 使用场景"
description: "这个功能适用的典型场景和业务价值"
placeholder: |
请描述具体的使用场景:
• 在什么情况下会使用这个功能?
• 解决了什么具体问题?
• 带来什么价值?
validations:
required: true

- type: textarea
id: complexity-risks
attributes:
label: "⚖️ 复杂性与风险评估"
description: "潜在的技术挑战、实现难度或可能的风险"
placeholder: |
请考虑并描述:
• 实现难度评估
• 可能的技术挑战
• 对现有功能的影响
• 性能考虑
validations:
required: false

- type: textarea
id: external-dependencies
attributes:
label: "🔗 外部依赖"
description: "实现此功能需要的第三方工具、服务或集成"
placeholder: |
列出所需的外部依赖:
• 第三方库或框架
• 外部服务
• 特定的环境要求
validations:
required: false

- type: textarea
id: additional-context
attributes:
label: "📚 附加信息"
description: "任何其他相关的上下文、截图或参考资料"
placeholder: |
提供任何有助于理解需求的信息:
• 相关文档或标准
• 参考实现
• 设计草图或截图
validations:
required: false

+ 0
- 80
.github/ISSUE_TEMPLATE/#2_question_zh.yml View File

@@ -1,80 +0,0 @@
name: "❓ 问题咨询"
description: "提出关于项目的疑问"
title: "[QUESTION] "
labels: ["question"]
body:
- type: markdown
attributes:
value: |
## 🤔 问题咨询
我们很乐意帮助您解答关于 Seata-go 的问题!

- type: checkboxes
id: verification
attributes:
label: "✅ 验证清单"
description: "请确认您已经完成以下操作:"
options:
- label: "🔍 我已经搜索过 [现有 Issues](https://github.com/apache/incubator-seata-go/issues),确信这不是重复问题"
required: true

- type: markdown
attributes:
value: |
---
## 🔧 环境信息(可选)

- type: input
id: seata-go-version
attributes:
label: "📦 Seata-go 版本"
description: "请提供您使用的 seata-go 版本"
placeholder: "例如:v1.2.0"
validations:
required: false

- type: markdown
attributes:
value: |
---
## ❓ 问题详情

- type: textarea
id: question
attributes:
label: "💬 您的问题"
description: "请详细描述您想了解的问题"
placeholder: |
请详细描述您的问题,包括:
• 具体想了解什么?
• 遇到了什么困惑?
• 期望得到什么样的帮助?
validations:
required: true

- type: textarea
id: context
attributes:
label: "📚 背景信息"
description: "添加任何可能帮助我们回答您问题的上下文"
placeholder: |
提供相关背景信息:
• 您在做什么项目?
• 为什么需要了解这个问题?
• 您已经尝试过什么?
validations:
required: false

- type: textarea
id: related-resources
attributes:
label: "🔗 相关资源"
description: "链接到任何相关文档、代码或资源"
placeholder: |
分享相关链接或资源:
• 相关文档链接
• 代码仓库或片段
• 参考资料
validations:
required: false

+ 0
- 47
.github/ISSUE_TEMPLATE/#3_proposal_zh.yml View File

@@ -1,47 +0,0 @@
name: "📝 提案"
description: "创建一个技术提案"
title: "[提案] "
labels: ["proposal"]
body:
- type: checkboxes
id: verification
attributes:
label: "⚠️ 验证"
description: "请确认您已经完成以下操作:"
options:
- label: 我已经搜索过 [issues](https://github.com/apache/incubator-seata-go/issues),确信这不是一个重复的提案。
required: true

- type: markdown
attributes:
value: |
## 📋 提案详情
请使用此模板提交具体的功能设计提案。
如果您只想请求新功能并讨论可能的业务价值,请创建功能请求。

- type: textarea
id: proposal-summary
attributes:
label: "✨ 提案摘要"
description: "您提案的简要概述"
placeholder: "提供您的技术提案的简明摘要"
validations:
required: true

- type: textarea
id: implementation-approach
attributes:
label: "🛠️ 实现方法"
description: "应该如何实现这个提案?"
placeholder: "描述实现此提案的方法"
validations:
required: true

- type: textarea
id: additional-context
attributes:
label: "📚 附加上下文"
description: "任何其他相关信息"
placeholder: "提供可能有助于理解您提案的任何其他上下文"
validations:
required: false

+ 0
- 26
.github/ISSUE_TEMPLATE/#4_discussion_zh.yml View File

@@ -1,26 +0,0 @@
name: "💬 讨论"
description: "开始一个关于项目的讨论"
title: "[讨论] "
labels: ["discussion"]
body:
- type: markdown
attributes:
value: "## 🔄 讨论主题"
- type: textarea
id: discussion-content
attributes:
label: "讨论详情"
description: "请描述您想要讨论的内容"
placeholder: "提供关于您想讨论的项目相关事项的详细信息"
validations:
required: true

- type: textarea
id: related-context
attributes:
label: "📚 相关背景"
description: "添加任何相关的上下文或背景信息"
placeholder: "分享有助于理解此讨论的背景信息"
validations:
required: false

+ 0
- 122
.github/ISSUE_TEMPLATE/0_bug_report.yml View File

@@ -1,122 +0,0 @@
name: "🐞 Bug Report"
description: "Report a bug to help us improve"
title: "[BUG] "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
## 👋 Thank you for your feedback!
Please fill out the following information to help us understand and resolve the issue.

- type: checkboxes
id: duplicate-check
attributes:
label: "✅ Verification Checklist"
description: "Please verify that you've completed the following:"
options:
- label: "🔍 I have searched the [existing issues](https://github.com/apache/incubator-seata-go/issues) and confirmed this is not a duplicate"
required: true

- type: markdown
attributes:
value: |
---
## 🔧 Environment Information

- type: input
id: go-version
attributes:
label: "🚀 Go Version"
description: "The version of Go you're using"
placeholder: "e.g., 1.23.0"
validations:
required: true

- type: input
id: seata-go-version
attributes:
label: "📦 Seata-go Version"
description: "The version of seata-go you're using"
placeholder: "e.g: v1.2.0"
validations:
required: true

- type: dropdown
id: platform
attributes:
label: "💾 Operating System"
description: "What platform are you using?"
options:
- "🪟 Windows"
- "🍎 macOS"
- "🐧 Linux"
validations:
required: true

- type: markdown
attributes:
value: |
---
## 🐛 Issue Details

- type: textarea
id: bug-description
attributes:
label: "📝 Bug Description"
description: "A clear and concise description of what the bug is"
placeholder: |
Please describe the bug in detail, including:
• Specific problem symptoms
• Error messages (if any)
• Impact scope
validations:
required: true

- type: textarea
id: reproduction-steps
attributes:
label: "🔄 Steps to Reproduce"
description: "Please provide detailed steps to reproduce this issue"
placeholder: |
Please list the steps to reproduce:
1. First step...
2. Second step...
3. Third step...
4. See error

💡 If possible, please provide a GitHub repository link or minimal reproduction code
validations:
required: true

- type: textarea
id: expected-behavior
attributes:
label: "✅ Expected Behavior"
description: "What did you expect to happen?"
placeholder: "Describe in detail what the correct behavior should be..."
validations:
required: true

- type: textarea
id: actual-behavior
attributes:
label: "❌ Actual Behavior"
description: "What actually happened?"
placeholder: |
Describe what actually happened, including:
• Error messages
• Exception stack traces
• Log output
validations:
required: true

- type: textarea
id: possible-solution
attributes:
label: "💡 Possible Solution"
description: "If you have ideas on how to fix this issue, please share them here"
placeholder: "Share your thoughts, suggestions, or attempted solutions..."
validations:
required: false

+ 0
- 60
.github/ISSUE_TEMPLATE/1_feature_request.yml View File

@@ -1,60 +0,0 @@
name: "✨ Feature Request"
description: "Suggest an idea for this project"
title: "[FEATURE] "
labels: ["enhancement"]
body:
- type: checkboxes
id: verification
attributes:
label: "⚠️ Verification"
description: "Please verify that you've done the following:"
options:
- label: I have searched the [issues](https://github.com/apache/incubator-seata-go/issues) of this repository and believe that this is not a duplicate.
required: true
- label: I have searched the [release notes](https://github.com/apache/incubator-seata-go/releases) of this repository and believe that this is not a duplicate.
required: true

- type: textarea
id: solution-description
attributes:
label: "🎯 Solution Description"
description: "A clear overview of the proposed approach or feature."
placeholder: "Describe the solution you'd like to see implemented"
validations:
required: true

- type: textarea
id: use-cases
attributes:
label: "📋 Use Cases"
description: "Typical scenarios where this solution would be applied."
placeholder: "Describe situations where this feature would be useful"
validations:
required: true

- type: textarea
id: complexity-risks
attributes:
label: "⚖️ Complexity & Risks"
description: "Potential challenges, technical hurdles, or downsides."
placeholder: "Describe any potential challenges or concerns"
validations:
required: false

- type: textarea
id: external-dependencies
attributes:
label: "🔗 External Dependencies"
description: "Required third-party tools, services, or integrations."
placeholder: "List any external tools or services needed"
validations:
required: false

- type: textarea
id: additional-context
attributes:
label: "📘 Additional Context"
description: "Add any other context or screenshots about the feature request here."
placeholder: "Add any other relevant information here"
validations:
required: false

+ 0
- 80
.github/ISSUE_TEMPLATE/2_question.yml View File

@@ -1,80 +0,0 @@
name: "❓ Question"
description: "Ask a question about the project"
title: "[QUESTION] "
labels: ["question"]
body:
- type: markdown
attributes:
value: |
## 🤔 Question
We're happy to help answer your questions about Seata-go!

- type: checkboxes
id: verification
attributes:
label: "✅ Verification Checklist"
description: "Please verify that you've completed the following:"
options:
- label: "🔍 I have searched the [existing issues](https://github.com/apache/incubator-seata-go/issues) and confirmed this is not a duplicate"
required: true

- type: markdown
attributes:
value: |
---
## 🔧 Configuration (Optional)"

- type: input
id: seata-go-version
attributes:
label: "📦 Seata-go Version"
description: "The version of seata-go you're using"
placeholder: "e.g: v1.2.0"
validations:
required: false

- type: markdown
attributes:
value: |
---
## ❓ Question Details

- type: textarea
id: question
attributes:
label: "💬 Your Question"
description: "Please describe your question in detail"
placeholder: |
Please describe your question in detail, including:
• What specifically would you like to know?
• What confusion have you encountered?
• What kind of help are you expecting?
validations:
required: true

- type: textarea
id: context
attributes:
label: "📚 Background Information"
description: "Add any context that might help us answer your question"
placeholder: |
Provide relevant background information:
• What project are you working on?
• Why do you need to understand this?
• What have you already tried?
validations:
required: false

- type: textarea
id: related-resources
attributes:
label: "🔗 Related Resources"
description: "Link to any related documents, code, or resources"
placeholder: |
Share related links or resources:
• Relevant documentation links
• Code repositories or snippets
• Reference materials
validations:
required: false

+ 0
- 47
.github/ISSUE_TEMPLATE/3_proposal.yml View File

@@ -1,47 +0,0 @@
name: "📝 Proposal"
description: "Create a technical proposal"
title: "[PROPOSAL] "
labels: ["proposal"]
body:
- type: checkboxes
id: verification
attributes:
label: "⚠️ Verification"
description: "Please verify that you've done the following:"
options:
- label: I have searched the [issues](https://github.com/apache/incubator-seata-go/issues) of this repository and believe that this is not a duplicate.
required: true

- type: markdown
attributes:
value: |
## 📋 Proposal Details
Please use this for a concrete design proposal for functionality.
If you just want to request a new feature and discuss the possible business value, create a Feature Request instead.

- type: textarea
id: proposal-summary
attributes:
label: "✨ Proposal Summary"
description: "A brief overview of your proposal"
placeholder: "Provide a concise summary of your technical proposal"
validations:
required: true

- type: textarea
id: implementation-approach
attributes:
label: "🛠️ Implementation Approach"
description: "How should this be implemented?"
placeholder: "Describe the approach to implementing this proposal"
validations:
required: true

- type: textarea
id: additional-context
attributes:
label: "📚 Additional Context"
description: "Any other relevant information"
placeholder: "Provide any other context that might help understand your proposal"
validations:
required: false

+ 0
- 26
.github/ISSUE_TEMPLATE/4_discussion.yml View File

@@ -1,26 +0,0 @@
name: "💬 Discussion"
description: "Start a discussion about the project"
title: "[DISCUSSION] "
labels: ["discussion"]
body:
- type: markdown
attributes:
value: "## 🔄 Discussion Topic"
- type: textarea
id: discussion-content
attributes:
label: "Discussion Details"
description: "Please describe what you'd like to discuss"
placeholder: "Provide details about what you want to discuss regarding the project"
validations:
required: true

- type: textarea
id: related-context
attributes:
label: "📚 Related Context"
description: "Add any relevant context or background information"
placeholder: "Share any background information that helps frame this discussion"
validations:
required: false

+ 26
- 0
.github/ISSUE_TEMPLATE/bug_report.md View File

@@ -0,0 +1,26 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
---

- [ ] I have searched the [issues](https://github.com/transaction-wg/seata-golang/issues) of this repository and believe that this is not a duplicate.

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Additional context**
Add any other context about the problem here.

+ 17
- 0
.github/ISSUE_TEMPLATE/feature_request.md View File

@@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.

+ 15
- 24
.github/PULL_REQUEST_TEMPLATE.md View File

@@ -1,24 +1,15 @@
<!-- Thanks for sending a pull request!
-->

**What this PR does**:

**Which issue(s) this PR fixes**:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Fixes #

**Special notes for your reviewer**:

**Does this PR introduce a user-facing change?**:
<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->
```release-note

```
ref: https://github.com/seata-golang/seata-golang/issues/<issueID>

### Ⅰ. Describe what this PR did


### Ⅱ. Does this pull request fix one issue?


### Ⅲ. Why don't you add test cases (unit test/integration test)?


### Ⅳ. Describe how to verify it


### Ⅴ. Special notes for reviews

+ 0
- 71
.github/actions/labeler/labeler.yml View File

@@ -1,71 +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.
#

coding:
- 'pkg/**/*'
- 'sample/**/*'
- 'test/**/*'
- 'cmd/**/*'

# directory .github
ci/cd:
- any: ['.github/**/*']

# directory sample
sample:
- any: ['sample/**/*']

test:
- any: ['test/**/*','testdata/**/*']

# directory cmd
cmd:
- any: ['cmd/**/*']

# directory changes
milestone:
- any: ['changes/**/*']


# directory pkg
common:
- any: ['pkg/common/**/*']

config:
- any: ['pkg/config/**/*']

imports:
- any: ['pkg/imports/**/*']

integration:
- any: ['pkg/integration/**/*']

protocol:
- any: ['pkg/protocol/**/*']

remoting:
- any: ['pkg/remoting/**/*']

rm:
- any: ['pkg/rm/**/*']

tc:
- any: ['pkg/tc/**/*']

tm:
- any: ['pkg/tm/**/*']


+ 1
- 0
.github/actions/review-dog

@@ -0,0 +1 @@
Subproject commit 6a895732124427993d93d4ccf93e2c664a9068cd

+ 0
- 155
.github/release-drafter.yml View File

@@ -1,155 +0,0 @@
name-template: '$RESOLVED_VERSION'
tag-template: '$RESOLVED_VERSION'

categories:
- title: 'alignment/seata-java'
labels:
- 'alignment/seata-java'
- title: 'bug'
labels:
- 'bug'
- title: 'ci/cd'
labels:
- 'ci/cd'
- title: 'coding'
labels:
- 'coding'
- title: 'documentation'
labels:
- 'documentation'
- title: 'enhancement'
labels:
- 'enhancement'
- title: 'good first issue'
labels:
- 'good first issue'
- title: 'integration'
labels:
- 'integration'
- title: 'milestone'
labels:
- 'milestone'
- title: 'module/at'
labels:
- 'module/at'
- title: 'module/rm'
labels:
- 'module/rm'
- title: 'module/saga'
labels:
- 'module/saga'
- title: 'module/tcc'
labels:
- 'module/tcc'
- title: 'module/tm'
labels:
- 'module/tm'
- title: 'module/xa'
labels:
- 'module/xa'
- title: 'optimise'
labels:
- 'optimise'
- title: 'protocol'
labels:
- 'protocol'
- title: 'question'
labels:
- 'question'
- title: 'refactor'
labels:
- 'refactor'
- title: 'remoting'
labels:
- 'remoting'
- title: 'rm'
labels:
- 'rm'
- title: 'task: help-wanted'
labels:
- 'task: help-wanted'
- title: 'tm'
labels:
- 'tm'

change-template: '- $TITLE (#$NUMBER)'
change-title-escapes: '\<*_&'
exclude-contributors:
- dependabot
- dependabot[bot]

version-resolver:
major:
labels:
- 'enhancement'
- 'module/at'
minor:
labels:
- 'enhancement'
- 'module/saga'
patch:
labels:
- 'bug'
- 'documentation'
- 'refactor'
default: patch

template: |
$CHANGES

**Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION
**Contributors**: $CONTRIBUTORS

autolabeler:
- label: 'documentation'
files:
- '*.md'
- 'docs/**'
title:
- '/(docs?|typo|doc:|\[doc\]|comment)/i'

- label: 'bug'
title:
- '/(fix|bug|error|fail|correct|missing)/i'
- '/(race|deadlock)/i'

- label: 'enhancement'
title:
- '/(feat|feature|add|implement|create)/i'

- label: 'refactor'
title:
- '/(refactor|cleanup|deprecate|remove|unused)/i'

- label: 'ci/cd'
files:
- '.github/workflows/**'
title:
- '/(ci|cd|workflow|pipeline)/i'

- label: 'coding'
title:
- '/(bump|upgrade|dependencies?)/i'
files:
- 'go.mod'
- 'go.sum'

- label: 'question'
title:
- '/(question|ask|inquiry)/i'

- label: 'good first issue'
title:
- '/(good first issue|easy|beginner|help wanted)/i'

- label: 'module/saga'
title:
- '/(saga)/i'

- label: 'module/at'
title:
- '/(at)/i'
- label: 'module/xa'
title:
- '/(xa)/i'

+ 0
- 75
.github/workflows/build.yml View File

@@ -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.
#

# This is a workflow to help you test the unit case and show codecov

name: "build and codecov"

on:
push:
branches: [ master ]
pull_request:
branches: ["*"]

jobs:
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
strategy:
matrix:
golang:
- 1.20

services:
mysql:
image: mysql:8.0
env:
# The MySQL docker container requires these environment variables to be set
# so we can create and migrate the test database.
# See: https://hub.docker.com/_/mysql
MYSQL_DATABASE: seata_go_test
MYSQL_ROOT_PASSWORD: seata_go
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3

steps:
- name: "set up go"
uses: actions/setup-go@v3
with:
go-version: 1.20.14


# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: "checkout ${{ github.ref }}"
uses: actions/checkout@v3
with:
fetch-depth: 2

- name: "run go build"
run: go build -v ./...

- name: "run go test and out codecov"
run: go test -v ./... -race -coverprofile=coverage.out -covermode=atomic

- name: "upload coverage"
uses: codecov/codecov-action@v4.0.1
with:
token: ${{ secrets.CODECOV_TOKEN }}
version: v0.6.0
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

+ 0
- 69
.github/workflows/codeql.yml View File

@@ -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.
#

# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#

name: CodeQL

on:
pull_request:
# The branches below must be a subset of the branches above
branches: "*"

permissions:
contents: read

jobs:
analyse:
permissions:
actions: read # for github/codeql-action/init to get workflow details
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/autobuild to send a status report
name: Analyse
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2

# Analysis
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2


+ 0
- 62
.github/workflows/golangci-lint.yml View File

@@ -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.
#

# This is a basic workflow to help you get started with Actions

name: "golang ci lint"

# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches: [ master ]
pull_request:
branches: "*"

# 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
strategy:
matrix:
golang:
- 1.20.0

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- name: "set up go"
uses: actions/setup-go@v3
with:
go-version: 1.20.0

# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: "checkout ${{ github.ref }}"
uses: actions/checkout@v3

- name: "golang ci lint"
uses: golangci/golangci-lint-action@v3.1.0
with:
version: v1.51.0
args: --timeout=10m
skip-go-installation: true
skip-cache: true
skip-pkg-cache: true

+ 0
- 83
.github/workflows/integrate-test.yml View File

@@ -1,83 +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.
#

name: "integrate-test"

on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches: [ master ]
pull_request:
branches: "*"

permissions:
contents: read

# 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"
test:
# The type of runner that the job will run on
name: test
runs-on: ubuntu-latest
strategy:
matrix:
golang:
- 1.20

steps:

- name: "set up go"
uses: actions/setup-go@v3
with:
go-version: 1.20.0

# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: "checkout ${{ github.ref }}"
uses: actions/checkout@v3

- name: Cache dependencies
uses: actions/cache@v3
with:
# Cache
path: ~/go/pkg/mod
# Cache key
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
# An ordered list of keys to use for restoring the cache if no cache hit occurred for key
restore-keys: |
${{ runner.os }}-go-

- name: Set up Docker
uses: docker/setup-buildx-action@v2

- name: Install Docker Compose
run: |
curl -L "https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose --version

# This step only runs when the event type is a pull_request
- name: Integrate Test
if: ${{ github.event_name == 'pull_request' }}
run: |
chmod +x integrate_test.sh && [[ -n "${{github.event.pull_request.head.repo.full_name}}" ]] && [[ -n "${{github.event.pull_request.head.sha}}" ]] && [[ -n "${{github.base_ref}}" ]] && ./integrate_test.sh ${{github.event.pull_request.head.repo.full_name}} ${{github.event.pull_request.head.sha}} ${{github.base_ref}}

# This step only runs when the event type is a push
- name: Integrate Test
if: ${{ github.event_name == 'push' }}
run: |
chmod +x integrate_test.sh && ./integrate_test.sh $GITHUB_REPOSITORY $GITHUB_SHA $GITHUB_BASE_REF

+ 0
- 42
.github/workflows/labeler.yml View File

@@ -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.
#

# This workflow will help me to auto set up label for pull request

name: "pull request labeler"
on:
- pull_request_target

jobs:
triage:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- name: "checkout ${{ github.ref }}"
uses: actions/checkout@v3
with:
persist-credentials: false
submodules: true

- name: "labeler"
uses: actions/labeler@v4
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
configuration-path: .github/actions/labeler/labeler.yml
sync-labels: true

+ 0
- 71
.github/workflows/license.yml View File

@@ -1,71 +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.
#

name: License checker

on:
pull_request:
branches: [ master ]
schedule:
- cron: "0 18 * * *" # TimeZone: UTC 0

jobs:
license-header:
name: License header
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Check license header
uses: apache/skywalking-eyes@985866ce7e324454f61e22eb2db2e998db09d6f3
with:
log: info
config: .licenserc.yaml
mode: check

dependency-license:
name: Dependency licenses
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@v3
with:
go-version: "1.20"
- name: Check Dependencies Licenses
run: |
mkdir -p ./dist-material/
cp ./licenses/LICENSE.tpl ./dist-material/LICENSE.tpl
go install github.com/apache/skywalking-eyes/cmd/license-eye@47febf5
license-eye dependency resolve --summary ./dist-material/LICENSE.tpl || exit 1
if [ -f "./dist-material/LICENSE)" ]; then
echo "echo LICENSE check"
cat ./dist-material/LICENSE
fi
- name: Check Dependencies Licenses Invalid
run: |
go install github.com/apache/skywalking-eyes/cmd/license-eye@47febf5
if [ ! -z "$(license-eye dependency check -v error | grep 'GPL\|LGPL\|ERROR')" ]; then
echo "GPL or LGPL dependency LICENSE exists"
license-eye dependency check -v error | grep 'GPL\|LGPL\|ERROR'
exit 1
fi

+ 63
- 0
.github/workflows/main.yml View File

@@ -0,0 +1,63 @@
# This is a basic workflow to help you get started with Actions

name: CI

# Controls when the action will run. Triggers the workflow on push or pull request
# events for all branches and tags
on:
push:
branches: [ '**' ]
pull_request:
branches: [ '**' ]

# 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 "lint"
lint-and-test:
strategy:
matrix:
go-version: [ 1.15.x ]
# 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:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}

# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Checkout code
uses: actions/checkout@v2

- name: Go Build
run: |
go build ./...

- name: Go Vet
run: |
go vet -v ./...

- name: GolangCI Lint
run: |
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.39.0
golangci-lint run ./...

- name: Unit Tests
run: |
mkdir -p build
go test ./... -coverprofile=./build/c.out

- name: Code Coverage
run: |
go get github.com/axw/gocov/gocov
go get github.com/AlekSi/gocov-xml
go tool cover -html=build/c.out -o build/coverage.html
gocov convert build/c.out | gocov-xml > build/coverage.xml

- name: Archive code coverage results
uses: actions/upload-artifact@v2
with:
name: code-coverage-report
path: build/

+ 0
- 23
.github/workflows/release-drafter.yml View File

@@ -1,23 +0,0 @@
name: Release Drafter

on:
push:
branches:
- unstable
pull_request_target:
types: [ opened, reopened, synchronize ]

permissions:
contents: write
pull-requests: write

jobs:
update_release_draft:
permissions:
contents: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

+ 53
- 0
.github/workflows/release.yml View File

@@ -0,0 +1,53 @@
name: Release
on:
release:
types: [created]

jobs:
releases-matrix:
name: Release Go Binary
runs-on: ubuntu-latest
strategy:
matrix:
# build and publish in parallel: linux/386, linux/amd64, windows/386, windows/amd64, darwin/amd64
goos: [linux, windows]
goarch: ["386", amd64, arm]
exclude:
- goarch: "arm"
goos: windows

steps:
- uses: actions/checkout@v2
- uses: wangyoucao577/go-release-action@v1.18
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
goversion: "https://golang.org/dl/go1.15.linux-amd64.tar.gz"
project_path: "./cmd/tc/"
binary_name: "seata-golang"

docker-build:
strategy:
matrix:
go-version: [ 1.15.x ]
# The type of runner that the job will run on
runs-on: ubuntu-latest
steps:
- name: Docker Build
if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/v2' || contains(github.ref, 'release') }}
env:
DOCKER_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
run: |
go mod tidy
REGISTRY=$DOCKER_USERNAME make build-images

- name: Push
if: ${{ github.ref == 'refs/heads/master' || github.ref == 'refs/heads/v2' || contains(github.ref, 'release') }}
env:
DOCKER_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
COMMIT: ${{ github.sha }}
run: |
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
REGISTRY=$DOCKER_USERNAME make push

+ 35
- 0
.github/workflows/reviewdog.yml View File

@@ -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.
#

name: reviewdog
on: [pull_request]
jobs:
golangci-lint:
name: review
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v2
with:
persist-credentials: false
submodules: true
- name: golangci-lint
uses: ./.github/actions/review-dog
with:
golangci_lint_flags: "--timeout=10m"

+ 0
- 50
.github/workflows/stale.yml View File

@@ -1,50 +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.
#


# https://github.com/actions/stale
name: 'close the stale content'
on:
schedule:
- cron: '0 0 * * *'
permissions:
pull-requests: write
issues: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v4
with:
#never automatically stale issues
days-before-issue-stale: -1
#never automatically close issues
days-before-issue-close: -1
exempt-issue-labels: 'feature'
stale-issue-message: >
This issue has not been active for the past 4 weeks, so we will automatically close this issue after 7 days
close-issue-message: >
This issue has not been active for the past 5 weeks, so we are closing it now

#never automatically stale pr
days-before-pr-stale: -1
#never automatically close pr
days-before-pr-close: -1
stale-pr-message: >
This PR has not been active for the past 12 weeks, so we will automatically close this issue after seven days
close-pr-message: >
This PR has not had any activity for the past 13 weeks, so we are now closing it down

+ 9
- 26
.gitignore View File

@@ -1,23 +1,3 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# Idea configuration file
.idea/

# Binaries for programs and plugins # Binaries for programs and plugins
*.exe *.exe
*.exe~ *.exe~
@@ -31,11 +11,14 @@
# Output of the go coverage tool, specifically when used with LiteIDE # Output of the go coverage tool, specifically when used with LiteIDE
*.out *.out


# build products
dist/

# Dependency directories (remove the comment below to include it) # Dependency directories (remove the comment below to include it)
# vendor/ # vendor/
.vscode
.codecc
vendor
.idea/
vendor/
root.data
root.data.1
trace.out
cmd/tc/cmd
cmd/tc/tc
cmd/tc/trace.out
dist/tc

+ 3
- 0
.gitmodules View File

@@ -0,0 +1,3 @@
[submodule ".github/actions/review-dog"]
path = .github/actions/review-dog
url = git@github.com:reviewdog/action-golangci-lint.git

+ 12
- 86
.golangci.yml View File

@@ -1,92 +1,18 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

linters-settings:
govet:
shadow: true
golint:
min-confidence: 0
gocyclo:
min-complexity: 10
maligned:
suggest-new: true
dupl:
threshold: 100
goconst:
min-len: 2
min-occurrences: 2
depguard:
list-type: blacklist
packages:
# logging is allowed only by logutils.Log, logrus
# is allowed to use only in logutils package
- github.com/sirupsen/logrus
misspell:
locale: US
lll:
line-length: 140
goimports:
local-prefixes: github.com/golangci/golangci-lint
gocritic:
enabled-tags:
- performance
- style
- experimental
disabled-checks:
- wrapperFunc
run:
deadline: 5m


linters: linters:
disable-all: true disable-all: true
enable: enable:
- deadcode
- errcheck
- gosimple
- govet - govet
- staticcheck
- ineffassign - ineffassign
- misspell
- asciicheck
- bodyclose
- rowserrcheck
- gofmt
- durationcheck
- sqlclosecheck

run:

issues:
exclude-dirs:
- test/testdata_etc
- pkg/golinters/goanalysis/(checker|passes)
exclude-rules:
- text: "weak cryptographic primitive"
linters:
- gosec
- linters:
- staticcheck
text: "SA1019:"
- path: _test\.go
linters:
- errcheck
- gosec
- rowserrcheck
- govet

# golangci.com configuration
# https://github.com/golangci/golangci/wiki/Configuration
service:
golangci-lint-version: 1.57.x # use the fixed version to not introduce new linters unexpectedly
prepare:
- echo "here I can run custom commands, but no preparation needed for this repo"

- staticcheck
- structcheck
- typecheck
- varcheck
- goimports
- gocritic
- revive

+ 0
- 78
.licenserc.yaml View File

@@ -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.
#

header: # `header` section is configurations for source codes license header.
license:
spdx-id: Apache-2.0 # the spdx id of the license, it's convenient when your license is standard SPDX license.
copyright-owner: Apache Software Foundation # the copyright owner to replace the [owner] in the `spdx-id` template.
content: | # `license` will be used as the content when `fix` command needs to insert a license header.
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
# `pattern` is optional regexp if all the file headers are the same as `license` or the license of `spdx-id` and `copyright-owner`.
pattern: |
Licensed to the Apache Software Foundation under one or more contributor
license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright
ownership. The Apache Software Foundation licenses this file to you under
the Apache License, Version 2.0 \(the "License"\); you may
not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
paths: # `paths` are the path list that will be checked (and fixed) by license-eye, default is ['**'].
- '**'

paths-ignore: # `paths-ignore` are the path list that will be ignored by license-eye.
- 'licenses'
- '**/go.mod'
- '**/go.sum'
- 'LICENSE'
- 'DISCLAIMER'
- 'NOTICE'
- '.github'
comment: on-failure # on what condition license-eye will comment on the pull request, `on-failure`, `always`, `never`.

language:
Go:
extensions:
- ".go"
comment_style_id: SlashAsterisk

# license-location-threshold specifies the index threshold where the license header can be located,
# after all, a "header" cannot be TOO far from the file start.
license-location-threshold: 80

dependency:
files:
- go.mod

+ 0
- 24
.pre-commit-config.yaml View File

@@ -1,24 +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.
#

# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: http://github.com/golangci/golangci-lint
rev: v1.42.1
hooks:
- id: golangci-lint

+ 6
- 0
.reviewdog.yml View File

@@ -0,0 +1,6 @@
runner:
golint:
cmd: golangci-lint run
errorformat:
- "%f:%l:%c: %m"
level: warning

+ 0
- 212
CONTRIBUTING.md View File

@@ -1,212 +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.
-->
# Contributing to seata-go

It is warmly welcomed if you have interest to hack on seata-go. First, we encourage this kind of willing very much. And here is a list of contributing guide for you.

[[中文贡献文档](./CONTRIBUTING_CN.md)]

## Topics

* [Reporting general issues](#reporting-general-issues)
* [Code and doc contribution](#code-and-doc-contribution)
* [Test case contribution](#test-case-contribution)
* [Engage to help anything](#engage-to-help-anything)
* [Code Style](#code-style)

## Reporting general issues

To be honest, we regard every user of seata-go as a very kind contributor. After experiencing seata-go, you may have some feedback for the project. Then feel free to open an issue via [NEW ISSUE](https://github.com/apache/incubator-seata-go/issues/new/choose).

Since we collaborate project seata-go in a distributed way, we appreciate **WELL-WRITTEN**, **DETAILED**, **EXPLICIT** issue reports. To make the communication more efficient, we wish everyone could search if your issue is an existing one in the searching list. If you find it existing, please add your details in comments under the existing issue instead of opening a brand new one.

To make the issue details as standard as possible, we setup an [ISSUE TEMPLATE](./.github/ISSUE_TEMPLATE) for issue reporters. Please **BE SURE** to follow the instructions to fill fields in template.

There are a lot of cases when you could open an issue:

* bug report
* feature request
* performance issues
* feature proposal
* feature design
* help wanted
* doc incomplete
* test improvement
* any questions on project
* and so on

Also we must remind that when filling a new issue, please remember to remove the sensitive data from your post. Sensitive data could be password, secret key, network locations, private business data and so on.

## Code and doc contribution

Every action to make project seata-go better is encouraged. On GitHub, every improvement for seata-go could be via a PR (short for pull request).

* If you find a typo, try to fix it!
* If you find a bug, try to fix it!
* If you find some redundant codes, try to remove them!
* If you find some test cases missing, try to add them!
* If you could enhance a feature, please **DO NOT** hesitate!
* If you find code implicit, try to add comments to make it clear!
* If you find code ugly, try to refactor that!
* If you can help to improve documents, it could not be better!
* If you find document incorrect, just do it and fix that!
* ...

Actually it is impossible to list them completely. Just remember one principle:

> WE ARE LOOKING FORWARD TO ANY PR FROM YOU.

Since you are ready to improve seata-go with a PR, we suggest you could take a look at the PR rules here.

* [Workspace Preparation](#workspace-preparation)
* [Branch Definition](#branch-definition)
* [Commit Rules](#commit-rules)
* [PR Description](#pr-description)

### Workspace Preparation

To put forward a PR, we assume you have registered a GitHub ID. Then you could finish the preparation in the following steps:

1. **FORK** seata-go to your repository. To make this work, you just need to click the button Fork in right-left of [seata/seata](https://github.com/apache/incubator-seata-go) main page. Then you will end up with your repository in `https://github.com/<your-username>/seata-go`, in which `your-username` is your GitHub username.

1. **CLONE** your own repository to develop locally. Use `git clone git@github.com:<your-username>/seata-go.git` to clone repository to your local machine. Then you can create new branches to finish the change you wish to make.

1. **Set Remote** upstream to be `git@github.com:apache/seata-go.git` using the following two commands:

```bash
git remote add upstream git@github.com:apache/seata-go.git
git remote set-url --push upstream no-pushing
```

With this remote setting, you can check your git remote configuration like this:

```shell
$ git remote -v
origin git@github.com:<your-username>/seata-go.git (fetch)
origin git@github.com:<your-username>/seata-go.git (push)
upstream git@github.com:apache/seata-go.git (fetch)
upstream no-pushing (push)
```

Adding this, we can easily synchronize local branches with upstream branches.

### Branch Definition

Right now we assume every contribution via pull request is for [branch develop](https://github.com/apache/incubator-seata-go/tree/master) in seata-go. Before contributing, be aware of branch definition would help a lot.

As a contributor, keep in mind again that every contribution via pull request is for branch develop. While in project seata-go, there are several other branches, we generally call them release branches(such as 0.6.0,0.6.1), feature branches, hotfix branches and master branch.

When officially releasing a version, there will be a release branch and named with the version number.

After the release, we will merge the commit of the release branch into the master branch.

When we find that there is a bug in a certain version, we will decide to fix it in a later version or fix it in a specific hotfix version. When we decide to fix the hotfix version, we will checkout the hotfix branch based on the corresponding release branch, perform code repair and verification, and merge it into the develop branch and the master branch.

For larger features, we will pull out the feature branch for development and verification.


### Commit Rules

Actually in seata-go, we take two rules serious when committing:

* [Commit Message](#commit-message)
* [Commit Content](#commit-content)

#### Commit Message

Commit message could help reviewers better understand what is the purpose of submitted PR. It could help accelerate the code review procedure as well. We encourage contributors to use **EXPLICIT** commit message rather than ambiguous message. In general, we advocate the following commit message type:

* docs: xxxx. For example, "docs: add docs about seata-go cluster installation".
* feature: xxxx.For example, "feature: support oracle in AT mode".
* bugfix: xxxx. For example, "bugfix: fix panic when input nil parameter".
* optimize: xxxx. For example, "optimize: simplify to make codes more readable".
* test: xxx. For example, "test: add unit test case for func InsertIntoArray".
* other readable and explicit expression ways.

On the other side, we discourage contributors from committing message like the following ways:

* ~~fix bug~~
* ~~update~~
* ~~add doc~~

If you get lost, please see [How to Write a Git Commit Message](http://chris.beams.io/posts/git-commit/) for a start.

#### Commit Content

Commit content represents all content changes included in one commit. We had better include things in one single commit which could support reviewer's complete review without any other commits' help. In another word, contents in one single commit can pass the CI to avoid code mess. In brief, there are three minor rules for us to keep in mind:

* avoid very large change in a commit;
* complete and reviewable for each commit.
* check git config(`user.name`, `user.email`) when committing to ensure that it is associated with your GitHub ID.

```bash
git config --get user.name
git config --get user.email
```

* when submitting pr, please add a brief description of the current changes to the dev.md file under the 'changes/' folder


In addition, in the code change part, we suggest that all contributors should read the [code style of seata-go](#code-style).

No matter commit message, or commit content, we do take more emphasis on code review.


#### Format your code

Before submitting the code, execute the script of formatting the code under the project root directory:

~~~shell
sh goimports.sh
~~~

### PR Description

PR is the only way to make change to seata-go project files. To help reviewers better get your purpose, PR description could not be too detailed. We encourage contributors to follow the [PR template](./.github/pull-request-template.md) to finish the pull request.

## Test case contribution

Any test case will be welcomed. Currently, seata-go functional test cases are of high priority.

- For unit tests, create a XXX_test.go file in the file directory of go file

## Engage to help anything

We choose GitHub as the primary place for seata-go to collaborate. So the latest updates of seata-go are always here. Although contributions via PR is an explicit way to help, we still call for any other ways.

* reply to other's issues if you could;
* help solve other user's problems;
* help review other's PR design;
* help review other's codes in PR;
* discuss about seata-go to make things clearer;
* advocate seata-go technology beyond GitHub;
* write blogs on seata-go and so on.


## Code Style

Seata-go code style reference [uber-go/guide](https://github.com/uber-go/guide) 。


### IDE Plugin Install(not necessary)

*It is not necessary to install, if you want to find a problem when you are coding.*

install go fmt 和 goimports plugin,detailed reference:https://github.com/golang/tools


In a word, **ANY HELP IS CONTRIBUTION.**

+ 0
- 210
CONTRIBUTING_CN.md View File

@@ -1,210 +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.
-->

# 为 seata-go 做贡献

如果你有兴趣为 seata-go 贡献代码,我们会热烈欢迎。首先,我们非常鼓励这种意愿。这是为您提供的贡献指南列表。

[[English Contributing Document](./CONTRIBUTING.md)]

## 话题

* [报告一般问题](#报告一般问题)
* [代码和文档贡献](#代码和文档贡献)
* [测试用例贡献](#测试用例贡献)
* [参与帮助任何事情](#参与帮助任何事情)
* [代码风格](#代码风格)

## 报告一般问题

老实说我们把每一个 seata-go 用户都视为非常善良的贡献者。在体验了 seata-go 之后,您可能会对项目有一些反馈。然后随时通过 [NEW ISSUE](https://github.com/apache/incubator-seata-go/issues/new/choose)打开一个问题。

因为我们在一个分布式的方式合作项目 seata-go,我们欣赏写得很好的,详细的,准确的问题报告。为了让沟通更高效,我们希望每个人都可以搜索您的问题是否在搜索列表中。如果您发现它存在,请在现有问题下的评论中添加您的详细信息,而不是打开一个全新的问题。

为了使问题细节尽可能标准,我们为问题报告者设置了一个[问题模板](./.github/ISSUE_TEMPLATE) 请务必按照说明填写模板中的字段。

有很多情况你可以打开一个问题:

* 错误报告
* 功能要求
* 性能问题
* 功能提案
* 功能设计
* 需要帮助
* 文档不完整
* 测试改进
* 关于项目的任何问题
* 等等

另外我们必须提醒的是,在填写新问题时,请记住从您的帖子中删除敏感数据。敏感数据可能是密码、密钥、网络位置、私人业务数据等。

## 代码和文档贡献

鼓励采取一切措施使 seata-go 项目变得更好。在 GitHub 上,seata-go 的每项改进都可以通过 PR(Pull Request 的缩写)实现。

* 如果您发现错别字,请尝试修复它!
* 如果您发现错误,请尝试修复它!
* 如果您发现一些多余的代码,请尝试删除它们!
* 如果您发现缺少一些测试用例,请尝试添加它们!
* 如果您可以增强功能,请**不要**犹豫!
* 如果您发现代码晦涩难懂,请尝试添加注释以使其更加易读!
* 如果您发现代码丑陋,请尝试重构它!
* 如果您能帮助改进文档,那就再好不过了!
* 如果您发现文档不正确,只需执行并修复它!
* ...

实际上不可能完整地列出它们。记住一个原则:

> 我们期待您的任何PR。

由于您已准备好通过 PR 改进 seata-go,我们建议您可以在此处查看 PR 规则。

* [工作区准备](#工作区准备)
* [分支定义](#分支定义)
* [提交规则](#提交规则)
* [PR说明](#PR说明)

### 工作区准备

为了提出 PR,我们假设你已经注册了一个 GitHub ID。然后您可以通过以下步骤完成准备工作:

1. **FORK** seata-go 到您的存储库。要完成这项工作,您只需单击 [apache/seata-go](https://github.com/apache/incubator-seata-go) 主页右侧的 Fork 按钮。然后你将在 中得到你的存储库`https://github.com/<your-username>/seata-go`,其中 your-username 是你的 GitHub 用户名。

2. **克隆** 您自己的存储库以在本地开发. 用于 `git clone git@github.com:<your-username>/seata-go.git` 将存储库克隆到本地计算机。 然后您可以创建新分支来完成您希望进行的更改。

3. **设置远程** 将上游设置为 `git@github.com:apache/seata-go.git` 使用以下两个命令:

```bash
git remote add upstream git@github.com:apache/seata-go.git
git remote set-url --push upstream no-pushing
```

使用此远程设置,您可以像这样检查您的 git 远程配置:

```shell
$ git remote -v
origin git@github.com:<your-username>/seata-go.git (fetch)
origin git@github.com:<your-username>/seata-go.git (push)
upstream git@github.com:apache/seata-go.git (fetch)
upstream no-pushing (push)
```

添加这个,我们可以轻松地将本地分支与上游分支同步。

### 分支定义

现在我们假设通过拉取请求的每个贡献都是针对 seata-go 中的 [开发分支](https://github.com/apache/incubator-seata-go/tree/master) 。在贡献之前,请注意分支定义会很有帮助。

作为贡献者,请再次记住,通过拉取请求的每个贡献都是针对分支开发的。而在 seata-go 项目中,还有其他几个分支,我们一般称它们为 release 分支(如0.6.0、0.6.1)、feature 分支、hotfix 分支和 master 分支。

当正式发布一个版本时,会有一个发布分支并以版本号命名。

在发布之后,我们会将发布分支的提交合并到主分支中。

当我们发现某个版本有 bug 时,我们会决定在以后的版本中修复它,或者在特定的 hotfix 版本中修复它。当我们决定修复 hotfix 版本时,我们会根据对应的 release 分支 checkout hotfix 分支,进行代码修复和验证,合并到 develop 分支和 master 分支。

对于较大的功能,我们将拉出功能分支进行开发和验证。


### 提交规则

实际上,在 seata-go 中,我们在提交时会认真对待两条规则:

* [提交消息](#提交消息)
* [提交内容](#提交内容)

#### 提交消息

提交消息可以帮助审稿人更好地理解提交 PR 的目的是什么。它还可以帮助加快代码审查过程。我们鼓励贡献者使用显式的提交信息,而不是模糊的信息。一般来说,我们提倡以下提交消息类型:

* docs: xxxx. For example, "docs: add docs about seata-go cluster installation".
* feature: xxxx.For example, "feature: support oracle in AT mode".
* bugfix: xxxx. For example, "bugfix: fix panic when input nil parameter".
* optimize: xxxx. For example, "optimize: simplify to make codes more readable".
* test: xxx. For example, "test: add unit test case for func InsertIntoArray".
* 其他可读和显式的表达方式。

另一方面,我们不鼓励贡献者通过以下方式提交消息:

* ~~修复错误~~
* ~~更新~~
* ~~添加文档~~

如果你不知道该怎么做,请参阅 [如何编写 Git 提交消息](http://chris.beams.io/posts/git-commit/) 作为开始。

#### 提交内容

提交内容表示一次提交中包含的所有内容更改。我们最好在一次提交中包含可以支持审阅者完整审查的内容,而无需任何其他提交的帮助。换句话说,一次提交中的内容可以通过 CI 以避免代码混乱。简而言之,我们需要牢记三个小规则:

* 避免在提交中进行非常大的更改;
* 每次提交都完整且可审查。
* 提交时检查 git config(`user.name`, `user.email`) 以确保它与您的 GitHub ID 相关联。

```bash
git config --get user.name
git config --get user.email
```

* 提交pr时,请在'changes/'文件夹下的dev.md文件中添加当前更改的简要说明


另外,在代码变更部分,我们建议所有贡献者阅读 seata-go 的 [代码风格](#代码风格)。

无论是提交信息,还是提交内容,我们都更加重视代码审查。

#### 格式化代码

提交代码之前,在项目根目录下执行格式化代码的脚本:

~~~shell
sh goimports.sh
~~~


### PR说明

PR 是更改 seata-go 项目文件的唯一方法。为了帮助审查人更好地理解你的目的,PR 描述不能太详细。我们鼓励贡献者遵循 [PR 模板](./.github/PULL_REQUEST_TEMPLATE.md) 来完成拉取请求。

## 测试用例贡献

任何测试用例都会受到欢迎。目前,seata-go 功能测试用例是高优先级的。

* 对于单元测试,在文件目录下创建一个 xxx_test.go 文件即可

## 参与帮助任何事情

我们选择 GitHub 作为 seata-go 协作的主要场所。所以 seata-go 的最新更新总是在这里。尽管通过 PR 贡献是一种明确的帮助方式,但我们仍然呼吁其他方式。

* 如果可以的话,回复别人的问题;
* 帮助解决其他用户的问题;
* 帮助审查他人的 PR 设计;
* 帮助审查其他人在 PR 中的代码;
* 讨论 seata-go以使事情更清楚;
* 在Github之外宣传 seata-go 技术;
* 写关于 seata-go 的博客等等。


## 代码风格

Seata-go 代码风格参考[uber-go/guide](https://github.com/uber-go/guide) 。


### IDE插件安装(非必须)

*没有必要安装,如果你想在编码的时候发现问题。*

安装 go fmt 和 goimports 插件,详情参考:https://github.com/golang/tools

+ 0
- 10
DISCLAIMER View File

@@ -1,10 +0,0 @@
Apache Seata (incubating) is an effort undergoing incubation at the Apache
Software Foundation (ASF), sponsored by the Apache Incubator PMC.

Incubation is required of all newly accepted projects until a further review
indicates that the infrastructure, communications, and decision making process
have stabilized in a manner consistent with other successful ASF projects.

While incubation status is not necessarily a reflection of the completeness
or stability of the code, it does indicate that the project has yet to be
fully endorsed by the ASF.

+ 45
- 0
Makefile View File

@@ -0,0 +1,45 @@
GOFILES_NOVENDOR = $(shell find . -type f -name '*.go' -not -path "./vendor/*")
GO_VERSION = 1.15

REGISTRY ?= seataio
TAG = $(shell git rev-parse --abbrev-ref HEAD)
COMMIT = git-$(shell git rev-parse --short HEAD)
DATE = $(shell date +"%Y-%m-%d_%H:%M:%S")
GOLDFLAGS = "-w -s -extldflags '-z now' -X github.com/opentrx/seata-golang/versions.COMMIT=$(COMMIT) -X github.com/opentrx/seata-golang/versions.BUILDDATE=$(DATE)"


.PHONY: build-go
build-go:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -buildmode=pie -o $(CURDIR)/dist/tc -ldflags $(GOLDFLAGS) -v ./cmd/tc

.PHONY: build-bin
build-bin:
docker run --rm -e GOOS=linux -e GOCACHE=/tmp -e GOARCH=$(ARCH) -e GOPROXY=https://goproxy.cn \
-u $(shell id -u):$(shell id -g) \
-v $(CURDIR):/go/src/github.com/opentrx/seata-golang:ro \
-v $(CURDIR)/dist:/go/src/github.com/opentrx/seata-golang/dist/ \
golang:$(GO_VERSION) /bin/bash -c '\
cd /go/src/github.com/opentrx/seata-golang && \
make build-go '

.PHONY: build-images
build-images: build-bin
docker build -t $(REGISTRY)/seata-golang:$(TAG) --build-arg ARCH=amd64 -f dist/Dockerfile dist/

.PHONY: push
push:
docker push $(REGISTRY)/seata-golang:$(TAG)

.PHONY: lint
lint:
@gofmt -d $(GOFILES_NOVENDOR)
@if [ $$(gofmt -l $(GOFILES_NOVENDOR) | wc -l) -ne 0 ]; then \
echo "Code differs from gofmt's style" 1>&2 && exit 1; \
fi
@GOOS=linux go vet ./...
@GOOS=linux gosec -exclude=G204,G601 ./...


.PHONY: clean
clean:
$(RM) dist/tc

+ 0
- 5
NOTICE View File

@@ -1,5 +0,0 @@
Apache Seata (Incubating)
Copyright 2023-2025 The Apache Software Foundation

This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).

+ 64
- 150
README.md View File

@@ -1,160 +1,74 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<div style="align: center">
<img src="https://img.alicdn.com/imgextra/i1/O1CN011z0JfQ2723QgDiWuH_!!6000000007738-2-tps-1497-401.png" height="100" width="426"/>
</div>

# Seata-go: Simple Extensible Autonomous Transaction Architecture(Go version)

[![CI](https://github.com/apache/incubator-seata-go/actions/workflows/build.yml/badge.svg)](https://github.com/apache/incubator-seata-go/actions/workflows/build.yml) [![license](https://img.shields.io/github/license/apache/incubator-seata-go.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) [![codecov](https://codecov.io/gh/apache/incubator-seata-go/branch/master/graph/badge.svg)](https://codecov.io/gh/apache/incubator-seata-go) [简体中文 ZH](./README_ZH.md)

## What is Seata-go?

Apache Seata(incubating) is a very mature distributed transaction framework, and is the de facto standard platform for distributed transaction technology in the Java field. Seata-go is the implementation version of go language in Seata multilingual ecosystem, which realizes the interoperability between Java and Go, so that Go developers can also use seata-go to realize distributed transactions. Please visit the [official website of Seata](https://seata.apache.org/) to view the quick start and documentation.

The principle of seata-go is consistent with that of Seata-java, which is composed of TM, RM and TC. The functions of TC are reused in Java, and the functions of TM and RM have been connected with Seata-java.
### Distributed Transaction Problem in Microservices

Let's imagine a traditional monolithic application. Its business is built up with 3 modules. They use a single local data source.

Naturally, data consistency will be guaranteed by the local transaction.

![Monolithic App](https://img.alicdn.com/imgextra/i3/O1CN01FTtjyG1H4vvVh1sNY_!!6000000000705-0-tps-1106-678.jpg)

Things have changed in a microservices architecture. The 3 modules mentioned above are designed to be 3 services on top of 3 different data sources ([Pattern: Database per service](http://microservices.io/patterns/data/database-per-service.html)). Data consistency within every single service is naturally guaranteed by the local transaction.

**But how about the whole business logic scope?**

![Microservices Problem](https://img.alicdn.com/imgextra/i1/O1CN01DXkc3o1te9mnJcHOr_!!6000000005926-0-tps-1268-804.jpg)

### How Seata-go do?

Seata-go is just a solution to the problem mentioned above.

![Seata solution](https://img.alicdn.com/imgextra/i1/O1CN01FheliH1k5VHIRob3p_!!6000000004632-0-tps-1534-908.jpg)

Firstly, how to define a **Distributed Transaction**?

We say, a **Distributed Transaction** is a **Global Transaction** which is made up with a batch of **Branch Transaction**, and normally **Branch Transaction** is just **Local Transaction**.

![Global & Branch](https://cdn.nlark.com/lark/0/2018/png/18862/1545015454979-a18e16f6-ed41-44f1-9c7a-bd82c4d5ff99.png)

There are three roles in Seata-go:

- **Transaction Coordinator(TC):** Maintain status of global and branch transactions, drive the global commit or rollback.
- **Transaction Manager(TM):** Define the scope of global transaction: begin a global transaction, commit or rollback a global transaction.
- **Resource Manager(RM):** Manage resources that branch transactions working on, talk to TC for registering branch transactions and reporting status of branch transactions, and drive the branch transaction commit or rollback.

![Model](https://cdn.nlark.com/lark/0/2018/png/18862/1545013915286-4a90f0df-5fda-41e1-91e0-2aa3d331c035.png)

A typical lifecycle of Seata-go managed distributed transaction:

1. TM asks TC to begin a new global transaction. TC generates an XID representing the global transaction.
2. XID is propagated through microservices' invoke chain.
3. RM registers local transaction as a branch of the corresponding global transaction of XID to TC.
4. TM asks TC for committing or rollbacking the corresponding global transaction of XID.
5. TC drives all branch transactions under the corresponding global transaction of XID to finish branch committing or rollbacking.

![Typical Process](https://cdn.nlark.com/lark/0/2018/png/18862/1545296917881-26fabeb9-71fa-4f3e-8a7a-fc317d3389f4.png)

For more details about principle and design, please go to [Seata wiki page](https://github.com/apache/incubator-seata/wiki).

### History

##### Alibaba

- **TXC**: Taobao Transaction Constructor. Alibaba middleware team started this project since 2014 to meet the distributed transaction problems caused by application architecture change from monolithic to microservices.
- **GTS**: Global Transaction Service. TXC as an Aliyun middleware product with new name GTS was published since 2016.
- **Fescar**: we started the open source project Fescar based on TXC/GTS since 2019 to work closely with the community in the future.


##### Ant Financial

- **XTS**: Extended Transaction Service. Ant Financial middleware team developed the distributed transaction middleware since 2007, which is widely used in Ant Financial and solves the problems of data consistency across databases and services.

- **DTX**: Distributed Transaction Extended. Since 2013, XTS has been published on the Ant Financial Cloud, with the name of DTX .


##### Seata Community

- **Seata** :Simple Extensible Autonomous Transaction Architecture. Ant Financial joins Fescar, which make it to be a more neutral and open community for distributed transaction, and Fescar be renamed to Seata.



## How to run?

```go
go get seata.apache.org/seata-go@v2.0.0

# seata-golang
[![LICENSE](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://github.com/opentrx/seata-golang/blob/v2/LICENSE)

## Introduction | [中文](https://github.com/opentrx/seata-golang/blob/v2/docs/README_ZH.md)
seata-golang is a distributed transaction middleware based on Golang.
### difference between seata-glang and [seata](https://github.com/seata/seata)
| feature | seata | seata-golang | remark |
| ---- | :----: | :----: | --- |
| AT mode | √ | √ | |
| TCC mode | √ | √ | |
| SAGA mode | √ | × | |
| rpc | √ | √ | [dev branch](https://github.com/opentrx/seata-golang/tree/dev) |
| grpc | × | √ | [v2 branch](https://github.com/opentrx/seata-golang/tree/v2) |

## Architecture
<img alt="seata-flow" width="500px" src="https://github.com/opentrx/seata-golang/blob/v2/docs/images/seata-flow.png" />

A typical lifecycle of Seata managed distributed transaction:

- TM asks TC to begin a new global transaction. TC generates an XID representing the global transaction.
- XID is propagated through microservices' invoke chain.
- RM registers local transaction as a branch of the corresponding global transaction of XID to TC.
- TM asks TC for committing or rolling back the corresponding global transaction of XID.
- TC drives all branch transactions under the corresponding global transaction of XID to finish branch committing or rolling back.

## Directory structure
- cmd: to startup TC server
- profiles/dev/config.yml: TC config file
- tc/main.go: TC startup entrance
- dist: to build in docker container
- docs: documentations
- pkg: TC + RM + TM implementation
- server/db/*.sql: sql scripts to create DB and tables for TC

## Getting started
- ### TC server
```bash
cd ${projectpath}/cmd/tc
go build -o tc_server
# create database `seata` for TC server
# update storage.dsn.mysql in ${projectpath}/cmd/profiles/dev/config.yml
./tc_server start -config ${projectpath}/cmd/profiles/dev/config.yml
``` ```


if you want to know how to use and integrate seata-go, please refer to [apache/seata-go-samples](https://github.com/apache/incubator-seata-go-samples)

## How to find the latest version
Visit Seata-Go's GitHub Releases page

Open:
https://github.com/seata/seata-go/releases

The latest tag / release is the latest stable version.


## Documentation
- ### Client
Please refer to demo [seata-go-samples](https://github.com/opentrx/seata-go-samples)


- ### Prerequisites
- MySQL server
- Golang version >= 1.15
- Business tables that require primary key


You can view the full documentation from Seata Official Website: [Seata Website page](https://seata.apache.org/zh-cn/docs/overview/what-is-seata).

## Reporting bugs

Please follow the [template](.github/ISSUE_TEMPLATE/BUG_REPORT_TEMPLATE.md) for reporting any issues.

## Security

Please do not use our public issue tracker but refer to our [security policy](https://github.com/apache/incubator-seata/blob/2.x/SECURITY.md)

## Contributing

Seata-go is currently in the construction stage. Welcome colleagues in the industry to join the group and work with us to promote the construction of seata-go! If you want to contribute code to seata-go, you can refer to the [**code contribution Specification**](./CONTRIBUTING_CN.md) document to understand the specifications of the community, or you can join our community DingTalk group: 33069364 and communicate together!
## Design and implementation
The seata-golang AT and TCC design are actually the same as [seata](https://github.com/seata/seata).
Please refer to [what-is-seata](https://seata.io/en-us/docs/overview/what-is-seata.html) for more details.


## Reference
- [what is seata AT mode?](https://seata.io/en-us/docs/dev/mode/at-mode.html)
- [what is seata TCC mode?](https://seata.io/en-us/docs/dev/mode/tcc-mode.html)
- [GRPC](https://grpc.io/)
- [dubbogo](https://github.com/dubbogo)
- [mysql-driver](https://github.com/opentrx/mysql)
- [seata-go-samples](https://github.com/opentrx/seata-go-samples)


## Contact ## Contact
Please contact us via DingTalk app if you have any issues. The chat group ID is 33069364.
<img alt="DingTalk Group" src="https://github.com/opentrx/seata-golang/blob/dev/docs/pics/33069364.png" width="200px" />


* Mailing list:
* dev@seata.apache.org , for dev/user discussion. [subscribe](mailto:dev-subscribe@seata.apache.org), [unsubscribe](mailto:dev-unsubscribe@seata.apache.org), [archive](https://lists.apache.org/list.html?dev@seata.apache.org)
* Online chat:

| Dingtalk group | Wechat official account | QQ group | Wechat assistant |
|:---------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------:|
| <img src="https://seata.apache.org/zh-cn/assets/images/dingtalk-group-67f42c9466fb2268b6927bb16b549d6c.jpg" width="150" /> | <img src="https://seata.apache.org/zh-cn/assets/images/wechat-official-467d10305f5449e6b2096e65d23a9d02.jpg" width="150" /> | <img src="https://seata.apache.org/zh-cn/assets/images/qq-group-8d8a89699cdb9ba8818364069475ba96.jpg" width="150" /> | <img src="https://seata.apache.org/zh-cn/assets/images/wechat-f8a87a96973942b826e32d1aed9bc8d9.jpg" width="150" /> |

## Seata ecosystem

* [Seata Website](https://github.com/apache/incubator-seata.github.io) - Seata official website
* [Seata](https://github.com/apache/incubator-seata)- Seata client and server
* [Seata GoLang](https://github.com/apache/incubator-seata-go) - Seata GoLang client and server
* [Seata Samples](https://github.com/apache/incubator-seata-samples) - Samples for Seata
* [Seata GoLang Samples](https://github.com/apache/incubator-seata-go-samples) - Samples for Seata GoLang
* [Seata K8s](https://github.com/apache/incubator-seata-k8s) - Seata integration with k8s
* [Seata CLI](https://github.com/apache/incubator-seata-ctl) - CLI tool for Seata

## Contributors

This project exists thanks to all the people who contribute. [[Contributors](https://github.com/apache/incubator-seata-go/graphs/contributors)].
## Contributing
Welcome to raise up issue or pull-request to seata-golang!
To contribute, fork from opentrx/seata-golang and push branch to your repo, then open a pull-request.


## License ## License

Seata-go is under the Apache 2.0 license. See the [LICENSE](https://github.com/apache/incubator-seata-go/blob/master/LICENSE) file for details.
seata-golang software is licenced under the Apache License Version 2.0. See the [LICENSE](https://github.com/opentrx/seata-golang/blob/v2/LICENSE) file for details.

+ 0
- 164
README_ZH.md View File

@@ -1,164 +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.
-->
<div style="align: center">

<img src="https://img.alicdn.com/imgextra/i1/O1CN011z0JfQ2723QgDiWuH_!!6000000007738-2-tps-1497-401.png" height="100" width="426"/>

</div>
# Seata-go:简单可扩展的自主事务架构(Go 语言版本)

[![CI](https://github.com/apache/incubator-seata-go/actions/workflows/build.yml/badge.svg)](https://github.com/apache/incubator-seata-go/actions/workflows/build.yml) [![license](https://img.shields.io/github/license/apache/incubator-seata-go.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) [![codecov](https://codecov.io/gh/apache/incubator-seata-go/branch/master/graph/badge.svg)](https://codecov.io/gh/apache/incubator-seata-go) [English](./README.md)


## 什么是 Seata-go?


Apache Seata(incubating)是一个非常成熟的分布式事务框架,是 Java 领域事实上的标准分布式事务平台。Seata-go 是其在多语言生态中 Go 语言的实现版本,实现了 Java 与 Go 之间的互操作,使得 Go 开发者也可以使用 seata-go 实现分布式事务。请访问 [Seata 官网](https://seata.apache.org/) 获取快速入门和文档。

Seata-go 的原理与 Seata-java 一致,由 TM、RM 和 TC 三部分组成。其中 TC 功能复用 Java 的实现,而 TM 和 RM 则已与 Seata-java 对接。

### 微服务中的分布式事务问题

假设我们有一个传统的单体应用,其业务由三个模块组成,使用一个本地数据源,自然由本地事务保障数据一致性。
![Monolithic App](https://img.alicdn.com/imgextra/i3/O1CN01FTtjyG1H4vvVh1sNY_!!6000000000705-0-tps-1106-678.jpg)
但在微服务架构中,这三个模块被设计成了三个不同的服务,分别使用不同的数据源([数据库每服务模式](http://microservices.io/patterns/data/database-per-service.html))。单个服务内的数据一致性可以通过本地事务保障。

但**整个业务范围的一致性如何保障?**
![Microservices Problem](https://img.alicdn.com/imgextra/i1/O1CN01DXkc3o1te9mnJcHOr_!!6000000005926-0-tps-1268-804.jpg)


### Seata-go 如何做?

Seata-go 就是为了解决上述问题而生。
![Seata solution](https://img.alicdn.com/imgextra/i1/O1CN01FheliH1k5VHIRob3p_!!6000000004632-0-tps-1534-908.jpg)
首先,如何定义一个**分布式事务**?
我们认为,分布式事务是一个**全局事务**,由一组**分支事务**组成,而**分支事务**通常就是**本地事务**。
![Global & Branch](https://cdn.nlark.com/lark/0/2018/png/18862/1545015454979-a18e16f6-ed41-44f1-9c7a-bd82c4d5ff99.png)


Seata-go 中有三个角色:

- **事务协调器(TC)**:维护全局和分支事务的状态,驱动全局提交或回滚。

- **事务管理器(TM)**:定义全局事务的范围,开始、提交或回滚全局事务。

- **资源管理器(RM)**:管理分支事务所处理的资源,与 TC 通信注册分支事务并报告状态,驱动分支事务提交或回滚。
![Model](https://cdn.nlark.com/lark/0/2018/png/18862/1545013915286-4a90f0df-5fda-41e1-91e0-2aa3d331c035.png)


Seata-go 分布式事务的典型生命周期如下:



1. TM 请求 TC 开启一个新的全局事务,TC 生成表示全局事务的 XID。

2. XID 在微服务调用链中传播。

3. RM 将本地事务注册为该 XID 对应的全局事务的分支事务。

4. TM 请求 TC 提交或回滚该 XID 对应的全局事务。

5. TC 驱动该 XID 对应的所有分支事务进行提交或回滚。

![Typical Process](https://cdn.nlark.com/lark/0/2018/png/18862/1545296917881-26fabeb9-71fa-4f3e-8a7a-fc317d3389f4.png)

更多原理和设计细节,请参阅 [Seata Wiki 页面](https://github.com/apache/incubator-seata/wiki)。



### 历史背景

##### 阿里巴巴

- **TXC**:淘宝事务构建器。2014 年阿里中间件团队启动,用于应对从单体架构转向微服务带来的分布式事务问题。

- **GTS**:全局事务服务。2016 年 TXC 在阿里云上线,更名为 GTS。

- **Fescar**:2019 年开始基于 TXC/GTS 启动开源项目 Fescar,与社区合作。

##### 蚂蚁金服

- **XTS**:扩展事务服务。自 2007 年开始开发的分布式事务中间件,被广泛应用于蚂蚁金服,解决跨库跨服务数据一致性问题。

- **DTX**:分布式事务扩展。2013 年起在蚂蚁金服云发布,命名为 DTX。
##### Seata 社区

- **Seata**:简单可扩展的自主事务架构。蚂蚁金服加入 Fescar,使其成为一个更加中立开放的社区,Fescar 更名为 Seata。

## 如何运行?
```go

go get seata.apache.org/seata-go@2.0.0

```
如果你想了解如何使用和集成 seata-go,请参考 [apache/seata-go-samples](https://github.com/apache/incubator-seata-go-samples)
## 如何查找最新版本
访问 Seata-Go 的 GitHub Releases 页面

打开:https://github.com/seata/seata-go/releases

最新的 tag / release 就是目前的最新稳定版本。
## 文档

你可以访问 Seata 官方网站获取完整文档:[Seata 官网](https://seata.apache.org/zh-cn/docs/overview/what-is-seata)
## 问题报告

若有问题,请遵循 [模板](./.github/ISSUE_TEMPLATE/BUG_REPORT_TEMPLATE.md) 报告问题。

## 安全

请勿使用公开的问题跟踪器,详情请参阅我们的 [安全政策](https://github.com/apache/incubator-seata/blob/2.x/SECURITY.md)

## 参与贡献
Seata-go 当前处于建设阶段,欢迎业界同仁加入我们,共同推进 Seata-go 建设!如果你想为 Seata-go 贡献代码,请参考 [代码贡献规范](./CONTRIBUTING_CN.md),也可以加入我们的社区钉钉群:33069364 一起交流!

## 联系方式

* 邮件列表:  

  * dev@seata.apache.org - 用于开发/用户讨论   [订阅](mailto:dev-subscribe@seata.apache.org)、[取消订阅](mailto:dev-unsubscribe@seata.apache.org)、[归档](https://lists.apache.org/list.html?dev@seata.apache.org)

* 在线交流:  

| 钉钉 | 微信公众号 | QQ | 微信助手 |
|:---------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------:|
| <img src="https://seata.apache.org/zh-cn/assets/images/dingtalk-group-67f42c9466fb2268b6927bb16b549d6c.jpg" width="150" /> | <img src="https://seata.apache.org/zh-cn/assets/images/wechat-official-467d10305f5449e6b2096e65d23a9d02.jpg" width="150" /> | <img src="https://seata.apache.org/zh-cn/assets/images/qq-group-8d8a89699cdb9ba8818364069475ba96.jpg" width="150" /> | <img src="https://seata.apache.org/zh-cn/assets/images/wechat-f8a87a96973942b826e32d1aed9bc8d9.jpg" width="150" /> |


## Seata 生态系统

* [Seata 官网](https://github.com/apache/incubator-seata.github.io)- Seata官方网站

* [Seata](https://github.com/apache/incubator-seata) - Seata 客户端和服务端

* [Seata GoLang](https://github.com/apache/incubator-seata-go) - Seata Go 客户端和服务端

* [Seata 示例](https://github.com/apache/incubator-seata-samples)- Seata 示例

* [Seata Go 示例](https://github.com/apache/incubator-seata-go-samples)- Seata GoLang 示例

* [Seata K8s 集成](https://github.com/apache/incubator-seata-k8s)- Seata 与 K8S 集成

* [Seata 命令行工具](https://github.com/apache/incubator-seata-ctl)- Seata CLI 工具

## 贡献者

Seata-go感谢所有贡献者的付出。[[贡献者列表](https://github.com/apache/incubator-seata-go/graphs/contributors)]
## 许可证

Seata-go 使用 Apache 2.0 协议,详情请查看 [LICENSE 文件](https://github.com/apache/incubator-seata-go/blob/master/LICENSE)

+ 0
- 78
changes/0.1.0.md View File

@@ -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.
-->

### 0.1.0-rc1

<details>
<summary><mark>Release notes</mark></summary>

### Seata-go 0.1.0-rc1

Seata-go 0.1.0-rc1 Released.

Seata-go is an easy-to-use, high-performance, open source distributed transaction solution.

The version is updated as follows:

### feature:

- [[#1](https://github.com/apache/incubator-seata-go/commit/06b9969bb3fd24071adc271dc543c3eb684070c9)] initialize project structure and support tcc local
- [[#2](https://github.com/apache/incubator-seata-go/commit/80913fa73e38fd3c159dcd28804344b9a87f718c)] add github Actions
- [[#122](https://github.com/apache/incubator-seata-go/pull/122)] feat: add two phase and tcc dubbo
- [[#127](https://github.com/apache/incubator-seata-go/pull/127)] feat: transaction at datasource

### bugfix:

- [[#5](https://github.com/apache/incubator-seata-go/commit/48f1b6bf6c8890d649ceac3d048f61695dce2f7a)] fix cli bug
- [[#15](https://github.com/apache/incubator-seata-go/commit/de615531e9d17af66067c54452ee5bce2d670008)] fix branch commit bug
- [[#34](https://github.com/apache/incubator-seata-go/commit/846a3b336194f9d188f07bf6af65f617b0baf489)] style:change bool to struct{}
- [[#130](https://github.com/apache/incubator-seata-go/pull/130)] fix: getty session auto close bug
- [[#155](https://github.com/apache/incubator-seata-go/pull/155)] bugfix: fix rollback response status bug

### optimize:

- [[#3](https://github.com/apache/incubator-seata-go/commit/65c2e1ed676a2306eb10f7d43e3bf5b37271ee3e)] adjust the structure of the project
- [[#18](https://github.com/apache/incubator-seata-go/commit/de615531e9d17af66067c54452ee5bce2d670008)] remove goetty
- [[#19](https://github.com/apache/incubator-seata-go/commit/de615531e9d17af66067c54452ee5bce2d670008)] optimize codec code
- [[#125](https://github.com/apache/incubator-seata-go/pull/125)] optimize named for the resource manager api
- [[#165](https://github.com/apache/incubator-seata-go/pull/165)] test: add unit test and labeler workflow

### test:

- [[#9f4d8](https://github.com/apache/incubator-seata-go/commit/9f4d8cc0b6f1e26860cded5ab05b504ad6a6d6ff)] add unit test for codec

### doc:

- [[#0](https://github.com/apache/incubator-seata-go/commit/fcda132629032321a7cc733a7a2ed02e05c2151b)] hello world
- [[#146](https://github.com/apache/incubator-seata-go/pull/146)] doc: add license
- [[#153](https://github.com/apache/incubator-seata-go/pull/153)] docs: add readme ,contributing and pr template doc
- [[#167](https://github.com/apache/incubator-seata-go/pull/167)] fix typo in reademe

### contributors:

Thanks to these contributors for their code commits. Please report an unintended omission.

- [AlexStocks](https://github.com/AlexStocks)
- [luky116](https://github.com/luky116)
- [106umao](https://github.com/106umao)
- [liiibpm](https://github.com/liiibpm)
- [cgDeepLearn](https://github.com/cgDeepLearn)
- [Penglq](https://github.com/Penglq)

Also, we receive many valuable issues, questions and advices from our community. Thanks for you all.

</detail>

+ 0
- 78
changes/0.1.0_zh.md View File

@@ -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.
-->

### 0.1.0-rc1

<details>
<summary><mark>Release notes</mark></summary>

### Seata-go 0.1.0-rc1

Seata-go 0.1.0-rc1 发布。

Seata-go 是一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。

此版本更新如下:

### feature:

- [[#1](https://github.com/apache/incubator-seata-go/commit/06b9969bb3fd24071adc271dc543c3eb684070c9)] 项目初始化,并且支持TCC本地模式
- [[#2](https://github.com/apache/incubator-seata-go/commit/80913fa73e38fd3c159dcd28804344b9a87f718c)] 添加 github 工作流
- [[#122](https://github.com/apache/incubator-seata-go/pull/122)] 添加二阶段提交和TCC dubbo调用
- [[#127](https://github.com/apache/incubator-seata-go/pull/127)] 添加事务数据源代理

### bugfix:

- [[#5](https://github.com/apache/incubator-seata-go/commit/48f1b6bf6c8890d649ceac3d048f61695dce2f7a)] 修复cli的问题
- [[#15](https://github.com/apache/incubator-seata-go/commit/de615531e9d17af66067c54452ee5bce2d670008)] 修复提交分支事务的问题
- [[#34](https://github.com/apache/incubator-seata-go/commit/846a3b336194f9d188f07bf6af65f617b0baf489)] 将bool改为struct{}
- [[#130](https://github.com/apache/incubator-seata-go/pull/130)] 修复getty 自动关闭session的问题
- [[#155](https://github.com/apache/incubator-seata-go/pull/155)] 修复分支事务回滚时返回值status的问题

### optimize:

- [[#3](https://github.com/apache/incubator-seata-go/commit/65c2e1ed676a2306eb10f7d43e3bf5b37271ee3e)] 调整项目结构
- [[#18](https://github.com/apache/incubator-seata-go/commit/de615531e9d17af66067c54452ee5bce2d670008)] 移除 goetty 包依赖
- [[#19](https://github.com/apache/incubator-seata-go/commit/de615531e9d17af66067c54452ee5bce2d670008)] 重构 codec 的代码
- [[#125](https://github.com/apache/incubator-seata-go/pull/125)] 重名 rm api 的接口
- [[#165](https://github.com/apache/incubator-seata-go/pull/165)] 完善 github 工作流

### test:

- [[#9f4d8](https://github.com/apache/incubator-seata-go/commit/9f4d8cc0b6f1e26860cded5ab05b504ad6a6d6ff)] 添加codec的单测

### doc:

- [[#0](https://github.com/apache/incubator-seata-go/commit/fcda132629032321a7cc733a7a2ed02e05c2151b)] hello world
- [[#146](https://github.com/apache/incubator-seata-go/pull/146)] 添加 license 文件
- [[#153](https://github.com/apache/incubator-seata-go/pull/153)] 添加 readme 、contributing 和 pr template 文件
- [[#167](https://github.com/apache/incubator-seata-go/pull/167)] 完善 reamdme 文件格式

### contributors:

非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。

- [AlexStocks](https://github.com/AlexStocks)
- [luky116](https://github.com/luky116)
- [106umao](https://github.com/106umao)
- [liiibpm](https://github.com/liiibpm)
- [cgDeepLearn](https://github.com/cgDeepLearn)
- [Penglq](https://github.com/Penglq)

同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。

</detail>

+ 0
- 156
changes/1.0.2-RC1.md View File

@@ -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.
-->

### 1.0.2-RC1

<details>
<summary><mark>Release notes</mark></summary>

### Seata-go 1.0.2-RC1

Seata-go 1.0.2-RC1 Released.

Seata-go is an easy-to-use, high-performance, open source distributed transaction solution.

The version is updated as follows:

### feature:
- [[#190](https://github.com/apache/incubator-seata-go/pull/190)] add TCC branch report
- [[#158](https://github.com/apache/incubator-seata-go/pull/158)] TCC mode supports grpc call
- [[#213](https://github.com/apache/incubator-seata-go/pull/213)] support data source proxy function
- [[#240](https://github.com/apache/incubator-seata-go/pull/240)] add undo log manager delete
- [[#243](https://github.com/apache/incubator-seata-go/pull/243)] add update sql parser
- [[#191](https://github.com/apache/incubator-seata-go/pull/191)] add fence for TCC, and add fence sample in TCC local mode
- [[#264](https://github.com/apache/incubator-seata-go/pull/264)] add update sql parser and remove tidb parser
- [[#280](https://github.com/apache/incubator-seata-go/pull/280)] TCC supports http calling
- [[#245](https://github.com/apache/incubator-seata-go/pull/245)] support hasLogTable logic
- [[#288](https://github.com/apache/incubator-seata-go/pull/288)] add MySQL update SQL undo log builder
- [[#296](https://github.com/apache/incubator-seata-go/pull/296)] add MySQL delete SQL undo log builder
- [[#303](https://github.com/apache/incubator-seata-go/pull/303)] add sync worker
- [[#289](https://github.com/apache/incubator-seata-go/pull/289)] add MySQL update SQL after undo log builder
- [[#294](https://github.com/apache/incubator-seata-go/pull/294)] add MySQL table meta query
- [[#309](https://github.com/apache/incubator-seata-go/pull/309)] init compressor type
- [[#301](https://github.com/apache/incubator-seata-go/pull/301)] add MySQL multi SQL undo log builder
- [[#321](https://github.com/apache/incubator-seata-go/pull/321)] add deflate compress
- [[#324](https://github.com/apache/incubator-seata-go/pull/324)] add LZ4 compressor
- [[#327](https://github.com/apache/incubator-seata-go/pull/327)] add zstd compressor
- [[#322](https://github.com/apache/incubator-seata-go/pull/322)] add gzip compressor
- [[#307](https://github.com/apache/incubator-seata-go/pull/307)] add flush undo log
- [[#329](https://github.com/apache/incubator-seata-go/pull/329)] add zip compressor
- [[#325](https://github.com/apache/incubator-seata-go/pull/325)] add MySQL multi update SQL undo log builder
- [[#330](https://github.com/apache/incubator-seata-go/pull/330)] add MySQL multi delete SQL undo log builder
- [[#319](https://github.com/apache/incubator-seata-go/pull/319)] add select for update
- [[#320](https://github.com/apache/incubator-seata-go/pull/320)] add undo logic
- [[#337](https://github.com/apache/incubator-seata-go/pull/337)] add insert undo log
- [[#355](https://github.com/apache/incubator-seata-go/pull/355)] support judging the number of undo log storage fields according to the configuration
- [[#365](https://github.com/apache/incubator-seata-go/pull/365)] do dirty data check before rolling back AT


### bugfix:

- [[#176](https://github.com/apache/incubator-seata-go/pull/176)] fix unit test bug of message
- [[#237](https://github.com/apache/incubator-seata-go/pull/237)] fix the bug of registering resources when executing the OpenConnector function
- [[#230](https://github.com/apache/incubator-seata-go/pull/230)] fix the bug of remote asynchronous call infinite loop
- [[#258](https://github.com/apache/incubator-seata-go/pull/258)] fix global transation time out bug
- [[#263](https://github.com/apache/incubator-seata-go/pull/263)] fix mock bug
- [[#326](https://github.com/apache/incubator-seata-go/pull/326)] fix fanout test data race
- [[#350](https://github.com/apache/incubator-seata-go/pull/350)] fix panic bug
- [[#359](https://github.com/apache/incubator-seata-go/pull/359)] fix insert undo log bug
- [[#368](https://github.com/apache/incubator-seata-go/pull/368)] fix AT rollback sample bug
- [[#363](https://github.com/apache/incubator-seata-go/pull/363)] fix meta data bug
- [[#365](https://github.com/apache/incubator-seata-go/pull/365)] fix decode undo log bug



### optimize:


- [[#187](https://github.com/apache/incubator-seata-go/pull/187)] optimize way of init seata-go
- [[#196](https://github.com/apache/incubator-seata-go/pull/196)] optimize remoting method's params
- [[#200](https://github.com/apache/incubator-seata-go/pull/200)] add TCC grpc sample and optimize register resource and branch register
- [[#208](https://github.com/apache/incubator-seata-go/pull/208)] optimize remove unnecessary codes
- [[#202](https://github.com/apache/incubator-seata-go/pull/202)] optimize workflow, add condecov and issue, stale robot
- [[#215](https://github.com/apache/incubator-seata-go/pull/215)] optimize the time parameter to improve readability
- [[#179](https://github.com/apache/incubator-seata-go/pull/179)] support instance BusinessActionContext outside the TCC try method
- [[#198](https://github.com/apache/incubator-seata-go/pull/198)] optimize function's parameters into one struct-rm_api.go
- [[#235](https://github.com/apache/incubator-seata-go/pull/235)] adjust MessageType enumeration value naming convention
- [[#238](https://github.com/apache/incubator-seata-go/pull/238)] add some todo comment, add a undo hook sample
- [[#229](https://github.com/apache/incubator-seata-go/pull/229)] add unit testing for common
- [[#261](https://github.com/apache/incubator-seata-go/pull/261)] optimize nested loop retries
- [[#284](https://github.com/apache/incubator-seata-go/pull/284)] optimize retry logic
- [[#286](https://github.com/apache/incubator-seata-go/pull/286)] separate the initialization logic of tm and rm
- [[#287](https://github.com/apache/incubator-seata-go/pull/287)] fefactor seata conn logic
- [[#281](https://github.com/apache/incubator-seata-go/pull/281)] optimize global transaction usage
- [[#295](https://github.com/apache/incubator-seata-go/pull/295)] fefactor seata conn logic
- [[#302](https://github.com/apache/incubator-seata-go/pull/302)] update dubbo-go version
- [[#336](https://github.com/apache/incubator-seata-go/pull/336)] optimize at overall process
- [[#346](https://github.com/apache/incubator-seata-go/pull/346)] optimize AT commit transaction process
- [[#352](https://github.com/apache/incubator-seata-go/pull/352)] optimize get meta data
- [[#354](https://github.com/apache/incubator-seata-go/pull/354)] optimize AT commit transaction process
- [[#353](https://github.com/apache/incubator-seata-go/pull/353)] modify some receiver name
- [[#356](https://github.com/apache/incubator-seata-go/pull/356)] optimize AT rollback transaction process


### test:

- [[#154](https://github.com/apache/incubator-seata-go/pull/154)] add unit test for message
- [[#163](https://github.com/apache/incubator-seata-go/pull/163)] add unit test for tm
- [[#203](https://github.com/apache/incubator-seata-go/pull/203)] add unit test for getty
- [[#204](https://github.com/apache/incubator-seata-go/pull/204)] add unit test for dubbo transtation filter
- [[#210](https://github.com/apache/incubator-seata-go/pull/210)] add unit test for Tcc branch report
- [[#192](https://github.com/apache/incubator-seata-go/pull/192)] add unit test for rm
- [[#229](https://github.com/apache/incubator-seata-go/pull/229)] add unit test for common
- [[#299](https://github.com/apache/incubator-seata-go/pull/299)] add unit test for SQL Parser
- [[#332](https://github.com/apache/incubator-seata-go/pull/332)] add unit test for multi delete undo log
- [[#358](https://github.com/apache/incubator-seata-go/pull/358)] add AT rollback sample


### doc:

- [[#202](https://github.com/apache/incubator-seata-go/pull/202)] optimize workflow, add condecov and issue
- [[#254](https://github.com/apache/incubator-seata-go/pull/254)] add license automatic check script
- [[#305](https://github.com/apache/incubator-seata-go/pull/305)] config github action not to automatically close pr or issue


### contributors:

Thanks to these contributors for their code commits. Please report an unintended omission.

- [AlexStocks](https://github.com/AlexStocks)
- [luky116](https://github.com/luky116)
- [106umao](https://github.com/106umao)
- [liiibpm](https://github.com/liiibpm)
- [elrond-g](https://github.com/elrond-g)
- [wang1309](https://github.com/wang1309)
- [iSuperCoder](https://github.com/apache/incubator-seata-go/commits?author=iSuperCoder)
- [a631807682](https://github.com/apache/incubator-seata-go/commits?author=a631807682)
- [betterwinsone](https://github.com/apache/incubator-seata-go/commits?author=betterwinsone)
- [jasondeng1997](https://github.com/apache/incubator-seata-go/commits?author=jasondeng1997)
- [chuntaojun](https://github.com/apache/incubator-seata-go/commits?author=chuntaojun)
- [complone](https://github.com/apache/incubator-seata-go/commits?author=complone)
- [miaoxueyu](https://github.com/apache/incubator-seata-go/commits?author=miaoxueyu)
- [PangXing](https://github.com/apache/incubator-seata-go/commits?author=PangXing)
- [georgehao](https://github.com/apache/incubator-seata-go/commits?author=georgehao)
- [baerwang](https://github.com/apache/incubator-seata-go/commits?author=baerwang)
- [raspberry-hu](https://github.com/apache/incubator-seata-go/commits?author=raspberry-hu)
- [WyattJia](https://github.com/apache/incubator-seata-go/commits?author=WyattJia)
- [Code-Fight](https://github.com/Code-Fight)
- [betterwinsone](https://github.com/betterwinsonet)

Also, we receive many valuable issues, questions and advices from our community. Thanks for you all.

</detail>

+ 0
- 157
changes/1.0.2-RC1_zh.md View File

@@ -1,157 +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.
-->

### 1.0.2-RC1

<details>
<summary><mark>Release notes</mark></summary>

### Seata-go 1.0.2-RC1

Seata-go 1.0.2-RC1 发布。

Seata-go 是一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。

此版本更新如下:

### feature:

- [[#190](https://github.com/apache/incubator-seata-go/pull/190)] 添加分支状态上报接口
- [[#158](https://github.com/apache/incubator-seata-go/pull/158)] TCC 模式支持 grapc 调用
- [[#213](https://github.com/apache/incubator-seata-go/pull/213)] 支持数据源代理功能
- [[#240](https://github.com/apache/incubator-seata-go/pull/240)] 删除日志管理功能
- [[#243](https://github.com/apache/incubator-seata-go/pull/243)] 添加 Update SQL 语法解析器
- [[#191](https://github.com/apache/incubator-seata-go/pull/191)] 支持 TCC 防悬挂、空回滚处理功能
- [[#264](https://github.com/apache/incubator-seata-go/pull/264)] 添加更新sql解析器并删除 tidb 解析器
- [[#280](https://github.com/apache/incubator-seata-go/pull/280)] TCC 支持 http 调用
- [[#245](https://github.com/apache/incubator-seata-go/pull/245)] 支持 hasLogTable 判断逻辑
- [[#288](https://github.com/apache/incubator-seata-go/pull/288)] 添加 update SQL 的 undo log 生成功能
- [[#296](https://github.com/apache/incubator-seata-go/pull/296)] 添加 delete SQL 的 undo log 生成功能
- [[#303](https://github.com/apache/incubator-seata-go/pull/303)] 添加异步处理器
- [[#289](https://github.com/apache/incubator-seata-go/pull/289)] 撤消日志生成器后添加 MySQL 更新
- [[#294](https://github.com/apache/incubator-seata-go/pull/294)] 添加 MySQL 元数据查询
- [[#309](https://github.com/apache/incubator-seata-go/pull/309)] 初始化压缩类型
- [[#301](https://github.com/apache/incubator-seata-go/pull/301)] 添加 Multi SQL 的 undo log 生成功能
- [[#321](https://github.com/apache/incubator-seata-go/pull/321)] 添加 deflate 压缩功能
- [[#324](https://github.com/apache/incubator-seata-go/pull/324)] 添加 lz4 压缩功能
- [[#327](https://github.com/apache/incubator-seata-go/pull/327)] 添加 zstd 压缩功能
- [[#322](https://github.com/apache/incubator-seata-go/pull/322)] 添加 gzip 压缩功能
- [[#307](https://github.com/apache/incubator-seata-go/pull/307)] 添加 flush undo log 功能
- [[#329](https://github.com/apache/incubator-seata-go/pull/329)] 添加 zip 压缩功能
- [[#325](https://github.com/apache/incubator-seata-go/pull/325)] 添加 Multi update SQL 的 undo log 生成功能
- [[#330](https://github.com/apache/incubator-seata-go/pull/330)] 添加 Multi delete SQL 的 undo log 生成功能
- [[#319](https://github.com/apache/incubator-seata-go/pull/319)] 添加选择更新执行器
- [[#320](https://github.com/apache/incubator-seata-go/pull/320)] 添加 undo 逻辑
- [[#337](https://github.com/apache/incubator-seata-go/pull/337)] 添加插入 undo log 逻辑
- [[#355](https://github.com/apache/incubator-seata-go/pull/355)] 支持根据配置判断 undo log 保存字段个数
- [[#365](https://github.com/apache/incubator-seata-go/pull/365)] 回滚 AT 之前做脏数据校验



### bugfix:

- [[#176](https://github.com/apache/incubator-seata-go/pull/176)] 修复 message 的单测的 bug
- [[#237](https://github.com/apache/incubator-seata-go/pull/237)] 修复在执行 OpenConnector 函数时候注册资源的 bug
- [[#230](https://github.com/apache/incubator-seata-go/pull/230)] 修复远程异步调用无限循环的bug
- [[#258](https://github.com/apache/incubator-seata-go/pull/258)] 修复全局事务超时的 bug
- [[#263](https://github.com/apache/incubator-seata-go/pull/263)] 修复 mock 数据的 bug
- [[#326](https://github.com/apache/incubator-seata-go/pull/326)] 修复 fanout 单元测试 bug
- [[#350](https://github.com/apache/incubator-seata-go/pull/350)] 修复 panic 的bug
- [[#359](https://github.com/apache/incubator-seata-go/pull/359)] 修复插入 undo log 的 MySQL 参数 bug
- [[#360](https://github.com/apache/incubator-seata-go/pull/360)] 修复 AT 回滚例子 bug
- [[#363](https://github.com/apache/incubator-seata-go/pull/363)] 修复 meta data bug
- [[#365](https://github.com/apache/incubator-seata-go/pull/365)] 修复反序列化 undo log bug


### optimize:

- [[#187](https://github.com/apache/incubator-seata-go/pull/187)] 优化 seata-go 初始化流程
- [[#196](https://github.com/apache/incubator-seata-go/pull/196)] 优化远程调用方法参数
- [[#200](https://github.com/apache/incubator-seata-go/pull/200)] 添加 tcc grpc 样例,优化注册资源和分支注册
- [[#208](https://github.com/apache/incubator-seata-go/pull/208)] 优化删除不必要代码
- [[#215](https://github.com/apache/incubator-seata-go/pull/215)] 优化使时间参数,提高可读性
- [[#179](https://github.com/apache/incubator-seata-go/pull/179)] 支持 TCC 一阶段传入用户自定义参数
- [[#198](https://github.com/apache/incubator-seata-go/pull/198)] 优化远程调用方法的传参
- [[#235](https://github.com/apache/incubator-seata-go/pull/235)] 调整 MessageType 枚举值命名规范
- [[#238](https://github.com/apache/incubator-seata-go/pull/238)] 添加一些待办事项注释,添加 hook 例子
- [[#261](https://github.com/apache/incubator-seata-go/pull/261)] 优化嵌套循环重试
- [[#284](https://github.com/apache/incubator-seata-go/pull/284)] 优化重试逻辑
- [[#286](https://github.com/apache/incubator-seata-go/pull/286)] 将 rm 和 tm 的初始化逻辑拆分
- [[#287](https://github.com/apache/incubator-seata-go/pull/287)] 重构 seata conn 逻辑
- [[#281](https://github.com/apache/incubator-seata-go/pull/281)] 优化全局事务使用
- [[#295](https://github.com/apache/incubator-seata-go/pull/295)] 重构 seata conn 逻辑
- [[#302](https://github.com/apache/incubator-seata-go/pull/302)] 修改 dubbo-go 版本
- [[#336](https://github.com/apache/incubator-seata-go/pull/336)] 优化 at 整体流程
- [[#346](https://github.com/apache/incubator-seata-go/pull/346)] 优化 at 事务提交流程
- [[#352](https://github.com/apache/incubator-seata-go/pull/352)] 优化获取元数据流程
- [[#354](https://github.com/apache/incubator-seata-go/pull/354)] 优化 at 事务提交流程
- [[#353](https://github.com/apache/incubator-seata-go/pull/353)] 修改方法接收者命名规范
- [[#356](https://github.com/apache/incubator-seata-go/pull/356)] 优化 at 事务回滚流程

### test:

- [[#154](https://github.com/apache/incubator-seata-go/pull/154)] 添加 message 单元单测
- [[#163](https://github.com/apache/incubator-seata-go/pull/163)] 添加 tm 单元单测
- [[#203](https://github.com/apache/incubator-seata-go/pull/203)] 添加 getty 单元测试
- [[#204](https://github.com/apache/incubator-seata-go/pull/204)] 添加 dubbo filter 单元测试
- [[#210](https://github.com/apache/incubator-seata-go/pull/210)] 添加 Tcc 分支报告测试
- [[#192](https://github.com/apache/incubator-seata-go/pull/192)] 添加 rm 单元测试
- [[#229](https://github.com/apache/incubator-seata-go/pull/229)] 添加 common 单元测试
- [[#299](https://github.com/apache/incubator-seata-go/pull/299)] 添加 SQL Parser 单元测试
- [[#332](https://github.com/apache/incubator-seata-go/pull/332)] 添加 multi delete undo log 单元测试
- [[#358](https://github.com/apache/incubator-seata-go/pull/358)] 添加 AT 回滚的例子


### doc:

- [[#202](https://github.com/apache/incubator-seata-go/pull/202)] 优化 github CI 流程,添加 condecov 、 issue CI 工作流
- [[#254](https://github.com/apache/incubator-seata-go/pull/254)] 添加自动检查 licence 的脚本
- [[#305](https://github.com/apache/incubator-seata-go/pull/305)] 修改 CI 不要自动关闭 issue 和 pr




### contributors:

非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。

- [AlexStocks](https://github.com/AlexStocks)
- [luky116](https://github.com/luky116)
- [106umao](https://github.com/106umao)
- [liiibpm](https://github.com/liiibpm)
- [elrond-g](https://github.com/elrond-g)
- [wang1309](https://github.com/wang1309)
- [iSuperCoder](https://github.com/apache/incubator-seata-go/commits?author=iSuperCoder)
- [a631807682](https://github.com/apache/incubator-seata-go/commits?author=a631807682)
- [betterwinsone](https://github.com/apache/incubator-seata-go/commits?author=betterwinsone)
- [jasondeng1997](https://github.com/apache/incubator-seata-go/commits?author=jasondeng1997)
- [chuntaojun](https://github.com/apache/incubator-seata-go/commits?author=chuntaojun)
- [complone](https://github.com/apache/incubator-seata-go/commits?author=complone)
- [miaoxueyu](https://github.com/apache/incubator-seata-go/commits?author=miaoxueyu)
- [PangXing](https://github.com/apache/incubator-seata-go/commits?author=PangXing)
- [georgehao](https://github.com/apache/incubator-seata-go/commits?author=georgehao)
- [baerwang](https://github.com/apache/incubator-seata-go/commits?author=baerwang)
- [raspberry-hu](https://github.com/apache/incubator-seata-go/commits?author=raspberry-hu)
- [WyattJia](https://github.com/apache/incubator-seata-go/commits?author=WyattJia)
- [Code-Fight](https://github.com/Code-Fight)
- [betterwinsone](https://github.com/betterwinsonet)


同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。

</detail>


+ 0
- 95
changes/1.0.3.md View File

@@ -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.
-->

### 1.0.3

<details>
<summary><mark>Release notes</mark></summary>

### Seata-go 1.0.3

Seata-go 1.0.3 Released.

Seata-go is an easy-to-use, high-performance, open source distributed transaction solution.

The version is updated as follows:

### feature:

- [[#380](https://github.com/apache/incubator-seata-go/pull/380)] support xa mysql connection
- [[#383](https://github.com/apache/incubator-seata-go/pull/383)] support read tcc fence configuration file
- [[#389](https://github.com/apache/incubator-seata-go/pull/389)] add the transaction id of xa mode
- [[#398](https://github.com/apache/incubator-seata-go/pull/398)] support read TM configuration file
- [[#399](https://github.com/apache/incubator-seata-go/pull/399)] support read getty configuration file
- [[#405](https://github.com/apache/incubator-seata-go/pull/405)] support at mode insert on duplicate sql parsing
- [[#406](https://github.com/apache/incubator-seata-go/pull/406)] support read transport configuration file
- [[#410](https://github.com/apache/incubator-seata-go/pull/410)] support read undo log configuration file
- [[#411](https://github.com/apache/incubator-seata-go/pull/411)] use tm's profile properties in the project
- [[#412](https://github.com/apache/incubator-seata-go/pull/412)] support read rm configuration file
- [[#412](https://github.com/apache/incubator-seata-go/pull/412)] support read service configuration file
- [[#419](https://github.com/apache/incubator-seata-go/pull/419)] use undo-log's profile properties in the project

### bugfix:

- [[#387](https://github.com/apache/incubator-seata-go/pull/387)] fix loop recursion problem in OpenConnector
- [[#401](https://github.com/apache/incubator-seata-go/pull/401)] fix branch register process
- [[#418](https://github.com/apache/incubator-seata-go/pull/418)] fix the configuration file problem of undo log
- [[#423](https://github.com/apache/incubator-seata-go/pull/423)] fix getty initialization failure
- [[#424](https://github.com/apache/incubator-seata-go/pull/424)] fix getty initialization failure
- [[#429](https://github.com/apache/incubator-seata-go/pull/429)] fix the problem of execution failure in at mode

### optimize:

- [[#366](https://github.com/apache/incubator-seata-go/pull/366)] add data check before rollbeck
- [[#367](https://github.com/apache/incubator-seata-go/pull/367)] simplify to make codes more readable
- [[#369](https://github.com/apache/incubator-seata-go/pull/369)] remove unless function
- [[#385](https://github.com/apache/incubator-seata-go/pull/385)] optimize the SQL used in AT sample
- [[#388](https://github.com/apache/incubator-seata-go/pull/388)] optimize comments and dead code
- [[#390](https://github.com/apache/incubator-seata-go/pull/390)] optime rm init
- [[#392](https://github.com/apache/incubator-seata-go/pull/392)] optimize code style
- [[#394](https://github.com/apache/incubator-seata-go/pull/394)] optimize at mode base executor
- [[#400](https://github.com/apache/incubator-seata-go/pull/400)] optime protocol init
- [[#408](https://github.com/apache/incubator-seata-go/pull/408)] optime log init
- [[#409](https://github.com/apache/incubator-seata-go/pull/409)] refactor logic of delete and insert sql in at mode
- [[#414](https://github.com/apache/incubator-seata-go/pull/414)] rename unit test file
- [[#422](https://github.com/apache/incubator-seata-go/pull/422)] remove unused config code

### test:

### doc:
- [[#417](https://github.com/apache/incubator-seata-go/pull/417)] optiomize readme file

### contributors:

Thanks to these contributors for their code commits. Please report an unintended omission.

- [AlexStocks](https://github.com/AlexStocks)
- [luky116](https://github.com/luky116)
- [georgehao](https://github.com/georgehao)
- [lxfeng1997](https://github.com/lxfeng1997)
- [106umao](https://github.com/106umao)
- [liiibpm](https://github.com/liiibpm)
- [wang1309](https://github.com/wang1309)
- [iSuperCoder](https://github.com/iSuperCoder)
- [jasondeng1997](https://github.com/jasondeng1997)
- [Charlie17Li](https://github.com/Charlie17Li)
- [Code-Fight](https://github.com/Code-Fight)
- [Kirhaku](https://github.com/Kirhaku)

Also, we receive many valuable issues, questions and advices from our community. Thanks all.

</detail>

+ 0
- 98
changes/1.0.3_zh.md View File

@@ -1,98 +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.
-->

### 1.0.3

<details>
<summary><mark>Release notes</mark></summary>

### Seata-go 1.0.3

Seata-go 1.0.3 发布。

Seata-go 是一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。

此版本更新如下:

### feature:

- [[#380](https://github.com/apache/incubator-seata-go/pull/380)] 支持 MySQL XA 的连接
- [[#383](https://github.com/apache/incubator-seata-go/pull/383)] 支持 TCC Fence 读取配置文件
- [[#389](https://github.com/apache/incubator-seata-go/pull/389)] 添加 XA 模式的事务ID
- [[#398](https://github.com/apache/incubator-seata-go/pull/398)] 支持 TM 读取配置文件
- [[#399](https://github.com/apache/incubator-seata-go/pull/399)] 支持 getty 读取配置文件
- [[#405](https://github.com/apache/incubator-seata-go/pull/405)] 支持 AT 模式 insert on duplicate SQL 解析
- [[#406](https://github.com/apache/incubator-seata-go/pull/406)] 支持 transport 读取配置文件
- [[#410](https://github.com/apache/incubator-seata-go/pull/410)] 支持 undo log 读取配置文件
- [[#411](https://github.com/apache/incubator-seata-go/pull/411)] 在项目中使用 tm 的配置文件属性
- [[#412](https://github.com/apache/incubator-seata-go/pull/412)] 支持 RM 读取配置文件
- [[#413](https://github.com/apache/incubator-seata-go/pull/413)] 支持 service 读取配置文件
- [[#419](https://github.com/apache/incubator-seata-go/pull/419)] 在项目中使用 undo log 的配置文件属性
- [[#421](https://github.com/apache/incubator-seata-go/pull/421)] 支持 service 读取配置文件

### bugfix:

- [[#387](https://github.com/apache/incubator-seata-go/pull/387)] 修复 OpenConnector 中死循环的问题
- [[#401](https://github.com/apache/incubator-seata-go/pull/401)] 优化注册事务分支的流程
- [[#418](https://github.com/apache/incubator-seata-go/pull/418)] 修复 undo log 的配置文件的问题
- [[#423](https://github.com/apache/incubator-seata-go/pull/423)] 修复 getty 初始化失败的问题
- [[#424](https://github.com/apache/incubator-seata-go/pull/424)] 修复 getty 初始化失败的问题
- [[#429](https://github.com/apache/incubator-seata-go/pull/429)] 修复 AT 模式执行失败的问题

### optimize:

- [[#366](https://github.com/apache/incubator-seata-go/pull/366)] AT 回滚前添加数据校验逻辑
- [[#367](https://github.com/apache/incubator-seata-go/pull/367)] 优化 AT 代码的命名
- [[#369](https://github.com/apache/incubator-seata-go/pull/369)] 移除不用的方法
- [[#385](https://github.com/apache/incubator-seata-go/pull/385)] 优化 AT sample 的建表SQL
- [[#388](https://github.com/apache/incubator-seata-go/pull/388)] 优化代码注释,删除不用的代码
- [[#390](https://github.com/apache/incubator-seata-go/pull/390)] 优化 RM 的初始化流程
- [[#392](https://github.com/apache/incubator-seata-go/pull/392)] 优化代码的风格问题
- [[#394](https://github.com/apache/incubator-seata-go/pull/394)] 重构 AT 模式的执行器
- [[#400](https://github.com/apache/incubator-seata-go/pull/400)] 优化 protocol 的初始化流程
- [[#408](https://github.com/apache/incubator-seata-go/pull/408)] 优化 log 的初始化流程
- [[#409](https://github.com/apache/incubator-seata-go/pull/409)] 重构 AT 模式的 delete 和 insert SQL 的执行逻辑
- [[#414](https://github.com/apache/incubator-seata-go/pull/414)] 重命名单测文件
- [[#422](https://github.com/apache/incubator-seata-go/pull/422)] 移除未使用的 config 代码

### test:

### doc:
- [[#417](https://github.com/apache/incubator-seata-go/pull/417)] 调整 readme 文件内容


### contributors:

非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。

- [AlexStocks](https://github.com/AlexStocks)
- [luky116](https://github.com/luky116)
- [georgehao](https://github.com/georgehao)
- [lxfeng1997](https://github.com/lxfeng1997)
- [106umao](https://github.com/106umao)
- [liiibpm](https://github.com/liiibpm)
- [wang1309](https://github.com/wang1309)
- [iSuperCoder](https://github.com/iSuperCoder)
- [jasondeng1997](https://github.com/jasondeng1997)
- [Charlie17Li](https://github.com/Charlie17Li)
- [Code-Fight](https://github.com/Code-Fight)
- [Kirhaku](https://github.com/Kirhaku)

同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。

</detail>


+ 0
- 91
changes/1.1.0.md View File

@@ -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.
-->

### 1.1.0

<details>
<summary><mark>Release notes</mark></summary>

### Seata-go 1.1.0

Seata-go 1.1.0 Released.

Seata-go is an easy-to-use, high-performance, open source distributed transaction solution.

The version is updated as follows:

### feature:

- [[#491](https://github.com/apache/incubator-seata-go/pull/491)] support query global lock key
- [[#482](https://github.com/apache/incubator-seata-go/pull/482)] support multi delete SQL executor in AT
- [[#481](https://github.com/apache/incubator-seata-go/pull/481)] support multi update SQL executor in AT
- [[#478](https://github.com/apache/incubator-seata-go/pull/478)] support select for update SQL executor in AT
- [[#477](https://github.com/apache/incubator-seata-go/pull/477)] support the json serialization method of undo log
- [[#456](https://github.com/apache/incubator-seata-go/pull/456)] support insert on update SQL executor in AT
- [[#444](https://github.com/apache/incubator-seata-go/pull/444)] support BZip2Compressor
- [[#436](https://github.com/apache/incubator-seata-go/pull/436)] use rm config file
- [[#433](https://github.com/apache/incubator-seata-go/pull/433)] support xa connect manager
- [[#430](https://github.com/apache/incubator-seata-go/pull/430)] use getty config file

### bugfix:

- [[#509](https://github.com/apache/incubator-seata-go/pull/509)] fix undo log SQLType when execute insert on update SQL in AT
- [[#495](https://github.com/apache/incubator-seata-go/pull/495)] fix undo log SQLType bug
- [[#487](https://github.com/apache/incubator-seata-go/pull/487)] fix at bug when execute
- [[#472](https://github.com/apache/incubator-seata-go/pull/472)] fix missing value of context When using global transactions
- [[#461](https://github.com/apache/incubator-seata-go/pull/461)] fix the problem of error_code_test
- [[#459](https://github.com/apache/incubator-seata-go/pull/459)] fix the rollback error log
- [[#452](https://github.com/apache/incubator-seata-go/pull/452)] fix the error of id self-increment when executing insert sql in AT

### optimize:

- [[#507](https://github.com/apache/incubator-seata-go/pull/507)] refactor logic of multiple update sql in AT
- [[#505](https://github.com/apache/incubator-seata-go/pull/505)] optimize multi SQL executor in AT
- [[#453](https://github.com/apache/incubator-seata-go/pull/453)] optimize the messageType and transactionErrorCode enum
- [[#447](https://github.com/apache/incubator-seata-go/pull/447)] optimize the datasource init process
- [[#466](https://github.com/apache/incubator-seata-go/pull/466)] optimize variable naming

### test:

- [[#445](https://github.com/apache/incubator-seata-go/pull/445)] add unit test for TransactionErrorCode and MessageType

### doc:

- [[#492](https://github.com/apache/incubator-seata-go/pull/492)] update feature list of readme
- [[#489](https://github.com/apache/incubator-seata-go/pull/489)] add change-log of version 1.1.0

### contributors:

Thanks to these contributors for their code commits. Please report an unintended omission.

- [luky116](https://github.com/luky116)
- [georgehao](https://github.com/georgehao)
- [lxfeng1997](https://github.com/lxfeng1997)
- [106umao](https://github.com/106umao)
- [wang1309](https://github.com/wang1309)
- [iSuperCoder](https://github.com/iSuperCoder)
- [Charlie17Li](https://github.com/Charlie17Li)
- [Code-Fight](https://github.com/Code-Fight)
- [Kirhaku](https://github.com/Kirhaku)
- [Vaderkai](https://github.com/VaderKai)
- [springrain](https://github.com/springrain)
- [Shaozhou Hu](https://github.com/raspberry-hu)
- [finkyky](https://github.com/Finkyky)

Also, we receive many valuable issues, questions and advices from our community. Thanks all.

</detail>

+ 0
- 92
changes/1.1.0_zh.md View File

@@ -1,92 +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.
-->

### 1.1.0

<details>
<summary><mark>Release notes</mark></summary>

### Seata-go 1.1.0

Seata-go 1.1.0 发布。

Seata-go 是一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。

此版本更新如下:

### feature:

- [[#491](https://github.com/apache/incubator-seata-go/pull/491)] 支持查询全局事务锁
- [[#482](https://github.com/apache/incubator-seata-go/pull/482)] 支持 AT 模式 multi delete SQL 执行器
- [[#481](https://github.com/apache/incubator-seata-go/pull/481)] 支持 AT 模式 multi update SQL 执行器
- [[#478](https://github.com/apache/incubator-seata-go/pull/478)] 支持 AT 模式 select for update SQL 执行器
- [[#477](https://github.com/apache/incubator-seata-go/pull/477)] 支持 undo log 的 json 序列化方式
- [[#456](https://github.com/apache/incubator-seata-go/pull/456)] 支持 AT 模式 insert on update SQL 执行器
- [[#444](https://github.com/apache/incubator-seata-go/pull/444)] 支持 BZip 压缩算法
- [[#436](https://github.com/apache/incubator-seata-go/pull/436)] 支持读取 rm 相关的配置文件
- [[#433](https://github.com/apache/incubator-seata-go/pull/433)] 支持 xa 连接管理
- [[#430](https://github.com/apache/incubator-seata-go/pull/430)] 支持读取 getty 相关的配置文件

### bugfix:

- [[#509](https://github.com/apache/incubator-seata-go/pull/509)] 修复 AT 模式下执行 insert on update 时 undo log 的 SQLType 字段的问题
- [[#495](https://github.com/apache/incubator-seata-go/pull/495)] 修复 undo log 的 SQLType 字段的问题
- [[#487](https://github.com/apache/incubator-seata-go/pull/487)] 修复 AT 执行时出现的问题
- [[#472](https://github.com/apache/incubator-seata-go/pull/472)] 修复全局事务中上下文丢失值问题
- [[#461](https://github.com/apache/incubator-seata-go/pull/461)] 修复 error_code_test 中变量未定义导致的 ci 失败问题
- [[#459](https://github.com/apache/incubator-seata-go/pull/459)] 修复 error 日志重复打印问题
- [[#452](https://github.com/apache/incubator-seata-go/pull/452)] 修复 AT 模式 执行 insert SQL 时 id 自增的报错问题

### optimize:

- [[#507](https://github.com/apache/incubator-seata-go/pull/507)] 优化 AT 模式 multiple update SQL 执行器
- [[#505](https://github.com/apache/incubator-seata-go/pull/505)] 优化 AT 模式 multi SQL 执行器
- [[#453](https://github.com/apache/incubator-seata-go/pull/453)] 优化 messageType 和 transactionErrorCode 枚举值
- [[#447](https://github.com/apache/incubator-seata-go/pull/447)] 优化数据源初始化流程
- [[#466](https://github.com/apache/incubator-seata-go/pull/466)] 优化变量的命名

### test:

- [[#445](https://github.com/apache/incubator-seata-go/pull/445)] 添加 TransactionErrorCode 的单元测试

### doc:

- [[#492](https://github.com/apache/incubator-seata-go/pull/492)] 更新 readme 文件的已完成功能列表
- [[#489](https://github.com/apache/incubator-seata-go/pull/489)] 添加 1.1.0 版本的 change log

### contributors:

非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。

- [luky116](https://github.com/luky116)
- [georgehao](https://github.com/georgehao)
- [lxfeng1997](https://github.com/lxfeng1997)
- [106umao](https://github.com/106umao)
- [wang1309](https://github.com/wang1309)
- [iSuperCoder](https://github.com/iSuperCoder)
- [Charlie17Li](https://github.com/Charlie17Li)
- [Code-Fight](https://github.com/Code-Fight)
- [Kirhaku](https://github.com/Kirhaku)
- [Vaderkai](https://github.com/VaderKai)
- [springrain](https://github.com/springrain)
- [Shaozhou Hu](https://github.com/raspberry-hu)
- [finkyky](https://github.com/Finkyky)

同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。

</detail>


+ 0
- 80
changes/1.2.0.md View File

@@ -1,80 +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.
-->

### 1.2.0

<details>
<summary><mark>Release notes</mark></summary>

### Seata-go 1.2.0

Seata-go 1.2.0 Released.

Seata-go is an easy-to-use, high-performance, open source distributed transaction solution.

The version is updated as follows:

### feature:

- [[#534](https://github.com/apache/incubator-seata-go/pull/534)] support session load balance
- [[#535](https://github.com/apache/incubator-seata-go/pull/535)] add integrate test

### bugfix:

- [[#540](https://github.com/apache/incubator-seata-go/pull/540)] fix init xa panic bug
- [[#545](https://github.com/apache/incubator-seata-go/pull/545)] fix get db version bug
- [[#548](https://github.com/apache/incubator-seata-go/pull/548)] fix start xa failed bug
- [[#556](https://github.com/apache/incubator-seata-go/pull/556)] fix start xa driver failed bug
- [[#562](https://github.com/apache/incubator-seata-go/pull/562)] fix commit xa panic bug
- [[#564](https://github.com/apache/incubator-seata-go/pull/564)] fix commit xa branch bug
- [[#566](https://github.com/apache/incubator-seata-go/pull/566)] fix execute local tx bug

### optimize:

- [[#523](https://github.com/apache/incubator-seata-go/pull/523)] optimize the golang ci lint
- [[#525](https://github.com/apache/incubator-seata-go/pull/456)] rename parser name from jackson to json
- [[#532](https://github.com/apache/incubator-seata-go/pull/532)] remove duplicate code
- [[#536](https://github.com/apache/incubator-seata-go/pull/536)] format go import
- [[#554](https://github.com/apache/incubator-seata-go/pull/554)] optimize the performance of XA transactions
- [[#561](https://github.com/apache/incubator-seata-go/pull/561)] optimize xa output log

### test:


### doc:
- [[#550](https://github.com/apache/incubator-seata-go/pull/550)] add change-log of version 1.2.0


### contributors:

Thanks to these contributors for their code commits. Please report an unintended omission.

- [georgehao](https://github.com/georgehao)
- [luky116](https://github.com/luky116)
- [jasondeng1997](https://github.com/jasondeng1997)
- [106umao](https://github.com/106umao)
- [wang1309](https://github.com/wang1309)
- [iSuperCoder](https://github.com/iSuperCoder)
- [Charlie17Li](https://github.com/Charlie17Li)
- [Code-Fight](https://github.com/Code-Fight)
- [Kirhaku](https://github.com/Kirhaku)
- [Vaderkai](https://github.com/VaderKai)


Also, we receive many valuable issues, questions and advices from our community. Thanks all.

</detail>

+ 0
- 83
changes/1.2.0_zh.md View File

@@ -1,83 +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.
-->

### 1.2.0

<details>
<summary><mark>Release notes</mark></summary>

### Seata-go 1.2.0

Seata-go 1.2.0 发布。

Seata-go 是一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。

此版本更新如下:

### feature:

- [[#534](https://github.com/apache/incubator-seata-go/pull/534)] 支持 session 的负载均衡
- [[#535](https://github.com/apache/incubator-seata-go/pull/535)] 添加加成测试

### bugfix:

- [[#540](https://github.com/apache/incubator-seata-go/pull/540)] 修复初始化 xa 模式的 bug
- [[#545](https://github.com/apache/incubator-seata-go/pull/545)] 修复 xa 模式获取 db 版本号的 bug
- [[#548](https://github.com/apache/incubator-seata-go/pull/548)] 修复启动 xa 时候会失败的 bug
- [[#556](https://github.com/apache/incubator-seata-go/pull/556)] 修复 xa 数据源的 bug
- [[#562](https://github.com/apache/incubator-seata-go/pull/562)] 修复提交 xa 全局事务的 bug
- [[#564](https://github.com/apache/incubator-seata-go/pull/564)] 修复提交 xa 分支事务的 bug
- [[#566](https://github.com/apache/incubator-seata-go/pull/566)] 修复使用 xa 数据源执行本地事务的 bug

### optimize:

- [[#523](https://github.com/apache/incubator-seata-go/pull/523)] 优化 CI 流程
- [[#525](https://github.com/apache/incubator-seata-go/pull/456)] 将 jackson 序列化重命名为 json
- [[#532](https://github.com/apache/incubator-seata-go/pull/532)] 移除重复的代码
- [[#536](https://github.com/apache/incubator-seata-go/pull/536)] 优化 go import 代码格式
- [[#554](https://github.com/apache/incubator-seata-go/pull/554)] 优化 xa 模式的性能
- [[#561](https://github.com/apache/incubator-seata-go/pull/561)] 优化 xa 模式的日志输出

### test:


### doc:
- [[#550](https://github.com/apache/incubator-seata-go/pull/550)] 添加 1.2.0 版本的改动日志


### contributors:

非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。

- [georgehao](https://github.com/georgehao)
- [luky116](https://github.com/luky116)
- [jasondeng1997](https://github.com/jasondeng1997)
- [106umao](https://github.com/106umao)
- [wang1309](https://github.com/wang1309)
- [iSuperCoder](https://github.com/iSuperCoder)
- [Charlie17Li](https://github.com/Charlie17Li)
- [Code-Fight](https://github.com/Code-Fight)
- [Kirhaku](https://github.com/Kirhaku)
- [Vaderkai](https://github.com/VaderKai)




同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。

</detail>


+ 0
- 173
changes/2.0.0.md View File

@@ -1,173 +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.
-->

### 2.0.0

<details>
<summary><mark>Release notes</mark></summary>
### Seata-go 2.0.0

Seata-go 2.0.0 Released.

Seata-go is an easy-to-use, high-performance, open source distributed transaction solution.

The version is updated as follows:

### feature:

- [[#761](https://github.com/apache/incubator-seata-go/pull/761)]Support Update join
- [[#806](https://github.com/apache/incubator-seata-go/pull/806)]Add Release Drafter configuration files
- [[#659](https://github.com/apache/incubator-seata-go/pull/659)] support compress for AT undo log
- [[#574](https://github.com/apache/incubator-seata-go/pull/574)] support file and nacos service registry
- [[#584](https://github.com/apache/incubator-seata-go/pull/584)] support the ConsistentHash load balancing strategy in the remoting module
- [[#585](https://github.com/apache/incubator-seata-go/pull/585)] support the LeastActive load balancing strategy in the remoting module
- [[#605](https://github.com/apache/incubator-seata-go/pull/605)] support the discovery service of Etcd
- [[#622](https://github.com/apache/incubator-seata-go/pull/622)] add round robin strategy of remote call
- [[#691](https://github.com/apache/incubator-seata-go/pull/691)] support protobuf undo log parser
- [[#738](https://github.com/apache/incubator-seata-go/pull/738)] remove session when send heart beat message failed
- [[#739](https://github.com/apache/incubator-seata-go/pull/739)] support automatic refresh functionality for table meta cache

### bugfix:

- [[#877](https://github.com/apache/incubator-seata-go/pull/857)]del metadatacache uppertablenamekey and increase tablemeta field uppertablename

- [[#861](https://github.com/apache/incubator-seata-go/pull/861)]update project icon in readme
- [[#834](https://github.com/apache/incubator-seata-go/pull/834)]Solve the conflict problem of introducing multiple versions of knadh
- [[#839](https://github.com/apache/incubator-seata-go/pull/839)]fix action errors
- [[#850](https://github.com/apache/incubator-seata-go/pull/850)]fix failed parsing table of delete sql
- [[#823](https://github.com/apache/incubator-seata-go/pull/823)]Remove issue translation workflow
- [[#820](https://github.com/apache/incubator-seata-go/pull/820)]Fix possible vulnerabilities caused by common libraries
- [[#810](https://github.com/apache/incubator-seata-go/pull/810)]fix transaction failed ,when using queryContext
- [[#813](https://github.com/apache/incubator-seata-go/pull/813)]add some licenser header
- [[#771](https://github.com/apache/incubator-seata-go/pull/771)]mysql insert on update duplicate sensitive case not matched
- [[#797](https://github.com/apache/incubator-seata-go/pull/797)] add ASF header to some files
- [[#781](https://github.com/apache/incubator-seata-go/pull/781)] Fixed that the same record has different lowkeys due to mixed case of table names
- [[#780](https://github.com/apache/incubator-seata-go/pull/780)] failed to decode ColumnImage mysql:text type by json
- [[#782](https://github.com/apache/incubator-seata-go/pull/782)] failed to decode ColumnImage mysql:text type by json
- [[#789](https://github.com/apache/incubator-seata-go/pull/789)] add 2025 to NOTICE
- [[#776](https://github.com/apache/incubator-seata-go/pull/776)] fix ci-lint typecheck error
- [[#540](https://github.com/apache/incubator-seata-go/pull/540)] fix init XA panic bug
- [[#590](https://github.com/apache/incubator-seata-go/pull/590)] fix some repo error
- [[#595](https://github.com/apache/incubator-seata-go/pull/595)] check the response error is nil for commit or rollback
- [[#607](https://github.com/apache/incubator-seata-go/pull/607)] fix the bug of jackson serialize
- [[#665](https://github.com/apache/incubator-seata-go/pull/665)] reclaim the heartbeat response message to avoid memory leakage of GettyRemoting.future
- [[#672](https://github.com/apache/incubator-seata-go/pull/672)] fix AT rollback bug
- [[#674](https://github.com/apache/incubator-seata-go/pull/674)] fix XA rollback bug
- [[#690](https://github.com/apache/incubator-seata-go/pull/690)] fix AT undo log jackson parser not found bug
- [[#701](https://github.com/apache/incubator-seata-go/pull/701)] fix the InsertOnDuplicateUpdate is an issue with bypassing modifying the primary key
- [[#717](https://github.com/apache/incubator-seata-go/pull/717)] support XA report state to TC
- [[#724](https://github.com/apache/incubator-seata-go/pull/724)] support ParenthesesExpr for SQL parser
- [[#736](https://github.com/apache/incubator-seata-go/pull/736)] fix SQL statement not closed's bug
- [[#743](https://github.com/apache/incubator-seata-go/pull/743)] fix bug of gomonkey
- [[#749](https://github.com/apache/incubator-seata-go/pull/749)] fix bug of heart beat


### optimize:

- [[#837](https://github.com/apache/incubator-seata-go/pull/837)]AT model optimize build lock key performance
- [[#824](https://github.com/apache/incubator-seata-go/pull/824)]update SHA256 checksum command in makefile for cross-platform compatibility
- [[#777](https://github.com/apache/incubator-seata-go/pull/777)]optimize transaction timeout judgment
- [[#786](https://github.com/apache/incubator-seata-go/pull/786)]support ipv6
- [[#802](https://github.com/apache/incubator-seata-go/pull/802)]support get db version in conn
- [[#745](https://github.com/apache/incubator-seata-go/pull/745)]optimized the daily deletion of fence logs
- [[#767](https://github.com/apache/incubator-seata-go/pull/767)]upgrade some dependent packages to eliminate dependencies on some archived repositories
- [[#768](https://github.com/apache/incubator-seata-go/pull/768)]update parser to v0.2.17
- [[#576](https://github.com/apache/incubator-seata-go/pull/576)] use mirromutth/mysql-action instead of icomponent/mysql-action
- [[#594](https://github.com/apache/incubator-seata-go/pull/594)] optimize the log of branch commit procesor
- [[#621](https://github.com/apache/incubator-seata-go/pull/621)] add codeql for ci
- [[#631](https://github.com/apache/incubator-seata-go/pull/631)] upgrade crypto version from 0.9.0 to 0.17.0
- [[#652](https://github.com/apache/incubator-seata-go/pull/652)] upgrade gRPC version from 1.51.0 ro 1.56.3
- [[#667](https://github.com/apache/incubator-seata-go/pull/667)] change mailbox of issues and pull requests from dev to notifications
- [[#678](https://github.com/apache/incubator-seata-go/pull/678)] rename module name to seata.apache.org/seata-go
- [[#679](https://github.com/apache/incubator-seata-go/pull/679)] upgrade getty version from 1.4.9 to 1.4.10
- [[#714](https://github.com/apache/incubator-seata-go/pull/714)] optimize the speed of build lock key
- [[#719](https://github.com/apache/incubator-seata-go/pull/719)] only save insertd filed when execute insert SQL in AT
- [[#721](https://github.com/apache/incubator-seata-go/pull/721)] fix the issue where the translation bot is not working
- [[#758](https://github.com/apache/incubator-seata-go/pull/758)] remove unusen files

### test:

- [[#570](https://github.com/apache/incubator-seata-go/pull/570)] add collection unit test
- [[#571](https://github.com/apache/incubator-seata-go/pull/571)] add convert unit test
- [[#572](https://github.com/apache/incubator-seata-go/pull/572)] add reflectx unit test
- [[#5835f0](https://github.com/apache/incubator-seata-go/commit/5835f09ecfd6edeb04c2961163bc4460f578e942)] add random loadbalance unit test
- [[#599](https://github.com/apache/incubator-seata-go/pull/599)] add xid loadbalance unit test


### doc:

- [[#844](https://github.com/apache/incubator-seata-go/pull/844)]Enrich the project ReadMe
- [[#760](https://github.com/apache/incubator-seata-go/pull/760)]V2.0.0 release updater
- [[#614](https://github.com/apache/incubator-seata-go/pull/614)] upgrade the unknown license dependency
- [[#632](https://github.com/apache/incubator-seata-go/pull/632)] add ASF basic config
- [[#633](https://github.com/apache/incubator-seata-go/pull/633)] optimize ASF basic config to remove th context check
- [[#644](https://github.com/apache/incubator-seata-go/pull/644)] optimize readme file
- [[#686](https://github.com/apache/incubator-seata-go/pull/686)] add more linter in ci
- [[#737](https://github.com/apache/incubator-seata-go/pull/737)] modify the readme file and update the currently completed work
- [[#756](https://github.com/apache/incubator-seata-go/pull/756)] update license checker


### contributors:

Thanks to these contributors for their code commits. Please report an unintended omission.

- [luky116](https://github.com/luky116)
- [Code-Fight](https://github.com/Code-Fight)
- [wt-better](https://github.com/wt-better)
- [luweiqianyi](https://github.com/luweiqianyi)
- [wang1309](https://github.com/wang1309)
- [576470954](https://github.com/576470954)
- [No-SilverBullet](https://github.com/No-SilverBullet)
- [solisamicus](https://github.com/solisamicus)
- [marsevilspirit](https://github.com/marsevilspirit)
- [lxfeng1997](https://github.com/lxfeng1997)
- [AlexStocks](https://github.com/AlexStocks)
- [smiletrl](https://github.com/smiletrl)
- [ptyin](https://github.com/ptyin)
- [yizhibian](https://github.com/yizhibian)
- [oldmee](https://github.com/oldmee)
- [air-3](https://github.com/air-3)
- [slievrly](https://github.com/slievrly)
- [xjlgod](https://github.com/xjlgod)
- [baerwang](https://github.com/baerwang)
- [xyombo](https://github.com/xyombo)
- [testwill](https://github.com/testwill)
- [jasondeng1997](https://github.com/jasondeng1997)
- [jsbxyyx](https://github.com/jsbxyyx)
- [iSuperCoder](https://github.com/iSuperCoder)
- [georgehao](https://github.com/georgehao)
- [liuyuecai](https://github.com/liuyuecai)
- [106umao](https://github.com/106umao)
- [FinnTew](https://github.com/FinnTew)
- [funky-eyes](https://github.com/funky-eyes)
- [tanzegen](https://github.com/tanzegen)
- [lovepoem](https://github.com/lovepoem)
- [MinatoWu](https://github.com/MinatoWu)
- [LucienShen-Liu](https://github.com/LucienShen-Liu)
- [panlei-coder](https://github.com/panlei-coder)
- [lixingjia77](https://github.com/lixingjia77)
- [Road2Melon](https://github.com/Road2Melon)
- [Similarityoung](https://github.com/Similarityoung)
- [YvCeung](https://github.com/YvCeung)
- [pjfanning](https://github.com/pjfanning)
- [hokkine](https://github.com/hokkine)
- [zhangymPerson](https://github.com/zhangymPerson)
- [ForestLH](https://github.com/ForestLH)

Also, we receive many valuable issues, questions and advices from our community. Thanks all.

</detail>

+ 0
- 169
changes/2.0.0_zh.md View File

@@ -1,169 +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.
-->

### 2.0.0

<details>
<summary><mark>版本变更</mark></summary>
# Seata-go 2.0.0

Seata-go 2.0.0 已发布。

Seata-go 是一个易于使用、高性能的开源分布式事务解决方案。

本版本更新内容如下:

## 新增特性(feature):

- [[#761](https://github.com/apache/incubator-seata-go/pull/761)] 支持 Update join。
- [[#806](https://github.com/apache/incubator-seata-go/pull/806)] 新增 Release Drafter 配置文件。
- [[#659](https://github.com/apache/incubator-seata-go/pull/659)] 为 AT undo log 支持压缩。
- [[#574](https://github.com/apache/incubator-seata-go/pull/574)] 支持基于文件(file)和 Nacos 的服务注册。
- [[#584](https://github.com/apache/incubator-seata-go/pull/584)] 在 remoting 模块中支持 ConsistentHash 负载均衡策略。
- [[#585](https://github.com/apache/incubator-seata-go/pull/585)] 在 remoting 模块中支持 LeastActive 负载均衡策略。
- [[#605](https://github.com/apache/incubator-seata-go/pull/605)] 支持 Etcd 的服务发现。
- [[#622](https://github.com/apache/incubator-seata-go/pull/622)] 为远程调用新增轮询(round robin)策略。
- [[#691](https://github.com/apache/incubator-seata-go/pull/691)] 支持 protobuf 格式的 undo log 解析器。
- [[#738](https://github.com/apache/incubator-seata-go/pull/738)] 在发送心跳消息失败时移除会话。
- [[#739](https://github.com/apache/incubator-seata-go/pull/739)] 支持表元数据缓存的自动刷新功能。

## 修复(bugfix):

- [[#877](https://github.com/apache/incubator-seata-go/pull/857)] 删除 metadatacache 的 uppertablenamekey,并在 tablemeta 中增加 uppertablename 字段。
- [[#861](https://github.com/apache/incubator-seata-go/pull/861)] 更新 README 中的项目图标。
- [[#834](https://github.com/apache/incubator-seata-go/pull/834)] 解决引入多个版本 knadh 导致的冲突问题。
- [[#839](https://github.com/apache/incubator-seata-go/pull/839)] 修复 Action 错误。
- [[#850](https://github.com/apache/incubator-seata-go/pull/850)] 修复删除类 SQL 的表解析失败问题。
- [[#823](https://github.com/apache/incubator-seata-go/pull/823)] 移除 issue 翻译工作流。
- [[#820](https://github.com/apache/incubator-seata-go/pull/820)] 修复由通用库引起的潜在安全漏洞。
- [[#810](https://github.com/apache/incubator-seata-go/pull/810)] 修复在使用 queryContext 时导致事务失败的问题。
- [[#813](https://github.com/apache/incubator-seata-go/pull/813)] 为若干文件添加许可头。
- [[#771](https://github.com/apache/incubator-seata-go/pull/771)] 修复 MySQL `INSERT ... ON DUPLICATE UPDATE` 在大小写敏感场景下匹配不正确的问题。
- [[#797](https://github.com/apache/incubator-seata-go/pull/797)] 为部分文件添加 ASF 头。
- [[#781](https://github.com/apache/incubator-seata-go/pull/781)] 修复因表名大小写混合导致相同记录出现不同 lowkeys 的问题。
- [[#780](https://github.com/apache/incubator-seata-go/pull/780)] 修复无法通过 JSON 解码 MySQL `TEXT` 类型的 ColumnImage 的问题。
- [[#782](https://github.com/apache/incubator-seata-go/pull/782)] 修复无法通过 JSON 解码 MySQL `TEXT` 类型的 ColumnImage 的问题(重复修复项)。
- [[#789](https://github.com/apache/incubator-seata-go/pull/789)] 在 NOTICE 中添加 2025 年。
- [[#776](https://github.com/apache/incubator-seata-go/pull/776)] 修复 CI lint 类型检查错误。
- [[#540](https://github.com/apache/incubator-seata-go/pull/540)] 修复初始化 XA 时的 panic 错误。
- [[#590](https://github.com/apache/incubator-seata-go/pull/590)] 修复若干仓库错误。
- [[#595](https://github.com/apache/incubator-seata-go/pull/595)] 在提交(commit)或回滚(rollback)时检查响应错误是否为 nil。
- [[#607](https://github.com/apache/incubator-seata-go/pull/607)] 修复 Jackson 序列化的相关 bug。
- [[#665](https://github.com/apache/incubator-seata-go/pull/665)] 回收心跳响应消息,以避免 GettyRemoting.future 的内存泄漏。
- [[#672](https://github.com/apache/incubator-seata-go/pull/672)] 修复 AT 回滚的错误。
- [[#674](https://github.com/apache/incubator-seata-go/pull/674)] 修复 XA 回滚的错误。
- [[#690](https://github.com/apache/incubator-seata-go/pull/690)] 修复 AT undo log 的 Jackson 解析器未找到的问题。
- [[#701](https://github.com/apache/incubator-seata-go/pull/701)] 修复 InsertOnDuplicateUpdate 绕过主键修改所导致的问题。
- [[#717](https://github.com/apache/incubator-seata-go/pull/717)] 支持 XA 向 TC 报告状态。
- [[#724](https://github.com/apache/incubator-seata-go/pull/724)] 为 SQL 解析器支持 ParenthesesExpr(括号表达式)。
- [[#736](https://github.com/apache/incubator-seata-go/pull/736)] 修复 SQL 语句未正确关闭的问题。
- [[#743](https://github.com/apache/incubator-seata-go/pull/743)] 修复 gomonkey 相关的 bug。
- [[#749](https://github.com/apache/incubator-seata-go/pull/749)] 修复心跳相关的 bug。

## 优化(optimize):

- [[#837](https://github.com/apache/incubator-seata-go/pull/837)] 优化 AT 模型中构建锁键的性能。
- [[#824](https://github.com/apache/incubator-seata-go/pull/824)] 更新 Makefile 中的 SHA256 校验命令以兼容跨平台。
- [[#777](https://github.com/apache/incubator-seata-go/pull/777)] 优化事务超时判断逻辑。
- [[#786](https://github.com/apache/incubator-seata-go/pull/786)] 支持 IPv6。
- [[#802](https://github.com/apache/incubator-seata-go/pull/802)] 在连接中支持获取数据库版本。
- [[#745](https://github.com/apache/incubator-seata-go/pull/745)] 优化 fence 日志的每日删除策略。
- [[#767](https://github.com/apache/incubator-seata-go/pull/767)] 升级若干依赖包以消除对部分已归档仓库的依赖。
- [[#768](https://github.com/apache/incubator-seata-go/pull/768)] 将解析器更新至 v0.2.17。
- [[#576](https://github.com/apache/incubator-seata-go/pull/576)] 在 CI 中使用 mirromutth/mysql-action 替换 icomponent/mysql-action。
- [[#594](https://github.com/apache/incubator-seata-go/pull/594)] 优化分支提交处理器的日志。
- [[#621](https://github.com/apache/incubator-seata-go/pull/621)] 为 CI 添加 CodeQL。
- [[#631](https://github.com/apache/incubator-seata-go/pull/631)] 将 crypto 版本从 0.9.0 升级至 0.17.0。
- [[#652](https://github.com/apache/incubator-seata-go/pull/652)] 将 gRPC 版本从 1.51.0 升级至 1.56.3。
- [[#667](https://github.com/apache/incubator-seata-go/pull/667)] 将 issue 与 pull request 的邮箱由 dev 更改为 notifications。
- [[#678](https://github.com/apache/incubator-seata-go/pull/678)] 将模块名重命名为 `seata.apache.org/seata-go`。
- [[#679](https://github.com/apache/incubator-seata-go/pull/679)] 将 getty 版本从 1.4.9 升级至 1.4.10。
- [[#714](https://github.com/apache/incubator-seata-go/pull/714)] 优化构建锁键的速度。
- [[#719](https://github.com/apache/incubator-seata-go/pull/719)] 在 AT 执行 INSERT SQL 时仅保存被插入的字段。
- [[#721](https://github.com/apache/incubator-seata-go/pull/721)] 修复翻译机器人不可用的问题。
- [[#758](https://github.com/apache/incubator-seata-go/pull/758)] 移除未使用的文件。

## 测试(test):

- [[#570](https://github.com/apache/incubator-seata-go/pull/570)] 添加 collection 单元测试。
- [[#571](https://github.com/apache/incubator-seata-go/pull/571)] 添加 convert 单元测试。
- [[#572](https://github.com/apache/incubator-seata-go/pull/572)] 添加 reflectx 单元测试。
- [[#5835f0](https://github.com/apache/incubator-seata-go/commit/5835f09ecfd6edeb04c2961163bc4460f578e942)] 添加 random loadbalance 单元测试。
- [[#599](https://github.com/apache/incubator-seata-go/pull/599)] 添加 xid loadbalance 单元测试。

## 文档(doc):

- [[#844](https://github.com/apache/incubator-seata-go/pull/844)] 丰富项目 README。
- [[#760](https://github.com/apache/incubator-seata-go/pull/760)] V2.0.0 发布更新器。
- [[#614](https://github.com/apache/incubator-seata-go/pull/614)] 升级具有未知许可证的依赖。
- [[#632](https://github.com/apache/incubator-seata-go/pull/632)] 添加 ASF 基本配置。
- [[#633](https://github.com/apache/incubator-seata-go/pull/633)] 优化 ASF 基本配置以移除上下文检查。
- [[#644](https://github.com/apache/incubator-seata-go/pull/644)] 优化 README 文件。
- [[#686](https://github.com/apache/incubator-seata-go/pull/686)] 在 CI 中添加更多 linter。
- [[#737](https://github.com/apache/incubator-seata-go/pull/737)] 修改 README 并更新当前已完成的工作项。
- [[#756](https://github.com/apache/incubator-seata-go/pull/756)] 更新许可检查器。

## 贡献者(contributors):

感谢以下贡献者的代码提交。若有遗漏请告知。

- [luky116](https://github.com/luky116)
- [Code-Fight](https://github.com/Code-Fight)
- [wt-better](https://github.com/wt-better)
- [luweiqianyi](https://github.com/luweiqianyi)
- [wang1309](https://github.com/wang1309)
- [576470954](https://github.com/576470954)
- [No-SilverBullet](https://github.com/No-SilverBullet)
- [solisamicus](https://github.com/solisamicus)
- [marsevilspirit](https://github.com/marsevilspirit)
- [lxfeng1997](https://github.com/lxfeng1997)
- [AlexStocks](https://github.com/AlexStocks)
- [smiletrl](https://github.com/smiletrl)
- [ptyin](https://github.com/ptyin)
- [yizhibian](https://github.com/yizhibian)
- [oldmee](https://github.com/oldmee)
- [air-3](https://github.com/air-3)
- [slievrly](https://github.com/slievrly)
- [xjlgod](https://github.com/xjlgod)
- [baerwang](https://github.com/baerwang)
- [xyombo](https://github.com/xyombo)
- [testwill](https://github.com/testwill)
- [jasondeng1997](https://github.com/jasondeng1997)
- [jsbxyyx](https://github.com/jsbxyyx)
- [iSuperCoder](https://github.com/iSuperCoder)
- [georgehao](https://github.com/georgehao)
- [liuyuecai](https://github.com/liuyuecai)
- [106umao](https://github.com/106umao)
- [FinnTew](https://github.com/FinnTew)
- [funky-eyes](https://github.com/funky-eyes)
- [tanzegen](https://github.com/tanzegen)
- [lovepoem](https://github.com/lovepoem)
- [MinatoWu](https://github.com/MinatoWu)
- [LucienShen-Liu](https://github.com/LucienShen-Liu)
- [panlei-coder](https://github.com/panlei-coder)
- [lixingjia77](https://github.com/lixingjia77)
- [Road2Melon](https://github.com/Road2Melon)
- [Similarityoung](https://github.com/Similarityoung)
- [YvCeung](https://github.com/YvCeung)
- [pjfanning](https://github.com/pjfanning)
- [hokkine](https://github.com/hokkine)
- [zhangymPerson](https://github.com/zhangymPerson)
- [ForestLH](https://github.com/ForestLH)

此外,我们从社区收到了许多有价值的问题、提问与建议,特此致谢。

</detail>

+ 0
- 48
changes/dev.md View File

@@ -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.
-->

### Development notes

### dev version

Seata-go is an easy-to-use, high-performance, open source distributed transaction solution.

The version is updated as follows:

### feature:

- [[#123](https://github.com/apache/incubator-seata-go/pull/123)] add two phase and dubbo

### bugfix:

- [[#130](https://github.com/apache/incubator-seata-go/pull/130)] getty session auto close bug

### optimize:

- [[#125](https://github.com/apache/incubator-seata-go/pull/125)] optimize named for the resource manager api and tcc resource

### test:

- [[#xxx](https://github.com/apache/incubator-seata-go/pull/xxx)] test case for xxx

### contributors:

Thanks to these contributors for their code commits. Please report an unintended omission.

- [slievrly](https://github.com/slievrly)

Also, we receive many valuable issues, questions and advices from our community. Thanks for you all.

+ 0
- 50
changes/dev_zh.md View File

@@ -1,50 +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.
-->

### 开发记录


### dev version

Seata-go 是一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。

此版本更新如下:

### feature:

- [[#123](https://github.com/apache/incubator-seata-go/pull/123)] 添加二阶段事务接口,以及dubbo集成

### bugfix:

- [[#130](https://github.com/apache/incubator-seata-go/pull/130)] 修复getty session自动关闭的bug

### optimize:

- [[#125](https://github.com/apache/incubator-seata-go/pull/125)] 优化resourceManagerApi和tccResource功能

### test:

- [[#xxx](https://github.com/apache/incubator-seata-go/pull/xxx)] 添加xxx的单元测试


### contributors:

非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。

- [slievrly](https://github.com/slievrly)

同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。

+ 50
- 0
cmd/profiles/dev/config.yml View File

@@ -0,0 +1,50 @@
server:
port: 8091
maxRollbackRetryTimeout: -1
maxCommitRetryTimeout: -1
rollbackRetryTimeoutUnlockEnable: true
asyncCommittingRetryPeriod: 1s
committingRetryPeriod: 5s
rollingBackRetryPeriod: 1s
timeoutRetryPeriod: 1s
streamMessageTimeout: 30s
rollbackDeadSeconds: 12
enforcementPolicy:
minTime: 5s
permitWithoutStream: true
serverParameters:
maxConnectionIdle: 15s
maxConnectionAge: 30s
maxConnectionAgeGrace: 5s
time: 5s
timeout: 1s
serverTLS:
enable: false
certFilePath: ""
keyFilePath: ""
clientParameters:
time: 10s
timeout: 1s
permitWithoutStream: true
storage:
# inMemory driver only for testing
# inmemory:
mysql:
dsn: "root:123456@tcp(127.0.0.1:3306)/seata?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8"
globaltable: global_table
branchtable: branch_table
locktable: lock_table
maxopenconnections: 100
maxidleconnections: 20
maxlifetime: 4h
# pgsql:
# dsn: "postgres://postgres:123456@127.0.0.1:5432/seata?search_path=public&sslmode=disable"
# globaltable: global_table
# branchtable: branch_table
# locktable: lock_table
# maxopenconnections: 100
# maxidleconnections: 20
# maxlifetime: 4h
log:
logPath: /Users/scottlewis/dksl/git/1/seata-golang/cmd/profiles/dev/seata.log
logLevel: info

+ 0
- 22
cmd/start.go View File

@@ -1,22 +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.
*/

package main

func main() {
// start the server
}

+ 138
- 0
cmd/tc/main.go View File

@@ -0,0 +1,138 @@
package main

import (
"fmt"
"net"
"net/http"
_ "net/http/pprof"
"os"

"github.com/urfave/cli/v2"
"google.golang.org/grpc"

"github.com/opentrx/seata-golang/v2/pkg/apis"
"github.com/opentrx/seata-golang/v2/pkg/tc/config"
_ "github.com/opentrx/seata-golang/v2/pkg/tc/metrics"
"github.com/opentrx/seata-golang/v2/pkg/tc/server"
_ "github.com/opentrx/seata-golang/v2/pkg/tc/storage/driver/inmemory"
_ "github.com/opentrx/seata-golang/v2/pkg/tc/storage/driver/mysql"
_ "github.com/opentrx/seata-golang/v2/pkg/tc/storage/driver/pgsql"
"github.com/opentrx/seata-golang/v2/pkg/util/log"
"github.com/opentrx/seata-golang/v2/pkg/util/uuid"
)

func main() {
app := &cli.App{
Commands: []*cli.Command{
{
Name: "start",
Usage: "start seata golang tc server",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
Usage: "Load configuration from `FILE`",
},
&cli.StringFlag{
Name: "serverNode",
Aliases: []string{"n"},
Value: "1",
Usage: "server node id, such as 1, 2, 3. default is 1",
},
},
Action: func(c *cli.Context) error {
configPath := c.String("config")
serverNode := c.Int64("serverNode")

cfg, err := resolveConfiguration(configPath)
if err != nil || cfg == nil {
return err
}

_ = uuid.Init(serverNode)
log.Init(cfg.Log.LogPath, cfg.Log.LogLevel)

address := fmt.Sprintf(":%v", cfg.Server.Port)
lis, err := net.Listen("tcp", address)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}

s := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(cfg.GetEnforcementPolicy()),
grpc.KeepaliveParams(cfg.GetServerParameters()), grpc.Creds(cfg.GetServerTLS()))

tc := server.NewTransactionCoordinator(cfg)
apis.RegisterTransactionManagerServiceServer(s, tc)
apis.RegisterResourceManagerServiceServer(s, tc)

go func() {
http.HandleFunc("/health", func(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(http.StatusOK)
})
err = http.ListenAndServe(":10001", nil)
if err != nil {
return
}
}()

printStartUpLogo()
log.Infof("start to serve on port %d", cfg.Server.Port)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
return nil
},
},
},
}

err := app.Run(os.Args)
if err != nil {
log.Error(err)
}
}

func resolveConfiguration(configPath string) (*config.Configuration, error) {
var configurationPath string

if configPath != "" {
configurationPath = configPath
} else if os.Getenv("SEATA_CONFIGURATION_PATH") != "" {
configurationPath = os.Getenv("SEATA_CONFIGURATION_PATH")
}

if configurationPath == "" {
return nil, fmt.Errorf("configuration path unspecified")
}

fp, err := os.Open(configurationPath)
if err != nil {
return nil, err
}

defer func(fp *os.File) {
err = fp.Close()
if err != nil {
log.Error(err)
}
}(fp)

cfg, err := config.Parse(fp)
if err != nil {
return nil, fmt.Errorf("error parsing %s: %v", configurationPath, err)
}

return cfg, nil
}

func printStartUpLogo() {
logoStr := " _ _ \n" +
" ___ ___ __ _| |_ __ _ __ _ ___ | | __ _ _ __ __ _ \n" +
"/ __|/ _ \\/ _` | __/ _` |_____ / _` |/ _ \\| |/ _` | '_ \\ / _` |\n" +
"\\__ \\ __/ (_| | || (_| |_____| (_| | (_) | | (_| | | | | (_| |\n" +
"|___/\\___|\\__,_|\\__\\__,_| \\__, |\\___/|_|\\__,_|_| |_|\\__, |\n" +
" |___/ |___/ "
fmt.Println(logoStr)
fmt.Println("Seata-Golang (v2) Transaction Coordinator (TC)")
fmt.Println()
}

+ 17
- 0
dist/Dockerfile View File

@@ -0,0 +1,17 @@
FROM alpine:3.14.1

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \
apk add --no-cache tcpdump lsof net-tools tzdata curl dumb-init libc6-compat

ENV TZ Asia/Shanghai
ENV PATH=$PATH:/opt/seata-golang/bin

WORKDIR /opt/seata-golang/bin

COPY tc /opt/seata-golang/bin/tc
COPY config.yml /etc/seata-golang/config.yml
RUN chmod +x /opt/seata-golang/bin/tc

ENTRYPOINT ["/usr/bin/dumb-init", "--"]

CMD ["/opt/seata-golang/bin/tc", "start", "-config", "/etc/seata-golang/config.yml"]

+ 44
- 0
dist/config.yml View File

@@ -0,0 +1,44 @@
server:
port: 8091
maxRollbackRetryTimeout: -1
maxCommitRetryTimeout: -1
rollbackRetryTimeoutUnlockEnable: true
asyncCommittingRetryPeriod: 10s
committingRetryPeriod: 1s
rollingBackRetryPeriod: 1s
timeoutRetryPeriod: 1s
enforcementPolicy:
minTime: 5s
permitWithoutStream: true
serverParameters:
maxConnectionIdle: 15s
maxConnectionAge: 30s
maxConnectionAgeGrace: 5s
time: 5s
timeout: 1s
clientParameters:
time: 10s
timeout: 1s
permitWithoutStream: true
storage:
# inMemory driver only for testing
inmemory:
# mysql:
# dsn: "root:123456@tcp(127.0.0.1:3306)/seata?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8"
# globaltable: global_table2
# branchtable: branch_table2
# locktable: lock_table
# maxopenconnections: 100
# maxidleconnections: 20
# maxlifetime: 4h
# pgsql:
# dsn: "postgres://postgres:123456@127.0.0.1:5432/seata?search_path=public&sslmode=disable"
# globaltable: global_table
# branchtable: branch_table
# locktable: lock_table
# maxopenconnections: 100
# maxidleconnections: 20
# maxlifetime: 4h
log:
logPath: seata.log
logLevel: info

+ 74
- 0
docs/README_ZH.md View File

@@ -0,0 +1,74 @@
# seata-golang
[![LICENSE](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://github.com/opentrx/seata-golang/blob/v2/LICENSE)

## 简介 | [English](https://github.com/opentrx/seata-golang/blob/v2/README.md)
seata-golang是一个用于解决分布式事务的中间件,是基于Go语言版本的seata。
### seata-golang与[seata](https://github.com/seata/seata) 的区别
| 特性 | seata | seata-golang | 备注 |
| ---- | :----: | :----: | --- |
| AT mode | √ | √ | |
| TCC mode | √ | √ | |
| SAGA mode | √ | × | |
| rpc | √ | √ | [dev branch](https://github.com/opentrx/seata-golang/tree/dev) |
| grpc | × | √ | [v2 branch](https://github.com/opentrx/seata-golang/tree/v2) |

## 架构
<img alt="seata-flow" width="500px" src="https://github.com/opentrx/seata-golang/blob/v2/docs/images/seata-flow.png" />

一个典型的seata分布式事务的生命周期:

- TM向TC发起全局分布式事务, TC为全局事务分配一个唯一事务id:XID。
- XID在微服务调用链中传播。
- RM向TC注册本地事务为全局事务的一个分支。
- TM向TC发起全局事务提交或全局事务回滚。
- TC向所有参与全局事务的分支事务发起本地提交或本地回滚。

## 目录结构
- cmd: 启动TC server的入口
- profiles/dev/config.yml: TC 配置文件
- tc/main.go: TC 启动文件
- dist: docker环境
- docs: 相关文档
- pkg: TC + RM + TM 核心模块实现
- server/db/*.sql: 用于启动TC所必须的创建数据库表的SQL

## 启动方法
- ### TC server
```bash
cd ${projectpath}/cmd/tc
go build -o tc_server
# 为TC server创建数据库 `seata`
# 修改配置文件 ${projectpath}/cmd/profiles/dev/config.yml 的配置项 storage.dsn.mysql
./tc_server start -config ${projectpath}/cmd/profiles/dev/config.yml
```

- ### Client
请查看demo演示[seata-go-samples](https://github.com/opentrx/seata-go-samples)

- ### 前提条件
- MySQL服务器
- Golang 版本 >= 1.15
- 带主键的业务数据表

## 设计与实现
seata-golang的AT模式和TCC模式的设计与[seata](https://github.com/seata/seata) 是一致的。
请参考[什么是seata](https://seata.io/en-us/docs/overview/what-is-seata.html)

## 相关参考
- [什么是seata AT模式?](https://seata.io/en-us/docs/dev/mode/at-mode.html)
- [什么是seata TCC模式?](https://seata.io/en-us/docs/dev/mode/tcc-mode.html)
- [grpc](https://grpc.io/)
- [dubbogo](https://github.com/dubbogo)
- [mysql-driver](https://github.com/opentrx/mysql)
- [seata-go-samples](https://github.com/opentrx/seata-go-samples)

## 联系方式
如果对seata-golang有问题,可以通过钉钉联系我们。钉钉群号是 33069364。
<img alt="DingTalk Group" src="https://github.com/opentrx/seata-golang/blob/dev/docs/pics/33069364.png" width="200px" />

## 贡献
欢迎来为seata-golang提交issue和pull-request!
要给seata-golang提交代码, 可以fork opentrx/seata-golang,然后提交代码到你fork的仓库分支上,最后提交pull request。

## 开源协议
seata-golang遵循Apache 2.0开源协议。 查看 [LICENSE](https://github.com/opentrx/seata-golang/blob/v2/LICENSE)

BIN
docs/images/seata-flow.png View File

Before After
Width: 794  |  Height: 478  |  Size: 45 kB

+ 18
- 108
go.mod View File

@@ -1,115 +1,25 @@
module seata.apache.org/seata-go
module github.com/opentrx/seata-golang/v2


go 1.20
go 1.15


require ( require (
dubbo.apache.org/dubbo-go/v3 v3.0.4
github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/apache/dubbo-getty v1.5.0
github.com/arana-db/parser v0.2.17
github.com/bluele/gcache v0.0.2
github.com/dsnet/compress v0.0.1
github.com/dubbogo/gost v1.13.2
github.com/gin-gonic/gin v1.9.1
github.com/go-sql-driver/mysql v1.6.0
github.com/goccy/go-json v0.10.2
github.com/golang/mock v1.6.0
github.com/google/uuid v1.3.0
github.com/dubbogo/gost v1.11.11
github.com/go-sql-driver/mysql v1.5.0
github.com/go-xorm/xorm v0.7.9
github.com/gogo/protobuf v1.3.2
github.com/lib/pq v1.0.0
github.com/natefinch/lumberjack v2.0.0+incompatible github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/pierrec/lz4/v4 v4.1.17
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.12.2
github.com/prometheus/common v0.32.1
github.com/sijms/go-ora/v2 v2.5.17
github.com/stretchr/testify v1.8.3
go.uber.org/atomic v1.9.0
go.uber.org/zap v1.27.0
google.golang.org/grpc v1.56.3
gopkg.in/yaml.v2 v2.4.0
vimagination.zapto.org/byteio v0.0.0-20200222190125-d27cba0f0b10
)

require (
github.com/agiledragon/gomonkey/v2 v2.12.0
github.com/golang/protobuf v1.5.3
go.etcd.io/etcd/api/v3 v3.5.6
go.etcd.io/etcd/client/v3 v3.5.6
google.golang.org/protobuf v1.30.0
)

require github.com/knadh/koanf v1.5.0

require (
github.com/RoaringBitmap/roaring v1.2.0 // indirect
github.com/Workiva/go-datastructures v1.0.52 // indirect
github.com/apache/dubbo-go-hessian2 v1.11.4 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.2.0 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/creasty/defaults v1.5.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/jinzhu/copier v0.3.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/k0kubun/pp v3.0.1+incompatible // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
github.com/shirou/gopsutil/v3 v3.22.2 // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.4.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.6 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/text v0.14.0 // indirect
github.com/prometheus/client_golang v1.9.0
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a
github.com/stretchr/testify v1.7.0 // indirect
github.com/urfave/cli/v2 v2.3.0
go.uber.org/atomic v1.7.0
go.uber.org/zap v1.17.0
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect
google.golang.org/grpc v1.38.0
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

require (
github.com/BurntSushi/toml v1.1.0 // indirect
github.com/go-playground/validator/v10 v10.14.0 // indirect
github.com/klauspost/compress v1.15.11
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/pelletier/go-toml v1.9.3 // indirect
github.com/pingcap/log v0.0.0-20210906054005-afc726e70354 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/sys v0.18.0 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
vimagination.zapto.org/memio v0.0.0-20200222190306-588ebc67b97d // indirect
gopkg.in/yaml.v2 v2.4.0
xorm.io/builder v0.3.9
) )

replace github.com/dubbogo/gost => github.com/dubbogo/gost v1.13.2

exclude github.com/polarismesh/polaris-go v1.3.0-alpha

+ 80
- 655
go.sum
File diff suppressed because it is too large
View File


+ 0
- 29
goimports.sh View File

@@ -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.
#

# format go imports style
go install golang.org/x/tools/cmd/goimports
goimports -local seata.apache.org/seata-go -w .

# format licence style
go install github.com/apache/skywalking-eyes/cmd/license-eye@latest
license-eye header fix
# check dependency licence is valid
license-eye dependency check

# format go.mod
go mod tidy

+ 0
- 48
integrate_test.sh View File

@@ -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.

#!/bin/bash

set -e
set -x

echo 'start integrate-test'

# set root workspace
ROOT_DIR=$(pwd)
echo "integrate-test root work-space -> ${ROOT_DIR}"

# show all github-env
echo "github current commit id -> $2"
echo "github pull request branch -> ${GITHUB_REF}"
echo "github pull request slug -> ${GITHUB_REPOSITORY}"
echo "github pull request repo slug -> ${GITHUB_REPOSITORY}"
echo "github pull request actor -> ${GITHUB_ACTOR}"
echo "github pull request repo param -> $1"
echo "github pull request base branch -> $3"
echo "github pull request head branch -> ${GITHUB_HEAD_REF}"

echo "use seata-go-samples $3 branch for integration testing"
git clone https://github.com/apache/incubator-seata-go-samples samples && cd samples

# update seata-go to current commit id

go mod edit -replace=seata.apache.org/seata-go=github.com/"$1"@"$2"

go mod tidy

# start integrate test
./start_integrate_test.sh

+ 0
- 9
licenses/LICENSE.tpl View File

@@ -1,9 +0,0 @@
{{.LicenseContent }}
{{ range .Groups }}
========================================================================
{{.LicenseID}} licenses
========================================================================
{{range .Deps}}
{{.Name}} {{.Version}} {{.LicenseID}}
{{- end }}
{{ end }}

+ 0
- 80
makefile View File

@@ -1,80 +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.
#

VERSION=$(shell cat "./VERSION" 2> /dev/null)

GO_FLAGS := -ldflags "-X main.Branch=$(GIT_BRANCH) -X main.Revision=$(GIT_REVISION) -X main.Version=$(VERSION) -extldflags \"-static\" -s -w" -tags netgo
GO = go
GO_PATH = $(shell $(GO) env GOPATH)
GO_OS = $(shell $(GO) env GOOS)
ifeq ($(GO_OS), darwin)
GO_OS = mac
endif
ifeq ($(shell uname -s), Darwin)
SHA256_CMD = shasum -a 256
else
SHA256_CMD = sha256sum
endif

# License environment
GO_LICENSE_CHECKER_DIR = license-header-checker-$(GO_OS)
GO_LICENSE_CHECKER = $(GO_PATH)/bin/license-header-checker
LICENSE_DIR = /tmp/tools/license

# format import code
format-import:
go get -d github.com/dubbogo/tools/cmd/imports-formatter
imports-formatter -path . -module seata.apache.org/seata-go -bl false

unit-test:
go test ./pkg/... -coverprofile=coverage.txt -covermode=atomic

# Generate binaries for a Cortex release
dist dist/seatago-linux-amd64 dist/seatago-darwin-amd64 dist/seatago-linux-amd64-sha-256 dist/seatago-darwin-amd64-sha-256:
rm -fr ./dist
mkdir -p ./dist
GOOS="linux" GOARCH="amd64" CGO_ENABLED=0 go build $(GO_FLAGS) -o ./dist/seatago-linux-amd64 ./cmd
GOOS="darwin" GOARCH="amd64" CGO_ENABLED=0 go build $(GO_FLAGS) -o ./dist/seatago-darwin-amd64 ./cmd
$(SHA256_CMD) ./dist/seatago-darwin-amd64 | cut -d ' ' -f 1 > ./dist/seatago-darwin-amd64-sha-256
$(SHA256_CMD) ./dist/seatago-linux-amd64 | cut -d ' ' -f 1 > ./dist/seatago-linux-amd64-sha-256

# Generate binaries for a Cortex release
build dist/seatago dist/seatago-sha-256:
rm -fr ./dist
mkdir -p ./dist
CGO_ENABLED=0 go build $(GO_FLAGS) -o ./dist/seatago ./cmd
$(SHA256_CMD) ./dist/seatago | cut -d ' ' -f 1 > ./dist/seatago-sha-256

#docker-build:
# docker build -t seatago/seatago:latest .

integration-test:
@go clean -testcache
go test -tags integration -v ./test/...

clean:
@rm -rf coverage.txt
@rm -rf dist

prepareLic:
echo 'The makefile is for ci test and has dependencies. Do not run it locally. If you want to run the unit tests, run command `go test ./...` directly.'
$(GO_LICENSE_CHECKER) -version || (wget https://github.com/lsm-dev/license-header-checker/releases/download/v1.2.0/$(GO_LICENSE_CHECKER_DIR).zip -O $(GO_LICENSE_CHECKER_DIR).zip && unzip -o $(GO_LICENSE_CHECKER_DIR).zip && mkdir -p $(GO_PATH)/bin/ && cp $(GO_LICENSE_CHECKER_DIR)/64bit/license-header-checker $(GO_PATH)/bin/)
ls /tmp/tools/license/license.txt || wget -P $(LICENSE_DIR) https://github.com/dubbogo/resources/raw/master/tools/license/license.txt

.PHONY: license
license: prepareLic
$(GO_LICENSE_CHECKER) -v -a -r -i vendor $(LICENSE_DIR)/license.txt . go && [[ -z `git status -s` ]]

+ 9636
- 0
pkg/apis/seata.pb.go
File diff suppressed because it is too large
View File


+ 413
- 0
pkg/apis/seata.proto View File

@@ -0,0 +1,413 @@
syntax = "proto3";

package apis;

import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "google/protobuf/any.proto";

option go_package="github.com/opentrx/seata-golang/v2/pkg/apis";

enum ResultCode {
ResultCodeFailed = 0;
ResultCodeSuccess = 1;
}

enum ExceptionCode {
// Unknown transaction error code.
UnknownErr = 0;

// BeginFailed
BeginFailed = 1;

// Lock key conflict transaction error code.
LockKeyConflict = 2;

// Io transaction error code.
IO = 3;

// Branch rollback failed retryable transaction error code.
BranchRollbackFailedRetryable = 4;

// Branch rollback failed unretryable transaction error code.
BranchRollbackFailedUnretryable = 5;

// Branch register failed transaction error code.
BranchRegisterFailed = 6;

// Branch report failed transaction error code.
BranchReportFailed = 7;

// Lockable check failed transaction error code.
LockableCheckFailed = 8;

// Branch transaction not exist transaction error code.
BranchTransactionNotExist = 9;

// Global transaction not exist transaction error code.
GlobalTransactionNotExist = 10;

// Global transaction not active transaction error code.
GlobalTransactionNotActive = 11;

// Global transaction status invalid transaction error code.
GlobalTransactionStatusInvalid = 12;

// Failed to send branch commit request transaction error code.
FailedToSendBranchCommitRequest = 13;

// Failed to send branch rollback request transaction error code.
FailedToSendBranchRollbackRequest = 14;

// Failed to add branch transaction error code.
FailedToAddBranch = 15;

// Failed to lock global transaction error code.
FailedLockGlobalTransaction = 16;

// FailedWriteSession
FailedWriteSession = 17;

// Failed to holder error code
FailedStore = 18;
}

enum BranchMessageType {
TypeBranchCommit = 0;
TypeBranchCommitResult = 1;
TypeBranchRollback = 2;
TypeBranchRollBackResult = 3;
}

message GlobalSession {
enum GlobalStatus {
// Un known global status.
UnknownGlobalStatus = 0;

// PHASE 1: can accept new branch registering.
Begin = 1;

// PHASE 2: Running Status: may be changed any time.
Committing = 2;

// The Commit retrying.
// Retrying commit after a recoverable failure.
CommitRetrying = 3;

// Rolling back global status.
RollingBack = 4;

// The Rollback retrying.
// Retrying rollback after a recoverable failure.
RollbackRetrying = 5;

// The Timeout rolling back.
// Rolling back since timeout
TimeoutRollingBack = 6;

// The Timeout rollback retrying.
// Retrying rollback (since timeout) after a recoverable failure.
TimeoutRollbackRetrying = 7;

// All branches can be async committed. The committing is NOT done yet, but it can be seen as
// committed for TM/RM rpc_client.
AsyncCommitting = 8;

// PHASE 2: Final Status: will NOT change any more.
// Finally: global transaction is successfully committed.
Committed = 9;

// The Commit failed.
// Finally: failed to commit
CommitFailed = 10;

// The RolledBack.
// Finally: global transaction is successfully rollback.
RolledBack = 11;

// The Rollback failed.
// Finally: failed to rollback
RollbackFailed = 12;

// The Timeout rolled back.
// Finally: global transaction is successfully rollback since timeout.
TimeoutRolledBack = 13;

// The Timeout rollback failed.
// Finally: failed to rollback since timeout
TimeoutRollbackFailed = 14;

// The Finished.
// Not managed in getty_session MAP any more
Finished = 15;
}

string Addressing = 1 [(gogoproto.moretags) = "xorm:\"addressing\""];
string XID = 2 [(gogoproto.moretags) = "xorm:\"xid\""];
int64 TransactionID = 3 [(gogoproto.moretags) = "xorm:\"transaction_id\""];
string TransactionName = 4 [(gogoproto.moretags) = "xorm:\"transaction_name\""];
int32 Timeout = 5 [(gogoproto.moretags) = "xorm:\"timeout\""];
int64 BeginTime = 6 [(gogoproto.moretags) = "xorm:\"begin_time\""];
GlobalStatus Status = 7 [(gogoproto.moretags) = "xorm:\"status\""];
bool Active = 8 [(gogoproto.moretags) = "xorm:\"active\""];
}

message BranchSession {
enum BranchType {
AT = 0;

TCC = 1;

SAGA = 2;

XA = 3;
}

enum BranchStatus {
// description:BranchStatus_Unknown branch status.
UnknownBranchStatus = 0;

// description:BranchStatus_Registered to TC.
Registered = 1;

// The Phase one done.
// description:Branch logic is successfully done at phase one.
PhaseOneDone = 2;

// The Phase one failed.
// description:Branch logic is failed at phase one.
PhaseOneFailed = 3;

// The Phase one timeout.
// description:Branch logic is NOT reported for a timeout.
PhaseOneTimeout = 4;

// The Phase two committed.
// description:Commit logic is successfully done at phase two.
PhaseTwoCommitted = 5;

// The Phase two commit failed retryable.
// description:Commit logic is failed but retryable.
PhaseTwoCommitFailedRetryable = 6;

// The Phase two commit failed and can not retry.
// description:Commit logic is failed and NOT retryable.
PhaseTwoCommitFailedCanNotRetry = 7;

// The Phase two rollback completed.
// description:Rollback logic is successfully done at phase two.
PhaseTwoRolledBack = 8;

// The Phase two rollback failed retryable.
// description:Rollback logic is failed but retryable.
PhaseTwoRollbackFailedRetryable = 9;

// The Phase two rollback failed and can not retry.
// description:Rollback logic is failed but NOT retryable.
PhaseTwoRollbackFailedCanNotRetry = 10;
}

string Addressing = 1 [(gogoproto.moretags) = "xorm:\"addressing\""];
string XID = 2 [(gogoproto.moretags) = "xorm:\"xid\""];
int64 BranchID = 3 [(gogoproto.moretags) = "xorm:\"branch_id\""];
int64 TransactionID = 4 [(gogoproto.moretags) = "xorm:\"transaction_id\""];
string ResourceID = 5 [(gogoproto.moretags) = "xorm:\"resource_id\""];
string LockKey = 6 [(gogoproto.moretags) = "xorm:\"lock_key\""];
BranchType Type = 7 [(gogoproto.moretags) = "xorm:\"branch_type\""];
BranchStatus Status = 8 [(gogoproto.moretags) = "xorm:\"status\""];
bytes ApplicationData = 9 [(gogoproto.moretags) = "xorm:\"application_data\""];
bool AsyncCommit = 10 [(gogoproto.moretags) = "xorm:\"async_commit\""];
}

message RowLock {
string XID = 1 [(gogoproto.moretags) = "xorm:\"xid\""];
int64 TransactionID = 2 [(gogoproto.moretags) = "xorm:\"transaction_id\""];
int64 BranchID = 3 [(gogoproto.moretags) = "xorm:\"branch_id\""];
string ResourceID = 4 [(gogoproto.moretags) = "xorm:\"resource_id\""];
string TableName = 5 [(gogoproto.moretags) = "xorm:\"table_name\""];
string PK = 6 [(gogoproto.moretags) = "xorm:\"pk\""];
string RowKey = 7 [(gogoproto.moretags) = "xorm:\"row_key\""];
}

// GlobalBeginRequest represents a global transaction begin
message GlobalBeginRequest {
string Addressing = 1;
int32 Timeout = 2;
string TransactionName = 3;
}

// GlobalBeginResponse represents a response to GlobalBeginRequest
message GlobalBeginResponse {
ResultCode ResultCode = 1;
ExceptionCode ExceptionCode = 2;
string Message = 3;
string XID = 4;
}

// BranchRegisterRequest represents a branch transaction join in the global transaction
message BranchRegisterRequest {
string Addressing = 1;
string XID = 2;
string ResourceID = 3;
string LockKey = 4;
BranchSession.BranchType BranchType = 5;
bytes ApplicationData = 6;
bool AsyncCommit = 7;
}

// BranchRegisterResponse represents a response to BranchRegisterRequest
message BranchRegisterResponse {
ResultCode ResultCode = 1;
ExceptionCode ExceptionCode = 2;
string Message = 3;
int64 BranchID = 4;
}

// BranchReportRequest represents a request to report branch transaction execution status
message BranchReportRequest {
string XID = 1;
int64 BranchID = 2;
string ResourceID = 3;
BranchSession.BranchType BranchType = 4;
BranchSession.BranchStatus BranchStatus = 5;
bytes ApplicationData = 6;
}

// BranchReportResponse represents a response to BranchReportRequest
message BranchReportResponse {
ResultCode ResultCode = 1;
ExceptionCode ExceptionCode = 2;
string Message = 3;
}

// GlobalLockQueryRequest represents a request to query the global lock
message GlobalLockQueryRequest {
string XID = 1;
string ResourceID = 2;
string LockKey = 3;
BranchSession.BranchType BranchType = 4;
}

// GlobalLockQueryResponse represents a response to GlobalLockQueryRequest
message GlobalLockQueryResponse {
ResultCode ResultCode = 1;
ExceptionCode ExceptionCode = 2;
string Message = 3;
bool Lockable = 4;
}

// GlobalStatusRequest represents a request to query the global transaction status
message GlobalStatusRequest {
string XID = 1;
}

// GlobalStatusResponse represents a response to GlobalStatusRequest
message GlobalStatusResponse {
ResultCode ResultCode = 1;
ExceptionCode ExceptionCode = 2;
string Message = 3;
GlobalSession.GlobalStatus GlobalStatus = 4;
}

// GlobalCommitRequest represents a request to commit global transaction
message GlobalCommitRequest {
string XID = 1;
}

// GlobalCommitResponse represents a response to GlobalCommitRequest
message GlobalCommitResponse {
ResultCode ResultCode = 1;
ExceptionCode ExceptionCode = 2;
string Message = 3;
GlobalSession.GlobalStatus GlobalStatus = 4;
}

// GlobalRollbackRequest represents a request to rollback global transaction
message GlobalRollbackRequest {
string XID = 1;
}

// GlobalRollbackResponse represents a response to GlobalRollbackRequest
message GlobalRollbackResponse {
ResultCode ResultCode = 1;
ExceptionCode ExceptionCode = 2;
string Message = 3;
GlobalSession.GlobalStatus GlobalStatus = 4;
}

// GlobalReportRequest represents a request to report global transaction execution status
message GlobalReportRequest {
string XID = 1;
GlobalSession.GlobalStatus GlobalStatus = 2;
}

// GlobalReportResponse represents a response to GlobalReportRequest
message GlobalReportResponse {
ResultCode ResultCode = 1;
ExceptionCode ExceptionCode = 2;
string Message = 3;
GlobalSession.GlobalStatus GlobalStatus = 4;
}

// BranchCommitRequest represents a request to commit branch transaction
message BranchCommitRequest {
string XID = 1;
int64 BranchID = 2;
string ResourceID = 3;
string LockKey = 4;
BranchSession.BranchType BranchType = 5;
bytes ApplicationData = 6;
}

// BranchCommitResponse represents a response to BranchCommitRequest
message BranchCommitResponse {
ResultCode ResultCode = 1;
ExceptionCode ExceptionCode = 2;
string Message = 3;
string XID = 4;
int64 BranchID = 5;
BranchSession.BranchStatus BranchStatus = 6;
}

// BranchCommitRequest represents a request to rollback branch transaction
message BranchRollbackRequest {
string XID = 1;
int64 BranchID = 2;
string ResourceID = 3;
string LockKey = 4;
BranchSession.BranchType BranchType = 5;
bytes ApplicationData = 6;
}

// BranchRollbackResponse represents a response to BranchRollbackRequest
message BranchRollbackResponse {
ResultCode ResultCode = 1;
ExceptionCode ExceptionCode = 2;
string Message = 3;
string XID = 4;
int64 BranchID = 5;
BranchSession.BranchStatus BranchStatus = 6;
}

message BranchMessage {
int64 ID = 1;
BranchMessageType BranchMessageType = 2;
google.protobuf.Any Message = 3;
}

service TransactionManagerService {
rpc Begin(GlobalBeginRequest) returns (GlobalBeginResponse);
rpc GetStatus(GlobalStatusRequest) returns (GlobalStatusResponse);
rpc GlobalReport(GlobalReportRequest) returns (GlobalReportResponse);
rpc Commit(GlobalCommitRequest) returns (GlobalCommitResponse);
rpc Rollback(GlobalRollbackRequest) returns (GlobalRollbackResponse);
}

service ResourceManagerService {
rpc BranchCommunicate(stream BranchMessage) returns (stream BranchMessage);
rpc BranchRegister(BranchRegisterRequest) returns (BranchRegisterResponse);
rpc BranchReport(BranchReportRequest) returns (BranchReportResponse);
rpc LockQuery(GlobalLockQueryRequest) returns (GlobalLockQueryResponse);
}




+ 468
- 0
pkg/apis/seata_grpc.pb.go View File

@@ -0,0 +1,468 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.

package apis

import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7

// TransactionManagerServiceClient is the client API for TransactionManagerService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type TransactionManagerServiceClient interface {
Begin(ctx context.Context, in *GlobalBeginRequest, opts ...grpc.CallOption) (*GlobalBeginResponse, error)
GetStatus(ctx context.Context, in *GlobalStatusRequest, opts ...grpc.CallOption) (*GlobalStatusResponse, error)
GlobalReport(ctx context.Context, in *GlobalReportRequest, opts ...grpc.CallOption) (*GlobalReportResponse, error)
Commit(ctx context.Context, in *GlobalCommitRequest, opts ...grpc.CallOption) (*GlobalCommitResponse, error)
Rollback(ctx context.Context, in *GlobalRollbackRequest, opts ...grpc.CallOption) (*GlobalRollbackResponse, error)
}

type transactionManagerServiceClient struct {
cc grpc.ClientConnInterface
}

func NewTransactionManagerServiceClient(cc grpc.ClientConnInterface) TransactionManagerServiceClient {
return &transactionManagerServiceClient{cc}
}

func (c *transactionManagerServiceClient) Begin(ctx context.Context, in *GlobalBeginRequest, opts ...grpc.CallOption) (*GlobalBeginResponse, error) {
out := new(GlobalBeginResponse)
err := c.cc.Invoke(ctx, "/apis.TransactionManagerService/Begin", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}

func (c *transactionManagerServiceClient) GetStatus(ctx context.Context, in *GlobalStatusRequest, opts ...grpc.CallOption) (*GlobalStatusResponse, error) {
out := new(GlobalStatusResponse)
err := c.cc.Invoke(ctx, "/apis.TransactionManagerService/GetStatus", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}

func (c *transactionManagerServiceClient) GlobalReport(ctx context.Context, in *GlobalReportRequest, opts ...grpc.CallOption) (*GlobalReportResponse, error) {
out := new(GlobalReportResponse)
err := c.cc.Invoke(ctx, "/apis.TransactionManagerService/GlobalReport", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}

func (c *transactionManagerServiceClient) Commit(ctx context.Context, in *GlobalCommitRequest, opts ...grpc.CallOption) (*GlobalCommitResponse, error) {
out := new(GlobalCommitResponse)
err := c.cc.Invoke(ctx, "/apis.TransactionManagerService/Commit", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}

func (c *transactionManagerServiceClient) Rollback(ctx context.Context, in *GlobalRollbackRequest, opts ...grpc.CallOption) (*GlobalRollbackResponse, error) {
out := new(GlobalRollbackResponse)
err := c.cc.Invoke(ctx, "/apis.TransactionManagerService/Rollback", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}

// TransactionManagerServiceServer is the server API for TransactionManagerService service.
// All implementations should embed UnimplementedTransactionManagerServiceServer
// for forward compatibility
type TransactionManagerServiceServer interface {
Begin(context.Context, *GlobalBeginRequest) (*GlobalBeginResponse, error)
GetStatus(context.Context, *GlobalStatusRequest) (*GlobalStatusResponse, error)
GlobalReport(context.Context, *GlobalReportRequest) (*GlobalReportResponse, error)
Commit(context.Context, *GlobalCommitRequest) (*GlobalCommitResponse, error)
Rollback(context.Context, *GlobalRollbackRequest) (*GlobalRollbackResponse, error)
}

// UnimplementedTransactionManagerServiceServer should be embedded to have forward compatible implementations.
type UnimplementedTransactionManagerServiceServer struct {
}

func (UnimplementedTransactionManagerServiceServer) Begin(context.Context, *GlobalBeginRequest) (*GlobalBeginResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Begin not implemented")
}
func (UnimplementedTransactionManagerServiceServer) GetStatus(context.Context, *GlobalStatusRequest) (*GlobalStatusResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetStatus not implemented")
}
func (UnimplementedTransactionManagerServiceServer) GlobalReport(context.Context, *GlobalReportRequest) (*GlobalReportResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GlobalReport not implemented")
}
func (UnimplementedTransactionManagerServiceServer) Commit(context.Context, *GlobalCommitRequest) (*GlobalCommitResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Commit not implemented")
}
func (UnimplementedTransactionManagerServiceServer) Rollback(context.Context, *GlobalRollbackRequest) (*GlobalRollbackResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Rollback not implemented")
}

// UnsafeTransactionManagerServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to TransactionManagerServiceServer will
// result in compilation errors.
type UnsafeTransactionManagerServiceServer interface {
mustEmbedUnimplementedTransactionManagerServiceServer()
}

func RegisterTransactionManagerServiceServer(s grpc.ServiceRegistrar, srv TransactionManagerServiceServer) {
s.RegisterService(&TransactionManagerService_ServiceDesc, srv)
}

func _TransactionManagerService_Begin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GlobalBeginRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TransactionManagerServiceServer).Begin(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/apis.TransactionManagerService/Begin",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TransactionManagerServiceServer).Begin(ctx, req.(*GlobalBeginRequest))
}
return interceptor(ctx, in, info, handler)
}

func _TransactionManagerService_GetStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GlobalStatusRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TransactionManagerServiceServer).GetStatus(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/apis.TransactionManagerService/GetStatus",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TransactionManagerServiceServer).GetStatus(ctx, req.(*GlobalStatusRequest))
}
return interceptor(ctx, in, info, handler)
}

func _TransactionManagerService_GlobalReport_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GlobalReportRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TransactionManagerServiceServer).GlobalReport(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/apis.TransactionManagerService/GlobalReport",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TransactionManagerServiceServer).GlobalReport(ctx, req.(*GlobalReportRequest))
}
return interceptor(ctx, in, info, handler)
}

func _TransactionManagerService_Commit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GlobalCommitRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TransactionManagerServiceServer).Commit(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/apis.TransactionManagerService/Commit",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TransactionManagerServiceServer).Commit(ctx, req.(*GlobalCommitRequest))
}
return interceptor(ctx, in, info, handler)
}

func _TransactionManagerService_Rollback_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GlobalRollbackRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TransactionManagerServiceServer).Rollback(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/apis.TransactionManagerService/Rollback",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TransactionManagerServiceServer).Rollback(ctx, req.(*GlobalRollbackRequest))
}
return interceptor(ctx, in, info, handler)
}

// TransactionManagerService_ServiceDesc is the grpc.ServiceDesc for TransactionManagerService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var TransactionManagerService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "apis.TransactionManagerService",
HandlerType: (*TransactionManagerServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Begin",
Handler: _TransactionManagerService_Begin_Handler,
},
{
MethodName: "GetStatus",
Handler: _TransactionManagerService_GetStatus_Handler,
},
{
MethodName: "GlobalReport",
Handler: _TransactionManagerService_GlobalReport_Handler,
},
{
MethodName: "Commit",
Handler: _TransactionManagerService_Commit_Handler,
},
{
MethodName: "Rollback",
Handler: _TransactionManagerService_Rollback_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "seata.proto",
}

// ResourceManagerServiceClient is the client API for ResourceManagerService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type ResourceManagerServiceClient interface {
BranchCommunicate(ctx context.Context, opts ...grpc.CallOption) (ResourceManagerService_BranchCommunicateClient, error)
BranchRegister(ctx context.Context, in *BranchRegisterRequest, opts ...grpc.CallOption) (*BranchRegisterResponse, error)
BranchReport(ctx context.Context, in *BranchReportRequest, opts ...grpc.CallOption) (*BranchReportResponse, error)
LockQuery(ctx context.Context, in *GlobalLockQueryRequest, opts ...grpc.CallOption) (*GlobalLockQueryResponse, error)
}

type resourceManagerServiceClient struct {
cc grpc.ClientConnInterface
}

func NewResourceManagerServiceClient(cc grpc.ClientConnInterface) ResourceManagerServiceClient {
return &resourceManagerServiceClient{cc}
}

func (c *resourceManagerServiceClient) BranchCommunicate(ctx context.Context, opts ...grpc.CallOption) (ResourceManagerService_BranchCommunicateClient, error) {
stream, err := c.cc.NewStream(ctx, &ResourceManagerService_ServiceDesc.Streams[0], "/apis.ResourceManagerService/BranchCommunicate", opts...)
if err != nil {
return nil, err
}
x := &resourceManagerServiceBranchCommunicateClient{stream}
return x, nil
}

type ResourceManagerService_BranchCommunicateClient interface {
Send(*BranchMessage) error
Recv() (*BranchMessage, error)
grpc.ClientStream
}

type resourceManagerServiceBranchCommunicateClient struct {
grpc.ClientStream
}

func (x *resourceManagerServiceBranchCommunicateClient) Send(m *BranchMessage) error {
return x.ClientStream.SendMsg(m)
}

func (x *resourceManagerServiceBranchCommunicateClient) Recv() (*BranchMessage, error) {
m := new(BranchMessage)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}

func (c *resourceManagerServiceClient) BranchRegister(ctx context.Context, in *BranchRegisterRequest, opts ...grpc.CallOption) (*BranchRegisterResponse, error) {
out := new(BranchRegisterResponse)
err := c.cc.Invoke(ctx, "/apis.ResourceManagerService/BranchRegister", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}

func (c *resourceManagerServiceClient) BranchReport(ctx context.Context, in *BranchReportRequest, opts ...grpc.CallOption) (*BranchReportResponse, error) {
out := new(BranchReportResponse)
err := c.cc.Invoke(ctx, "/apis.ResourceManagerService/BranchReport", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}

func (c *resourceManagerServiceClient) LockQuery(ctx context.Context, in *GlobalLockQueryRequest, opts ...grpc.CallOption) (*GlobalLockQueryResponse, error) {
out := new(GlobalLockQueryResponse)
err := c.cc.Invoke(ctx, "/apis.ResourceManagerService/LockQuery", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}

// ResourceManagerServiceServer is the server API for ResourceManagerService service.
// All implementations should embed UnimplementedResourceManagerServiceServer
// for forward compatibility
type ResourceManagerServiceServer interface {
BranchCommunicate(ResourceManagerService_BranchCommunicateServer) error
BranchRegister(context.Context, *BranchRegisterRequest) (*BranchRegisterResponse, error)
BranchReport(context.Context, *BranchReportRequest) (*BranchReportResponse, error)
LockQuery(context.Context, *GlobalLockQueryRequest) (*GlobalLockQueryResponse, error)
}

// UnimplementedResourceManagerServiceServer should be embedded to have forward compatible implementations.
type UnimplementedResourceManagerServiceServer struct {
}

func (UnimplementedResourceManagerServiceServer) BranchCommunicate(ResourceManagerService_BranchCommunicateServer) error {
return status.Errorf(codes.Unimplemented, "method BranchCommunicate not implemented")
}
func (UnimplementedResourceManagerServiceServer) BranchRegister(context.Context, *BranchRegisterRequest) (*BranchRegisterResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method BranchRegister not implemented")
}
func (UnimplementedResourceManagerServiceServer) BranchReport(context.Context, *BranchReportRequest) (*BranchReportResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method BranchReport not implemented")
}
func (UnimplementedResourceManagerServiceServer) LockQuery(context.Context, *GlobalLockQueryRequest) (*GlobalLockQueryResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method LockQuery not implemented")
}

// UnsafeResourceManagerServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ResourceManagerServiceServer will
// result in compilation errors.
type UnsafeResourceManagerServiceServer interface {
mustEmbedUnimplementedResourceManagerServiceServer()
}

func RegisterResourceManagerServiceServer(s grpc.ServiceRegistrar, srv ResourceManagerServiceServer) {
s.RegisterService(&ResourceManagerService_ServiceDesc, srv)
}

func _ResourceManagerService_BranchCommunicate_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(ResourceManagerServiceServer).BranchCommunicate(&resourceManagerServiceBranchCommunicateServer{stream})
}

type ResourceManagerService_BranchCommunicateServer interface {
Send(*BranchMessage) error
Recv() (*BranchMessage, error)
grpc.ServerStream
}

type resourceManagerServiceBranchCommunicateServer struct {
grpc.ServerStream
}

func (x *resourceManagerServiceBranchCommunicateServer) Send(m *BranchMessage) error {
return x.ServerStream.SendMsg(m)
}

func (x *resourceManagerServiceBranchCommunicateServer) Recv() (*BranchMessage, error) {
m := new(BranchMessage)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}

func _ResourceManagerService_BranchRegister_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(BranchRegisterRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResourceManagerServiceServer).BranchRegister(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/apis.ResourceManagerService/BranchRegister",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResourceManagerServiceServer).BranchRegister(ctx, req.(*BranchRegisterRequest))
}
return interceptor(ctx, in, info, handler)
}

func _ResourceManagerService_BranchReport_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(BranchReportRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResourceManagerServiceServer).BranchReport(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/apis.ResourceManagerService/BranchReport",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResourceManagerServiceServer).BranchReport(ctx, req.(*BranchReportRequest))
}
return interceptor(ctx, in, info, handler)
}

func _ResourceManagerService_LockQuery_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GlobalLockQueryRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResourceManagerServiceServer).LockQuery(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/apis.ResourceManagerService/LockQuery",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResourceManagerServiceServer).LockQuery(ctx, req.(*GlobalLockQueryRequest))
}
return interceptor(ctx, in, info, handler)
}

// ResourceManagerService_ServiceDesc is the grpc.ServiceDesc for ResourceManagerService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var ResourceManagerService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "apis.ResourceManagerService",
HandlerType: (*ResourceManagerServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "BranchRegister",
Handler: _ResourceManagerService_BranchRegister_Handler,
},
{
MethodName: "BranchReport",
Handler: _ResourceManagerService_BranchReport_Handler,
},
{
MethodName: "LockQuery",
Handler: _ResourceManagerService_LockQuery_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "BranchCommunicate",
Handler: _ResourceManagerService_BranchCommunicate_Handler,
ServerStreams: true,
ClientStreams: true,
},
},
Metadata: "seata.proto",
}

+ 11
- 0
pkg/client/base/context/business_action_context.go View File

@@ -0,0 +1,11 @@
package context

// BusinessActionContext store the tcc branch transaction context
type BusinessActionContext struct {
*RootContext
XID string
BranchID int64
ActionName string
ActionContext map[string]interface{}
AsyncCommit bool
}

+ 151
- 0
pkg/client/base/context/root_context.go View File

@@ -0,0 +1,151 @@
package context

import (
"context"
"fmt"
"strings"

"github.com/opentrx/seata-golang/v2/pkg/apis"
"github.com/opentrx/seata-golang/v2/pkg/util/log"
)

const (
KeyXID = "TX_XID"
KeyXIDInterceptorType = "tx-xid-interceptor-type"
KeyGlobalLockFlag = "TX_LOCK"
)

// RootContext store the global transaction context
type RootContext struct {
context.Context

// like thread local map
localMap map[string]interface{}
}

// NewRootContext return a pointer to RootContext
func NewRootContext(ctx context.Context) *RootContext {
rootCtx := &RootContext{
Context: ctx,
localMap: make(map[string]interface{}),
}

xID := ctx.Value(KeyXID)
if xID != nil {
xid := xID.(string)
rootCtx.Bind(xid)
}
return rootCtx
}

// Set store key value to RootContext
func (c *RootContext) Set(key string, value interface{}) {
if c.localMap == nil {
c.localMap = make(map[string]interface{})
}
c.localMap[key] = value
}

// Get get a value by given key from RootContext
func (c *RootContext) Get(key string) (value interface{}, exists bool) {
value, exists = c.localMap[key]
return
}

// GetXID from RootContext get xid
func (c *RootContext) GetXID() string {
xID := c.localMap[KeyXID]
xid, ok := xID.(string)
if ok && xid != "" {
return xid
}

xIDType := c.localMap[KeyXIDInterceptorType]
xidType, success := xIDType.(string)

if success && xidType != "" && strings.Contains(xidType, "_") {
return strings.Split(xidType, "_")[0]
}

return ""
}

// GetXIDInterceptorType from RootContext get xid interceptor type
func (c *RootContext) GetXIDInterceptorType() string {
xIDType := c.localMap[KeyXIDInterceptorType]
xidType, _ := xIDType.(string)
return xidType
}

// Bind bind xid with RootContext
func (c *RootContext) Bind(xid string) {
log.Debugf("bind %s", xid)
c.Set(KeyXID, xid)
}

// BindInterceptorType bind interceptor type with RootContext
func (c *RootContext) BindInterceptorType(xidType string) {
if xidType != "" {
xidTypes := strings.Split(xidType, "_")

if len(xidTypes) == 2 {
c.BindInterceptorTypeWithBranchType(xidTypes[0],
apis.BranchSession_BranchType(apis.BranchSession_BranchType_value[xidTypes[1]]))
}
}
}

// BindInterceptorTypeWithBranchType bind interceptor type and branch type with RootContext
func (c *RootContext) BindInterceptorTypeWithBranchType(xid string, branchType apis.BranchSession_BranchType) {
xidType := fmt.Sprintf("%s_%s", xid, branchType.String())
log.Debugf("bind interceptor type xid=%s branchType=%s", xid, branchType.String())
c.Set(KeyXIDInterceptorType, xidType)
}

// BindGlobalLockFlag bind global lock flag with RootContext
func (c *RootContext) BindGlobalLockFlag() {
log.Debug("local transaction global lock support enabled")
c.Set(KeyGlobalLockFlag, KeyGlobalLockFlag)
}

// Unbind unbind xid with RootContext
func (c *RootContext) Unbind() string {
xID := c.localMap[KeyXID]
xid, ok := xID.(string)
if ok && xid != "" {
log.Debugf("unbind %s", xid)
delete(c.localMap, KeyXID)
return xid
}
return ""

}

// UnbindInterceptorType unbind interceptor type with RootContext
func (c *RootContext) UnbindInterceptorType() string {
xidType := c.localMap[KeyXIDInterceptorType]
xt, ok := xidType.(string)
if ok && xt != "" {
log.Debugf("unbind inteceptor type %s", xidType)
delete(c.localMap, KeyXIDInterceptorType)
return xt
}
return ""
}

// UnbindGlobalLockFlag unbind global lock flag with RootContext
func (c *RootContext) UnbindGlobalLockFlag() {
log.Debug("unbind global lock flag")
delete(c.localMap, KeyGlobalLockFlag)
}

// InGlobalTransaction determine whether the context is in global transaction
func (c *RootContext) InGlobalTransaction() bool {
return c.localMap[KeyXID] != nil
}

// RequireGlobalLock return global lock flag
func (c *RootContext) RequireGlobalLock() bool {
_, exists := c.localMap[KeyGlobalLockFlag]
return exists
}

+ 56
- 0
pkg/client/base/exception/transaction_exception.go View File

@@ -0,0 +1,56 @@
package exception

import (
"errors"

"github.com/opentrx/seata-golang/v2/pkg/apis"
)

// TransactionException
type TransactionException struct {
Code apis.ExceptionCode
Message string
Err error
}

// Error
func (e *TransactionException) Error() string {
return "TransactionException: " + e.Message
}

// Unwrap
func (e *TransactionException) Unwrap() error { return e.Err }

// TransactionExceptionOption for edit TransactionException
type TransactionExceptionOption func(exception *TransactionException)

// WithExceptionCode edit exception code in TransactionException
func WithExceptionCode(code apis.ExceptionCode) TransactionExceptionOption {
return func(exception *TransactionException) {
exception.Code = code
}
}

// WithMessage edit message in TransactionException
func WithMessage(message string) TransactionExceptionOption {
return func(exception *TransactionException) {
exception.Message = message
}
}

// NewTransactionException return a pointer to TransactionException
func NewTransactionException(err error, opts ...TransactionExceptionOption) *TransactionException {
var ex *TransactionException
if errors.As(err, &ex) {
return ex
}
ex = &TransactionException{
Code: apis.UnknownErr,
Message: err.Error(),
Err: err,
}
for _, o := range opts {
o(ex)
}
return ex
}

+ 12
- 0
pkg/client/base/model/resource.go View File

@@ -0,0 +1,12 @@
package model

import (
"github.com/opentrx/seata-golang/v2/pkg/apis"
)

// Resource used to manage transaction resource
type Resource interface {
GetResourceID() string

GetBranchType() apis.BranchSession_BranchType
}

+ 47
- 0
pkg/client/base/model/transaction_info.go View File

@@ -0,0 +1,47 @@
package model

import "fmt"

// Propagation transaction isolation level
type Propagation byte

const (
Required Propagation = iota

RequiresNew

NotSupported

Supports

Never

Mandatory
)

// String
func (t Propagation) String() string {
switch t {
case Required:
return "Required"
case RequiresNew:
return "REQUIRES_NEW"
case NotSupported:
return "NOT_SUPPORTED"
case Supports:
return "Supports"
case Never:
return "Never"
case Mandatory:
return "Mandatory"
default:
return fmt.Sprintf("%d", t)
}
}

// TransactionInfo used to configure global transaction parameters
type TransactionInfo struct {
TimeOut int32
Name string
Propagation Propagation
}

+ 27
- 95
pkg/client/client.go View File

@@ -1,107 +1,39 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package client package client


import ( import (
"sync"

"seata.apache.org/seata-go/pkg/datasource"
at "seata.apache.org/seata-go/pkg/datasource/sql"
"seata.apache.org/seata-go/pkg/datasource/sql/exec/config"
"seata.apache.org/seata-go/pkg/discovery"
"seata.apache.org/seata-go/pkg/integration"
remoteConfig "seata.apache.org/seata-go/pkg/remoting/config"
"seata.apache.org/seata-go/pkg/remoting/getty"
"seata.apache.org/seata-go/pkg/remoting/processor/client"
"seata.apache.org/seata-go/pkg/rm"
"seata.apache.org/seata-go/pkg/rm/tcc"
"seata.apache.org/seata-go/pkg/tm"
"seata.apache.org/seata-go/pkg/util/log"
)
"log"


// Init seata client client
func Init() {
InitPath("")
}
"google.golang.org/grpc"


// InitPath init client with config path
func InitPath(configFilePath string) {
cfg := LoadPath(configFilePath)
initRegistry(cfg)
initRmClient(cfg)
initTmClient(cfg)
initDatasource()
}

var (
onceInitTmClient sync.Once
onceInitRmClient sync.Once
onceInitDatasource sync.Once
onceInitRegistry sync.Once
"github.com/opentrx/seata-golang/v2/pkg/apis"
"github.com/opentrx/seata-golang/v2/pkg/client/config"
"github.com/opentrx/seata-golang/v2/pkg/client/rm"
"github.com/opentrx/seata-golang/v2/pkg/client/tcc"
"github.com/opentrx/seata-golang/v2/pkg/client/tm"
) )


// InitTmClient init client tm client
func initTmClient(cfg *Config) {
onceInitTmClient.Do(func() {
tm.InitTm(cfg.ClientConfig.TmConfig)
})
}

// initRemoting init remoting
func initRemoting(cfg *Config) {
seataConfig := remoteConfig.SeataConfig{
ApplicationID: cfg.ApplicationID,
TxServiceGroup: cfg.TxServiceGroup,
ServiceVgroupMapping: cfg.ServiceConfig.VgroupMapping,
ServiceGrouplist: cfg.ServiceConfig.Grouplist,
LoadBalanceType: cfg.GettyConfig.LoadBalanceType,
// Init init resource manager,init transaction manager, expose a port to listen tc
// call back request.
func Init(config *config.Configuration) {
var conn *grpc.ClientConn
var err error
if config.GetClientTLS() == nil {
conn, err = grpc.Dial(config.ServerAddressing,
grpc.WithInsecure(),
grpc.WithKeepaliveParams(config.GetClientParameters()))
} else {
conn, err = grpc.Dial(config.ServerAddressing,
grpc.WithKeepaliveParams(config.GetClientParameters()), grpc.WithTransportCredentials(config.GetClientTLS()))
} }


getty.InitGetty(&cfg.GettyConfig, &seataConfig)
}

// InitRmClient init client rm client
func initRmClient(cfg *Config) {
onceInitRmClient.Do(func() {
log.Init()
initRemoting(cfg)
rm.InitRm(rm.RmConfig{
Config: cfg.ClientConfig.RmConfig,
ApplicationID: cfg.ApplicationID,
TxServiceGroup: cfg.TxServiceGroup,
})
config.Init(cfg.ClientConfig.RmConfig.LockConfig)
client.RegisterProcessor()
integration.Init()
tcc.InitTCC(cfg.TCCConfig.FenceConfig)
at.InitAT(cfg.ClientConfig.UndoConfig, cfg.AsyncWorkerConfig)
at.InitXA(cfg.ClientConfig.XaConfig)
})
}
if err != nil {
log.Fatalf("did not connect: %v", err)
}


func initDatasource() {
onceInitDatasource.Do(func() {
datasource.Init()
})
}
resourceManagerClient := apis.NewResourceManagerServiceClient(conn)
transactionManagerClient := apis.NewTransactionManagerServiceClient(conn)


func initRegistry(cfg *Config) {
onceInitRegistry.Do(func() {
discovery.InitRegistry(&cfg.ServiceConfig, &cfg.RegistryConfig)
})
rm.InitResourceManager(config.Addressing, resourceManagerClient)
tm.InitTransactionManager(config.Addressing, transactionManagerClient)
rm.RegisterTransactionServiceServer(tcc.GetTCCResourceManager())
} }

+ 0
- 254
pkg/client/config.go View File

@@ -1,254 +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.
*/

package client

import (
"flag"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"

"github.com/knadh/koanf"
"github.com/knadh/koanf/parsers/json"
"github.com/knadh/koanf/parsers/toml"
"github.com/knadh/koanf/parsers/yaml"
"github.com/knadh/koanf/providers/rawbytes"

"seata.apache.org/seata-go/pkg/discovery"

"seata.apache.org/seata-go/pkg/datasource/sql"
"seata.apache.org/seata-go/pkg/datasource/sql/undo"
remoteConfig "seata.apache.org/seata-go/pkg/remoting/config"
"seata.apache.org/seata-go/pkg/rm"
"seata.apache.org/seata-go/pkg/rm/tcc"
"seata.apache.org/seata-go/pkg/tm"
"seata.apache.org/seata-go/pkg/util/flagext"
)

const (
configFileEnvKey = "SEATA_GO_CONFIG_PATH"
configPrefix = "seata"
)

const (
jsonSuffix = "json"
tomlSuffix = "toml"
yamlSuffix = "yaml"
ymlSuffix = "yml"
)

type ClientConfig struct {
TmConfig tm.TmConfig `yaml:"tm" json:"tm,omitempty" koanf:"tm"`
RmConfig rm.Config `yaml:"rm" json:"rm,omitempty" koanf:"rm"`
UndoConfig undo.Config `yaml:"undo" json:"undo,omitempty" koanf:"undo"`
XaConfig sql.XAConfig `yaml:"xa" json:"xa" koanf:"xa"`
}

func (c *ClientConfig) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) {
c.TmConfig.RegisterFlagsWithPrefix(prefix+".tm", f)
c.RmConfig.RegisterFlagsWithPrefix(prefix+".rm", f)
c.UndoConfig.RegisterFlagsWithPrefix(prefix+".undo", f)
c.XaConfig.RegisterFlagsWithPrefix(prefix+".xa", f)
}

type Config struct {
Enabled bool `yaml:"enabled" json:"enabled,omitempty" koanf:"enabled"`
ApplicationID string `yaml:"application-id" json:"application-id,omitempty" koanf:"application-id"`
TxServiceGroup string `yaml:"tx-service-group" json:"tx-service-group,omitempty" koanf:"tx-service-group"`
AccessKey string `yaml:"access-key" json:"access-key,omitempty" koanf:"access-key"`
SecretKey string `yaml:"secret-key" json:"secret-key,omitempty" koanf:"secret-key"`
EnableAutoDataSourceProxy bool `yaml:"enable-auto-data-source-proxy" json:"enable-auto-data-source-proxy,omitempty" koanf:"enable-auto-data-source-proxy"`
DataSourceProxyMode string `yaml:"data-source-proxy-mode" json:"data-source-proxy-mode,omitempty" koanf:"data-source-proxy-mode"`

AsyncWorkerConfig sql.AsyncWorkerConfig `yaml:"async" json:"async" koanf:"async"`
TCCConfig tcc.Config `yaml:"tcc" json:"tcc" koanf:"tcc"`
ClientConfig ClientConfig `yaml:"client" json:"client" koanf:"client"`
GettyConfig remoteConfig.Config `yaml:"getty" json:"getty" koanf:"getty"`
TransportConfig remoteConfig.TransportConfig `yaml:"transport" json:"transport" koanf:"transport"`
ServiceConfig discovery.ServiceConfig `yaml:"service" json:"service" koanf:"service"`
RegistryConfig discovery.RegistryConfig `yaml:"registry" json:"registry" koanf:"registry"`
}

func (c *Config) RegisterFlags(f *flag.FlagSet) {
f.BoolVar(&c.Enabled, "enabled", true, "Whether enable auto configuration.")
f.StringVar(&c.ApplicationID, "application-id", "seata-go", "Application id.")
f.StringVar(&c.TxServiceGroup, "tx-service-group", "default_tx_group", "Transaction service group.")
f.StringVar(&c.AccessKey, "access-key", "", "Used for aliyun accessKey.")
f.StringVar(&c.SecretKey, "secret-key", "", "Used for aliyun secretKey.")
f.BoolVar(&c.EnableAutoDataSourceProxy, "enable-auto-data-source-proxy", true, "Whether enable auto proxying of datasource bean.")
f.StringVar(&c.DataSourceProxyMode, "data-source-proxy-mode", "AT", "Data source proxy mode.")

c.AsyncWorkerConfig.RegisterFlagsWithPrefix("async-worker", f)
c.TCCConfig.RegisterFlagsWithPrefix("tcc", f)
c.ClientConfig.RegisterFlagsWithPrefix("client", f)
c.GettyConfig.RegisterFlagsWithPrefix("getty", f)
c.TransportConfig.RegisterFlagsWithPrefix("transport", f)
c.RegistryConfig.RegisterFlagsWithPrefix("registry", f)
c.ServiceConfig.RegisterFlagsWithPrefix("service", f)
}

type loaderConf struct {
suffix string // loaderConf file extension default yaml
path string // loaderConf file path default ./conf/seatago.yaml
delim string // loaderConf file delim default .
bytes []byte // config bytes
name string // config file name
}

// Load parse config from user config path
func LoadPath(configFilePath string) *Config {
if configFilePath == "" {
configFilePath = os.Getenv(configFileEnvKey)
if configFilePath == "" {
panic("system variable SEATA_GO_CONFIG_PATH is empty")
}
}

var cfg Config
// This sets default values from flags to the config.
// It needs to be called before parsing the config file!
flagext.RegisterFlags(&cfg)

conf := newLoaderConf(configFilePath)
koan := getConfigResolver(conf)
if err := koan.UnmarshalWithConf(configPrefix, &cfg, koanf.UnmarshalConf{Tag: yamlSuffix}); err != nil {
panic(err)
}
return &cfg
}

// Load parse config from json bytes
func LoadJson(bytes []byte) *Config {
var cfg Config
// This sets default values from flags to the config.
// It needs to be called before parsing the config file!
flagext.RegisterFlags(&cfg)

koan := getJsonConfigResolver(bytes)
if err := koan.Unmarshal("", &cfg); err != nil {
panic(err)
}
return &cfg
}

// getJsonConfigResolver get json config resolver
func getJsonConfigResolver(bytes []byte) *koanf.Koanf {
k := koanf.New(".")
if err := k.Load(rawbytes.Provider(bytes), json.Parser()); err != nil {
panic(err)
}
return k
}

// resolverFilePath resolver file path
// eg: give a ./conf/seatago.yaml return seatago and yaml
func resolverFilePath(path string) (name, suffix string) {
paths := strings.Split(path, "/")
fileName := strings.Split(paths[len(paths)-1], ".")
if len(fileName) < 2 {
return fileName[0], yamlSuffix
}
return fileName[0], fileName[1]
}

// getConfigResolver get config resolver
func getConfigResolver(conf *loaderConf) *koanf.Koanf {
var (
k *koanf.Koanf
err error
)
if len(conf.suffix) <= 0 {
conf.suffix = yamlSuffix
}
if len(conf.delim) <= 0 {
conf.delim = "."
}
bytes := conf.bytes
if len(bytes) <= 0 {
panic(fmt.Errorf("bytes is nil,please set bytes or file path"))
}
k = koanf.New(conf.delim)

switch conf.suffix {
case yamlSuffix, ymlSuffix:
err = k.Load(rawbytes.Provider(bytes), yaml.Parser())
case jsonSuffix:
err = k.Load(rawbytes.Provider(bytes), json.Parser())
case tomlSuffix:
err = k.Load(rawbytes.Provider(bytes), toml.Parser())
default:
err = fmt.Errorf("no support %s file suffix", conf.suffix)
}

if err != nil {
panic(err)
}
return k
}

func newLoaderConf(configFilePath string) *loaderConf {
name, suffix := resolverFilePath(configFilePath)
conf := &loaderConf{
suffix: suffix,
path: absolutePath(configFilePath),
delim: ".",
name: name,
}

if len(conf.bytes) <= 0 {
if bytes, err := ioutil.ReadFile(conf.path); err != nil {
panic(err)
} else {
conf.bytes = bytes
}
}
return conf
}

// absolutePath get absolut path
func absolutePath(inPath string) string {
if inPath == "$HOME" || strings.HasPrefix(inPath, "$HOME"+string(os.PathSeparator)) {
inPath = userHomeDir() + inPath[5:]
}

if filepath.IsAbs(inPath) {
return filepath.Clean(inPath)
}

p, err := filepath.Abs(inPath)
if err == nil {
return filepath.Clean(p)
}

return ""
}

// userHomeDir get gopath
func userHomeDir() string {
if runtime.GOOS == "windows" {
home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
if home == "" {
home = os.Getenv("USERPROFILE")
}
return home
}
return os.Getenv("HOME")
}

+ 151
- 0
pkg/client/config/configuration.go View File

@@ -0,0 +1,151 @@
package config

import (
"io"
"io/ioutil"
"os"
"time"

"google.golang.org/grpc/credentials"
"google.golang.org/grpc/keepalive"

"github.com/opentrx/seata-golang/v2/pkg/util/log"
"github.com/opentrx/seata-golang/v2/pkg/util/parser"
)

var configuration *Configuration

// Configuration client configuration
type Configuration struct {
Addressing string `yaml:"addressing" json:"addressing"`
ServerAddressing string `yaml:"serverAddressing" json:"serverAddressing"`

TMConfig TMConfig `yaml:"tm" json:"tm,omitempty"`

ATConfig ATConfig `yaml:"at" json:"at,omitempty"`

ClientParameters struct {
Time time.Duration `yaml:"time"`
Timeout time.Duration `yaml:"timeout"`
PermitWithoutStream bool `yaml:"permitWithoutStream"`
} `yaml:"clientParameters"`

ClientTLS struct {
Enable bool `yaml:"enable"`
CertFilePath string `yaml:"certFilePath"`
ServerName string `yaml:"serverName"`
} `yaml:"clientTLS"`

Log struct {
LogPath string `yaml:"logPath"`
LogLevel log.Level `yaml:"logLevel"`
} `yaml:"log"`
}

// TMConfig
type TMConfig struct {
CommitRetryCount int32 `default:"5" yaml:"commitRetryCount" json:"commitRetryCount,omitempty"`
RollbackRetryCount int32 `default:"5" yaml:"rollbackRetryCount" json:"rollbackRetryCount,omitempty"`
}

// ATConfig
type ATConfig struct {
DSN string `yaml:"dsn" json:"dsn,omitempty"`
ReportRetryCount int `default:"5" yaml:"reportRetryCount" json:"reportRetryCount,omitempty"`
ReportSuccessEnable bool `default:"false" yaml:"reportSuccessEnable" json:"reportSuccessEnable,omitempty"`
LockRetryInterval time.Duration `default:"10ms" yaml:"lockRetryInterval" json:"lockRetryInterval,omitempty"`
LockRetryTimes int `default:"30" yaml:"lockRetryTimes" json:"lockRetryTimes,omitempty"`
}

// GetTMConfig return TMConfig
func GetTMConfig() TMConfig {
return configuration.TMConfig
}

// GetATConfig return ATConfig
func GetATConfig() ATConfig {
return configuration.ATConfig
}

// GetClientParameters used to config grpc connection keep alive
func GetClientParameters() keepalive.ClientParameters {
return configuration.GetClientParameters()
}

// GetClientParameters used to config grpc connection keep alive
func (configuration *Configuration) GetClientParameters() keepalive.ClientParameters {
cp := keepalive.ClientParameters{
Time: 10 * time.Second,
Timeout: time.Second,
PermitWithoutStream: true,
}
if configuration.ClientParameters.Time > 0 {
cp.Time = configuration.ClientParameters.Timeout
}
if configuration.ClientParameters.Timeout > 0 {
cp.Timeout = configuration.ClientParameters.Timeout
}
cp.PermitWithoutStream = configuration.ClientParameters.PermitWithoutStream
return cp
}

func (configuration *Configuration) GetClientTLS() credentials.TransportCredentials {
if !configuration.ClientTLS.Enable {
return nil
}
cred, err := credentials.NewClientTLSFromFile(configuration.ClientTLS.CertFilePath, configuration.ClientTLS.ServerName)
if err != nil {
log.Fatalf("%v using TLS failed", err)
}
return cred
}

// Parse parses an input configuration yaml document into a Configuration struct
//
// Environment variables may be used to override configuration parameters other than version,
// following the scheme below:
// Configuration.Abc may be replaced by the value of SEATA_ABC,
// Configuration.Abc.Xyz may be replaced by the value of SEATA_ABC_XYZ, and so forth
func parse(rd io.Reader) (*Configuration, error) {
in, err := ioutil.ReadAll(rd)
if err != nil {
return nil, err
}

p := parser.NewParser("seata")

config := new(Configuration)
err = p.Parse(in, config)
if err != nil {
return nil, err
}

return config, nil
}

// InitConfiguration init configuration from a file path
func InitConfiguration(configurationPath string) *Configuration {
fp, err := os.Open(configurationPath)
if err != nil {
log.Fatalf("open configuration file fail, %v", err)
}

config, err := parse(fp)
if err != nil {
log.Fatalf("error parsing %s: %v", configurationPath, err)
}

defer func() {
err = fp.Close()
if err != nil {
log.Error(err)
}
}()

configuration = config
return configuration
}

func SetConfiguration(config *Configuration) {
configuration = config
}

+ 0
- 226
pkg/client/config_test.go View File

@@ -1,226 +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.
*/

package client

import (
"flag"
"os"
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestLoadPath(t *testing.T) {
cfg := LoadPath("../../testdata/conf/seatago.yml")
assert.NotNil(t, cfg)
assert.Equal(t, true, cfg.Enabled)
assert.Equal(t, "applicationName", cfg.ApplicationID)
assert.Equal(t, "default_tx_group", cfg.TxServiceGroup)
assert.Equal(t, "aliyunAccessKey", cfg.AccessKey)
assert.Equal(t, "aliyunSecretKey", cfg.SecretKey)
assert.Equal(t, true, cfg.EnableAutoDataSourceProxy)
assert.Equal(t, "AT", cfg.DataSourceProxyMode)

assert.NotNil(t, cfg.TCCConfig)
assert.NotNil(t, cfg.TCCConfig.FenceConfig)
assert.Equal(t, false, cfg.TCCConfig.FenceConfig.Enable)
assert.Equal(t, "root:12345678@tcp(127.0.0.1:3306)/seata_client1?charset=utf8&parseTime=True", cfg.TCCConfig.FenceConfig.Url)
assert.Equal(t, "tcc_fence_log_test", cfg.TCCConfig.FenceConfig.LogTableName)
assert.Equal(t, time.Second*60, cfg.TCCConfig.FenceConfig.CleanPeriod)

assert.NotNil(t, cfg.ClientConfig)
assert.NotNil(t, cfg.ClientConfig.TmConfig)
assert.Equal(t, 5, cfg.ClientConfig.TmConfig.CommitRetryCount)
assert.Equal(t, 5, cfg.ClientConfig.TmConfig.RollbackRetryCount)
assert.Equal(t, time.Second*60, cfg.ClientConfig.TmConfig.DefaultGlobalTransactionTimeout)
assert.Equal(t, false, cfg.ClientConfig.TmConfig.DegradeCheck)
assert.Equal(t, 2000, cfg.ClientConfig.TmConfig.DegradeCheckPeriod)
assert.Equal(t, time.Second*10, cfg.ClientConfig.TmConfig.DegradeCheckAllowTimes)
assert.Equal(t, -2147482648, cfg.ClientConfig.TmConfig.InterceptorOrder)

assert.Equal(t, 10000, cfg.ClientConfig.RmConfig.AsyncCommitBufferLimit)
assert.Equal(t, 5, cfg.ClientConfig.RmConfig.ReportRetryCount)
assert.Equal(t, false, cfg.ClientConfig.RmConfig.TableMetaCheckEnable)
assert.Equal(t, false, cfg.ClientConfig.RmConfig.ReportSuccessEnable)
assert.Equal(t, false, cfg.ClientConfig.RmConfig.SagaBranchRegisterEnable)
assert.Equal(t, "fastjson", cfg.ClientConfig.RmConfig.SagaJsonParser)
assert.Equal(t, false, cfg.ClientConfig.RmConfig.SagaCompensatePersistModeUpdate)
assert.Equal(t, false, cfg.ClientConfig.RmConfig.SagaRetryPersistModeUpdate)
assert.Equal(t, -2147482648, cfg.ClientConfig.RmConfig.TccActionInterceptorOrder)
assert.Equal(t, "druid", cfg.ClientConfig.RmConfig.SqlParserType)
assert.Equal(t, 30*time.Second, cfg.ClientConfig.RmConfig.LockConfig.RetryInterval)
assert.Equal(t, 10, cfg.ClientConfig.RmConfig.LockConfig.RetryTimes)
assert.Equal(t, true, cfg.ClientConfig.RmConfig.LockConfig.RetryPolicyBranchRollbackOnConflict)

assert.NotNil(t, cfg.ClientConfig.UndoConfig)
assert.Equal(t, true, cfg.ClientConfig.UndoConfig.DataValidation)
assert.Equal(t, "json", cfg.ClientConfig.UndoConfig.LogSerialization)
assert.Equal(t, "undo_log", cfg.ClientConfig.UndoConfig.LogTable)
assert.Equal(t, true, cfg.ClientConfig.UndoConfig.OnlyCareUpdateColumns)
assert.NotNil(t, cfg.ClientConfig.UndoConfig.CompressConfig)
assert.Equal(t, true, cfg.ClientConfig.UndoConfig.CompressConfig.Enable)
assert.Equal(t, "zip", cfg.ClientConfig.UndoConfig.CompressConfig.Type)
assert.Equal(t, "64k", cfg.ClientConfig.UndoConfig.CompressConfig.Threshold)

assert.NotNil(t, cfg.GettyConfig)
assert.NotNil(t, cfg.GettyConfig.SessionConfig)
assert.Equal(t, 0, cfg.GettyConfig.ReconnectInterval)
assert.Equal(t, 1, cfg.GettyConfig.ConnectionNum)
assert.Equal(t, false, cfg.GettyConfig.SessionConfig.CompressEncoding)
assert.Equal(t, true, cfg.GettyConfig.SessionConfig.TCPNoDelay)
assert.Equal(t, true, cfg.GettyConfig.SessionConfig.TCPKeepAlive)
assert.Equal(t, time.Minute*2, cfg.GettyConfig.SessionConfig.KeepAlivePeriod)
assert.Equal(t, 262144, cfg.GettyConfig.SessionConfig.TCPRBufSize)
assert.Equal(t, 65536, cfg.GettyConfig.SessionConfig.TCPWBufSize)
assert.Equal(t, time.Second, cfg.GettyConfig.SessionConfig.TCPReadTimeout)
assert.Equal(t, time.Second*5, cfg.GettyConfig.SessionConfig.TCPWriteTimeout)
assert.Equal(t, time.Second, cfg.GettyConfig.SessionConfig.WaitTimeout)
assert.Equal(t, 16498688, cfg.GettyConfig.SessionConfig.MaxMsgLen)
assert.Equal(t, "client_test", cfg.GettyConfig.SessionConfig.SessionName)
assert.Equal(t, time.Second, cfg.GettyConfig.SessionConfig.CronPeriod)

assert.NotNil(t, cfg.TransportConfig)
assert.NotNil(t, cfg.TransportConfig.ShutdownConfig)
assert.Equal(t, time.Second*3, cfg.TransportConfig.ShutdownConfig.Wait)
assert.Equal(t, "TCP", cfg.TransportConfig.Type)
assert.Equal(t, "NIO", cfg.TransportConfig.Server)
assert.Equal(t, true, cfg.TransportConfig.Heartbeat)
assert.Equal(t, "seata", cfg.TransportConfig.Serialization)
assert.Equal(t, "none", cfg.TransportConfig.Compressor)
assert.Equal(t, false, cfg.TransportConfig.EnableTmClientBatchSendRequest)
assert.Equal(t, true, cfg.TransportConfig.EnableRmClientBatchSendRequest)
assert.Equal(t, time.Second*30, cfg.TransportConfig.RPCRmRequestTimeout)
assert.Equal(t, time.Second*30, cfg.TransportConfig.RPCTmRequestTimeout)

assert.NotNil(t, cfg.ServiceConfig)
assert.Equal(t, false, cfg.ServiceConfig.EnableDegrade)
assert.Equal(t, false, cfg.ServiceConfig.DisableGlobalTransaction)
assert.Equal(t, "default", cfg.ServiceConfig.VgroupMapping["default_tx_group"])
assert.Equal(t, "127.0.0.1:8091", cfg.ServiceConfig.Grouplist["default"])

assert.NotNil(t, cfg.RegistryConfig)
assert.Equal(t, "file", cfg.RegistryConfig.Type)
assert.Equal(t, "seatago.yml", cfg.RegistryConfig.File.Name)
assert.Equal(t, "seata-server", cfg.RegistryConfig.Nacos.Application)
assert.Equal(t, "127.0.0.1:8848", cfg.RegistryConfig.Nacos.ServerAddr)
assert.Equal(t, "SEATA_GROUP", cfg.RegistryConfig.Nacos.Group)
assert.Equal(t, "test-namespace", cfg.RegistryConfig.Nacos.Namespace)
assert.Equal(t, "test-username", cfg.RegistryConfig.Nacos.Username)
assert.Equal(t, "test-password", cfg.RegistryConfig.Nacos.Password)
assert.Equal(t, "test-access-key", cfg.RegistryConfig.Nacos.AccessKey)
assert.Equal(t, "test-secret-key", cfg.RegistryConfig.Nacos.SecretKey)
assert.Equal(t, "default", cfg.RegistryConfig.Etcd3.Cluster)
assert.Equal(t, "http://localhost:2379", cfg.RegistryConfig.Etcd3.ServerAddr)

// reset flag.CommandLine
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
}

func TestLoadJson(t *testing.T) {
confJson := `{"enabled":false,"application-id":"application_test","tx-service-group":"default_tx_group","access-key":"test","secret-key":"test","enable-auto-data-source-proxy":false,"data-source-proxy-mode":"AT","client":{"rm":{"async-commit-buffer-limit":10000,"report-retry-count":5,"table-meta-check-enable":false,"report-success-enable":false,"saga-branch-register-enable":false,"saga-json-parser":"fastjson","saga-retry-persist-mode-update":false,"saga-compensate-persist-mode-update":false,"tcc-action-interceptor-order":-2147482648,"sql-parser-type":"druid","lock":{"retry-interval":"30s","retry-times":10,"retry-policy-branch-rollback-on-conflict":true}},"tm":{"commit-retry-count":5,"rollback-retry-count":5,"default-global-transaction-timeout":"60s","degrade-check":false,"degrade-check-period":2000,"degrade-check-allow-times":"10s","interceptor-order":-2147482648},"undo":{"data-validation":false,"log-serialization":"jackson222","only-care-update-columns":false,"log-table":"undo_log333","compress":{"enable":false,"type":"zip111","threshold":"128k"}}},"tcc":{"fence":{"enable":false,"url":"root:12345678@tcp(127.0.0.1:3306)/seata_client1?charset=utf8&parseTime=True","log-table-name":"tcc_fence_log_test2","clean-period":80000000000}},"getty":{"reconnect-interval":1,"connection-num":10,"session":{"compress-encoding":true,"tcp-no-delay":false,"tcp-keep-alive":false,"keep-alive-period":"120s","tcp-r-buf-size":261120,"tcp-w-buf-size":32768,"tcp-read-timeout":"2s","tcp-write-timeout":"8s","wait-timeout":"2s","max-msg-len":261120,"session-name":"client_test","cron-period":"2s"}},"transport":{"shutdown":{"wait":"3s"},"type":"TCP","server":"NIO","heartbeat":true,"serialization":"seata","compressor":"none"," enable-tm-client-batch-send-request":false,"enable-rm-client-batch-send-request":true,"rpc-rm-request-timeout":"30s","rpc-tm-request-timeout":"30s"},"service":{"enable-degrade":true,"disable-global-transaction":true,"vgroup-mapping":{"default_tx_group":"default_test"},"grouplist":{"default":"127.0.0.1:8092"}}}`
cfg := LoadJson([]byte(confJson))
assert.NotNil(t, cfg)
assert.Equal(t, false, cfg.Enabled)
assert.Equal(t, "application_test", cfg.ApplicationID)
assert.Equal(t, "default_tx_group", cfg.TxServiceGroup)
assert.Equal(t, "test", cfg.AccessKey)
assert.Equal(t, "test", cfg.SecretKey)
assert.Equal(t, false, cfg.EnableAutoDataSourceProxy)
assert.Equal(t, "AT", cfg.DataSourceProxyMode)

assert.Equal(t, 10000, cfg.ClientConfig.RmConfig.AsyncCommitBufferLimit)
assert.Equal(t, 5, cfg.ClientConfig.RmConfig.ReportRetryCount)
assert.Equal(t, false, cfg.ClientConfig.RmConfig.TableMetaCheckEnable)
assert.Equal(t, false, cfg.ClientConfig.RmConfig.ReportSuccessEnable)
assert.Equal(t, false, cfg.ClientConfig.RmConfig.SagaBranchRegisterEnable)
assert.Equal(t, "fastjson", cfg.ClientConfig.RmConfig.SagaJsonParser)
assert.Equal(t, false, cfg.ClientConfig.RmConfig.SagaCompensatePersistModeUpdate)
assert.Equal(t, false, cfg.ClientConfig.RmConfig.SagaRetryPersistModeUpdate)
assert.Equal(t, -2147482648, cfg.ClientConfig.RmConfig.TccActionInterceptorOrder)
assert.Equal(t, "druid", cfg.ClientConfig.RmConfig.SqlParserType)
assert.Equal(t, 30*time.Second, cfg.ClientConfig.RmConfig.LockConfig.RetryInterval)
assert.Equal(t, 10, cfg.ClientConfig.RmConfig.LockConfig.RetryTimes)
assert.Equal(t, true, cfg.ClientConfig.RmConfig.LockConfig.RetryPolicyBranchRollbackOnConflict)

assert.NotNil(t, cfg.ClientConfig.UndoConfig)
assert.Equal(t, false, cfg.ClientConfig.UndoConfig.DataValidation)
assert.Equal(t, "jackson222", cfg.ClientConfig.UndoConfig.LogSerialization)
assert.Equal(t, "undo_log333", cfg.ClientConfig.UndoConfig.LogTable)
assert.Equal(t, false, cfg.ClientConfig.UndoConfig.OnlyCareUpdateColumns)
assert.NotNil(t, cfg.ClientConfig.UndoConfig.CompressConfig)
assert.Equal(t, false, cfg.ClientConfig.UndoConfig.CompressConfig.Enable)
assert.Equal(t, "zip111", cfg.ClientConfig.UndoConfig.CompressConfig.Type)
assert.Equal(t, "128k", cfg.ClientConfig.UndoConfig.CompressConfig.Threshold)

assert.NotNil(t, cfg.TCCConfig)
assert.NotNil(t, cfg.TCCConfig.FenceConfig)
assert.Equal(t, false, cfg.TCCConfig.FenceConfig.Enable)
assert.Equal(t, "root:12345678@tcp(127.0.0.1:3306)/seata_client1?charset=utf8&parseTime=True", cfg.TCCConfig.FenceConfig.Url)
assert.Equal(t, "tcc_fence_log_test2", cfg.TCCConfig.FenceConfig.LogTableName)
assert.Equal(t, time.Second*80, cfg.TCCConfig.FenceConfig.CleanPeriod)

assert.NotNil(t, cfg.ClientConfig)
assert.NotNil(t, cfg.ClientConfig.TmConfig)
assert.Equal(t, 5, cfg.ClientConfig.TmConfig.CommitRetryCount)
assert.Equal(t, 5, cfg.ClientConfig.TmConfig.RollbackRetryCount)
assert.Equal(t, time.Second*60, cfg.ClientConfig.TmConfig.DefaultGlobalTransactionTimeout)
assert.Equal(t, false, cfg.ClientConfig.TmConfig.DegradeCheck)
assert.Equal(t, 2000, cfg.ClientConfig.TmConfig.DegradeCheckPeriod)
assert.Equal(t, time.Second*10, cfg.ClientConfig.TmConfig.DegradeCheckAllowTimes)
assert.Equal(t, -2147482648, cfg.ClientConfig.TmConfig.InterceptorOrder)

assert.NotNil(t, cfg.GettyConfig)
assert.NotNil(t, cfg.GettyConfig.SessionConfig)
assert.Equal(t, 1, cfg.GettyConfig.ReconnectInterval)
assert.Equal(t, 10, cfg.GettyConfig.ConnectionNum)
assert.Equal(t, true, cfg.GettyConfig.SessionConfig.CompressEncoding)
assert.Equal(t, false, cfg.GettyConfig.SessionConfig.TCPNoDelay)
assert.Equal(t, false, cfg.GettyConfig.SessionConfig.TCPKeepAlive)
assert.Equal(t, time.Minute*2, cfg.GettyConfig.SessionConfig.KeepAlivePeriod)
assert.Equal(t, 261120, cfg.GettyConfig.SessionConfig.TCPRBufSize)
assert.Equal(t, 32768, cfg.GettyConfig.SessionConfig.TCPWBufSize)
assert.Equal(t, time.Second*2, cfg.GettyConfig.SessionConfig.TCPReadTimeout)
assert.Equal(t, time.Second*8, cfg.GettyConfig.SessionConfig.TCPWriteTimeout)
assert.Equal(t, time.Second*2, cfg.GettyConfig.SessionConfig.WaitTimeout)
assert.Equal(t, 261120, cfg.GettyConfig.SessionConfig.MaxMsgLen)
assert.Equal(t, "client_test", cfg.GettyConfig.SessionConfig.SessionName)
assert.Equal(t, time.Second*2, cfg.GettyConfig.SessionConfig.CronPeriod)

assert.NotNil(t, cfg.TransportConfig)
assert.NotNil(t, cfg.TransportConfig.ShutdownConfig)
assert.Equal(t, time.Second*3, cfg.TransportConfig.ShutdownConfig.Wait)
assert.Equal(t, "TCP", cfg.TransportConfig.Type)
assert.Equal(t, "NIO", cfg.TransportConfig.Server)
assert.Equal(t, true, cfg.TransportConfig.Heartbeat)
assert.Equal(t, "seata", cfg.TransportConfig.Serialization)
assert.Equal(t, "none", cfg.TransportConfig.Compressor)
assert.Equal(t, false, cfg.TransportConfig.EnableTmClientBatchSendRequest)
assert.Equal(t, true, cfg.TransportConfig.EnableRmClientBatchSendRequest)
assert.Equal(t, time.Second*30, cfg.TransportConfig.RPCRmRequestTimeout)
assert.Equal(t, time.Second*30, cfg.TransportConfig.RPCTmRequestTimeout)

assert.NotNil(t, cfg.ServiceConfig)
assert.Equal(t, true, cfg.ServiceConfig.EnableDegrade)
assert.Equal(t, true, cfg.ServiceConfig.DisableGlobalTransaction)
assert.Equal(t, "default_test", cfg.ServiceConfig.VgroupMapping["default_tx_group"])
assert.Equal(t, "127.0.0.1:8092", cfg.ServiceConfig.Grouplist["default"])

// reset flag.CommandLine
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
}

+ 169
- 0
pkg/client/proxy/service.go View File

@@ -0,0 +1,169 @@
package proxy

import (
"context"
"reflect"
"sync"
"unicode"
"unicode/utf8"

ctx "github.com/opentrx/seata-golang/v2/pkg/client/base/context"
"github.com/opentrx/seata-golang/v2/pkg/util/log"
)

var (
// serviceDescriptorMap, string -> *ServiceDescriptor
serviceDescriptorMap = sync.Map{}
)

// MethodDescriptor
type MethodDescriptor struct {
Method reflect.Method
CallerValue reflect.Value
CtxType reflect.Type
ArgsType []reflect.Type
ArgsNum int
ReturnValuesType []reflect.Type
ReturnValuesNum int
}

// ServiceDescriptor
type ServiceDescriptor struct {
Name string
ReflectType reflect.Type
ReflectValue reflect.Value
Methods sync.Map // string -> *MethodDescriptor
}

// Register
func Register(service interface{}, methodName string) *MethodDescriptor {
serviceType := reflect.TypeOf(service)
serviceValue := reflect.ValueOf(service)
svcName := reflect.Indirect(serviceValue).Type().Name()

svcDesc, _ := serviceDescriptorMap.LoadOrStore(svcName, &ServiceDescriptor{
Name: svcName,
ReflectType: serviceType,
ReflectValue: serviceValue,
Methods: sync.Map{},
})
svcDescriptor := svcDesc.(*ServiceDescriptor)
methodDesc, methodExist := svcDescriptor.Methods.Load(methodName)
if methodExist {
methodDescriptor := methodDesc.(*MethodDescriptor)
return methodDescriptor
}

method, methodFounded := serviceType.MethodByName(methodName)
if methodFounded {
methodDescriptor := describeMethod(method)
if methodDescriptor != nil {
methodDescriptor.CallerValue = serviceValue
svcDescriptor.Methods.Store(methodName, methodDescriptor)
return methodDescriptor
}
}
return nil
}

// describeMethod
// might return nil when method is not exported or some other error
func describeMethod(method reflect.Method) *MethodDescriptor {
methodType := method.Type
methodName := method.Name
inNum := methodType.NumIn()
outNum := methodType.NumOut()

// Method must be exported.
if method.PkgPath != "" {
return nil
}

var (
ctxType reflect.Type
argsType, returnValuesType []reflect.Type
)

for index := 1; index < inNum; index++ {
if methodType.In(index).String() == "context.Context" {
ctxType = methodType.In(index)
}
argsType = append(argsType, methodType.In(index))
// need not be a pointer.
if !isExportedOrBuiltinType(methodType.In(index)) {
log.Errorf("argument type of method %q is not exported %v", methodName, methodType.In(index))
return nil
}
}

// returnValuesType
for num := 0; num < outNum; num++ {
returnValuesType = append(returnValuesType, methodType.Out(num))
}

return &MethodDescriptor{
Method: method,
CtxType: ctxType,
ArgsType: argsType,
ArgsNum: inNum,
ReturnValuesType: returnValuesType,
ReturnValuesNum: outNum,
}
}

// Is this an exported - upper case - name
func isExported(name string) bool {
s, _ := utf8.DecodeRuneInString(name)
return unicode.IsUpper(s)
}

// Is this type exported or a builtin?
func isExportedOrBuiltinType(t reflect.Type) bool {
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
// PkgPath will be non-empty even for an exported type,
// so we need to check the type name as well.
return isExported(t.Name()) || t.PkgPath() == ""
}

// Invoke
func Invoke(methodDesc *MethodDescriptor, ctx *ctx.RootContext, args []interface{}) []reflect.Value {

in := []reflect.Value{methodDesc.CallerValue}

for i := 0; i < len(args); i++ {
t := reflect.ValueOf(args[i])
if methodDesc.ArgsType[i].String() == "context.Context" {
t = SuiteContext(ctx, methodDesc)
}
if !t.IsValid() {
at := methodDesc.ArgsType[i]
if at.Kind() == reflect.Ptr {
at = at.Elem()
}
t = reflect.New(at)
}
in = append(in, t)
}

returnValues := methodDesc.Method.Func.Call(in)

return returnValues
}

func SuiteContext(ctx context.Context, methodDesc *MethodDescriptor) reflect.Value {
if contextValue := reflect.ValueOf(ctx); contextValue.IsValid() {
return contextValue
}
return reflect.Zero(methodDesc.CtxType)
}

func ReturnWithError(methodDesc *MethodDescriptor, err error) []reflect.Value {
var result = make([]reflect.Value, 0)
for i := 0; i < methodDesc.ReturnValuesNum-1; i++ {
result = append(result, reflect.Zero(methodDesc.ReturnValuesType[i]))
}
result = append(result, reflect.ValueOf(err))
return result
}

+ 221
- 0
pkg/client/proxy/service_test.go View File

@@ -0,0 +1,221 @@
package proxy

import (
"context"
"reflect"
"testing"

"github.com/opentrx/seata-golang/v2/pkg/client/base/model"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)

type Svc struct{}

var service = &Svc{}

type ProxyService struct {
*Svc
CreateSo func(ctx context.Context, rollback bool) error
}

var methodTransactionInfo = make(map[string]*model.TransactionInfo)

func (svc *ProxyService) GetMethodTransactionInfo(methodName string) *model.TransactionInfo {
return methodTransactionInfo[methodName]
}
func (svc *ProxyService) GetProxyService() interface{} {
return svc.Svc
}
func (svc *Svc) CreateSo(ctx context.Context, rollback bool) error {
return nil
}

var ProxySvc = &ProxyService{
Svc: service,
}

func TestRegister(t *testing.T) {
ps := ProxySvc.GetProxyService()
method, _ := reflect.TypeOf(ps).MethodByName("CreateSo")

tests := []struct {
name string
service interface{}
methodName string
expectedResult *MethodDescriptor
}{
{
name: "test register",
service: ps,
methodName: "CreateSo",
expectedResult: &MethodDescriptor{
ArgsNum: 3,
Method: reflect.Method{Name: "CreateSo"},
ReturnValuesNum: 1,
ReturnValuesType: []reflect.Type{
method.Type.Out(0),
},
ArgsType: []reflect.Type{
method.Type.In(1),
method.Type.In(2),
},
CtxType: method.Type.In(1),
CallerValue: reflect.ValueOf(ps),
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actualResult := Register(tt.service, tt.methodName)

assert.Equal(t, tt.expectedResult.ArgsNum, actualResult.ArgsNum)
assert.Equal(t, tt.expectedResult.Method.Name, actualResult.Method.Name)
assert.Equal(t, tt.expectedResult.ReturnValuesNum, actualResult.ReturnValuesNum)
assert.Equal(t, tt.expectedResult.ReturnValuesType, actualResult.ReturnValuesType)
})
}
}

func TestSuiteContext(t *testing.T) {
type key string
const aa key = "aa"
const bb key = "bb"

emptyContext := context.TODO()
validContext := context.WithValue(context.TODO(), aa, bb)

tests := []struct {
name string
methodDesc *MethodDescriptor
ctx context.Context
expectedResult reflect.Value
}{
{
name: "test suite valid context",
methodDesc: &MethodDescriptor{},
ctx: emptyContext,
expectedResult: reflect.ValueOf(emptyContext),
},
{
name: "test suite invalid context",
methodDesc: &MethodDescriptor{
CtxType: reflect.TypeOf(validContext),
},
ctx: nil,
expectedResult: reflect.Zero(reflect.TypeOf(validContext)),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actualResult := SuiteContext(tt.ctx, tt.methodDesc)

assert.Equal(t, tt.expectedResult, actualResult)
})
}
}

func TestReturnWithError(t *testing.T) {
testingErr := errors.New("testing err")

tests := []struct {
name string
methodDesc *MethodDescriptor
err error
expectedResult []reflect.Value
}{
{
name: "test return with error when methodDesc.ReturnValuesNum is 2",
methodDesc: &MethodDescriptor{
ReturnValuesNum: 2,
ReturnValuesType: []reflect.Type{
reflect.TypeOf("1"),
reflect.TypeOf(testingErr),
},
},
err: testingErr,
expectedResult: []reflect.Value{
reflect.Zero(reflect.TypeOf("1")),
reflect.ValueOf(testingErr),
},
},
{
name: "test return with error when methodDesc.ReturnValuesNum is 1",
methodDesc: &MethodDescriptor{
ReturnValuesNum: 1,
ReturnValuesType: []reflect.Type{
reflect.TypeOf(testingErr),
},
},
err: testingErr,
expectedResult: []reflect.Value{
reflect.ValueOf(testingErr),
},
},
{
name: "test return with error when methodDesc.ReturnValuesNum is 0",
methodDesc: &MethodDescriptor{
ReturnValuesNum: 0,
ReturnValuesType: []reflect.Type{},
},
err: testingErr,
expectedResult: []reflect.Value{
reflect.ValueOf(testingErr),
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actualResult := ReturnWithError(tt.methodDesc, tt.err)

for idx := range tt.expectedResult {
assert.Equal(t, tt.expectedResult[idx].Type(), actualResult[idx].Type())
}
})
}
}

func TestIsExportedOrBuiltinType(t *testing.T) {
type ExportedStruct struct {
Abb string
}
type notExportedStruct struct {
Cdd string
}
tests := []struct {
name string
typeOf reflect.Type
expectedResult bool
}{
{
name: "test type is exported and not builtin",
typeOf: reflect.TypeOf(ExportedStruct{
Abb: "testing",
}),
expectedResult: true,
},
{
name: "test type is not exported and not builtin",
typeOf: reflect.TypeOf(notExportedStruct{
Cdd: "testing",
}),
expectedResult: false,
},
{
name: "test type is builtin",
typeOf: reflect.TypeOf("Abb"), // string type
expectedResult: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actualResult := isExportedOrBuiltinType(tt.typeOf)

assert.Equal(t, tt.expectedResult, actualResult)
})
}
}

+ 257
- 0
pkg/client/rm/resource_manager.go View File

@@ -0,0 +1,257 @@
package rm

import (
"context"
"fmt"
"io"
"time"

"github.com/gogo/protobuf/types"
"github.com/opentrx/seata-golang/v2/pkg/apis"
"github.com/opentrx/seata-golang/v2/pkg/client/base/exception"
"github.com/opentrx/seata-golang/v2/pkg/client/base/model"
"github.com/opentrx/seata-golang/v2/pkg/util/log"
"github.com/opentrx/seata-golang/v2/pkg/util/runtime"
"google.golang.org/grpc/metadata"
)

var defaultResourceManager *ResourceManager

type ResourceManagerOutbound interface {
// BranchRegister register branch transaction.
BranchRegister(ctx context.Context, xid string, resourceID string, branchType apis.BranchSession_BranchType,
applicationData []byte, lockKeys string) (int64, error)

// BranchReport report branch transaction status.
BranchReport(ctx context.Context, xid string, branchID int64, branchType apis.BranchSession_BranchType,
status apis.BranchSession_BranchStatus, applicationData []byte) error

// LockQuery lock resource by lockKeys.
LockQuery(ctx context.Context, xid string, resourceID string, branchType apis.BranchSession_BranchType, lockKeys string) (bool, error)
}

type ResourceManagerInterface interface {
BranchCommit(ctx context.Context, request *apis.BranchCommitRequest) (*apis.BranchCommitResponse, error)

BranchRollback(ctx context.Context, request *apis.BranchRollbackRequest) (*apis.BranchRollbackResponse, error)

// RegisterResource Register a Resource to be managed by Resource Manager.
RegisterResource(resource model.Resource)

// UnregisterResource Unregister a Resource from the Resource Manager.
UnregisterResource(resource model.Resource)

// GetBranchType ...
GetBranchType() apis.BranchSession_BranchType
}

type ResourceManager struct {
addressing string
rpcClient apis.ResourceManagerServiceClient
managers map[apis.BranchSession_BranchType]ResourceManagerInterface
branchMessages chan *apis.BranchMessage
}

func InitResourceManager(addressing string, client apis.ResourceManagerServiceClient) {
defaultResourceManager = &ResourceManager{
addressing: addressing,
rpcClient: client,
managers: make(map[apis.BranchSession_BranchType]ResourceManagerInterface),
branchMessages: make(chan *apis.BranchMessage),
}
runtime.GoWithRecover(func() {
defaultResourceManager.branchCommunicate()
}, nil)
}

func RegisterTransactionServiceServer(rm ResourceManagerInterface) {
defaultResourceManager.managers[rm.GetBranchType()] = rm
}

func GetResourceManager() *ResourceManager {
return defaultResourceManager
}

func (manager *ResourceManager) branchCommunicate() {
for {
ctx := metadata.AppendToOutgoingContext(context.Background(), "addressing", manager.addressing)
stream, err := manager.rpcClient.BranchCommunicate(ctx)
if err != nil {
time.Sleep(time.Second)
continue
}

done := make(chan bool)
runtime.GoWithRecover(func() {
for {
select {
case _, ok := <-done:
if !ok {
return
}
case msg := <-manager.branchMessages:
err := stream.Send(msg)
if err != nil {
return
}
}
}
}, nil)

for {
msg, err := stream.Recv()
if err == io.EOF {
close(done)
break
}
if err != nil {
close(done)
break
}
switch msg.BranchMessageType {
case apis.TypeBranchCommit:
request := &apis.BranchCommitRequest{}
data := msg.GetMessage().GetValue()
err := request.Unmarshal(data)
if err != nil {
log.Error(err)
continue
}
response, err := manager.BranchCommit(context.Background(), request)
if err == nil {
content, err := types.MarshalAny(response)
if err == nil {
manager.branchMessages <- &apis.BranchMessage{
ID: msg.ID,
BranchMessageType: apis.TypeBranchCommitResult,
Message: content,
}
}
}
case apis.TypeBranchRollback:
request := &apis.BranchRollbackRequest{}
data := msg.GetMessage().GetValue()
err := request.Unmarshal(data)
if err != nil {
log.Error(err)
continue
}
response, err := manager.BranchRollback(context.Background(), request)
if err == nil {
content, err := types.MarshalAny(response)
if err == nil {
manager.branchMessages <- &apis.BranchMessage{
ID: msg.ID,
BranchMessageType: apis.TypeBranchRollBackResult,
Message: content,
}
}
}
}
}
err = stream.CloseSend()
if err != nil {
log.Error(err)
}
}
}

func (manager *ResourceManager) BranchRegister(ctx context.Context, xid string, resourceID string,
branchType apis.BranchSession_BranchType, applicationData []byte, lockKeys string, asyncCommit bool) (int64, error) {
request := &apis.BranchRegisterRequest{
Addressing: manager.addressing,
XID: xid,
ResourceID: resourceID,
LockKey: lockKeys,
BranchType: branchType,
ApplicationData: applicationData,
AsyncCommit: asyncCommit,
}
resp, err := manager.rpcClient.BranchRegister(ctx, request)
if err != nil {
return 0, err
}
if resp.ResultCode == apis.ResultCodeSuccess {
return resp.BranchID, nil
}
return 0, &exception.TransactionException{
Code: resp.GetExceptionCode(),
Message: resp.GetMessage(),
}
}

func (manager *ResourceManager) BranchReport(ctx context.Context, xid string, branchID int64,
branchType apis.BranchSession_BranchType, status apis.BranchSession_BranchStatus, applicationData []byte) error {
request := &apis.BranchReportRequest{
XID: xid,
BranchID: branchID,
BranchType: branchType,
BranchStatus: status,
ApplicationData: applicationData,
}
resp, err := manager.rpcClient.BranchReport(ctx, request)
if err != nil {
return err
}
if resp.ResultCode == apis.ResultCodeFailed {
return &exception.TransactionException{
Code: resp.GetExceptionCode(),
Message: resp.GetMessage(),
}
}
return nil
}

func (manager *ResourceManager) LockQuery(ctx context.Context, xid string, resourceID string, branchType apis.BranchSession_BranchType,
lockKeys string) (bool, error) {
request := &apis.GlobalLockQueryRequest{
XID: xid,
ResourceID: resourceID,
LockKey: lockKeys,
BranchType: branchType,
}

resp, err := manager.rpcClient.LockQuery(ctx, request)
if err != nil {
return false, err
}
if resp.ResultCode == apis.ResultCodeSuccess {
return resp.Lockable, nil
}
return false, &exception.TransactionException{
Code: resp.GetExceptionCode(),
Message: resp.GetMessage(),
}
}

func (manager ResourceManager) BranchCommit(ctx context.Context, request *apis.BranchCommitRequest) (*apis.BranchCommitResponse, error) {
rm, ok := manager.managers[request.BranchType]
if ok {
return rm.BranchCommit(ctx, request)
}
return &apis.BranchCommitResponse{
ResultCode: apis.ResultCodeFailed,
Message: fmt.Sprintf("there is no resource manager for %s", request.BranchType.String()),
}, nil
}

func (manager *ResourceManager) BranchRollback(ctx context.Context, request *apis.BranchRollbackRequest) (*apis.BranchRollbackResponse, error) {
rm, ok := manager.managers[request.BranchType]
if ok {
return rm.BranchRollback(ctx, request)
}
return &apis.BranchRollbackResponse{
ResultCode: apis.ResultCodeFailed,
Message: fmt.Sprintf("there is no resource manager for %s", request.BranchType.String()),
}, nil
}

func (manager *ResourceManager) RegisterResource(resource model.Resource) {
rm := manager.managers[resource.GetBranchType()]
rm.RegisterResource(resource)
}

func (manager *ResourceManager) UnregisterResource(resource model.Resource) {
rm := manager.managers[resource.GetBranchType()]
rm.UnregisterResource(resource)
}

+ 179
- 0
pkg/client/tcc/proxy.go View File

@@ -0,0 +1,179 @@
package tcc

import (
"encoding/json"
"reflect"

gxnet "github.com/dubbogo/gost/net"
"github.com/pkg/errors"

"github.com/opentrx/seata-golang/v2/pkg/apis"
ctx "github.com/opentrx/seata-golang/v2/pkg/client/base/context"
"github.com/opentrx/seata-golang/v2/pkg/client/proxy"
"github.com/opentrx/seata-golang/v2/pkg/client/rm"
"github.com/opentrx/seata-golang/v2/pkg/util/log"
"github.com/opentrx/seata-golang/v2/pkg/util/time"
)

var (
TccActionName = "TccActionName"

TryMethod = "Try"
ConfirmMethod = "Confirm"
CancelMethod = "Cancel"

ActionStartTime = "action-start-time"
ActionName = "actionName"
PrepareMethod = "sys::prepare"
CommitMethod = "sys::commit"
RollbackMethod = "sys::rollback"
HostName = "host-name"

TccMethodArguments = "arguments"
TccMethodResult = "result"

businessActionContextType = reflect.TypeOf(&ctx.BusinessActionContext{})
)

type TccService interface {
Try(ctx *ctx.BusinessActionContext, async bool) (bool, error)
Confirm(ctx *ctx.BusinessActionContext) bool
Cancel(ctx *ctx.BusinessActionContext) bool
}

type TccProxyService interface {
GetTccService() TccService
}

func ImplementTCC(v TccProxyService) {
valueOf := reflect.ValueOf(v)
log.Debugf("[implement] reflect.TypeOf: %s", valueOf.String())

valueOfElem := valueOf.Elem()
typeOf := valueOfElem.Type()

// check incoming interface, incoming interface's elem must be a struct.
if typeOf.Kind() != reflect.Struct {
log.Errorf("%s must be a struct ptr", valueOf.String())
return
}
proxyService := v.GetTccService()
makeCallProxy := func(methodDesc *proxy.MethodDescriptor, resource *TCCResource) func(in []reflect.Value) []reflect.Value {
return func(in []reflect.Value) []reflect.Value {
businessContextValue := in[0]
businessActionContext := businessContextValue.Interface().(*ctx.BusinessActionContext)
rootContext := businessActionContext.RootContext
businessActionContext.XID = rootContext.GetXID()
businessActionContext.ActionName = resource.ActionName
if !rootContext.InGlobalTransaction() {
args := make([]interface{}, 0)
args = append(args, businessActionContext)
return proxy.Invoke(methodDesc, nil, args)
}

returnValues, err := proceed(methodDesc, businessActionContext, resource)
if err != nil {
return proxy.ReturnWithError(methodDesc, errors.WithStack(err))
}
return returnValues
}
}

numField := valueOfElem.NumField()
for i := 0; i < numField; i++ {
t := typeOf.Field(i)
methodName := t.Name
f := valueOfElem.Field(i)
if f.Kind() == reflect.Func && f.IsValid() && f.CanSet() && methodName == TryMethod {
if t.Type.NumIn() != 1 && t.Type.In(0) != businessActionContextType {
panic("prepare method argument is not BusinessActionContext")
}

actionName := t.Tag.Get(TccActionName)
if actionName == "" {
panic("must tag TccActionName")
}

commitMethodDesc := proxy.Register(proxyService, ConfirmMethod)
cancelMethodDesc := proxy.Register(proxyService, CancelMethod)
tryMethodDesc := proxy.Register(proxyService, methodName)

tccResource := &TCCResource{
ActionName: actionName,
PrepareMethodName: TryMethod,
CommitMethodName: ConfirmMethod,
CommitMethod: commitMethodDesc,
RollbackMethodName: CancelMethod,
RollbackMethod: cancelMethodDesc,
}

tccResourceManager.RegisterResource(tccResource)

// do method proxy here:
f.Set(reflect.MakeFunc(f.Type(), makeCallProxy(tryMethodDesc, tccResource)))
log.Debugf("set method [%s]", methodName)
}
}
}

func proceed(methodDesc *proxy.MethodDescriptor, ctx *ctx.BusinessActionContext, resource *TCCResource) ([]reflect.Value, error) {
var (
args = make([]interface{}, 0)
)

branchID, err := doTccActionLogStore(ctx, resource)
if err != nil {
return nil, errors.WithStack(err)
}
ctx.BranchID = branchID

args = append(args, ctx)
returnValues := proxy.Invoke(methodDesc, nil, args)
errValue := returnValues[len(returnValues)-1]
if errValue.IsValid() && !errValue.IsNil() {
err := rm.GetResourceManager().BranchReport(ctx.RootContext, ctx.XID, branchID, apis.TCC, apis.PhaseOneFailed, nil)
if err != nil {
log.Errorf("branch report err: %v", err)
}
}

return returnValues, nil
}

func doTccActionLogStore(ctx *ctx.BusinessActionContext, resource *TCCResource) (int64, error) {
ctx.ActionContext[ActionStartTime] = time.CurrentTimeMillis()
ctx.ActionContext[PrepareMethod] = resource.PrepareMethodName
ctx.ActionContext[CommitMethod] = resource.CommitMethodName
ctx.ActionContext[RollbackMethod] = resource.RollbackMethodName
ctx.ActionContext[ActionName] = ctx.ActionName
ip, err := gxnet.GetLocalIP()
if err == nil {
ctx.ActionContext[HostName] = ip
} else {
log.Warn("getLocalIP error")
}

applicationContext := make(map[string]interface{})
applicationContext[TccActionContext] = ctx.ActionContext

applicationData, err := json.Marshal(applicationContext)
if err != nil {
log.Errorf("marshal applicationContext failed:%v", applicationContext)
return 0, err
}

branchID, err := rm.GetResourceManager().BranchRegister(
ctx.RootContext,
ctx.XID,
resource.GetResourceID(),
resource.GetBranchType(),
applicationData,
"",
ctx.AsyncCommit,
)
if err != nil {
log.Errorf("TCC branch Register error, xid: %s", ctx.XID)
return 0, errors.WithStack(err)
}
return branchID, nil
}

+ 23
- 0
pkg/client/tcc/tcc_resource.go View File

@@ -0,0 +1,23 @@
package tcc

import (
"github.com/opentrx/seata-golang/v2/pkg/apis"
"github.com/opentrx/seata-golang/v2/pkg/client/proxy"
)

type TCCResource struct {
ActionName string
PrepareMethodName string
CommitMethodName string
CommitMethod *proxy.MethodDescriptor
RollbackMethodName string
RollbackMethod *proxy.MethodDescriptor
}

func (resource *TCCResource) GetResourceID() string {
return resource.ActionName
}

func (resource *TCCResource) GetBranchType() apis.BranchSession_BranchType {
return apis.TCC
}

+ 153
- 0
pkg/client/tcc/tcc_resource_manager.go View File

@@ -0,0 +1,153 @@
package tcc

import (
"context"
"encoding/json"
"fmt"

"github.com/opentrx/seata-golang/v2/pkg/apis"
ctx "github.com/opentrx/seata-golang/v2/pkg/client/base/context"
"github.com/opentrx/seata-golang/v2/pkg/client/base/model"
"github.com/opentrx/seata-golang/v2/pkg/client/proxy"
"github.com/opentrx/seata-golang/v2/pkg/util/log"
)

var (
TccActionContext = "actionContext"
)

var tccResourceManager TCCResourceManager

type TCCResourceManager struct {
ResourceCache map[string]model.Resource
}

func init() {
tccResourceManager = TCCResourceManager{ResourceCache: make(map[string]model.Resource)}
}

func GetTCCResourceManager() TCCResourceManager {
return tccResourceManager
}

func (resourceManager TCCResourceManager) BranchCommit(ctx context.Context, request *apis.BranchCommitRequest) (*apis.BranchCommitResponse, error) {
resource := resourceManager.ResourceCache[request.ResourceID]
if resource == nil {
log.Errorf("TCC resource is not exist, resourceID: %s", request.ResourceID)
return &apis.BranchCommitResponse{
ResultCode: apis.ResultCodeFailed,
Message: fmt.Sprintf("TCC resource is not exist, resourceID: %s", request.ResourceID),
}, nil
}
tccResource := resource.(*TCCResource)
if tccResource.CommitMethod == nil {
log.Errorf("TCC resource is not available, resourceID: %s", request.ResourceID)
return &apis.BranchCommitResponse{
ResultCode: apis.ResultCodeFailed,
Message: fmt.Sprintf("TCC resource is not available, resourceID: %s", request.ResourceID),
}, nil
}

result := false
businessActionContext := getBusinessActionContext(request.XID, request.BranchID, request.ResourceID, request.ApplicationData)
args := make([]interface{}, 0)
args = append(args, businessActionContext)
returnValues := proxy.Invoke(tccResource.CommitMethod, nil, args)
log.Debugf("TCC resource commit result : %v, xid: %s, branchID: %d, resourceID: %s", returnValues, request.XID, request.BranchID, request.ResourceID)
if len(returnValues) == 1 {
result = returnValues[0].Interface().(bool)
}
if result {
return &apis.BranchCommitResponse{
ResultCode: apis.ResultCodeSuccess,
XID: request.XID,
BranchID: request.BranchID,
BranchStatus: apis.PhaseTwoCommitted,
}, nil
}
return &apis.BranchCommitResponse{
ResultCode: apis.ResultCodeSuccess,
XID: request.XID,
BranchID: request.BranchID,
BranchStatus: apis.PhaseTwoCommitFailedRetryable,
}, nil
}

func (resourceManager TCCResourceManager) BranchRollback(ctx context.Context, request *apis.BranchRollbackRequest) (*apis.BranchRollbackResponse, error) {
resource := resourceManager.ResourceCache[request.ResourceID]
if resource == nil {
return &apis.BranchRollbackResponse{
ResultCode: apis.ResultCodeFailed,
Message: fmt.Sprintf("TCC resource is not exist, resourceID: %s", request.ResourceID),
}, nil
}
tccResource := resource.(*TCCResource)
if tccResource.RollbackMethod == nil {
return &apis.BranchRollbackResponse{
ResultCode: apis.ResultCodeFailed,
Message: fmt.Sprintf("TCC resource is not available, resourceID: %s", request.ResourceID),
}, nil
}

result := false
businessActionContext := getBusinessActionContext(request.XID, request.BranchID, request.ResourceID, request.ApplicationData)
args := make([]interface{}, 0)
args = append(args, businessActionContext)
returnValues := proxy.Invoke(tccResource.RollbackMethod, nil, args)
log.Debugf("TCC resource rollback result : %v, xid: %s, branchID: %d, resourceID: %s", returnValues, request.XID, request.BranchID, request.ResourceID)
if len(returnValues) == 1 {
result = returnValues[0].Interface().(bool)
}
if result {
return &apis.BranchRollbackResponse{
ResultCode: apis.ResultCodeSuccess,
XID: request.XID,
BranchID: request.BranchID,
BranchStatus: apis.PhaseTwoRolledBack,
}, nil
}
return &apis.BranchRollbackResponse{
ResultCode: apis.ResultCodeSuccess,
XID: request.XID,
BranchID: request.BranchID,
BranchStatus: apis.PhaseTwoRollbackFailedRetryable,
}, nil
}

func getBusinessActionContext(xid string, branchID int64, resourceID string, applicationData []byte) *ctx.BusinessActionContext {
var (
tccContext = make(map[string]interface{})
actionContextMap = make(map[string]interface{})
)
if len(applicationData) > 0 {
err := json.Unmarshal(applicationData, &tccContext)
if err != nil {
log.Errorf("getBusinessActionContext, unmarshal applicationData err=%v", err)
}
}

acMap := tccContext[TccActionContext]
if acMap != nil {
actionContextMap = acMap.(map[string]interface{})
}

businessActionContext := &ctx.BusinessActionContext{
XID: xid,
BranchID: branchID,
ActionName: resourceID,
ActionContext: actionContextMap,
}
return businessActionContext
}

func (resourceManager TCCResourceManager) RegisterResource(resource model.Resource) {
resourceManager.ResourceCache[resource.GetResourceID()] = resource
}

func (resourceManager TCCResourceManager) UnregisterResource(resource model.Resource) {
delete(resourceManager.ResourceCache, resource.GetResourceID())
}

func (resourceManager TCCResourceManager) GetBranchType() apis.BranchSession_BranchType {
return apis.TCC
}

+ 261
- 0
pkg/client/tm/global_transaction.go View File

@@ -0,0 +1,261 @@
package tm

import (
"fmt"

"github.com/pkg/errors"

"github.com/opentrx/seata-golang/v2/pkg/apis"
ctx "github.com/opentrx/seata-golang/v2/pkg/client/base/context"
"github.com/opentrx/seata-golang/v2/pkg/client/config"
"github.com/opentrx/seata-golang/v2/pkg/util/log"
)

const (
DefaultGlobalTxTimeout = 60000
DefaultGlobalTxName = "default"
)

type SuspendedResourcesHolder struct {
Xid string
}

type GlobalTransaction interface {
Begin(ctx *ctx.RootContext) error
BeginWithTimeout(timeout int32, ctx *ctx.RootContext) error
BeginWithTimeoutAndName(timeout int32, name string, ctx *ctx.RootContext) error
Commit(ctx *ctx.RootContext) error
Rollback(ctx *ctx.RootContext) error
Suspend(unbindXid bool, ctx *ctx.RootContext) (*SuspendedResourcesHolder, error)
Resume(suspendedResourcesHolder *SuspendedResourcesHolder, ctx *ctx.RootContext) error
GetStatus(ctx *ctx.RootContext) (apis.GlobalSession_GlobalStatus, error)
GetXid(ctx *ctx.RootContext) string
GlobalReport(globalStatus apis.GlobalSession_GlobalStatus, ctx *ctx.RootContext) error
GetLocalStatus() apis.GlobalSession_GlobalStatus
}

type GlobalTransactionRole byte

const (
// The Launcher. The one begins the current global transaction.
Launcher GlobalTransactionRole = iota

// The Participant. The one just joins into a existing global transaction.
Participant
)

func (role GlobalTransactionRole) String() string {
switch role {
case Launcher:
return "Launcher"
case Participant:
return "Participant"
default:
return fmt.Sprintf("%d", role)
}
}

type DefaultGlobalTransaction struct {
conf config.TMConfig
XID string
Status apis.GlobalSession_GlobalStatus
Role GlobalTransactionRole
transactionManager TransactionManagerInterface
}

func (gtx *DefaultGlobalTransaction) Begin(ctx *ctx.RootContext) error {
return gtx.BeginWithTimeout(DefaultGlobalTxTimeout, ctx)
}

func (gtx *DefaultGlobalTransaction) BeginWithTimeout(timeout int32, ctx *ctx.RootContext) error {
return gtx.BeginWithTimeoutAndName(timeout, DefaultGlobalTxName, ctx)
}

func (gtx *DefaultGlobalTransaction) BeginWithTimeoutAndName(timeout int32, name string, ctx *ctx.RootContext) error {
if gtx.Role != Launcher {
if gtx.XID == "" {
return errors.New("xid should not be empty")
}
log.Debugf("Ignore Begin(): just involved in global transaction [%s]", gtx.XID)
return nil
}
if gtx.XID != "" {
return errors.New("xid should be empty")
}
if ctx.InGlobalTransaction() {
return errors.New("xid should be empty")
}
xid, err := gtx.transactionManager.Begin(ctx, name, timeout)
if err != nil {
return errors.WithStack(err)
}
gtx.XID = xid
gtx.Status = apis.Begin
ctx.Bind(xid)
log.Infof("begin new global transaction [%s]", xid)
return nil
}

func (gtx *DefaultGlobalTransaction) Commit(ctx *ctx.RootContext) error {
defer func() {
ctxXid := ctx.GetXID()
if ctxXid != "" && gtx.XID == ctxXid {
ctx.Unbind()
}
}()
if gtx.Role == Participant {
log.Debugf("ignore Commit(): just involved in global transaction [%s]", gtx.XID)
return nil
}
if gtx.XID == "" {
return errors.New("xid should not be empty")
}
retry := gtx.conf.CommitRetryCount
for retry > 0 {
status, err := gtx.transactionManager.Commit(ctx, gtx.XID)
if err != nil {
log.Errorf("failed to report global commit [%s],Retry Countdown: %d, reason: %s", gtx.XID, retry, err.Error())
} else {
gtx.Status = status
break
}
retry--
if retry == 0 {
return errors.New("Failed to report global commit")
}
}
log.Infof("[%s] commit status: %s", gtx.XID, gtx.Status.String())
return nil
}

func (gtx *DefaultGlobalTransaction) Rollback(ctx *ctx.RootContext) error {
defer func() {
ctxXid := ctx.GetXID()
if ctxXid != "" && gtx.XID == ctxXid {
ctx.Unbind()
}
}()
if gtx.Role == Participant {
log.Debugf("ignore Rollback(): just involved in global transaction [%s]", gtx.XID)
return nil
}
if gtx.XID == "" {
return errors.New("xid should not be empty")
}
retry := gtx.conf.RollbackRetryCount
for retry > 0 {
status, err := gtx.transactionManager.Rollback(ctx, gtx.XID)
if err != nil {
log.Errorf("failed to report global rollback [%s],Retry Countdown: %d, reason: %s", gtx.XID, retry, err.Error())
} else {
gtx.Status = status
break
}
retry--
if retry == 0 {
return errors.New("Failed to report global rollback")
}
}
log.Infof("[%s] rollback status: %s", gtx.XID, gtx.Status.String())
return nil
}

func (gtx *DefaultGlobalTransaction) Suspend(unbindXid bool, ctx *ctx.RootContext) (*SuspendedResourcesHolder, error) {
xid := ctx.GetXID()
if xid != "" && unbindXid {
ctx.Unbind()
log.Debugf("suspending current transaction,xid = %s", xid)
}
return &SuspendedResourcesHolder{Xid: xid}, nil
}

func (gtx *DefaultGlobalTransaction) Resume(suspendedResourcesHolder *SuspendedResourcesHolder, ctx *ctx.RootContext) error {
if suspendedResourcesHolder == nil {
return nil
}
xid := suspendedResourcesHolder.Xid
if xid != "" {
ctx.Bind(xid)
log.Debugf("resuming the transaction,xid = %s", xid)
}
return nil
}

func (gtx *DefaultGlobalTransaction) GetStatus(ctx *ctx.RootContext) (apis.GlobalSession_GlobalStatus, error) {
if gtx.XID == "" {
return apis.UnknownGlobalStatus, nil
}
status, err := gtx.transactionManager.GetStatus(ctx, gtx.XID)
if err != nil {
return 0, errors.WithStack(err)
}

gtx.Status = status
return gtx.Status, nil
}

func (gtx *DefaultGlobalTransaction) GetXid(ctx *ctx.RootContext) string {
return gtx.XID
}

func (gtx *DefaultGlobalTransaction) GlobalReport(globalStatus apis.GlobalSession_GlobalStatus, ctx *ctx.RootContext) error {
defer func() {
ctxXid := ctx.GetXID()
if ctxXid != "" && gtx.XID == ctxXid {
ctx.Unbind()
}
}()

if gtx.XID == "" {
return errors.New("xid should not be empty")
}

if globalStatus == 0 {
return errors.New("globalStatus should not be zero")
}

status, err := gtx.transactionManager.GlobalReport(ctx, gtx.XID, globalStatus)
if err != nil {
return errors.WithStack(err)
}

gtx.Status = status
log.Infof("[%s] report status: %s", gtx.XID, gtx.Status.String())
return nil
}

func (gtx *DefaultGlobalTransaction) GetLocalStatus() apis.GlobalSession_GlobalStatus {
return gtx.Status
}

func CreateNew() *DefaultGlobalTransaction {
return &DefaultGlobalTransaction{
conf: config.GetTMConfig(),
XID: "",
Status: apis.UnknownGlobalStatus,
Role: Launcher,
transactionManager: defaultTransactionManager,
}
}

func GetCurrent(ctx *ctx.RootContext) *DefaultGlobalTransaction {
xid := ctx.GetXID()
if xid == "" {
return nil
}
return &DefaultGlobalTransaction{
conf: config.GetTMConfig(),
XID: xid,
Status: apis.Begin,
Role: Participant,
transactionManager: defaultTransactionManager,
}
}

func GetCurrentOrCreate(ctx *ctx.RootContext) *DefaultGlobalTransaction {
tx := GetCurrent(ctx)
if tx == nil {
return CreateNew()
}
return tx
}

+ 151
- 0
pkg/client/tm/proxy.go View File

@@ -0,0 +1,151 @@
package tm

import (
"context"
"reflect"

"github.com/pkg/errors"

ctx "github.com/opentrx/seata-golang/v2/pkg/client/base/context"
"github.com/opentrx/seata-golang/v2/pkg/client/base/model"
"github.com/opentrx/seata-golang/v2/pkg/client/proxy"
"github.com/opentrx/seata-golang/v2/pkg/util/log"
)

type GlobalTransactionProxyService interface {
GetProxyService() interface{}
GetMethodTransactionInfo(methodName string) *model.TransactionInfo
}

var (
typError = reflect.Zero(reflect.TypeOf((*error)(nil)).Elem()).Type()
)

func Implement(v GlobalTransactionProxyService) {
valueOf := reflect.ValueOf(v)
log.Debugf("[implement] reflect.TypeOf: %s", valueOf.String())

valueOfElem := valueOf.Elem()
typeOf := valueOfElem.Type()

// check incoming interface, incoming interface's elem must be a struct.
if typeOf.Kind() != reflect.Struct {
log.Errorf("%s must be a struct ptr", valueOf.String())
return
}
proxyService := v.GetProxyService()

makeCallProxy := func(methodDesc *proxy.MethodDescriptor, txInfo *model.TransactionInfo) func(in []reflect.Value) []reflect.Value {
return func(in []reflect.Value) []reflect.Value {
var (
args []interface{}
returnValues []reflect.Value
suspendedResourcesHolder *SuspendedResourcesHolder
)

if txInfo == nil {
// testing phase, this problem should be resolved
panic(errors.New("transactionInfo does not exist"))
}

inNum := len(in)
if inNum+1 != methodDesc.ArgsNum {
// testing phase, this problem should be resolved
panic(errors.New("args does not match"))
}

invCtx := ctx.NewRootContext(context.Background())
for i := 0; i < inNum; i++ {
if in[i].Type().String() == "context.Context" {
if !in[i].IsNil() {
// the user declared context as method's parameter
invCtx = ctx.NewRootContext(in[i].Interface().(context.Context))
}
}
args = append(args, in[i].Interface())
}

tx := GetCurrentOrCreate(invCtx)
defer func() {
err := tx.Resume(suspendedResourcesHolder, invCtx)
if err != nil {
log.Error(err)
}
}()

switch txInfo.Propagation {
case model.Required:
case model.RequiresNew:
suspendedResourcesHolder, _ = tx.Suspend(true, invCtx)
case model.NotSupported:
suspendedResourcesHolder, _ = tx.Suspend(true, invCtx)
returnValues = proxy.Invoke(methodDesc, invCtx, args)
return returnValues
case model.Supports:
if !invCtx.InGlobalTransaction() {
returnValues = proxy.Invoke(methodDesc, invCtx, args)
return returnValues
}
case model.Never:
if invCtx.InGlobalTransaction() {
return proxy.ReturnWithError(methodDesc, errors.Errorf("Existing transaction found for transaction marked with propagation 'never',xid = %s", invCtx.GetXID()))
}
returnValues = proxy.Invoke(methodDesc, invCtx, args)
return returnValues
case model.Mandatory:
if !invCtx.InGlobalTransaction() {
return proxy.ReturnWithError(methodDesc, errors.New("No existing transaction found for transaction marked with propagation 'mandatory'"))
}
default:
return proxy.ReturnWithError(methodDesc, errors.Errorf("Not Supported Propagation: %s", txInfo.Propagation.String()))
}

beginErr := tx.BeginWithTimeoutAndName(txInfo.TimeOut, txInfo.Name, invCtx)
if beginErr != nil {
return proxy.ReturnWithError(methodDesc, errors.WithStack(beginErr))
}

returnValues = proxy.Invoke(methodDesc, invCtx, args)

errValue := returnValues[len(returnValues)-1]

// todo 只要出错就回滚,未来可以优化一下,某些错误才回滚,某些错误的情况下,可以提交
if errValue.IsValid() && !errValue.IsNil() {
rollbackErr := tx.Rollback(invCtx)
if rollbackErr != nil {
return proxy.ReturnWithError(methodDesc, errors.WithStack(rollbackErr))
}
return returnValues
}

commitErr := tx.Commit(invCtx)
if commitErr != nil {
return proxy.ReturnWithError(methodDesc, errors.WithStack(commitErr))
}

return returnValues
}
}

numField := valueOfElem.NumField()
for i := 0; i < numField; i++ {
t := typeOf.Field(i)
methodName := t.Name
f := valueOfElem.Field(i)
if f.Kind() == reflect.Func && f.IsValid() && f.CanSet() {
outNum := t.Type.NumOut()

// The latest return type of the method must be error.
if returnType := t.Type.Out(outNum - 1); returnType != typError {
log.Warnf("the latest return type %s of method %q is not error", returnType, t.Name)
continue
}

methodDescriptor := proxy.Register(proxyService, methodName)

// do method proxy here:
f.Set(reflect.MakeFunc(f.Type(), makeCallProxy(methodDescriptor, v.GetMethodTransactionInfo(methodName))))
log.Debugf("set method [%s]", methodName)
}
}
}

+ 125
- 0
pkg/client/tm/transaction_manager.go View File

@@ -0,0 +1,125 @@
package tm

import (
"context"

"github.com/opentrx/seata-golang/v2/pkg/apis"
"github.com/opentrx/seata-golang/v2/pkg/client/base/exception"
)

var defaultTransactionManager *TransactionManager

type TransactionManagerInterface interface {
// GlobalStatus_Begin a new global transaction.
Begin(ctx context.Context, name string, timeout int32) (string, error)

// Global commit.
Commit(ctx context.Context, xid string) (apis.GlobalSession_GlobalStatus, error)

// Global rollback.
Rollback(ctx context.Context, xid string) (apis.GlobalSession_GlobalStatus, error)

// Get current status of the give transaction.
GetStatus(ctx context.Context, xid string) (apis.GlobalSession_GlobalStatus, error)

// Global report.
GlobalReport(ctx context.Context, xid string, globalStatus apis.GlobalSession_GlobalStatus) (apis.GlobalSession_GlobalStatus, error)
}

type TransactionManager struct {
addressing string
rpcClient apis.TransactionManagerServiceClient
}

func InitTransactionManager(addressing string, client apis.TransactionManagerServiceClient) {
defaultTransactionManager = &TransactionManager{
addressing: addressing,
rpcClient: client,
}
}

func GetTransactionManager() *TransactionManager {
return defaultTransactionManager
}

func (manager *TransactionManager) Begin(ctx context.Context, name string, timeout int32) (string, error) {
request := &apis.GlobalBeginRequest{
Addressing: manager.addressing,
Timeout: timeout,
TransactionName: name,
}
resp, err := manager.rpcClient.Begin(ctx, request)
if err != nil {
return "", err
}
if resp.ResultCode == apis.ResultCodeSuccess {
return resp.XID, nil
}
return "", &exception.TransactionException{
Code: resp.GetExceptionCode(),
Message: resp.GetMessage(),
}
}

func (manager *TransactionManager) Commit(ctx context.Context, xid string) (apis.GlobalSession_GlobalStatus, error) {
request := &apis.GlobalCommitRequest{XID: xid}
resp, err := manager.rpcClient.Commit(ctx, request)
if err != nil {
return 0, err
}
if resp.ResultCode == apis.ResultCodeSuccess {
return resp.GlobalStatus, nil
}
return 0, &exception.TransactionException{
Code: resp.GetExceptionCode(),
Message: resp.GetMessage(),
}
}

func (manager *TransactionManager) Rollback(ctx context.Context, xid string) (apis.GlobalSession_GlobalStatus, error) {
request := &apis.GlobalRollbackRequest{XID: xid}
resp, err := manager.rpcClient.Rollback(ctx, request)
if err != nil {
return 0, err
}
if resp.ResultCode == apis.ResultCodeSuccess {
return resp.GlobalStatus, nil
}
return 0, &exception.TransactionException{
Code: resp.GetExceptionCode(),
Message: resp.GetMessage(),
}
}

func (manager *TransactionManager) GetStatus(ctx context.Context, xid string) (apis.GlobalSession_GlobalStatus, error) {
request := &apis.GlobalStatusRequest{XID: xid}
resp, err := manager.rpcClient.GetStatus(context.Background(), request)
if err != nil {
return 0, err
}
if resp.ResultCode == apis.ResultCodeSuccess {
return resp.GlobalStatus, nil
}
return 0, &exception.TransactionException{
Code: resp.GetExceptionCode(),
Message: resp.GetMessage(),
}
}

func (manager *TransactionManager) GlobalReport(ctx context.Context, xid string, globalStatus apis.GlobalSession_GlobalStatus) (apis.GlobalSession_GlobalStatus, error) {
request := &apis.GlobalReportRequest{
XID: xid,
GlobalStatus: globalStatus,
}
resp, err := manager.rpcClient.GlobalReport(ctx, request)
if err != nil {
return 0, err
}
if resp.ResultCode == apis.ResultCodeSuccess {
return resp.GlobalStatus, nil
}
return 0, &exception.TransactionException{
Code: resp.GetExceptionCode(),
Message: resp.GetMessage(),
}
}

+ 19
- 0
pkg/common/message_future.go View File

@@ -0,0 +1,19 @@
package common

import "github.com/opentrx/seata-golang/v2/pkg/apis"

// MessageFuture ...
type MessageFuture struct {
ID int64
Err error
Response interface{}
Done chan bool
}

// NewMessageFuture ...
func NewMessageFuture(message *apis.BranchMessage) *MessageFuture {
return &MessageFuture{
ID: message.ID,
Done: make(chan bool),
}
}

+ 0
- 18
pkg/compressor/7z_compress.go View File

@@ -1,18 +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.
*/

package compressor

+ 0
- 67
pkg/compressor/bzip2_compress.go View File

@@ -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.
*/

package compressor

import (
"bytes"
"io/ioutil"

"github.com/dsnet/compress/bzip2"
)

type Bzip2 struct {
}

// Compress Bzip2 compress
func (g *Bzip2) Compress(b []byte) ([]byte, error) {
var buffer bytes.Buffer
gz, err := bzip2.NewWriter(&buffer, &bzip2.WriterConfig{Level: bzip2.DefaultCompression})
if err != nil {
return nil, err
}

if _, err := gz.Write(b); err != nil {
return nil, err
}

if err := gz.Close(); err != nil {
return nil, err
}

return buffer.Bytes(), nil
}

// Decompress Bzip2 decompress
func (g *Bzip2) Decompress(in []byte) ([]byte, error) {
reader, err := bzip2.NewReader(bytes.NewReader(in), nil)
if err != nil {
return nil, err
}
if err = reader.Close(); err != nil {
return nil, err
}
output, err := ioutil.ReadAll(reader)
if err != nil {
return nil, err
}
return output, nil
}

func (g *Bzip2) GetCompressorType() CompressorType {
return CompressorBzip2
}

+ 0
- 40
pkg/compressor/bzip2_compress_test.go View File

@@ -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.
*/

package compressor

import (
"strings"
"testing"

"github.com/stretchr/testify/assert"
)

func TestBzip2Compress(t *testing.T) {
str := strings.Repeat(" bzip2 ", 100)

b := &Bzip2{}
compressRes, err := b.Compress([]byte(str))
assert.NoError(t, err)
t.Logf("compress res: %v", string(compressRes))

decompressRes, err := b.Decompress(compressRes)
assert.NoError(t, err)
assert.Equal(t, str, string(decompressRes))

t.Logf("decompress res: %v", string(decompressRes))
}

+ 0
- 24
pkg/compressor/compressor.go View File

@@ -1,24 +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.
*/

package compressor

type Compressor interface {
Compress([]byte) ([]byte, error)
Decompress([]byte) ([]byte, error)
GetCompressorType() CompressorType
}

+ 0
- 53
pkg/compressor/compressor_type.go View File

@@ -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.
*/

package compressor

type CompressorType string

const (
// "None" means no compressor is used
CompressorNone CompressorType = "None"
CompressorGzip CompressorType = "Gzip"
CompressorZip CompressorType = "Zip"
CompressorSevenz CompressorType = "Sevenz"
CompressorBzip2 CompressorType = "Bzip2"
CompressorLz4 CompressorType = "Lz4"
CompressorDeflate CompressorType = "Deflate"
CompressorZstd CompressorType = "Zstd"
)

func (c CompressorType) GetCompressor() Compressor {
switch c {
case CompressorNone:
return &NoneCompressor{}
case CompressorGzip:
return &Gzip{}
case CompressorZip:
return &Zip{}
case CompressorBzip2:
return &Bzip2{}
case CompressorLz4:
return &Lz4{}
case CompressorZstd:
return &Zstd{}
case CompressorDeflate:
return &DeflateCompress{}
default:
return &NoneCompressor{}
}
}

+ 0
- 51
pkg/compressor/deflate_compress.go View File

@@ -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.
*/

package compressor

import (
"bytes"
"compress/flate"
"io"

"seata.apache.org/seata-go/pkg/util/log"
)

type DeflateCompress struct{}

func (*DeflateCompress) Compress(data []byte) ([]byte, error) {
var buf bytes.Buffer
fw, err := flate.NewWriter(&buf, flate.BestCompression)
if err != nil {
log.Error(err)
return nil, err
}
defer fw.Close()
fw.Write(data)
fw.Flush()
return buf.Bytes(), nil
}

func (*DeflateCompress) Decompress(data []byte) ([]byte, error) {
fr := flate.NewReader(bytes.NewBuffer(data))
defer fr.Close()
return io.ReadAll(fr)
}

func (*DeflateCompress) GetCompressorType() CompressorType {
return CompressorDeflate
}

+ 0
- 53
pkg/compressor/deflate_compress_test.go View File

@@ -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.
*/

package compressor

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestDeflateCompress(t *testing.T) {
ts := []struct {
text string
}{
{
text: "Don't communicate by sharing memory, share memory by communicating.",
},
{
text: "Concurrency is not parallelism.",
},
{
text: "The bigger the interface, the weaker the abstraction.",
},
{
text: "Documentation is for users.",
},
}

dc := &DeflateCompress{}
assert.EqualValues(t, CompressorDeflate, dc.GetCompressorType())

for _, s := range ts {
var data []byte = []byte(s.text)
dataCompressed, _ := dc.Compress(data)
ret, _ := dc.Decompress(dataCompressed)
assert.EqualValues(t, s.text, string(ret))
}
}

+ 0
- 66
pkg/compressor/gzip_compress.go View File

@@ -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.
*/

package compressor

import (
"bytes"
"compress/gzip"
"io/ioutil"
)

type Gzip struct {
}

// Compress gzip compress
func (g *Gzip) Compress(b []byte) ([]byte, error) {
var buffer bytes.Buffer

gz := gzip.NewWriter(&buffer)

if _, err := gz.Write(b); err != nil {
return nil, err
}

if err := gz.Flush(); err != nil {
return nil, err
}

if err := gz.Close(); err != nil {
return nil, err
}

return buffer.Bytes(), nil
}

// Decompress gzip decompress
func (g *Gzip) Decompress(in []byte) ([]byte, error) {
reader, err := gzip.NewReader(bytes.NewReader(in))
if err != nil {
return nil, err
}

if err = reader.Close(); err != nil {
return nil, err
}

return ioutil.ReadAll(reader)
}

func (g *Gzip) GetCompressorType() CompressorType {
return CompressorGzip
}

+ 0
- 40
pkg/compressor/gzip_compress_test.go View File

@@ -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.
*/

package compressor

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestGzipCompress(t *testing.T) {
str := "test"

g := &Gzip{}

compressRes, err := g.Compress([]byte(str))
assert.NoError(t, err)
t.Logf("compress res: %v", string(compressRes))

decompressRes, err := g.Decompress(compressRes)
assert.NoError(t, err)
t.Logf("decompress res: %v", string(decompressRes))

assert.Equal(t, str, string(decompressRes))
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save