diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000000000000000000000000000000000..3f844d13728cdc2a4cbabdbfa38c7b3a5436267a --- /dev/null +++ b/.clang-format @@ -0,0 +1,154 @@ +# +Language: Cpp +# +SortIncludes: false +# +AccessModifierOffset: -4 +# +DerivePointerAlignment: false +# +PointerAlignment: Right +# +ConstructorInitializerIndentWidth: 4 +# +AlignEscapedNewlinesLeft: true +# +AlignTrailingComments: true +# +AllowShortBlocksOnASingleLine: false +# +AllowShortFunctionsOnASingleLine: false +# +AllowShortIfStatementsOnASingleLine: false +# +AllowShortCaseLabelsOnASingleLine: false +# +AllowShortLoopsOnASingleLine: false +# +AlwaysBreakTemplateDeclarations: true +# +BinPackArguments: true +# +AlwaysBreakBeforeMultilineStrings: false +# +BreakBeforeBinaryOperators: None +# +BreakBeforeTernaryOperators: false +# +BreakConstructorInitializersBeforeComma: false +# +BinPackParameters: true +# +ColumnLimit: 120 +# +ConstructorInitializerAllOnOneLineOrOnePerLine: true +# +DerivePointerBinding: true +# +ExperimentalAutoDetectBinPacking: false +# +IndentCaseLabels: true +# +MaxEmptyLinesToKeep: 1 +# +NamespaceIndentation: None +# +ObjCSpaceBeforeProtocolList: false +# +PenaltyBreakBeforeFirstCallParameter: 1 +# +PenaltyBreakComment: 200 +# +PenaltyBreakString: 1000 +# +PenaltyBreakFirstLessLess: 120 +# +PenaltyExcessCharacter: 1000000 +# +AlwaysBreakAfterDefinitionReturnType: None +# +AlwaysBreakAfterReturnType: None +# +PointerBindsToType: true +# +Cpp11BracedListStyle: true +# +Standard: Auto +# +IndentWidth: 4 +# +TabWidth: 4 +# +UseTab: Never +# +BreakBeforeBraces: Custom +# +BraceWrapping: +# + AfterClass: false +# + AfterControlStatement: false +# + AfterEnum: false +# + AfterFunction: true +# + AfterNamespace: false +# + AfterObjCDeclaration: false +# + AfterStruct: false +# + AfterUnion: false +# + AfterExternBlock: false +# + BeforeCatch: false + # + BeforeElse: false +# + IndentBraces: false +# + SplitEmptyFunction: false +# + SplitEmptyRecord: false +# + SplitEmptyNamespace: false +# +IndentFunctionDeclarationAfterType: true +# +SpacesInParentheses: false +# +SpacesInAngles: false +# +SpaceInEmptyParentheses: false +# +SpacesInCStyleCastParentheses: false +# +SpaceAfterControlStatementKeyword: true +# +SpacesBeforeTrailingComments: 2 +# +ContinuationIndentWidth: 4 +# +CommentPragmas: '^lint' +# +MacroBlockBegin: " + +^ *PROG *$| + +CATCH_ALL_ERROR.*$" + +# +MacroBlockEnd: " + +^ *END_PROG *$| + +END_CATCH_ERROR$" + +# +AlignAfterOpenBracket: DontAlign +# +AlignConsecutiveAssignments: false +# +AlignConsecutiveDeclarations: false \ No newline at end of file diff --git a/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md new file mode 100644 index 0000000000000000000000000000000000000000..65891e672a5bad66b78b6f5523c1261e2dce635a --- /dev/null +++ b/.gitee/PULL_REQUEST_TEMPLATE.zh-CN.md @@ -0,0 +1,43 @@ + + + + +【标题】(请简要描述下实现的内容) + +必填项,否则禁止合入 + +【实现内容】: + +必填项,否则禁止合入 + +【根因分析】: + +必填项,否则禁止合入 + +【实现方案】: + +必填项,否则禁止合入 + +【关联需求或issue】: + +必填项,否则禁止合入 + +【开发自验报告】: +1. 请附上自验结果(内容或者截图) + +必填项,否则禁止合入 + +2. 是否涉及资料修改,如是,请在docs仓库补充资料 + +必填项,否则禁止合入 + +3. 是否涉及接口修改,如是,请在openGauss-server仓库同步 + +必填项,否则禁止合入 + +4. 是否对其他模块产生影响 + +必填项,否则禁止合入 + +【其他说明】: +选填 \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ae07f34a57b3d71eaa09bc63dd4d40f069c88465 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,229 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.12.1) +PROJECT(wr) + +message(${CMAKE_BUILD_TYPE}) +if (${CMAKE_BUILD_TYPE} STREQUAL "Debug" + OR ${CMAKE_BUILD_TYPE} STREQUAL "") + message(STATUS "CMAKE_BUILD_TYPE is Debug") + set(CMAKE_BUILD_TYPE Debug) + add_compile_definitions(_DEBUG DB_DEBUG_VERSION) +elseif (${CMAKE_BUILD_TYPE} STREQUAL "Memcheck" OR ${CMAKE_BUILD_TYPE} STREQUAL "MemcheckWRtest") + message(STATUS "CMAKE_BUILD_TYPE is Memcheck") + set(CMAKE_BUILD_TYPE Memcheck) + add_compile_definitions(_DEBUG DB_DEBUG_VERSION) + add_compile_options(-fsanitize=address -fsanitize=leak -fno-omit-frame-pointer -lasan) + add_link_options(-fsanitize=address -fsanitize=leak -fno-omit-frame-pointer -lasan) + message(STATUS "Toolchain: Build with ASAN TEST Configure") +elseif (${CMAKE_BUILD_TYPE} STREQUAL "Release") + message(STATUS "CMAKE_BUILD_TYPE is Release") + set(CMAKE_BUILD_TYPE Release) + set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") +else () + message(STATUS "unknown CMAKE_BUILD_TYPE = " ${CMAKE_BUILD_TYPE}) +endif () + +set(COMPONENT "GaussDB Kernel") + +option(OPENGAUSS_FLAG OFF) +if (OPENGAUSS_FLAG) + add_definitions(-DOPENGAUSS) + message(STATUS "openGauss on") + set(COMPONENT "openGauss") +endif (OPENGAUSS_FLAG) + +option(IOFENCE_FLAG OFF) +if (IOFENCE_FLAG) + add_definitions(-DIOFENCE) + message(STATUS "iofence on") +endif (IOFENCE_FLAG) + +option(VG_FILE_LOCK OFF) +if (VG_FILE_LOCK) + add_definitions(-DVG_FILE_LOCK) + message(STATUS "vg file lock on") +endif (VG_FILE_LOCK) + +EXECUTE_PROCESS( + COMMAND bash -c "git rev-parse HEAD | cut -b 1-8" + OUTPUT_VARIABLE COMMIT_ID + OUTPUT_STRIP_TRAILING_WHITESPACE +) +EXECUTE_PROCESS( + COMMAND bash -c "date \"+%Y-%m-%d %H:%M:%S\"" + OUTPUT_VARIABLE COMPILE_TIME + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +# WR_VERSION_STR can be used for api/cmd/server +# WR_VERSION_STR like: (openGauss build ab4a14da) compiled at 2000-01-01 00:00:00 debug) +if (ENABLE_WRTEST) + SET(WR_VERSION_STR + "(${COMPONENT} build ${COMMIT_ID}) compiled at ${COMPILE_TIME} ${CMAKE_BUILD_TYPE} (WRTEST ON)" + ) +else() + SET(WR_VERSION_STR + "(${COMPONENT} build ${COMMIT_ID}) compiled at ${COMPILE_TIME} ${CMAKE_BUILD_TYPE} (WRTEST OFF)" + ) +endif() + +message(STATUS "Version info: ${WR_VERSION_STR}") + +set(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS} -D__FILE_NAME__='\"$(notdir $(subst .o,,$(abspath $@)))\"'" ) +add_compile_options(-fPIC -Wall -MMD -fno-strict-aliasing -fsigned-char -fms-extensions -lpthread) +add_compile_definitions(_GNU_SOURCE _LARGEFILE64_SOURCE KNL_PREFIX _REENTRANT __PERF_STAT__) +add_link_options(-pie) +add_link_options(-Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now) +add_compile_options(-fvisibility=default -fstack-protector-strong --param ssp-buffer-size=4) + +# 安全编译选项 +set(CMAKE_SKIP_RPATH TRUE) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -ldl -pthread -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now") +add_compile_options(-fno-common) +add_compile_options(-Wtrampolines) +add_compile_options(-freg-struct-return) +add_compile_options(-Wl,-Bsymbolic) +add_compile_options(-rdynamic) +add_compile_options(-Wall) +# add_compile_options(-Werror) + +add_compile_options(-Wvla) +add_compile_options(-Wcast-align) +add_compile_options(-Wshadow) +add_compile_options(-Wundef) +add_compile_options(-Wswitch-default) +add_compile_options(-Wfloat-equal) +add_compile_options(-Wdate-time) +add_compile_options(-Wunused) +add_compile_options(-fstrong-eval-order) +add_compile_options(-Werror=frame-larger-than=1048576) +add_compile_options(-Wextra) +add_compile_options(-Wstack-usage=1048576) +add_compile_options(-Wno-sign-compare) +add_compile_options(-Wno-type-limits) +add_compile_options(-Wno-implicit-fallthrough) +add_compile_options(-Wno-unused-parameter) +add_compile_options(-Wno-missing-field-initializers) +add_compile_options(-Wno-ignored-qualifiers) +add_compile_options(-Wno-cast-function-type) +add_compile_options(-Wno-enum-conversion) +if (NOT HOT_PATCH_SPEC) + add_compile_options(-pipe) +endif() + +OPTION(ENABLE_GCOV "Enable gcov (debug, Linux builds only)" OFF) +message(STATUS "ENABLE_GCOV = ${ENABLE_GCOV}") +IF (ENABLE_GCOV AND NOT WIN32 AND NOT APPLE) + message(STATUS "Enable gcov (debug, Linux builds only).") + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage") + SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage") + SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage -lgcov") + add_definitions(-DENABLE_GCOV) +ENDIF() + +OPTION(USE_ASAN "Enable ASAN (debug, Linux builds only)" OFF) +message(STATUS "USE_ASAN = ${USE_ASAN}") +IF (USE_ASAN AND NOT WIN32 AND NOT APPLE) + message(STATUS "Enable ASAN (debug, Linux builds only).") + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fsanitize=leak -fsanitize-recover=address,all -O0 -Wall -g -fPIC -fno-omit-frame-pointer") + SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fsanitize=address -fsanitize=leak -fsanitize-recover=address,all -O0 -Wall -g -fPIC -fno-omit-frame-pointer") + SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fsanitize=address -fsanitize=leak -fsanitize-recover=address,all -O0 -Wall -g -fPIC -fno-omit-frame-pointer") +ENDIF() + +OPTION(ENABLE_FUZZASAN "ENABLE FUZZASAN (debug, Linux builds only)" OFF) +message(STATUS "ENABLE_FUZZASAN = ${ENABLE_FUZZASAN}") +IF (ENABLE_FUZZASAN) + SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage") + SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage") + SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fprofile-arcs -ftest-coverage -lgcov") + set(WR_FUZZ_LIB_PATH ${PROJECT_SOURCE_DIR}/test/fuzz_test/lib) + message(STATUS "WR_FUZZ_LIB_PATH = ${WR_FUZZ_LIB_PATH}") +ENDIF() + +OPTION(ENABLE_EXPORT_API "Enable hidden internal api" OFF) +message(STATUS "ENABLE_EXPORT_API = ${ENABLE_EXPORT_API}") +IF (ENABLE_EXPORT_API) + add_compile_options(-fvisibility=hidden) +ENDIF() + +OPTION(ENABLE_DEFAULT_FILE_FLAG_INNER_INITED "Enable default file flag inited" OFF) +message(STATUS "ENABLE_DEFAULT_FILE_FLAG_INNER_INITED = ${ENABLE_DEFAULT_FILE_FLAG_INNER_INITED}") +IF (ENABLE_DEFAULT_FILE_FLAG_INNER_INITED) + add_definitions(-DWR_DEFAULT_FILE_FLAG_INNER_INITED) +ENDIF() + +OPTION(ENABLE_WRTEST "Enable wr test" OFF) +message(STATUS "ENABLE_WRTEST = ${ENABLE_WRTEST}") +IF (ENABLE_WRTEST) + add_definitions(-DENABLE_WRTEST) +ENDIF() + +execute_process( + COMMAND uname -m + OUTPUT_VARIABLE OS_ARCH + OUTPUT_STRIP_TRAILING_WHITESPACE +) +set(CMAKE_SYSTEM_PROCESSOR ${OS_ARCH}) +if (OS_ARCH STREQUAL "aarch64") + option(USE_H1620 OFF) + if (USE_H1620) + add_compile_options(-march=armv8-a+crc+lse) + message(STATUS "Toolchain: Build aarch64 USE_H1620") + else () + add_compile_options(-march=armv8-a+crc) + endif (USE_H1620) + + add_compile_options(-mtune=cortex-a72 -fsigned-char -g -ggdb3 -march=armv8-a+crc -funwind-tables) +else () + add_compile_options(-msse4.2 ) +endif () +Add_Definitions(-DWSEC_COMPILE_CAC_OPENSSL -DWSEC_AES_GCM_SUPPORT -DWSEC_USE_OPENSSL_110) + +## wr include_directories +set(WR_COMMON_PATH ${PROJECT_SOURCE_DIR}/src/common) +set(WR_LOG_PATH ${PROJECT_SOURCE_DIR}/src/log) +set(WR_PARAMS_PATH ${PROJECT_SOURCE_DIR}/src/params) +set(WR_COMMON_API_PATH ${PROJECT_SOURCE_DIR}/src/common_api) +set(WR_CMD_PATH ${PROJECT_SOURCE_DIR}/src/cmd) +set(WR_SER_PATH ${PROJECT_SOURCE_DIR}/src/service) +set(WR_INTERFACE_PATH ${PROJECT_SOURCE_DIR}/src/interface) + +## other dependency include +set(WR_SECUREC_INC_PATH "${CMAKE_CURRENT_SOURCE_DIR}/library/huawei_security/include") +set(WR_OPENSSL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/library/openssl/include") +set(WR_CBB_PATH "${CMAKE_CURRENT_SOURCE_DIR}/library/cbb/include") +set(LIBAIO_INC_PATH "${CMAKE_CURRENT_SOURCE_DIR}/library/libaio/include") +set(ZLIB_INC_PATH "${CMAKE_CURRENT_SOURCE_DIR}/library/zlib/include") +set(LZ4_INC_PATH "${CMAKE_CURRENT_SOURCE_DIR}/library/lz4/include") +set(JAVA_HOME "$ENV{JAVA_HOME}/include") +set(JAVA_HOME_INCLUDE "$ENV{JAVA_HOME}/include/linux") + +## lib +set(SECUREC_LIB_PATH "${CMAKE_CURRENT_SOURCE_DIR}/library/huawei_security/lib") +set(OPENSSL_LIB_PATH "${CMAKE_CURRENT_SOURCE_DIR}/library/openssl/lib") +set(CBB_LIB_PATH "${CMAKE_CURRENT_SOURCE_DIR}/library/cbb/lib") +set(LIBZ_PATH "${CMAKE_CURRENT_SOURCE_DIR}/library/zlib/lib") +set(LZ4_PATH "${CMAKE_CURRENT_SOURCE_DIR}/library/lz4/lib") + +## output path +set (LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/output/lib) +set (EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/output/bin) + +CONFIGURE_FILE(config.h.in ${WR_COMMON_API_PATH}/config.h) +CONFIGURE_FILE(config.h.in ${WR_SER_PATH}/config.h) +## add source +link_directories(${LIBRARY_OUTPUT_PATH} ${SECUREC_LIB_PATH} ${LIBZ_PATH} ${LZ4_PATH} ${CBB_LIB_PATH}) +IF (ENABLE_FUZZASAN) + link_directories(${WR_FUZZ_LIB_PATH}) + set(fuzz_lib "libSecodefuzz.a") +ENDIF() + +set(vpp_libsecurec "libsecurec.a") +set(3rd_libccb "libcbb.a") +set(libz "libz.a") +set(lz4 "lz4") + +set(vpp_libipsi_crypto "libcrypto.a") +set(3rd_libssl "libssl.a") +link_directories(${OPENSSL_LIB_PATH}) + +add_subdirectory(src) diff --git a/License.txt b/License.txt new file mode 100644 index 0000000000000000000000000000000000000000..320c890a65587b10de613ef64a12cdcf4467132c --- /dev/null +++ b/License.txt @@ -0,0 +1,124 @@ +ľ֤ 2 + +20201 http://license.coscl.org.cn/MulanPSL2 + +ԡĸơʹá޸ļַľ֤2棨֤Լ + +0. + + ָɡסɵڡ֤µijĵļϡ + +ס ָһߡڡ֤µܰȨƷ + +ߡ ָܰȨƷڡ֤µȻ˻򡰷ʵ塱 + +ʵ塱 ָύ׵Ļ䡰ʵ塱 + +ʵ塱 ָԡ֤µΪԣơܿƻ乲ͬܿƵĻ˴Ŀָܿطͬܿط50%ֱӻӵͶƱȨʽм֤ȯ + +1. Ȩ + +ÿߡݡ֤ԵġȫԵġѵġǶռġɳİȨɣԸơʹá޸ġַ䡰ס޸ + +2. ר + +ÿߡݡ֤ԵġȫԵġѵġǶռġɳģݱ涨⣩רɣ졢ί졢ʹáŵۡۡ䡰סʽת䡰סǰרɽڡߡڻӵлƵ䡰ס䡰סɡסʱġ϶ȻַרȨҪ󣬲ԡס޸Ļסϡġʵ塱ֱӻӵأ͡еġסκ˷רȨϣ߻򽻲ϣרάȨжַָרȨ򡰱֤ԡרϻάȨжֹ֮ + +3. ̱ + +֤ṩԡߡƷơ̱ꡢ־ƷƵ̱ɣΪ4涨ʹó⡣ + +4. ַ + +κýнԴʽִʽ·ַ޸񣬵ṩ֤ĸеİȨ̱ꡢר + +5. + +еġסṩʱκʾĬʾĵκ£ߡȨ߲κʹáеġסκֱӻʧеΣԭ»߻ںַ,ʹдʧĿԡ + +6. + +֤Ӣ˫Ӣİ汾ͬȷЧӢİ汾κγͻһ£İΪ׼ + + + +νľ֤2棬Ӧõ + +ϣľ֤2棬ӦõΪ˷߲ģ + +1 еĿհף״ηԼΪȨ˵֣ + +2 һĿ¼´ԡLICENSEΪļ֤ıļУ + +3 뽫ıÿԴļͷעС + +Copyright (c) [Year] [name of copyright holder] +[Software Name] is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. +Mulan Permissive Software LicenseVersion 2 +Mulan Permissive Software LicenseVersion 2 (Mulan PSL v2) + +January 2020 http://license.coscl.org.cn/MulanPSL2 + +Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: + +0. Definition + +Software means the program and related documents which are licensed under this License and comprise all Contribution(s). + +Contribution means the copyrightable work licensed by a particular Contributor under this License. + +Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. + +Legal Entity means the entity making a Contribution and all its Affiliates. + +Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, control means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. + +1. Grant of Copyright License + +Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. + +2. Grant of Patent License + +Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. + +3. No Trademark License + +No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in section 4. + +4. Distribution Restriction + +You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. + +5. Disclaimer of Warranty and Limitation of Liability + +THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW ITS CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +6. Language + +THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. + +END OF THE TERMS AND CONDITIONS + +How to Apply the Mulan Permissive Software LicenseVersion 2 (Mulan PSL v2) to Your Software + +To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: + +Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; +Create a file named "LICENSE" which contains the whole context of this License in the first directory of your software package; +Attach the statement to the appropriate annotated syntax at the beginning of each source file. +Copyright (c) [Year] [name of copyright holder] +[Software Name] is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. \ No newline at end of file diff --git a/README.en.md b/README.en.md index a41895ef080f5794a307fa2ae5810b9d24f57bfc..1c1762e6c4c165e46d1bd98f4639dd51f770972f 100644 --- a/README.en.md +++ b/README.en.md @@ -1,36 +1,54 @@ # WR -#### Description -{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} +WR: WAL Recorder, a basic component providing WAL log recording services. -#### Software Architecture -Software architecture description +## 1. Project Description -#### Installation +### 1. Programming Language +- C -1. xxxx -2. xxxx -3. xxxx +### 2. Build Tools +- cmake or make, cmake is recommended -#### Instructions +### 3. Directory Structure +- **WR**: Main directory, CMakeLists.txt is the main project entry; +- **src**: Source code directory, divided into subdirectories for common function modules; +- **build/build.sh**: Project build script -1. xxxx -2. xxxx -3. xxxx +## 2. Compilation Guide -#### Contribution +### 1. Supported Operating Systems and Software Dependencies +Supported operating systems: +- CentOS 7.6 (x86) +- openEuler-20.03-LTS +- openEuler-22.03-LTS +- openEuler-24.03-LTS -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request +For other systems, refer to the openGauss database compilation guide. +### 2. Download WR +WR can be downloaded from the open-source community. -#### Gitee Feature +### 3. Code Compilation +Use `WR/build/build.sh` to compile the code. The parameters are explained in the table below. -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) +| Option | Parameter | Description | +|--------|--------------------|--------------------------------------------------| +| -3rd | [binarylibs path] | Specify the binarylibs path. It must be an absolute path. | +| -m | [version_mode] | Target version for compilation, Debug or Release. Default is Release. | +| -t | [build_tool] | Specify the build tool, cmake or make. Default is cmake. | + +To compile, simply use the following command: + +```bash +[user@linux]$ sh build.sh -3rd [binarylibs path] -m Release -t cmake +``` + +After compilation, the dynamic libraries are generated in the `WR/output/lib` directory, and the executables are generated in the `WR/output/bin` directory. + +### 4. UT Testing +Modify `WR/test/test_home/test_env` to set `CODE_BASE` to the absolute path of the WR directory. Execute `WR/test/gtest/build.sh` to compile the UT code. + +```bash +./test_wr_api +``` \ No newline at end of file diff --git a/README.md b/README.md index 020b0f61ab81675914620cc886e73648c4a3c58c..543e8d0bdc7d79d2a65524c43515b560fddb867a 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,54 @@ # WR -#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +WR:WAL Recorder,WAL日志记录器,是一款提供WAL日志记录服务的基础组件。 -#### 软件架构 -软件架构说明 +## 一、工程说明 +### 1. 编程语言 +- C -#### 安装教程 +### 2. 编译工具 +- cmake或make,建议使用cmake -1. xxxx -2. xxxx -3. xxxx +### 3. 目录说明 +- **WR**:主目录,CMakeLists.txt为主工程入口; +- **src**: 源代码目录,按子目录划分通用功能函数; +- **build/build.sh**:工程构建脚本 -#### 使用说明 +## 二、编译指导 -1. xxxx -2. xxxx -3. xxxx +### 1. 操作系统和软件依赖要求 +支持以下操作系统: +- CentOS 7.6(x86) +- openEuler-20.03-LTS +- openEuler-22.03-LTS +- openEuler-24.03-LTS -#### 参与贡献 +适配其他系统,可参照openGauss数据库编译指导。 -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +### 2. 下载WR +可以从开源社区下载WR。 +### 3. 代码编译 +使用 `WR/build/build.sh` 编译代码, 参数说明请见以下表格。 -#### 特技 +| 选项 | 参数 | 说明 | +|------|--------------------|------------------------------------------| +| -3rd | [binarylibs path] | 指定binarylibs路径。该路径必须是绝对路径。| +| -m | [version_mode] | 编译目标版本,Debug或者Release。默认Release| +| -t | [build_tool] | 指定编译工具,cmake或者make。默认cmake | -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) +现在只需使用如下命令即可编译: + +```bash +[user@linux]$ sh build.sh -3rd [binarylibs path] -m Release -t cmake +``` + +完成编译后,动态库生成在 `WR/output/lib` 目录中,可执行文件生成在 `WR/output/bin` 目录中。 + +### 4. UT测试 +修改 `WR/test/test_home/test_env` 中的 `CODE_BASE` 为WR目录的绝对路径。执行 `WR/test/gtest/build.sh` 编译UT代码。 + +```bash +./test_wr_api +``` \ No newline at end of file diff --git a/build/build.sh b/build/build.sh new file mode 100644 index 0000000000000000000000000000000000000000..07676a48f149878e5af76caa0e0d6698a04b4721 --- /dev/null +++ b/build/build.sh @@ -0,0 +1,192 @@ +#!/bin/bash +############################################################################# +# Copyright (c) 2020 Huawei Technologies Co.,Ltd. +# +# openGauss is licensed under Mulan PSL v2. +# You can use this software according to the terms +# and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# ---------------------------------------------------------------------------- +# Description : wr build for opengauss +############################################################################# + +set -e + +function print_help() +{ + echo "Usage: $0 [OPTION] + -h|--help show help information. + -3rd|--binarylib_dir the directory of third party binarylibs. + -m|--version_mode this values of paramenter is Debug, Release, Memcheck, DebugWRtest, ReleaseWRtest, MemcheckWRtest the default value is Release. + -t|--build_tool this values of parameter is cmake, make, the default value is cmake. + -s|--storage_mode storage device type. values is disk, ceph. default is disk. +" +} + +while [ $# -gt 0 ]; do + case "$1" in + -h|--help) + print_help + exit 1 + ;; + -3rd|--binarylib_dir) + if [ "$2"X = X ]; then + echo "no given binarylib directory values" + exit 1 + fi + binarylib_dir=$2 + shift 2 + ;; + -m|--version_mode) + if [ "$2"X = X ]; then + echo "no given version number values" + exit 1 + fi + version_mode=$2 + shift 2 + ;; + -t|--build_tool) + if [ "$2"X = X ]; then + echo "no given build_tool values" + exit 1 + fi + build_tool=$2 + shift 2 + ;; + -s|--storage_mode) + storage_mode=$2 + shift 2 + ;; + *) + echo "Internal Error: option processing error: $1" 1>&2 + echo "please input right paramtenter, the following command may help you" + echo "./build.sh --help or ./build.sh -h" + exit 1 + esac +done + +enable_wrtest=OFF +if [ -z "${version_mode}" ] || [ "$version_mode"x == ""x ]; then + version_mode=Release +fi +if [ -z "${binarylib_dir}" ]; then + echo "ERROR: 3rd bin dir not set" + exit 1 +fi +if [ -z "${build_tool}" ] || [ "$build_tool"x == ""x ]; then + build_tool=cmake +fi +if [ ! "$version_mode"x == "Debug"x ] && [ ! "$version_mode"x == "Release"x ] && [ ! "$version_mode"x == "DebugWRtest"x ] && [ ! "$version_mode"x == "ReleaseWRtest"x ] && [ ! "$version_mode"x == "Memcheck"x ] && [ ! "$version_mode"x == "MemcheckWRtest"x ]; then + echo "ERROR: version_mode param is error" + exit 1 +fi +if [ "$version_mode"x == "DebugWRtest"x ]; then + version_mode=Debug + enable_wrtest=ON +fi +if [ "$version_mode"x == "ReleaseWRtest"x ]; then + version_mode=Release + enable_wrtest=ON +fi +if [ "$version_mode"x == "MemcheckWRtest"x ]; then + version_mode=Memcheck + enable_wrtest=ON +fi +if [ ! "$build_tool"x == "make"x ] && [ ! "$build_tool"x == "cmake"x ]; then + echo "ERROR: build_tool param is error" + exit 1 +fi + +declare export_api=ON + +export CFLAGS="-std=gnu99" + +LOCAL_PATH=${0} + +CUR_PATH=$(pwd) +LOCAL_DIR=$(dirname "${LOCAL_PATH}") +export PACKAGE=$CUR_PATH/../ +export OUT_PACKAGE=wr + +export WR_OPEN_SRC_PATH=$(pwd)/../open_source +export WR_LIBRARYS=$(pwd)/../library + +[ -d "${WR_LIBRARYS}" ] && rm -rf ${WR_LIBRARYS} +mkdir -p $WR_LIBRARYS/huawei_security +mkdir -p $WR_LIBRARYS/openssl +mkdir -p $WR_LIBRARYS/zlib +mkdir -p $WR_LIBRARYS/lz4 +mkdir -p $WR_LIBRARYS/libaio/include +mkdir -p $WR_LIBRARYS/cbb + +export LIB_PATH=$binarylib_dir/kernel/dependency +export P_LIB_PATH=$binarylib_dir/kernel/platform +COPT_LIB_PATH=${binarylib_dir}/kernel/component + +cp -r $P_LIB_PATH/Huawei_Secure_C/comm/lib $WR_LIBRARYS/huawei_security/lib +cp -r $LIB_PATH/openssl/comm/lib $WR_LIBRARYS/openssl/lib +cp -r $LIB_PATH/zlib1.2.11/comm/lib $WR_LIBRARYS/zlib/lib +cp -r $LIB_PATH/lz4/comm/lib $WR_LIBRARYS/lz4/lib + +cp -r $P_LIB_PATH/Huawei_Secure_C/comm/include $WR_LIBRARYS/huawei_security/include +cp -r $LIB_PATH/openssl/comm/include $WR_LIBRARYS/openssl/include +cp -r $LIB_PATH/zlib1.2.11/comm/include $WR_LIBRARYS/zlib/include +cp -r $LIB_PATH/lz4/comm/include $WR_LIBRARYS/lz4/include + +status=0 +if [ -f "/usr/include/libaio.h" ];then + echo "begin cp libaio.h from /usr/include/" + cp -r /usr/include/libaio.h $WR_LIBRARYS/libaio/include + status=1 +fi + +if [ ${status} -eq 0 ];then + for file in "${WR_OPEN_SRC_PATH}"/libaio/libaio-*/src/libaio.h + do + if [ -f "${file}" ];then + echo "begin cp libaio.h from open_source/libaio/" + cp -r ${WR_OPEN_SRC_PATH}/libaio/libaio-*/src/libaio.h $WR_LIBRARYS/libaio/include + status=1 + fi + done + + if [ ${status} -eq 0 ];then + echo "system does not install libaio software, pls install by yum install libaio-devel" + exit 1 + fi +fi + +cp -r $COPT_LIB_PATH/cbb/include $WR_LIBRARYS/cbb/include +cp -r $COPT_LIB_PATH/cbb/lib $WR_LIBRARYS/cbb/lib + +cd $WR_LIBRARYS/openssl/lib +cp -r libssl_static.a libssl.a +cp -r libcrypto_static.a libcrypto.a + +cd $PACKAGE +if [ "$build_tool"x == "cmake"x ];then + cmake_opts="-DCMAKE_BUILD_TYPE=${version_mode} -DENABLE_WRTEST=${enable_wrtest} -DOPENGAUSS_FLAG=ON -DIOFENCE_FLAG=OFF -DVG_FILE_LOCK=OFF \ + -DENABLE_EXPORT_API=${export_api}" + cmake ${cmake_opts} CMakeLists.txt + make all -sj 8 +else + make clean + make BUILD_TYPE=${version_mode} -sj 8 +fi + +mkdir -p $binarylib_dir/kernel/component/${OUT_PACKAGE}/bin +mkdir -p $binarylib_dir/kernel/component/${OUT_PACKAGE}/lib +mkdir -p $binarylib_dir/kernel/component/${OUT_PACKAGE}/include +cp -r output/lib/libwr* $binarylib_dir/kernel/component/${OUT_PACKAGE}/lib +cp -r output/bin/wr* $binarylib_dir/kernel/component/${OUT_PACKAGE}/bin +cp -r $COPT_LIB_PATH/cbb/bin/perctrl $binarylib_dir/kernel/component/${OUT_PACKAGE}/bin +cp -r install/wr_clear.sh $binarylib_dir/kernel/component/${OUT_PACKAGE}/bin +cp -r src/interface/*.h $binarylib_dir/kernel/component/${OUT_PACKAGE}/include +echo "build WR SUCCESS" diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000000000000000000000000000000000000..3f1e5ab6861dbca23683a75aae148f4a9c4417b8 --- /dev/null +++ b/config.h.in @@ -0,0 +1,3 @@ +#ifndef DEF_WR_VERSION +#define DEF_WR_VERSION "@WR_VERSION_STR@" +#endif \ No newline at end of file diff --git a/install/common_func.sh b/install/common_func.sh new file mode 100644 index 0000000000000000000000000000000000000000..8d23be0afc2148fb1620e03a83b72fb75442ddfd --- /dev/null +++ b/install/common_func.sh @@ -0,0 +1,129 @@ +#!/bin/bash +# +# Copyright (C), 2022-2038, Huawei Tech. Co., Ltd. +# File Name : common_func.sh +# Description : common function +# +set -e + +curr_path=$(dirname $(readlink -f $0)) +curr_filename=$(basename $(readlink -f $0)) +os_user=$(whoami) +file_user=$(ls -l ${curr_path}"/${curr_filename}" | awk '{print $3}') + +if [ ${file_user} != ${os_user} ]; then + echo "Can't run ${curr_filename}, because it does not belong to the current user!" + exit 1 +fi + +log() +{ + time=$(date "+%Y-%m-%d %H:%M:%S") + echo "$time $1" +} + +assert_empty() +{ + return +} + +assert_nonempty() +{ + if [[ -z ${2} ]] + then + log "The ${1} parameter is empty." + exit 1 + fi +} + +wrserver_pid() +{ + pid=$(ps -f f -u \`whoami\` | grep -v grep | grep "wrserver "| grep ${1}$ | awk '{print $2}') + echo ${pid} +} + +kill_program() +{ + assert_nonempty 1 ${1} + pid=$(wrserver_pid $1) + if [[ -z ${pid} ]] + then + log "wrserver is already dead." + return + fi + + kill -9 ${pid} + sleep 3 + ps -f -p "${pid}" | grep wrserver + if [ $? = 0 ] + then + log "ERROR! wrserver with pid:${pid} is not killed..." + exit 0 + fi +} + +check_wr_start() +{ + started=0 + for (( i=1; i<30; i++ )) + do + pid=$(wrserver_pid ${1}) + if [[ ! -z ${pid} ]] + then + started=1 + break + fi + sleep 1 + done + + if [[ ${started} -eq 0 ]] + then + log "ERROR! start wrserver in dir ${1} failed" + exit 1 + fi +} + +function clear_script_log() +{ + local _log_dir=$1 + local _log_name=$2 + local _max_log_backup=$3 + + if [ -L ${_log_dir} ]; then + typeset log_num=$(find -L "${_log_dir}" -maxdepth 1 -type f -name "${_log_name}*" | wc -l) + if [ ${log_num} -ge ${_max_log_backup} ];then + find -L "${_log_dir}" -maxdepth 1 -type f -name "${_log_name}*" | xargs ls -t {} 2>/dev/null | tail -n $(expr ${log_num} - ${_max_log_backup}) | xargs -i rm -f {} + fi + else + typeset log_num=$(find "${_log_dir}" -maxdepth 1 -type f -name "${_log_name}*" | wc -l) + if [ ${log_num} -ge ${_max_log_backup} ];then + find "${_log_dir}" -maxdepth 1 -type f -name "${_log_name}*" | xargs ls -t {} 2>/dev/null | tail -n $(expr ${log_num} - ${_max_log_backup}) | xargs -i rm -f {} + fi + fi +} + +check_log_file() +{ + log_path=$1 + log_file=$2 + operation=$3 + # max log file size 16 * 1024 * 1024 + MAX_LOG_SIZE=16777216 + MAX_LOG_BACKUP=10 + log_file_size=$(ls -l ${log_file} |awk '{print $5}') + if [ -f ${log_file} ];then + if [ ${log_file_size} -ge ${MAX_LOG_SIZE} ];then + mv -f ${log_file} "${log_path}/${operation}-$(date +%Y-%m-%d_%H%M%S).log" 2>/dev/null + clear_script_log "${log_path}" "${operation}-" $MAX_LOG_BACKUP + fi + fi +} + +touch_logfile() +{ + log_file=$1 + if [ ! -f "$log_file" ] + then + touch "$log_file" + fi +} diff --git a/install/initwr.sh b/install/initwr.sh new file mode 100644 index 0000000000000000000000000000000000000000..000aa87c71b71f88917cd31f6776e9b75262376f --- /dev/null +++ b/install/initwr.sh @@ -0,0 +1,90 @@ +#!/bin/bash +# +# Copyright (C), 2022-2038, Huawei Tech. Co., Ltd. +# File Name : init_wr.sh +# Description : init wr +# +set -e + +declare VG_COUNT=0 +declare -a VG_NAME +declare -a VOLUMN_NAME + +curr_path=$(dirname $(readlink -f $0)) +curr_filename=$(basename $(readlink -f $0)) +os_user=$(whoami) +file_user=$(ls -l ${curr_path}"/${curr_filename}" | awk '{print $3}') + +if [ ${file_user} != ${os_user} ]; then + echo "Can't run ${curr_filename}, because it does not belong to the current user!" + exit 1 +fi + +source $(dirname $0)/common_func.sh + +usage() +{ + echo "Usage: $0 [local_datadir]" + echo "local_datadir:" + echo " local datadir" +} + +if [[ $# -ne 1 ]] +then + log "parameter numbers not meet, num=$#." + usage + exit 255 +fi + +#variables +assert_nonempty 1 ${1} +LOCAL_DATADIR=$1 + +check_wr_config() +{ + log "Checking wr_inst.ini before start wr..." + if [[ ! -e ${LOCAL_DATADIR}/cfg/wr_inst.ini ]] + then + log "${LOCAL_DATADIR}/cfg/wr_inst.ini must exist" + exit 255 + fi + + log "Checking wr_vg_conf.ini before start wr..." + if [[ ! -e ${LOCAL_DATADIR}/cfg/wr_vg_conf.ini ]] + then + log "${LOCAL_DATADIR}/cfg/wr_vg_conf.ini must exist" + exit 255 + fi +} + +get_vg_data() +{ + FILE_NAME=${LOCAL_DATADIR}/cfg/wr_vg_conf.ini + while read line + do + echo $line >>/dev/null + if [[ $? == 0 ]] ;then + let VG_COUNT++ + VG_NAME[$VG_COUNT]=$(echo $line | awk -F ":" '{print $1}') + VOLUME_NAME[$VG_COUNT]=$(echo $line | awk -F ":" '{print $2}') + fi + done <$FILE_NAME +} + +create_vg() +{ + export WR_HOME=${LOCAL_DATADIR} + for((i=1;i<=${VG_COUNT};i++)) + do + echo "> creating volume group ${VG_NAME[$i]}" + chmod 600 ${VOLUME_NAME[$i]} + dd if=/dev/zero bs=2048 count=1000 of=${VOLUME_NAME[$i]} + wrcmd cv -g ${VG_NAME[$i]} -v ${VOLUME_NAME[$i]} -D ${LOCAL_DATADIR} >> /dev/null 2>&1 + done +} + +check_wr_config +get_vg_data +create_vg +echo "initwr success." +exit 0 diff --git a/install/wr_clear.sh b/install/wr_clear.sh new file mode 100644 index 0000000000000000000000000000000000000000..293d367c15d3b9b744d21589a01949a53cde86a3 --- /dev/null +++ b/install/wr_clear.sh @@ -0,0 +1,310 @@ +#!/bin/bash +# +# Copyright (C), 2022-2038, Huawei Tech. Co., Ltd. +# File Name : wr_clear.sh +# Description : clear wr +# + +curr_path=$(dirname $(readlink -f $0)) +curr_filename=$(basename $(readlink -f $0)) +os_user=$(whoami) +file_user=$(ls -l ${curr_path}"/${curr_filename}" | awk '{print $3}') + +if [ ${file_user} != ${os_user} ]; then + echo "Can't run ${curr_filename}, because it does not belong to the current user!" + exit 1 +fi + +usage() +{ + echo "Usage: $0 [WR_HOME] [type]" + echo "WR_HOME:" + echo " wrserver data path" + echo "type:" + echo " if type is NULL, default value is unregister" + echo " -clearshm: clean share memory used by wr" + echo " -clearVg: Clearing and Recreating Vg base on your backup information" + echo " Usage: $0 [WR_HOME] -clearVg [backup_file] [except_vg_name]" + echo " backup_file:" + echo " backup information file path, get backup_file from wrcmd lsvg -t d" + echo " except_vg_name:" + echo " --except_vg_name=xxx, xxx is vg name which you do not want to clear" + echo " if you want to clear all vg, just do not put the param" +} + +if [ $# -lt 1 ] +then + echo "parameter numbers not meet, num=$#." + usage + exit 1 +fi + +assert_nonempty() +{ + if [[ -z "${2}" ]] + then + echo "[SCRIPT]The ${1} parameter is empty." + exit 1 + fi +} + +assert_nonempty 1 ${1} +export WR_HOME=${1} +CMD=${2} +clear_wr_log=${WR_HOME}/clear_wr.log + +log() +{ + time=$(date "+%Y-%m-%d %H:%M:%S") + echo "[$time][WR]$1" + echo "[$time][WR]$1" >> ${clear_wr_log} 2>&1 +} + +function check_wr_config() +{ + log "Checking wr_inst.ini before wr clear" + if [[ ! -e ${WR_HOME}/cfg/wr_inst.ini ]] + then + log "${WR_HOME}/cfg/wr_inst.ini must exist" + exit 1 + fi + + log "Checking wr_vg_conf.ini before wr clear" + if [[ ! -e ${WR_HOME}/cfg/wr_vg_conf.ini ]] + then + log "${WR_HOME}/cfg/wr_vg_conf.ini must exist" + exit 1 + fi +} + +create_log_directory() +{ + log_directory=$1 + if [ ! -d "$log_directory" ] + then + mkdir -p $log_directory + chmod 700 $log_directory + fi +} + +touch_logfile() +{ + log_file=$1 + if [ ! -f "$log_file" ] + then + touch $log_file + chmod 600 $log_file + fi +} + +get_clear_wr_log() +{ + LOG_HOME=$(cat ${WR_HOME}/cfg/wr_inst.ini | sed s/[[:space:]]//g | grep -Eo "^LOG_HOME=.*" | awk -F '=' '{ print $2 }') + if [[ ! -z "${LOG_HOME}" ]] + then + create_log_directory ${LOG_HOME} + clear_wr_log=${LOG_HOME}/clear_wr.log + touch_logfile $clear_wr_log + else + if [[ ! -d "${WR_HOME}" ]] + then + clear_wr_log=/dev/null + else + touch_logfile $clear_wr_log + fi + fi +} + +function parse_vg_info() +{ + vg_flag=0 + volume_count=0 + p_vg_volume_index=0 + while read line + do + if [[ "$line" == *volume_name:* ]]; then + if [[ "$volume_count" == "0" ]] || [[ "$vg_flag" != "2" ]]; then + log "[CLEARVG]Invalid vg info file!" + exit 1 + fi + volume_name=${line:12} + VOLUME_NAME[$p_vg_volume_index]=$volume_name + let volume_count-- + let p_vg_volume_index++ + if [[ "$volume_count" == "0" ]]; then + let VG_COUNT++ + vg_flag=0 + fi + elif [[ "$line" == *vg_name:* ]]; then + if [[ "$volume_count" != "0" ]] || [[ "$vg_flag" != "0" ]]; then + log "[CLEARVG]Invalid vg info file!" + exit 1 + fi + vg_name=${line:8} + let vg_flag++ + volume_count=0 + VG_NAME[$VG_COUNT]=$vg_name + continue + elif [[ "$line" == *volume_count:* ]]; then + if [[ "$volume_count" != "0" ]] || [[ "$vg_flag" != "1" ]]; then + log "[CLEARVG]Invalid vg info file!" + exit 1 + fi + let vg_flag++ + volume_count=${line:13} + VOLUME_COUNT[$VG_COUNT]=$volume_count + fi + done <$VG_INFO_FILE + + if [[ "$p_vg_volume_index" == "0" ]]; then + log "[CLEARVG]Invalid vg info file, volume count is 0!" + exit 1 + elif [[ "$vg_flag" != "0" ]]; then + log "[CLEARVG]Invalid vg info file!" + exit 1 + fi +} + +function check_except_param() +{ + except_param=$1 + if [[ "$except_param" == --except_vg_name=* ]]; then + EXCEPT=${except_param:17} + log "[CLEARVG]except_vg_name is $EXCEPT" + elif [[ -z "$except_param" ]]; then + log "[CLEARVG]except_vg_name is NULL" + else + log "[CLEARVG]Invalid except_vg_name parameter!" + exit 1 + fi + except_flag=0 + for ((i=0; i<$VG_COUNT; i++)); do + if [[ ${VG_NAME["$i"]} == "$EXCEPT" ]]; then + if [[ "$except_flag" == "1" ]]; then + log "[CLEARVG]Except_vg_name match two vg, please check parameter or backup file!" + exit 1 + fi + let except_flag++ + continue + fi + done + if [[ ! -z "$except_param" ]] && [[ "$except_flag" == "0" ]]; then + log "[CLEARVG]Invalid except_vg_name parameter, not match vg name" + exit 1 + fi +} + +function clear_vg() +{ + if [ $# -ne 4 ] && [ $# -ne 3 ] + then + log "[CLEARVG]-clearVg parameter numbers not meet 3 or 4, num=$#." + usage + exit 1 + fi + declare -a VG_NAME + declare -a VOLUME_COUNT + declare -a VOLUME_NAME + assert_nonempty 3 ${3} + VG_COUNT=0 + VG_INFO_FILE=$3 + CLEAR_VG_EXCEPT=$4 + parse_vg_info + volume_index=0 + check_except_param $4 + for ((i=0; i<$VG_COUNT; i++)); do + if [[ ${VG_NAME["$i"]} == "$CLEAR_VG_EXCEPT" ]]; then + log "[CLEARVG]except_vg_name, skip clear Vg:${VG_NAME[$i]}, volume count:${VOLUME_COUNT[$i]}" + volume_index=$(($volume_index+${VOLUME_COUNT[$i]})) + continue + fi + log "[CLEARVG]Begin to clear Vg ${VG_NAME[$i]}, ${VOLUME_COUNT[$i]}" + for ((j=0; j<${VOLUME_COUNT[$i]}; j++)); do + log "[CLEARVG]Begin to clear volume is ${VOLUME_NAME[$volume_index]}" + if [[ "$j" == "0" ]]; then + log "[CLEARVG]Clear vg:${VG_NAME[$i]}, volume:${VOLUME_NAME[$volume_index]}, index:$j" + dd if=/dev/zero of=${VOLUME_NAME[$volume_index]} bs=512 count=1 seek=0 conv=notrunc + log "[CLEARVG]wrcmd create vg:${VG_NAME[$i]} volume:${VOLUME_NAME[$volume_index]}, home:$WR_HOME" + wrcmd cv -g ${VG_NAME[$i]} -v ${VOLUME_NAME[$volume_index]} -D $WR_HOME + let volume_index++ + continue + fi + log "[CLEARVG]Clear vg:${VG_NAME[$i]}, volume:${VOLUME_NAME[$volume_index]}, index:$j" + dd if=/dev/zero of=${VOLUME_NAME[$volume_index]} bs=512 count=1 seek=0 conv=notrunc + log "[CLEARVG]wrcmd add volume vg:${VG_NAME[$i]} volume:${VOLUME_NAME[$volume_index]}" + expect << EOF + set timeout -1 + spawn wrcmd adv -g ${VG_NAME[$i]} -v ${VOLUME_NAME[$volume_index]} -f + expect { + "Please ensure that the cluster is stopped, enter yes*" { send "yes\r"; exp_continue } + } + expect eof + exit +EOF + let volume_index++ + continue + done + done + log "[CLEARVG]Success to clear Vg" +} + +function unregister() +{ + LOCAL_INSTANCE_ID=$(awk '/INST_ID/{print}' ${WR_HOME}/cfg/wr_inst.ini | awk -F= '{print $2}' | xargs) + if [[ -z ${LOCAL_INSTANCE_ID} ]] + then + log "[UNREG]can't find inst id. Aborting." + exit 1 + fi + + log "[UNREG] Start unreg." + wrcmd unreghl -t 0 -D ${WR_HOME} >> /dev/null 2>&1 + log "[UNREG] Unreg success." +} + +function cleanshmkey() +{ + groups=`ipcs -m|awk '{ print $1 }'` + array=(${groups// / }) + LOCAL_INSTANCE_ID=`cat ${WR_HOME}/cfg/wr_inst.ini | sed s/[[:space:]]//g | grep -Eo "^INST_ID=.*" | awk -F '=' '{ print $2 }'` + LOCAL_SHM_KEY=`cat ${WR_HOME}/cfg/wr_inst.ini | sed s/[[:space:]]//g | grep -Eo "^_SHM_KEY=.*" | awk -F '=' '{ print $2 }'` + CM_GA_SHM_MAX_ID=20480 + CM_FIXED_SHM_ID_TAIL=3 + CM_HASH_SHM_MAX_ID=65 + WR_MAX_SHM_KEY_BITS=8 + WR_MAX_SHM_ID=$((CM_FIXED_SHM_ID_TAIL + CM_HASH_SHM_MAX_ID + CM_GA_SHM_MAX_ID)) + SHM_KEY=$(((LOCAL_SHM_KEY << WR_MAX_SHM_KEY_BITS) + LOCAL_INSTANCE_ID)) + log "[CLEANSHMKEY]Begin to cleanshmkey, shm key is $SHM_KEY" + MIN_SHM_KEY=$((((SHM_KEY & 0xFFFF) << 16) | (1 & 0xFFFF))) + MAX_SHM_KEY=$((((SHM_KEY & 0xFFFF) << 16) | (WR_MAX_SHM_ID & 0xFFFF))) + for var in "${array[@]}" + do + if [[ $var =~ "0x" ]]; then + SHM_CHECK_KEY=$(printf "%u" $var) + if ((SHM_CHECK_KEY >= MIN_SHM_KEY && SHM_CHECK_KEY <= MAX_SHM_KEY)); then + echo $var + ipcrm -M $SHM_CHECK_KEY + fi + fi + done + log "[CLEANSHMKEY]Success to cleanshmkey" +} + +function Main() +{ + get_clear_wr_log + check_wr_config + if [ "$CMD" == "-clearshm" ]; then + cleanshmkey + exit 0 + elif [ "$CMD" == "-clearVg" ]; then + clear_vg "$@" + exit 0 + else + unregister + cleanshmkey + exit 0 + fi +} + +Main "$@" \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e542db95fd28bd9e9232f2679e9e7345dcb607bd --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,6 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.12.1) + +ADD_SUBDIRECTORY(interface) +ADD_SUBDIRECTORY(cmd) +ADD_SUBDIRECTORY(service) + diff --git a/src/cmd/CMakeLists.txt b/src/cmd/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..eb1f09c8d2678e20a23a4a0e8cc6d30e3323a690 --- /dev/null +++ b/src/cmd/CMakeLists.txt @@ -0,0 +1,53 @@ +## include +include_directories(${WR_COMMON_PATH}) +include_directories(${WR_COMMON_PATH}/persist) +include_directories(${WR_LOG_PATH}) +include_directories(${WR_PARAMS_PATH}) +include_directories(${WR_COMMON_API_PATH}) +include_directories(${WR_INTERFACE_PATH}) +include_directories(${WR_HOTPATCH_PATH}) + +option(ENABLE_FUZZASAN OFF) +if (ENABLE_FUZZASAN) + add_compile_options(-fsanitize-coverage=trace-pc) +endif (ENABLE_FUZZASAN) + +## other dependency include +include_directories(${WR_SECUREC_INC_PATH}) +include_directories(${WR_OPENSSL_PATH}) +include_directories(${WR_CBB_PATH}) + +aux_source_directory(${WR_COMMON_PATH} COMMON_SRC) +aux_source_directory(${WR_COMMON_PATH}/persist COMMON_SRC) +aux_source_directory(${WR_LOG_PATH} LOG_SRC) +aux_source_directory(${WR_PARAMS_PATH} PARAMS_SRC) +aux_source_directory(${WR_COMMON_API_PATH} COMMON_API_SRC) +aux_source_directory(${WR_CMD_PATH} CMD_SRC) + +link_directories(${LIBRARY_OUTPUT_PATH} ${CBB_LIB_PATH}) + +set(COMMON_ALL_SRC + ${COMMON_SRC} + ${LOG_SRC} + ${PARAMS_SRC} + ${COMMON_API_SRC} + ${CMD_SRC} + ) + +ADD_EXECUTABLE(wrcmd ${COMMON_ALL_SRC}) + +if (ENABLE_FUZZASAN) + target_link_libraries(wrcmd wrapi pthread dl rt -Wl,--whole-archive ${vpp_libsecurec} ${libz} ${lz4} ${3rd_libssl} ${3rd_libccb} ${vpp_libipsi_crypto} ${fuzz_lib} -Wl,--no-whole-archive) +else() + target_link_libraries(wrcmd wrapi pthread dl rt -Wl,--whole-archive ${vpp_libsecurec} ${libz} ${lz4} ${3rd_libssl} ${3rd_libccb} ${vpp_libipsi_crypto} -Wl,--no-whole-archive) +endif(ENABLE_FUZZASAN) + +if (ENABLE_WRTEST) + add_library(wrcmd_test SHARED ${COMMON_ALL_SRC}) + if (ENABLE_FUZZASAN) + target_link_libraries(wrcmd_test wrapi pthread dl rt -Wl,--whole-archive ${vpp_libsecurec} ${libz} ${lz4} ${3rd_libssl} ${3rd_libccb} ${vpp_libipsi_crypto} ${fuzz_lib} -Wl,--no-whole-archive) + else() + target_link_libraries(wrcmd_test wrapi pthread dl rt -Wl,--whole-archive ${vpp_libsecurec} ${libz} ${lz4} ${3rd_libssl} ${3rd_libccb} ${vpp_libipsi_crypto} -Wl,--no-whole-archive) + endif(ENABLE_FUZZASAN) +endif(ENABLE_WRTEST) + diff --git a/src/cmd/wrcmd.c b/src/cmd/wrcmd.c new file mode 100644 index 0000000000000000000000000000000000000000..0a74b04db170ad1efb314a91d0bd7000cb5c68b5 --- /dev/null +++ b/src/cmd/wrcmd.c @@ -0,0 +1,2137 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wrcmd.c + * + * + * IDENTIFICATION + * src/cmd/wrcmd.c + * + * ------------------------------------------------------------------------- + */ + +#ifndef WIN32 +#include +#include +#endif + +#include "cm_base.h" +#include "cm_config.h" +#include "cm_dlock.h" +#include "cm_list.h" +#include "cm_system.h" +#include "cm_cipher.h" +#include "cm_encrypt.h" +#include "cm_utils.h" +#include "cm_signal.h" +#include "cm_sec_file.h" + +#include "wr_errno.h" +#include "wr_defs.h" +#include "wr_malloc.h" +#include "wr_file.h" +#include "wr_io_fence.h" +#include "wr_api.h" +#include "wr_api_impl.h" +#include "wrcmd_inq.h" +#include "wrcmd_encrypt.h" +#include "wrcmd_conn_opt.h" +#include "wrcmd_interactive.h" +#include "wr_cli_conn.h" +#ifndef WIN32 +#include "config.h" +#endif + +#ifdef WIN32 +#define DEF_WR_VERSION "Windows does not support this feature because it is built using vs." +#endif + +// cmd format : cmd subcmd [-f val] +#define CMD_COMMAND_INJECTION_COUNT 22 +#define WR_DEFAULT_MEASURE "B" +#define WR_SUBSTR_UDS_PATH "UDS:" +#define WR_DEFAULT_VG_TYPE 't' /* show vg information in table format by default */ +static const char wr_ls_print_flag[] = {'d', '-', 'l'}; + +typedef struct st_wr_print_help_t { + char fmt; + uint32 bytes; +} wr_print_help_t; + +// add uni-check function after here +// ------------------------ +static status_t cmd_check_flag(const char *input_flag) +{ + uint64 flag; + status_t ret = cm_str2uint64(input_flag, &flag); + if (ret != CM_SUCCESS) { + WR_PRINT_ERROR("The value of flag is invalid.\n"); + return CM_ERROR; + } + if (flag != 0 && flag != WR_FILE_FLAG_INNER_INITED) { + WR_PRINT_ERROR("The value of flag must be 0 or 2147483648(means 0x80000000).\n"); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t cmd_check_length(const char *input_length) +{ + uint64 length; + status_t ret = cm_str2uint64(input_length, &length); + if (ret != CM_SUCCESS) { + WR_PRINT_ERROR("The value of length is invalid.\n"); + return CM_ERROR; + } + if ((int64)length < 0) { + WR_PRINT_ERROR("The value of length must not be a negative number.\n"); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t cmd_check_zero_or_one(const char *zero_or_one_str) +{ + uint32 zero_or_one; + status_t ret = cm_str2uint32(zero_or_one_str, &zero_or_one); + if (ret != CM_SUCCESS) { + WR_PRINT_ERROR("The value of zero_or_one is invalid.\n"); + return CM_ERROR; + } + if (zero_or_one != 0 && zero_or_one != 1) { + WR_PRINT_ERROR("The value of zero_or_one should be 0 or 1.\n"); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t cmd_check_uds(const char *uds) +{ + const char *uds_prefix = "UDS:"; + /* if uds path only has "UDS:", it is invalid */ + if (strlen(uds) <= strlen(uds_prefix) || memcmp(uds, uds_prefix, strlen(uds_prefix)) != 0) { + WR_PRINT_ERROR("uds name should start with %s, also it should not be empty.\n", uds_prefix); + return CM_ERROR; + } + return wr_check_path(uds + strlen(uds_prefix)); +} + +static status_t wr_fetch_uds_path(char *server_path, char *path, char **file) +{ + char *pos = strrchr(server_path, '/'); + if (pos == NULL) { + *file = server_path; + path[0] = '.'; + path[1] = '\0'; + return CM_SUCCESS; + } + + if (pos[1] == 0x00) { + WR_PRINT_ERROR("the format of UDS is wrong.\n"); + return CM_ERROR; + } + + if (pos == server_path) { + *file = (char *)(server_path + 1); + path[0] = '/'; + path[1] = '\0'; + } else { + *file = pos; + errno_t errcode = memcpy_sp(path, (size_t)WR_MAX_PATH_BUFFER_SIZE, server_path, (size_t)(pos - server_path)); + if (SECUREC_UNLIKELY(errcode != EOK)) { + CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode); + return CM_ERROR; + } + path[(int)(pos - server_path)] = '\0'; + } + return CM_SUCCESS; +} + +static status_t cmd_check_convert_uds_home(const char *input_args, void **convert_result, int *convert_size) +{ + const char *server_path = (const char *)(input_args + strlen(WR_SUBSTR_UDS_PATH)); + char path[WR_MAX_PATH_BUFFER_SIZE]; + char *file = NULL; + status_t status = wr_fetch_uds_path((char *)server_path, (char *)path, (char **)&file); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Fetch uds path failed.\n"); + return CM_ERROR; + } + + status = cmd_realpath_home(path, (char **)convert_result, convert_size); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("home realpath failed, home: %s.\n", input_args); + return status; + } + + errno_t errcode = strcat_sp((char *)*convert_result, CM_FILE_NAME_BUFFER_SIZE, file); + if (SECUREC_UNLIKELY(errcode != EOK)) { + CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode); + free(*convert_result); + *convert_result = NULL; + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t cmd_check_measure_type(const char *measure) +{ + if (strlen(measure) != 1) { + WR_PRINT_ERROR("The measure type len should be 1.\n"); + return CM_ERROR; + } + if ((measure[0] != 'B' && measure[0] != 'K' && measure[0] != 'M' && measure[0] != 'G' && measure[0] != 'T')) { + WR_PRINT_ERROR("measure_type error.\n"); + return CM_ERROR; + } + + return CM_SUCCESS; +} + +static status_t cmd_check_inst_id(const char *inst_str) +{ + uint32 inst_id; + status_t ret = cm_str2uint32(inst_str, &inst_id); + if (ret != CM_SUCCESS) { + WR_PRINT_ERROR("The value of inst_id is invalid.\n"); + return CM_ERROR; + } + if (inst_id < WR_MIN_INST_ID || inst_id >= WR_MAX_INST_ID) { + WR_PRINT_ERROR("The value of inst_id should be in [%u, %u).\n", WR_MIN_INST_ID, WR_MAX_INST_ID); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t cmd_check_inq_type(const char *inq_type) +{ + if (strcmp(inq_type, "lun") != 0 && strcmp(inq_type, "reg") != 0) { + WR_PRINT_ERROR("The show type should be [lun|reg].\n"); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t cmd_check_offset(const char *offset_str) +{ + int64 offset; + status_t ret = cm_str2bigint(offset_str, &offset); + if (ret != CM_SUCCESS) { + WR_PRINT_ERROR("The value of offset is invalid.\n"); + return CM_ERROR; + } + if (offset < 0 || offset % WR_DISK_UNIT_SIZE != 0) { + WR_PRINT_ERROR("offset must be >= 0 and be align %d.\n", WR_DISK_UNIT_SIZE); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t cmd_check_format(const char *format) +{ + uint32 len = strlen(format); + if (len == 0) { + WR_PRINT_ERROR("The value of format is invalid.\n"); + return CM_ERROR; + } + if (format[0] != 'c' && format[0] != 'h' && format[0] != 'u' && format[0] != 'l' && format[0] != 's' && + format[0] != 'x') { + WR_PRINT_ERROR("The name's letter of format should be [c|h|u|l|s|x].\n"); + return CM_ERROR; + } + if (format[1] != 0x00) { + WR_PRINT_ERROR("The name's letter of format should be [c|h|u|l|s|x].\n"); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t cmd_check_read_size(const char *read_size_str) +{ + int32 read_size; + status_t ret = cm_str2int(read_size_str, &read_size); + if (ret != CM_SUCCESS) { + WR_PRINT_ERROR("The value of read_size is invalid.\n"); + return CM_ERROR; + } + + if (read_size < 0) { + WR_PRINT_ERROR("The read_size should >= 0.\n"); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t cmd_check_cfg_name(const char *name) +{ + uint32 len = strlen(name); + for (uint32 i = 0; i < len; i++) { + if (!isalpha((int)name[i]) && !isdigit((int)name[i]) && name[i] != '-' && name[i] != '_') { + WR_PRINT_ERROR("The name's letter should be [alpha|digit|-|_].\n"); + return CM_ERROR; + } + } + return CM_SUCCESS; +} + +static status_t cmd_check_cfg_value(const char *value) +{ + uint32 len = strlen(value); + if (len < 0) { + WR_PRINT_ERROR("The value is invalid.\n"); + return CM_ERROR; + } + for (uint32 i = 0; i < len; i++) { + if (!isprint((int)value[i])) { + WR_PRINT_ERROR("The value's letter should be print-able.\n"); + return CM_ERROR; + } + } + return CM_SUCCESS; +} + +static status_t cmd_check_cfg_scope(const char *scope) +{ + const char *scope_memory = "memory"; + const char *scope_pfile = "pfile"; + const char *scope_both = "both"; + if (strcmp(scope, scope_memory) != 0 && strcmp(scope, scope_pfile) != 0 && strcmp(scope, scope_both) != 0) { + WR_PRINT_ERROR("scope should be [%s | %s | %s].\n", scope_memory, scope_pfile, scope_both); + return CM_ERROR; + } + return CM_SUCCESS; +} + +// ------------------------ +// add uni-check function before here +static inline void help_param_wrhome(void) +{ + (void)printf("-D/--WR_HOME , [optional], the run path of wrserver, default value is $WR_HOME\n"); +} + +static inline void help_param_uds(void) +{ + (void)printf("-U/--UDS , [optional], the unix socket path of wrserver, " + "default value is UDS:$WR_HOME/.wr_unix_d_socket\n"); +} + +double wr_convert_size(double size, const char *measure) +{ + double result = size; + switch (measure[0]) { + case 'T': + result /= SIZE_T(1); + break; + case 'G': + result /= SIZE_G(1); + break; + case 'M': + result /= SIZE_M(1); + break; + case 'K': + result /= SIZE_K(1); + break; + default: + break; + } + return result; +} + +static void cmd_print_no_path_err() +{ + WR_PRINT_ERROR("Need to input arg [-p|--path] or cd to a path.\n"); +} + +static wr_args_t cmd_mkdir_args[] = { + {'p', "path", CM_TRUE, CM_TRUE, wr_cmd_check_device_path, cmd_check_convert_path, cmd_clean_check_convert, 0, NULL, + NULL, 0}, + {'d', "dir_name", CM_TRUE, CM_TRUE, wr_check_name, NULL, NULL, 0, NULL, NULL, 0}, + {'U', "UDS", CM_FALSE, CM_TRUE, cmd_check_uds, cmd_check_convert_uds_home, cmd_clean_check_convert, 0, NULL, NULL, + 0}, +}; +static wr_args_set_t cmd_mkdir_args_set = { + cmd_mkdir_args, + sizeof(cmd_mkdir_args) / sizeof(wr_args_t), + NULL, +}; + +static void mkdir_help(const char *prog_name, int print_flag) +{ + if (g_run_interatively) { + (void)printf("\nUsage:%s mkdir <-d dir_name> [-p path] [-U UDS:socket_domain]\n", prog_name); + } else { + (void)printf("\nUsage:%s mkdir <-p path> <-d dir_name> [-U UDS:socket_domain]\n", prog_name); + } + (void)printf("[client command]make dir\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + if (g_run_interatively) { + (void)printf("-p/--path , [optional], the name need to add dir\n"); + } else { + (void)printf("-p/--path , , the name need to add dir\n"); + } + (void)printf("-d/--dir_name , , the dir name need to be added to path\n"); + help_param_uds(); +} + +static status_t mkdir_proc(void) +{ + const char *path = cmd_mkdir_args[WR_ARG_IDX_0].input_args; + if (cmd_mkdir_args[WR_ARG_IDX_0].convert_result != NULL) { + path = cmd_mkdir_args[WR_ARG_IDX_0].convert_result; + } + if (path == NULL) { + if (g_cur_path[0] == '\0') { + cmd_print_no_path_err(); + return CM_ERROR; + } + path = g_cur_path; + } + + const char *dir_name = cmd_mkdir_args[WR_ARG_IDX_1].input_args; + const char *uds_path = cmd_mkdir_args[WR_ARG_IDX_2].input_args; + wr_conn_t *conn = wr_get_connection_opt(uds_path); + if (conn == NULL) { + return CM_ERROR; + } + status_t status = wr_vfs_create_impl(conn, dir_name); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to make dir, path is %s, dir name is %s.\n", path, dir_name); + } else { + WR_PRINT_INF("Succeed to make dir, path is %s, dir name is %s.\n", path, dir_name); + } + return status; +} + +#define WR_CMD_TOUCH_ARGS_PATH 0 +#define WR_CMD_TOUCH_ARGS_UDS 1 +#define WR_CMD_TOUCH_ARGS_FLAG 2 +static wr_args_t cmd_touch_args[] = { + {'p', "path", CM_TRUE, CM_TRUE, wr_cmd_check_device_path, cmd_check_convert_path, cmd_clean_check_convert, 0, NULL, + NULL, 0}, + {'U', "UDS", CM_FALSE, CM_TRUE, cmd_check_uds, cmd_check_convert_uds_home, cmd_clean_check_convert, 0, NULL, NULL, + 0}, + {'f', "flag", CM_FALSE, CM_TRUE, cmd_check_flag, NULL, NULL, 0, NULL, NULL, 0}, +}; +static wr_args_set_t cmd_touch_args_set = { + cmd_touch_args, + sizeof(cmd_touch_args) / sizeof(wr_args_t), + NULL, +}; + +static void touch_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s touch <-p path> [-U UDS:socket_domain]\n", prog_name); + (void)printf("[client command]create file\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + if (g_run_interatively) { + (void)printf("-p/--path , , file need to touch\n"); + } else { + (void)printf("-p/--path , , file need to touch, path must begin with '+'\n"); + } + (void)printf("-f/--flag , [optional], file flag need to set\n"); + help_param_uds(); +} + +static status_t touch_proc(void) +{ + const char *path = cmd_touch_args[WR_CMD_TOUCH_ARGS_PATH].input_args; + if (cmd_touch_args[WR_CMD_TOUCH_ARGS_PATH].convert_result != NULL) { + path = cmd_touch_args[WR_CMD_TOUCH_ARGS_PATH].convert_result; + } + + const char *input_args = cmd_touch_args[WR_CMD_TOUCH_ARGS_UDS].input_args; + wr_conn_t *conn = wr_get_connection_opt(input_args); + if (conn == NULL) { + return CM_ERROR; + } + + int64 flag = 0; + if (cmd_touch_args[WR_CMD_TOUCH_ARGS_FLAG].inputed) { + status_t status = cm_str2bigint(cmd_touch_args[WR_CMD_TOUCH_ARGS_FLAG].input_args, &flag); + if (status != CM_SUCCESS) { + return status; + } + } + + status_t status = (status_t)wr_create_file_impl(conn, path, (int32)flag); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to create file, name is %s.\n", path); + } else { + WR_PRINT_INF("Succeed to create file, name is %s.\n", path); + } + return status; +} + +static wr_args_t cmd_ts_args[] = { + {'U', "UDS", CM_FALSE, CM_TRUE, cmd_check_uds, cmd_check_convert_uds_home, cmd_clean_check_convert, 0, NULL, NULL, + 0}, +}; + +static wr_args_set_t cmd_ts_args_set = { + cmd_ts_args, + sizeof(cmd_ts_args) / sizeof(wr_args_t), + NULL, +}; + +static void ts_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s ts [-U UDS:socket_domain]\n", prog_name); + (void)printf("[client command]Show current API invoking time\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + help_param_uds(); +} + +static status_t ts_proc(void) +{ + status_t status = CM_SUCCESS; + const char *input_args = cmd_ts_args[WR_ARG_IDX_0].input_args; + wr_conn_t *conn = wr_get_connection_opt(input_args); + if (conn == NULL) { + return CM_ERROR; + } + + wr_stat_item_t time_stat[WR_EVT_COUNT]; + status = wr_get_time_stat_on_server(conn, time_stat, WR_EVT_COUNT); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to get time stat.\n"); + return CM_ERROR; + } + (void)printf("| event | count | total_wait_time | avg_wait_time | max_single_time \n"); + (void)printf("+------------------------+-----------+-----------------+---------------+-----------------\n"); + for (int i = 0; i < WR_EVT_COUNT; i++) { + if (time_stat[i].wait_count == 0) { + (void)printf("|%-24s|%-11d|%-17d|%-15d|%-17d\n", wr_get_stat_event(i), 0, 0, 0, 0); + continue; + } + (void)printf("|%-24s|%-11lld|%-17lld|%-15lld|%-17lld\n", wr_get_stat_event(i), time_stat[i].wait_count, + time_stat[i].total_wait_time, time_stat[i].total_wait_time / time_stat[i].wait_count, + time_stat[i].max_single_time); + } + (void)printf("+------------------------+-----------+-----------------+---------------+-----------------\n"); + return CM_SUCCESS; +} + +#define WR_CMD_LS_PATH_IDX 0 +#define WR_CMD_LS_MEASURE_IDX 1 +#define WR_CMD_LS_UDS_IDX 2 +#define WR_CMD_LS_MIN_INITED_SIZE 3 + +static wr_args_t cmd_ls_args[] = { + {'p', "path", CM_TRUE, CM_TRUE, wr_cmd_check_device_path, cmd_check_convert_path, cmd_clean_check_convert, 0, NULL, + NULL, 0}, + {'m', "measure_type", CM_FALSE, CM_TRUE, cmd_check_measure_type, NULL, NULL, 0, NULL, NULL, 0}, + {'U', "UDS", CM_FALSE, CM_TRUE, cmd_check_uds, cmd_check_convert_uds_home, cmd_clean_check_convert, 0, NULL, NULL, + 0}, + {'w', "min_inited_size", CM_FALSE, CM_TRUE, cmd_check_zero_or_one, NULL, NULL, 0, NULL, NULL, 0}, +}; + +static wr_args_set_t cmd_ls_args_set = { + cmd_ls_args, + sizeof(cmd_ls_args) / sizeof(wr_args_t), + NULL, +}; + +static void ls_help(const char *prog_name, int print_flag) +{ + if (g_run_interatively) { + (void)printf( + "\nUsage:%s ls [-p path] [-m measure_type] [-w min_inited_size] [-U UDS:socket_domain]\n", prog_name); + } else { + (void)printf( + "\nUsage:%s ls <-p path> [-m measure_type] [-w min_inited_size] [-U UDS:socket_domain]\n", prog_name); + } + (void)printf("[client command]Show information of volume group and disk usage space\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + if (g_run_interatively) { + (void)printf("-p/--path , [optional], show information for it\n"); + } else { + (void)printf("-p/--path , , show information for it\n"); + } + (void)printf("-m/--measure_type , [optional], B show size by Byte, K show size by kB ," + "M show size by MB ,G show size by GB, T show size by TB, default show size by Byte\n"); + (void)printf("-w/ --min_inited_size , [optional], " + "1 show min_inited_size, 0 not show min_inited_size\n"); + help_param_uds(); +} + +static status_t ls_get_parameter(const char **path, const char **measure, uint32 *show_min_inited_size) +{ + *path = cmd_ls_args[WR_CMD_LS_PATH_IDX].input_args; + if (cmd_ls_args[WR_CMD_LS_PATH_IDX].convert_result != NULL) { + *path = cmd_ls_args[WR_CMD_LS_PATH_IDX].convert_result; + } + if (*path == NULL) { + if (g_cur_path[0] == '\0') { + cmd_print_no_path_err(); + return CM_ERROR; + } + *path = g_cur_path; + } + + char *ls_measure_input_args = cmd_ls_args[WR_CMD_LS_MEASURE_IDX].input_args; + *measure = ls_measure_input_args != NULL ? ls_measure_input_args : WR_DEFAULT_MEASURE; + if (cmd_ls_args[WR_CMD_LS_MIN_INITED_SIZE].input_args == NULL) { + *show_min_inited_size = 0; + } else { + status_t status = cm_str2uint32(cmd_ls_args[WR_CMD_LS_MIN_INITED_SIZE].input_args, show_min_inited_size); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("The value of zero_or_one is invalid.\n"); + return CM_ERROR; + } + } + return CM_SUCCESS; +} + +static void wr_ls_show_base(uint32 show_min_inited_size) +{ + if (show_min_inited_size == 0) { + (void)printf( + "%-5s%-20s%-14s %-14s %-64s%-5s%-5s\n", "type", "time", "size", "written_size", "name", "fid", "node_id"); + } else { + (void)printf("%-5s%-20s%-14s %-14s %-14s %-64s%-5s%-5s\n", "type", "time", "size", "written_size", + "min_inited_size", "name", "fid", "node_id"); + } +} + +static status_t wr_ls_print_node_info(gft_node_t *node, const char *measure, uint32 show_min_inited_size) +{ + char time[512] = {0}; + if (cm_time2str(node->create_time, "YYYY-MM-DD HH24:mi:ss", time, sizeof(time)) != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to get create time of node %s.\n", node->name); + return CM_ERROR; + } + double size = (double)node->size; + if (node->size != 0) { + size = wr_convert_size(size, measure); + } + char type = wr_ls_print_flag[node->type]; + double written_size = (double)node->written_size; + if (node->written_size != 0) { + written_size = wr_convert_size(written_size, measure); + } + if (show_min_inited_size == 0) { + (void)printf("%-5c%-20s%-14.05f %-14.05f %-64s%-5llu%-5llu\n", type, time, size, written_size, node->name, + node->fid, WR_ID_TO_U64(node->id)); + } else { + double min_inited_size = node->min_inited_size; + if (node->min_inited_size != 0) { + min_inited_size = wr_convert_size((double)node->min_inited_size, measure); + } + (void)printf("%-5c%-20s%-14.05f %-14.05f %-14.05f %-64s%-5llu%-5llu\n", type, time, size, written_size, + min_inited_size, node->name, node->fid, WR_ID_TO_U64(node->id)); + } + + return CM_SUCCESS; +} + +static status_t wr_ls_print_file(wr_conn_t *conn, const char *path, const char *measure, uint32 show_min_inited_size) +{ + gft_node_t *node = NULL; + wr_check_dir_output_t output_info = {&node, NULL, NULL, CM_FALSE}; + WR_RETURN_IF_ERROR(wr_check_dir(conn->session, path, GFT_FILE, &output_info, CM_FALSE)); + if (node == NULL) { + LOG_DEBUG_INF("Failed to find path %s with the file type", path); + return CM_ERROR; + } + wr_ls_show_base(show_min_inited_size); + return wr_ls_print_node_info(node, measure, show_min_inited_size); +} + +static status_t ls_proc_core(wr_conn_t *conn, const char *path, const char *measure, uint32 show_min_inited_size) +{ + gft_node_t *node = NULL; + wr_vg_info_item_t *vg_item = NULL; + char name[WR_MAX_NAME_LEN] = {0}; + status_t status = CM_ERROR; + bool32 exist = false; + gft_item_type_t type; + WR_RETURN_IFERR2( + wr_find_vg_by_dir(path, name, &vg_item), WR_PRINT_ERROR("Failed to find vg when ls the path %s.\n", path)); + WR_RETURN_IFERR2( + wr_exist_impl(conn, path, &exist, &type), WR_PRINT_ERROR("Failed to check the path %s exists.\n", path)); + if (!exist) { + WR_PRINT_ERROR("The path %s is not exist.\n", path); + return CM_ERROR; + } + if (type == GFT_FILE) { + WR_LOCK_VG_META_S_RETURN_ERROR(vg_item, conn->session); + status = wr_ls_print_file(conn, path, measure, show_min_inited_size); + WR_UNLOCK_VG_META_S(vg_item, conn->session); + if (status == CM_SUCCESS) { + WR_PRINT_INF("Succeed to ls file info %s.\n", path); + return status; + } + } + wr_vfs_t *dir = wr_open_dir_impl(conn, path, CM_TRUE); + if (dir == NULL) { + WR_PRINT_ERROR("Failed to open dir %s.\n", path); + return CM_ERROR; + } + wr_ls_show_base(show_min_inited_size); + while ((node = wr_read_dir_impl(conn, dir, CM_TRUE)) != NULL) { + status = wr_ls_print_node_info(node, measure, show_min_inited_size); + if (status != CM_SUCCESS) { + (void)wr_close_dir_impl(conn, dir); + return CM_ERROR; + } + } + (void)wr_close_dir_impl(conn, dir); + WR_PRINT_INF("Succeed to ls dir info %s.\n", path); + return CM_SUCCESS; +} + +static status_t ls_proc(void) +{ + const char *path = NULL; + const char *measure = NULL; + uint32 show_min_inited_size = 0; + status_t status = ls_get_parameter(&path, &measure, &show_min_inited_size); + if (status != CM_SUCCESS) { + return status; + } + const char *input_args = cmd_ls_args[WR_CMD_LS_UDS_IDX].input_args; + wr_conn_t *conn = wr_get_connection_opt(input_args); + if (conn == NULL) { + WR_PRINT_ERROR("Failed to get uds connection.\n"); + return CM_ERROR; + } + status = ls_proc_core(conn, path, measure, show_min_inited_size); + return status; +} + +static wr_args_t cmd_rm_args[] = { + {'p', "path", CM_TRUE, CM_TRUE, wr_cmd_check_device_path, cmd_check_convert_path, cmd_clean_check_convert, 0, NULL, + NULL, 0}, + {'U', "UDS", CM_FALSE, CM_TRUE, cmd_check_uds, cmd_check_convert_uds_home, cmd_clean_check_convert, 0, NULL, NULL, + 0}, +}; +static wr_args_set_t cmd_rm_args_set = { + cmd_rm_args, + sizeof(cmd_rm_args) / sizeof(wr_args_t), + NULL, +}; + +static void rm_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s rm <-p path> [-U UDS:socket_domain]\n", prog_name); + (void)printf("[client command]remove device\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + if (g_run_interatively) { + (void)printf("-p/--path , , device path\n"); + } else { + (void)printf("-p/--path , , device path, must begin with '+'\n"); + } + help_param_uds(); +} + +static status_t rm_proc(void) +{ + const char *path = cmd_rm_args[WR_ARG_IDX_0].input_args; + if (cmd_rm_args[WR_ARG_IDX_0].convert_result != NULL) { + path = cmd_rm_args[WR_ARG_IDX_0].convert_result; + } + status_t status = CM_SUCCESS; + const char *input_args = cmd_rm_args[WR_ARG_IDX_1].input_args; + wr_conn_t *conn = wr_get_connection_opt(input_args); + if (conn == NULL) { + return CM_ERROR; + } + + status = wr_remove_file_impl(conn, path); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to remove device %s.\n", path); + } else { + WR_PRINT_INF("Succeed to remove device %s.\n", path); + } + return status; +} + +static wr_args_t cmd_rmdir_args[] = { + {'p', "path", CM_TRUE, CM_TRUE, wr_cmd_check_device_path, cmd_check_convert_path, cmd_clean_check_convert, 0, NULL, + NULL, 0}, + {'r', "recursive", CM_FALSE, CM_FALSE, NULL, NULL, NULL, 0, NULL, NULL, 0}, + {'U', "UDS", CM_FALSE, CM_TRUE, cmd_check_uds, cmd_check_convert_uds_home, cmd_clean_check_convert, 0, NULL, NULL, + 0}, +}; +static wr_args_set_t cmd_rmdir_args_set = { + cmd_rmdir_args, + sizeof(cmd_rmdir_args) / sizeof(wr_args_t), + NULL, +}; + +static void rmdir_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s rmdir <-p path> [-r] [-U UDS:socket_domain path]\n", prog_name); + (void)printf("[client command] remove dir or with it's contents recursively\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + (void)printf("-p/--path , , the name need to remove\n"); + (void)printf("-r/--recursive [optional], remove dir and it's contents recursively\n"); + help_param_uds(); +} + +static status_t rmdir_proc(void) +{ + const char *path = cmd_rmdir_args[WR_ARG_IDX_0].input_args; + if (cmd_rmdir_args[WR_ARG_IDX_0].convert_result != NULL) { + path = cmd_rmdir_args[WR_ARG_IDX_0].convert_result; + } + + status_t status = CM_SUCCESS; + const char *input_args = cmd_rmdir_args[WR_ARG_IDX_2].input_args; + wr_conn_t *conn = wr_get_connection_opt(input_args); + if (conn == NULL) { + return CM_ERROR; + } + + status = wr_vfs_delete_impl(conn, path); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to rm dir, path is %s.\n", path); + } else { + WR_PRINT_INF("Succeed to rm dir, path is %s.\n", path); + } + return status; +} + +static wr_args_t cmd_inq_args[] = { + {'t', "inq_type", CM_TRUE, CM_TRUE, cmd_check_inq_type, NULL, NULL, 0, NULL, NULL, 0}, + {'D', "WR_HOME", CM_FALSE, CM_TRUE, cmd_check_wr_home, cmd_check_convert_wr_home, cmd_clean_check_convert, 0, + NULL, NULL, 0}, +}; +static wr_args_set_t cmd_inq_args_set = { + cmd_inq_args, + sizeof(cmd_inq_args) / sizeof(wr_args_t), + NULL, +}; + +static void inq_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s inq <-t inq_type> [-D WR_HOME]\n", prog_name); + (void)printf("[raid command] inquiry LUN information or reservations\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + (void)printf("-t/--type , , the type need to inquiry, values [lun|reg]" + "lun :inquiry LUN information, reg:inquiry reservations\n"); + help_param_wrhome(); +} + +static status_t inq_proc(void) +{ + return CM_SUCCESS; +} + +static wr_args_t cmd_inq_req_args[] = { + {'i', "inst_id", CM_TRUE, CM_TRUE, cmd_check_inst_id, NULL, NULL, 0, NULL, NULL, 0}, + {'D', "WR_HOME", CM_FALSE, CM_TRUE, cmd_check_wr_home, cmd_check_convert_wr_home, cmd_clean_check_convert, 0, + NULL, NULL, 0}, +}; +static wr_args_set_t cmd_inq_req_args_set = { + cmd_inq_req_args, + sizeof(cmd_inq_req_args) / sizeof(wr_args_t), + NULL, +}; + +static void inq_reg_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s inq_reg <-i inst_id> [-D WR_HOME]\n", prog_name); + (void)printf("[raid command]check whether the node is registered\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + (void)printf("-i/--inst_id , , the id of the host need to reg\n"); + help_param_wrhome(); +} + +static status_t inq_reg_proc(void) +{ + return CM_SUCCESS; +} + +static wr_args_set_t cmd_lscli_args_set = { + NULL, + 0, + NULL, +}; + +static void lscli_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s lscli\n", prog_name); + (void)printf("[client command] Show information of client\n"); +} + +static status_t lscli_proc(void) +{ + errno_t errcode; + wr_cli_info_t cli_info; + + cli_info.cli_pid = cm_sys_pid(); + status_t status = cm_sys_process_start_time(cli_info.cli_pid, &cli_info.start_time); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to get process start time pid %llu.\n", cli_info.cli_pid); + return CM_ERROR; + } + errcode = strncpy_s( + cli_info.process_name, sizeof(cli_info.process_name), cm_sys_program_name(), strlen(cm_sys_program_name())); + if (errcode != EOK) { + WR_THROW_ERROR(ERR_SYSTEM_CALL, errcode); + WR_PRINT_ERROR("Failed to lscli.\n"); + return CM_ERROR; + } + + (void)printf("%-20s%-20s%-256s\n", "cli_pid", "start_time", "process_name"); + (void)printf("%-20llu%-20lld%-256s\n", cli_info.cli_pid, cli_info.start_time, cli_info.process_name); + return CM_SUCCESS; +} + +static wr_args_t cmd_kickh_args[] = { + {'i', "inst_id", CM_TRUE, CM_TRUE, cmd_check_inst_id, NULL, NULL, 0, NULL, NULL, 0}, + {'D', "WR_HOME", CM_FALSE, CM_TRUE, cmd_check_wr_home, cmd_check_convert_wr_home, cmd_clean_check_convert, 0, + NULL, NULL, 0}, +}; +static wr_args_set_t cmd_kickh_args_set = { + cmd_kickh_args, + sizeof(cmd_kickh_args) / sizeof(wr_args_t), + NULL, +}; + +static void kickh_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s kickh <-i inst_id> [-D WR_HOME]\n", prog_name); + (void)printf("[client command] kick off the host from the array\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + (void)printf("-i/--inst_id , , the id of the host need to kick off\n"); + help_param_wrhome(); +} + +static status_t kickh_proc(void) +{ + return CM_SUCCESS; +} + +static wr_args_t cmd_reghl_args[] = { + {'D', "WR_HOME", CM_FALSE, CM_TRUE, cmd_check_wr_home, cmd_check_convert_wr_home, cmd_clean_check_convert, 0, + NULL, NULL, 0}, +}; +static wr_args_set_t cmd_reghl_args_set = { + cmd_reghl_args, + sizeof(cmd_reghl_args) / sizeof(wr_args_t), + NULL, +}; + +static void reghl_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s reghl [-D WR_HOME]\n", prog_name); + (void)printf("[manage command] register host to array\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + help_param_wrhome(); +} + +static status_t reghl_proc(void) +{ + return CM_SUCCESS; +} + +static wr_args_t cmd_unreghl_args[] = { + {'t', "type", CM_FALSE, CM_TRUE, NULL, NULL, NULL, 0, NULL, NULL, 0}, + {'D', "WR_HOME", CM_FALSE, CM_TRUE, cmd_check_wr_home, cmd_check_convert_wr_home, cmd_clean_check_convert, 0, + NULL, NULL, 0}, +}; +static wr_args_set_t cmd_unreghl_args_set = { + cmd_unreghl_args, + sizeof(cmd_unreghl_args) / sizeof(wr_args_t), + NULL, +}; + +static void unreghl_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s unreghl [-t type] [-D WR_HOME]\n", prog_name); + (void)printf("[manage command] unregister host from array\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + (void)printf("-t/--type , [optional], value is int, 0 without lock, otherwise with lock\n"); + help_param_wrhome(); +} + +static status_t unreghl_proc(void) +{ + return CM_SUCCESS; +} + +#define WR_CMD_PRINT_BLOCK_SIZE SIZE_K(4) +#define WR_PRINT_RETURN_BYTES 16 +#define WR_PRINT_FMT_NUM 6 + +static wr_args_t cmd_examine_args[] = { + {'p', "path", CM_TRUE, CM_TRUE, wr_cmd_check_device_path, cmd_check_convert_path, cmd_clean_check_convert, 0, NULL, + NULL, 0}, + {'o', "offset", CM_TRUE, CM_TRUE, cmd_check_offset, NULL, NULL, 0, NULL, NULL, 0}, + {'f', "format", CM_TRUE, CM_TRUE, cmd_check_format, NULL, NULL, 0, NULL, NULL, 0}, + {'s', "read_size", CM_FALSE, CM_TRUE, cmd_check_read_size, NULL, NULL, 0, NULL, NULL, 0}, + {'D', "WR_HOME", CM_FALSE, CM_TRUE, cmd_check_wr_home, cmd_check_convert_wr_home, cmd_clean_check_convert, 0, + NULL, NULL, 0}, + {'U', "UDS", CM_FALSE, CM_TRUE, cmd_check_uds, cmd_check_convert_uds_home, cmd_clean_check_convert, 0, NULL, NULL, + 0}, +}; +static wr_args_set_t cmd_examine_args_set = { + cmd_examine_args, + sizeof(cmd_examine_args) / sizeof(wr_args_t), + NULL, +}; + +static void examine_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s examine <-p path> <-o offset> <-f format> [-s read_size] [-D WR_HOME] " + "[-U UDS:socket_domain]\n", + prog_name); + (void)printf("[client command] display wr file content\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + if (g_run_interatively) { + (void)printf("-p/--path , , device path\n"); + } else { + (void)printf("-p/--path , , device path, must begin with '+'\n"); + } + (void)printf("-o/--offset , , the offset of the file need to examine\n"); + (void)printf("-f/--format , , value is[c|h|u|l|s|x]\n" + "c char, h unsigned short, u unsigned int, l unsigned long, s string, x hex.\n"); + (void)printf("-s/--read_size , [optional], size to show, default value is 512byte\n"); + help_param_wrhome(); + help_param_uds(); +} + +static inline char escape_char(char c) +{ + if (c > 0x1f && c < 0x7f) { + return c; + } else { + return '.'; + } +} + +static status_t print_buf(const char *o_buf, uint32 buf_size, char format, int64 offset, uint32 read_size) +{ + uint32 pos = 0; + int16 index = -1; + wr_print_help_t print_help[] = {{'c', sizeof(char)}, {'h', sizeof(uint16)}, {'u', sizeof(uint32)}, + {'l', sizeof(uint64)}, {'s', sizeof(char)}, {'x', sizeof(uint8)}}; + + for (int16 i = 0; i < WR_PRINT_FMT_NUM; i++) { + if (format == print_help[i].fmt) { + index = i; + break; + } + } + if (index == -1) { + LOG_DEBUG_ERR("Invalid format.\n"); + return CM_ERROR; + } + + while ((pos + print_help[index].bytes) <= read_size) { + if (pos % WR_PRINT_RETURN_BYTES == 0) { + (void)printf("%016llx ", (uint64)offset + pos); + } + + if (format == 'x') { + (void)printf("%02x", *(uint8 *)(o_buf + pos)); + } else if (format == 'c') { + (void)printf("%c", escape_char(*(o_buf + pos))); + } else if (format == 'h') { + (void)printf("%5hu", *(uint16 *)(o_buf + pos)); + } else if (format == 'u') { + (void)printf("%10u", *(uint32 *)(o_buf + pos)); + } else if (format == 'l') { + (void)printf("%20llu", *(uint64 *)(o_buf + pos)); + } else if (format == 's') { + (void)printf("%c", escape_char(*(o_buf + pos))); + } + + pos += print_help[index].bytes; + + if (pos % WR_PRINT_RETURN_BYTES == 0) { + (void)printf("\n"); + } else { + if (format != 's') { + (void)printf(" "); + } + } + } + if ((read_size / print_help[index].bytes) % (WR_PRINT_RETURN_BYTES / print_help[index].bytes) != 0) { + (void)printf("\n"); + } + + return CM_SUCCESS; +} + +static status_t get_examine_parameter(char **path, int64 *offset, char *fmt) +{ + *path = cmd_examine_args[WR_ARG_IDX_0].input_args; + if (cmd_examine_args[WR_ARG_IDX_0].convert_result != NULL) { + *path = cmd_examine_args[WR_ARG_IDX_0].convert_result; + } + + status_t status = cm_str2bigint(cmd_examine_args[WR_ARG_IDX_1].input_args, offset); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Invalid offset.\n"); + return CM_ERROR; + } + *fmt = cmd_examine_args[WR_ARG_IDX_2].input_args[0]; + return CM_SUCCESS; +} + +static status_t get_examine_opt_parameter(int32 *read_size) +{ + *read_size = WR_DISK_UNIT_SIZE; + if (cmd_examine_args[WR_ARG_IDX_3].input_args != NULL) { + *read_size = (int32)strtol(cmd_examine_args[WR_ARG_IDX_3].input_args, NULL, CM_DEFAULT_DIGIT_RADIX); + } + if (*read_size <= 0) { + LOG_DEBUG_ERR("Invalid read_size.\n"); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t print_file_proc(wr_conn_t *conn, int32 handle, int64 offset, int32 read_size, char fmt) +{ +#ifndef WIN32 + char o_buf[WR_CMD_PRINT_BLOCK_SIZE] __attribute__((__aligned__(WR_DISK_UNIT_SIZE))); +#else + char o_buf[WR_CMD_PRINT_BLOCK_SIZE]; +#endif + int32 read_cnt = 0; + int32 cur_read_size; + int64 row_aligned_offset = (offset / WR_PRINT_RETURN_BYTES) * WR_PRINT_RETURN_BYTES; + int64 print_offset = row_aligned_offset - (offset / WR_DISK_UNIT_SIZE) * WR_DISK_UNIT_SIZE; + int64 offset_shift = offset - row_aligned_offset; + + while (read_cnt < read_size) { + CM_RETURN_IFERR_EX(wr_read_file_impl(conn, handle, o_buf, sizeof(o_buf), &cur_read_size), + LOG_DEBUG_ERR("Failed to read file.\n")); + + if (cur_read_size > read_size - read_cnt) { + cur_read_size = read_size - read_cnt; + } + char *buf = o_buf + print_offset; + uint32 buf_size = (uint32)(sizeof(o_buf) - print_offset); + + CM_RETURN_IFERR_EX(print_buf(buf, buf_size, fmt, offset - offset_shift, (uint32)(cur_read_size - print_offset)), + LOG_DEBUG_ERR("Failed to print.\n")); + + read_cnt += cur_read_size; + offset += (cur_read_size - print_offset) - offset_shift; + print_offset = 0; + offset_shift = 0; + } + return CM_SUCCESS; +} + +static int64 adjust_readsize(int64 offset, int32 *read_size, int64 file_size) +{ + int64 unit_aligned_offset = (offset / WR_DISK_UNIT_SIZE) * WR_DISK_UNIT_SIZE; + int64 new_read_size = *read_size; + + if (unit_aligned_offset != offset) { + new_read_size += (offset - unit_aligned_offset); + } + + if (new_read_size + unit_aligned_offset > file_size) { + if (file_size < unit_aligned_offset) { + new_read_size = 0; + } else { + new_read_size = file_size - unit_aligned_offset; + } + } + + if (new_read_size < 0) { + new_read_size = 0; + } + + if (new_read_size > INT32_MAX) { + new_read_size = INT32_MAX; + } + + *read_size = (int32)new_read_size; + return unit_aligned_offset; +} + +static status_t examine_proc(void) +{ + char *path; + int64 offset; + char format; + int32 read_size = WR_DISK_UNIT_SIZE; + wr_config_t *inst_cfg = wr_get_g_inst_cfg(); + + status_t status = get_examine_parameter(&path, &offset, &format); + if (status != CM_SUCCESS) { + return status; + } + + status = get_examine_opt_parameter(&read_size); + if (status != CM_SUCCESS) { + return status; + } + + char *input_args = cmd_examine_args[WR_ARG_IDX_4].input_args; + status = set_config_info(input_args, inst_cfg); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to load config info!\n"); + return status; + } + + wr_conn_t *conn = wr_get_connection_opt(input_args); + if (conn == NULL) { + WR_PRINT_ERROR("Failed to get uds connection.\n"); + return CM_ERROR; + } + + int32 handle; + status = wr_open_file_impl(conn, path, O_RDONLY, &handle); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to open dir, path is %s.\n", path); + return CM_ERROR; + } + + int64 file_size = wr_seek_file_impl(conn, handle, 0, SEEK_END); + if (file_size == CM_INVALID_INT64) { + WR_PRINT_ERROR("Failed to seek file %s size.\n", path); + (void)wr_close_file_impl(conn, handle); + return CM_ERROR; + } + int64 unit_aligned_offset = adjust_readsize(offset, &read_size, file_size); + + unit_aligned_offset = wr_seek_file_impl(conn, handle, unit_aligned_offset, SEEK_SET); + if (unit_aligned_offset == -1) { + WR_PRINT_ERROR("Failed to seek file %s.\n", path); + (void)wr_close_file_impl(conn, handle); + return CM_ERROR; + } + (void)printf("filename is %s, offset is %lld.\n", path, offset); + status = print_file_proc(conn, handle, offset, read_size, format); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to print file %s.\n", path); + } + (void)wr_close_file_impl(conn, handle); + return status; +} + +int32 wr_open_memory_file(const char *file_name) +{ + int32 file_fd; + uint32 mode = O_RDONLY | O_BINARY; + char realpath[CM_FILE_NAME_BUFFER_SIZE] = {0}; + if (realpath_file(file_name, realpath, CM_FILE_NAME_BUFFER_SIZE) != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to find realpath file %s", file_name); + return -1; + } + if (!cm_file_exist(realpath)) { + WR_THROW_ERROR_EX(ERR_WR_FILE_NOT_EXIST, "%s not exist, please check", realpath); + return -1; + } + if (cm_open_file(realpath, mode, &file_fd) != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to open memory file %s", realpath); + return -1; + } + return file_fd; +} + +static status_t wr_load_buffer_pool_from_file(int32 file_fd, ga_pool_id_e pool_id) +{ + uint64 total_size; + int32 read_size; + status_t status = cm_read_file(file_fd, &total_size, sizeof(uint64), &read_size); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to read pool size.")); + char *pool_ft_block_buf = cm_malloc(total_size); + if (pool_ft_block_buf == NULL) { + LOG_DEBUG_ERR("Failed to malloc ft block pool."); + return CM_ERROR; + } + ga_pool_t *pool = &g_app_pools[GA_POOL_IDX((uint32)pool_id)]; + if (pool == NULL) { + CM_FREE_PTR(pool_ft_block_buf); + LOG_DEBUG_ERR("Failed to get ga pool from file."); + return CM_ERROR; + } + status = cm_read_file(file_fd, pool_ft_block_buf, (int32)total_size, &read_size); + if (status != CM_SUCCESS) { + CM_FREE_PTR(pool_ft_block_buf); + LOG_DEBUG_ERR("Failed to read file."); + return CM_ERROR; + } + pool->addr = pool_ft_block_buf; + pool->ctrl = (ga_pool_ctrl_t *)pool->addr; + pool->def = pool->ctrl->def; + uint32 object_cost = pool->ctrl->def.object_size + (uint32)sizeof(ga_object_map_t); + uint64 ex_pool_size = (uint64)object_cost * pool->ctrl->def.object_count; + pool->capacity = CM_ALIGN_512((uint32)sizeof(ga_pool_ctrl_t)) + CM_ALIGN_512(ex_pool_size); + if (pool->ctrl->ex_count > GA_MAX_EXTENDED_POOLS) { + LOG_RUN_ERR("Invalid pool info[id=%u]: ex_count is %u, larger than maximum %u", pool_id, pool->ctrl->ex_count, + GA_MAX_EXTENDED_POOLS); + return CM_ERROR; + } + for (uint32 i = 0; i < pool->ctrl->ex_count; i++) { + pool->ex_pool_addr[i] = pool_ft_block_buf + pool->capacity + i * ex_pool_size; + } + return CM_SUCCESS; +} + +static status_t wr_load_wr_ctrl_from_file(int32 file_fd, wr_vg_info_item_t *vg_item) +{ + int32 read_size; + vg_item->wr_ctrl = cm_malloc(sizeof(wr_ctrl_t)); + if (vg_item->wr_ctrl == NULL) { + LOG_DEBUG_ERR("Malloc wr_ctrl failed.\n"); + return CM_ERROR; + } + status_t status = cm_read_file(file_fd, vg_item->wr_ctrl, sizeof(wr_ctrl_t), &read_size); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to read file.")); + return CM_SUCCESS; +} + +static status_t wr_load_buffer_cache_from_file(int32 file_fd, wr_vg_info_item_t *vg_item, int64 *offset) +{ + int32 read_size; + char *buffer = NULL; + uint64 dir_size = WR_MAX_SEGMENT_NUM * (uint32)sizeof(uint32_t); + buffer = cm_malloc(sizeof(shm_hashmap_t) + dir_size); + if (buffer == NULL) { + LOG_DEBUG_ERR("Malloc failed.\n"); + return CM_ERROR; + } + status_t status = cm_read_file(file_fd, buffer, sizeof(shm_hashmap_t), &read_size); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to read file.")); + uint32 id = vg_item->id; + uint32 shm_key = cm_shm_key_of(SHM_TYPE_HASH, id); + vg_item->buffer_cache = (shm_hashmap_t *)buffer; + vg_item->buffer_cache->hash_ctrl.dirs = cm_trans_shm_offset_from_malloc(shm_key, buffer + sizeof(shm_hashmap_t)); + vg_item->buffer_cache->shm_id = id; + vg_item->buffer_cache->hash_ctrl.func = cm_oamap_uint64_compare; + status = cm_read_file(file_fd, buffer + sizeof(shm_hashmap_t), (int32)dir_size, &read_size); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to read file.")); + *offset = *offset + (int64)sizeof(shm_hashmap_t) + (int64)dir_size; + return CM_SUCCESS; +} + +static status_t wr_get_group_num(int32 file_fd, int64 *offset, uint32 *group_num) +{ + int32 read_size = 0; + status_t status = cm_read_file(file_fd, group_num, sizeof(uint32), &read_size); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to read group num.")); + *offset += (int64)sizeof(uint32); + return CM_SUCCESS; +} + +bool32 wr_check_software_version(int32 file_fd, int64 *offset) +{ + int32 read_size = 0; + uint32 software_version; + status_t status = cm_read_file(file_fd, &software_version, sizeof(uint32), &read_size); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to read software_version"); + return CM_FALSE; + } + if (software_version > (uint32)WR_SOFTWARE_VERSION) { + LOG_DEBUG_ERR("The file software_version which is %u is bigger than the actural software_version which is %u.", + software_version, (uint32)WR_SOFTWARE_VERSION); + return CM_FALSE; + } + *offset += (int64)sizeof(uint32); + return CM_TRUE; +} + +// length| vg_num| vg_name|size|buckets|map->num| +// vg_name|size|buckets|map->num|...|pool_size|pool->addr|pool->ex_pool_addr[0]|...|pool->ex_pool_addr[excount-1]|... +status_t wr_load_buffer_cache_group_from_file( + int32 file_fd, int64 *length, const char *vg_name, wr_vg_info_item_t *vg_item) +{ + uint32 group_num = 0; + int64 offset = *length; + int32 read_size = 0; + bool32 result; + status_t status = cm_read_file(file_fd, length, sizeof(int64), &read_size); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to read file.")); + offset += (int64)sizeof(int64); + WR_RETURN_IF_ERROR(wr_get_group_num(file_fd, &offset, &group_num)); + char read_vg_name[WR_MAX_NAME_LEN]; + uint32 i; + bool32 find = CM_FALSE; + for (i = 0; i < group_num; i++) { + status = cm_read_file(file_fd, read_vg_name, WR_MAX_NAME_LEN, &read_size); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to read file.")); + offset += WR_MAX_NAME_LEN; + if (strcmp(vg_name, read_vg_name) != 0) { + uint64 bucket_size = WR_MAX_SEGMENT_NUM * (uint32)sizeof(uint32_t); + uint64 hashmap_size = sizeof(shm_hashmap_t) + bucket_size; + offset = offset + (int64)hashmap_size; + result = (bool32)(cm_seek_file(file_fd, offset, SEEK_SET) != -1); + WR_RETURN_IF_FALSE2(result, LOG_DEBUG_ERR("Failed to seek file %d", file_fd)); + continue; + } + WR_RETURN_IF_ERROR(wr_load_buffer_cache_from_file(file_fd, vg_item, &offset)); + find = CM_TRUE; + } + if (!find) { + LOG_DEBUG_ERR("Failed to find vg: %s.", vg_name); + return CM_ERROR; + } + WR_RETURN_IF_ERROR(wr_load_buffer_pool_from_file(file_fd, GA_8K_POOL)); + WR_RETURN_IF_ERROR(wr_load_buffer_pool_from_file(file_fd, GA_16K_POOL)); + WR_RETURN_IF_ERROR(wr_load_buffer_pool_from_file(file_fd, GA_FS_AUX_POOL)); + WR_RETURN_IF_ERROR(wr_load_buffer_pool_from_file(file_fd, GA_SEGMENT_POOL)); + return CM_SUCCESS; +} + +status_t wr_load_wr_ctrl_group_from_file( + int32 file_fd, int64 *length, const char *vg_name, wr_vg_info_item_t *vg_item) +{ + uint32 group_num = 0; + int64 offset = 0; + int32 read_size = 0; + status_t status = cm_read_file(file_fd, length, sizeof(int64), &read_size); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to read file.")); + offset += (int64)sizeof(int64); + WR_RETURN_IF_ERROR(wr_get_group_num(file_fd, &offset, &group_num)); + char read_vg_name[WR_MAX_NAME_LEN]; + uint32 i; + bool32 find = CM_FALSE; + bool32 result = CM_FALSE; + for (i = 0; i < group_num; i++) { + WR_RETURN_IF_FALSE2(wr_check_software_version(file_fd, &offset), + LOG_DEBUG_ERR("Failed to check software_version of vg %u", i)); + status = cm_read_file(file_fd, read_vg_name, WR_MAX_NAME_LEN, &read_size); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to read file.")); + offset += WR_MAX_NAME_LEN; + if (strcmp(vg_name, read_vg_name) != 0) { + offset += (int64)sizeof(wr_ctrl_t); + result = (bool32)(cm_seek_file(file_fd, offset, SEEK_SET) != -1); + WR_RETURN_IF_FALSE2(result, LOG_DEBUG_ERR("Failed to seek file %d", file_fd)); + continue; + } + WR_RETURN_IF_ERROR(wr_load_wr_ctrl_from_file(file_fd, vg_item)); + offset += (int64)sizeof(wr_ctrl_t); + find = CM_TRUE; + } + if (!find) { + LOG_DEBUG_ERR("Failed to find vg: %s.", vg_name); + return CM_ERROR; + } + return CM_SUCCESS; +} + +status_t wr_load_vg_item_and_pool_from_file(const char *file_name, const char *vg_name, wr_vg_info_item_t *vg_item) +{ + int32 file_fd = wr_open_memory_file(file_name); + if (file_fd == -1) { + LOG_DEBUG_ERR("Failed to open memory file %s", file_name); + return CM_ERROR; + } + int64 size = cm_file_size(file_fd); + if (size == -1) { + cm_close_file(file_fd); + LOG_DEBUG_ERR("Failed to read file size %s", file_name); + return CM_ERROR; + } + int64 length = -1; + status_t status; + bool32 result = (bool32)(cm_seek_file(file_fd, 0, SEEK_SET) != -1); + WR_RETURN_IF_FALSE2(result, LOG_DEBUG_ERR("Failed to seek file %s", file_name)); + do { + status = wr_load_wr_ctrl_group_from_file(file_fd, &length, vg_name, vg_item); + if (status != CM_SUCCESS) { + if (length == -1) { + break; + } + result = (bool32)(cm_seek_file(file_fd, length, SEEK_SET) != -1); + WR_RETURN_IF_FALSE2(result, LOG_DEBUG_ERR("Failed to seek file %s", file_name)); + } + + status = wr_load_buffer_cache_group_from_file(file_fd, &length, vg_name, vg_item); + WR_BREAK_IF_ERROR(status); + } while (CM_FALSE); + cm_close_file(file_fd); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to load vg item %s", vg_name); + } + return status; +} + +static wr_args_t cmd_rename_args[] = { + {'o', "old_name", CM_TRUE, CM_TRUE, wr_cmd_check_device_path, cmd_check_convert_path, cmd_clean_check_convert, 0, + NULL, NULL, 0}, + {'n', "new_name", CM_TRUE, CM_TRUE, wr_cmd_check_device_path, cmd_check_convert_path, cmd_clean_check_convert, 0, + NULL, NULL, 0}, + {'U', "UDS", CM_FALSE, CM_TRUE, cmd_check_uds, cmd_check_convert_uds_home, cmd_clean_check_convert, 0, NULL, NULL, + 0}, +}; +static wr_args_set_t cmd_rename_args_set = { + cmd_rename_args, + sizeof(cmd_rename_args) / sizeof(wr_args_t), + NULL, +}; + +static void rename_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s rename <-o old_name> <-n new_name> [-U UDS:socket_domain]\n", prog_name); + if (g_run_interatively) { + (void)printf("[client command] rename file\n"); + } else { + (void)printf("[client command] rename file, all file name must begin with '+'\n"); + } + if (print_flag == WR_HELP_SIMPLE) { + return; + } + (void)printf("-o/--old_name , , the old file name\n"); + (void)printf("-n/--new_name , , the new file name\n"); + help_param_uds(); +} + +static status_t rename_proc(void) +{ + const char *old_name = cmd_rename_args[WR_ARG_IDX_0].input_args; + if (cmd_rename_args[WR_ARG_IDX_0].convert_result != NULL) { + old_name = cmd_rename_args[WR_ARG_IDX_0].convert_result; + } + + const char *new_name = cmd_rename_args[WR_ARG_IDX_1].input_args; + if (cmd_rename_args[WR_ARG_IDX_1].convert_result != NULL) { + new_name = cmd_rename_args[WR_ARG_IDX_1].convert_result; + } + + status_t status = CM_SUCCESS; + const char *input_args = cmd_rename_args[WR_ARG_IDX_2].input_args; + wr_conn_t *conn = wr_get_connection_opt(input_args); + if (conn == NULL) { + return CM_ERROR; + } + + status = wr_rename_file_impl(conn, old_name, new_name); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to rename file, old name is %s, new name is %s.\n", old_name, new_name); + } else { + WR_PRINT_INF("Succeed to rename file, old name is %s, new name is %s.\n", old_name, new_name); + } + return status; +} + +static wr_args_set_t cmd_encrypt_args_set = { + NULL, + 0, + NULL, +}; + +static void encrypt_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s encrypt\n", prog_name); + (void)printf("[client command] password encrypt\n"); +} + +static status_t wr_save_random_file(const uchar *value, int32 value_len) +{ + char file_name[CM_FILE_NAME_BUFFER_SIZE]; + char dir_name[CM_FILE_NAME_BUFFER_SIZE]; + int32 handle; + PRTS_RETURN_IFERR(snprintf_s( + dir_name, CM_FILE_NAME_BUFFER_SIZE, CM_FILE_NAME_BUFFER_SIZE - 1, "%s/wr_protect", g_inst_cfg->home)); + PRTS_RETURN_IFERR(snprintf_s(file_name, CM_FILE_NAME_BUFFER_SIZE, CM_FILE_NAME_BUFFER_SIZE - 1, "%s/wr_protect/%s", + g_inst_cfg->home, WR_FKEY_FILENAME)); + if (!cm_dir_exist(dir_name)) { + WR_RETURN_IF_ERROR(cm_create_dir(dir_name)); + } + if (access(file_name, R_OK | F_OK) == 0) { + (void)chmod(file_name, S_IRUSR | S_IWUSR); + WR_RETURN_IF_ERROR(cm_overwrite_file(file_name)); + WR_RETURN_IF_ERROR(cm_remove_file(file_name)); + } + WR_RETURN_IF_ERROR( + cm_open_file_ex(file_name, O_SYNC | O_CREAT | O_RDWR | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR, &handle)); + status_t ret = cm_write_file(handle, value, value_len); + cm_close_file(handle); + return ret; +} + +static status_t encrypt_proc(void) +{ + status_t status; + char plain[CM_PASSWD_MAX_LEN + 1] = {0}; + status = wr_catch_input_text(plain, CM_PASSWD_MAX_LEN + 1); + if (status != CM_SUCCESS) { + (void)(memset_s(plain, CM_PASSWD_MAX_LEN + 1, 0, CM_PASSWD_MAX_LEN + 1)); + WR_PRINT_RUN_ERROR("[ENCRYPT]Failed to encrypt password when catch input.\n"); + return CM_ERROR; + } + LOG_RUN_INF("[ENCRYPT]Succeed to encrypt password when catch input.\n"); + cipher_t cipher; + status = cm_encrypt_pwd((uchar *)plain, (uint32)strlen(plain), &cipher); + if (status != CM_SUCCESS) { + (void)(memset_s(plain, CM_PASSWD_MAX_LEN + 1, 0, CM_PASSWD_MAX_LEN + 1)); + WR_PRINT_RUN_ERROR("[ENCRYPT]Failed to encrypt password.\n"); + return CM_ERROR; + } + LOG_RUN_INF("[ENCRYPT]Succeed to encrypt password.\n"); + (void)(memset_s(plain, CM_PASSWD_MAX_LEN + 1, 0, CM_PASSWD_MAX_LEN + 1)); + status = wr_save_random_file(cipher.rand, RANDOM_LEN + 1); + if (status != CM_SUCCESS) { + WR_PRINT_RUN_ERROR("[ENCRYPT]Failed to save random component.\n"); + return CM_ERROR; + } + LOG_RUN_INF("[ENCRYPT]Succeed to save random component.\n"); + (void)(memset_s(cipher.rand, RANDOM_LEN + 1, 0, RANDOM_LEN + 1)); + char buf[CM_MAX_SSL_CIPHER_LEN] = {0}; + uint32_t buf_len = CM_MAX_SSL_CIPHER_LEN; + status = cm_base64_encode((uchar *)&cipher, (uint32)sizeof(cipher_t), buf, &buf_len); + if (status != CM_SUCCESS) { + WR_PRINT_RUN_ERROR("[ENCRYPT]Failed to encrypt password when encode.\n"); + return CM_ERROR; + } + (void)printf("Cipher: \t\t%s\n", buf); + (void)fflush(stdout); + LOG_RUN_INF("[ENCRYPT]Succeed to print cipher, length is %u.\n", (uint32)strlen(buf)); + return CM_SUCCESS; +} + +static wr_args_t cmd_setcfg_args[] = { + {'n', "name", CM_TRUE, CM_TRUE, cmd_check_cfg_name, NULL, NULL, 0, NULL, NULL, 0}, + {'v', "value", CM_TRUE, CM_TRUE, cmd_check_cfg_value, NULL, NULL, 0, NULL, NULL, 0}, + {'s', "scope", CM_FALSE, CM_TRUE, cmd_check_cfg_scope, NULL, NULL, 0, NULL, NULL, 0}, + {'U', "UDS", CM_FALSE, CM_TRUE, cmd_check_uds, cmd_check_convert_uds_home, cmd_clean_check_convert, 0, NULL, NULL, + 0}, +}; +static wr_args_set_t cmd_setcfg_args_set = { + cmd_setcfg_args, + sizeof(cmd_setcfg_args) / sizeof(wr_args_t), + NULL, +}; + +static void setcfg_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s setcfg <-n name> <-v value> [-s scope] [-U UDS:socket_domain]\n", prog_name); + (void)printf("[client command] set config value by name\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + (void)printf("-n/--name , , the config name to set\n"); + (void)printf("-v/--value , , the value of the config name to set\n"); + (void)printf("-s/--scope , [optional], the scope to save the config\n"); + (void)printf("scope optional values: [memory | pfile | both]. default value is both\n" + "Memory indicates that the modification is made in memory and takes effect immediately;\n" + "Pfile indicates that the modification is performed in the pfile. \n" + "The database must be restarted for the modification to take effect.\n"); + help_param_uds(); +} + +static status_t setcfg_proc(void) +{ + char *name = cmd_setcfg_args[WR_ARG_IDX_0].input_args; + char *value = cmd_setcfg_args[WR_ARG_IDX_1].input_args; + char *scope = + cmd_setcfg_args[WR_ARG_IDX_2].input_args != NULL ? cmd_setcfg_args[WR_ARG_IDX_2].input_args : "both"; + + const char *input_args = cmd_setcfg_args[WR_ARG_IDX_3].input_args; + wr_conn_t *conn = wr_get_connection_opt(input_args); + if (conn == NULL) { + return CM_ERROR; + } + + status_t status = wr_setcfg_impl(conn, name, value, scope); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to set cfg, name is %s, value is %s.\n", name, value); + } else { + WR_PRINT_INF("Succeed to set cfg, name is %s, value is %s.\n", name, value); + } + return status; +} + +static wr_args_t cmd_getcfg_args[] = { + {'n', "name", CM_TRUE, CM_TRUE, cmd_check_cfg_name, NULL, NULL, 0, NULL, NULL, 0}, + {'U', "UDS", CM_FALSE, CM_TRUE, cmd_check_uds, cmd_check_convert_uds_home, cmd_clean_check_convert, 0, NULL, NULL, + 0}, +}; +static wr_args_set_t cmd_getcfg_args_set = { + cmd_getcfg_args, + sizeof(cmd_getcfg_args) / sizeof(wr_args_t), + NULL, +}; + +static void getcfg_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s getcfg <-n name> [-U UDS:socket_domain]\n", prog_name); + (void)printf("[client command] get config value by name\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + (void)printf("-n/--name , , the config name to set\n"); + help_param_uds(); +} + +static status_t getcfg_proc(void) +{ + char *name = cmd_getcfg_args[WR_ARG_IDX_0].input_args; + const char *input_args = cmd_getcfg_args[WR_CMD_TOUCH_ARGS_UDS].input_args; + wr_conn_t *conn = wr_get_connection_opt(input_args); + if (conn == NULL) { + return CM_ERROR; + } + char value[WR_PARAM_BUFFER_SIZE] = {0}; + status_t status = wr_getcfg_impl(conn, name, value, WR_PARAM_BUFFER_SIZE); + if (status != CM_SUCCESS) { + if (strlen(value) != 0 && cm_str_equal_ins(name, "SSL_PWD_CIPHERTEXT")) { + LOG_DEBUG_ERR("Failed to get cfg, name is %s, value is ***.\n", name); + (void)printf("Failed to get cfg, name is %s, value is %s.\n", name, value); + (void)fflush(stdout); + wr_print_detail_error(); + } else { + WR_PRINT_ERROR("Failed to get cfg, name is %s, value is %s.\n", name, (strlen(value) == 0) ? NULL : value); + } + } else { + if (strlen(value) != 0 && cm_str_equal_ins(name, "SSL_PWD_CIPHERTEXT")) { + LOG_DEBUG_INF("Succeed to get cfg, name is %s, value is ***.\n", name); + (void)printf("Succeed to get cfg, name is %s, value is %s.\n", name, value); + (void)fflush(stdout); + } else { + WR_PRINT_INF("Succeed to get cfg, name is %s, value is %s.\n", name, (strlen(value) == 0) ? NULL : value); + } + } + return status; +} + +static wr_args_t cmd_getstatus_args[] = { + {'U', "UDS", CM_FALSE, CM_TRUE, cmd_check_uds, cmd_check_convert_uds_home, cmd_clean_check_convert, 0, NULL, NULL, + 0}, +}; + +static wr_args_set_t cmd_getstatus_args_set = { + cmd_getstatus_args, + sizeof(cmd_getstatus_args) / sizeof(wr_args_t), + NULL, +}; + +static void getstatus_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s getstatus [-U UDS:socket_domain]\n", prog_name); + (void)printf("[client command] get wr server status\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + help_param_uds(); +} + +static status_t getstatus_proc(void) +{ + const char *input_args = cmd_getstatus_args[WR_ARG_IDX_0].input_args; + wr_conn_t *conn = wr_get_connection_opt(input_args); + if (conn == NULL) { + return CM_ERROR; + } + + wr_server_status_t wr_status; + status_t status = wr_get_inst_status_on_server(conn, &wr_status); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to get server status.\n"); + } else { + WR_PRINT_INF("Server status of instance %u is %s and %s.\nMaster id is %u .\nWR_MAINTAIN is %s.\n", + wr_status.local_instance_id, wr_status.instance_status, wr_status.server_status, wr_status.master_id, + (wr_status.is_maintain ? "TRUE" : "FALSE")); + } + return status; +} + +static wr_args_t cmd_stopwr_args[] = { + {'U', "UDS", CM_FALSE, CM_TRUE, cmd_check_uds, cmd_check_convert_uds_home, cmd_clean_check_convert, 0, NULL, NULL, + 0}, +}; +static wr_args_set_t cmd_stopwr_args_set = { + cmd_stopwr_args, + sizeof(cmd_stopwr_args) / sizeof(wr_args_t), + NULL, +}; + +static void stopwr_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s stopwr [-U UDS:socket_domain]\n", prog_name); + (void)printf("[client command] stop wr server\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + help_param_uds(); +} + +static status_t stopwr_proc(void) +{ + const char *input_args = cmd_stopwr_args[WR_ARG_IDX_0].input_args; + wr_conn_t *conn = wr_get_connection_opt(input_args); + if (conn == NULL) { + return CM_ERROR; + } + + status_t status = wr_stop_server_impl(conn); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to stop server.\n"); + } else { + WR_PRINT_INF("Succeed to stop server.\n"); + } + wr_conn_opt_exit(); + return status; +} + +#define WR_CMD_TRUNCATE_ARGS_PATH 0 +#define WR_CMD_TRUNCATE_ARGS_LENGTH 1 +#define WR_CMD_TRUNCATE_ARGS_UDS 2 + +static wr_args_t cmd_truncate_args[] = { + {'p', "path", CM_TRUE, CM_TRUE, wr_cmd_check_device_path, NULL, NULL, 0, NULL, NULL, 0}, + {'l', "length", CM_TRUE, CM_TRUE, cmd_check_length, NULL, NULL, 0, NULL, NULL, 0}, + {'U', "UDS", CM_FALSE, CM_TRUE, cmd_check_uds, cmd_check_convert_uds_home, cmd_clean_check_convert, 0, NULL, NULL, + 0}, +}; + +static wr_args_set_t cmd_truncate_args_set = { + cmd_truncate_args, + sizeof(cmd_truncate_args) / sizeof(wr_args_t), + NULL, +}; + +static void truncate_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s truncate <-p path> <-l length> [-U UDS:socket_domain]\n", prog_name); + (void)printf("[client command]truncate file to length\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + if (g_run_interatively) { + (void)printf("-p/--path , , file need to truncate\n"); + } else { + (void)printf("-p/--path , , file need to truncate, path must begin with '+'\n"); + } + (void)printf("-l/--length , , length need to truncate\n"); + help_param_uds(); +} + +static status_t truncate_proc(void) +{ + const char *path = cmd_truncate_args[WR_CMD_TRUNCATE_ARGS_PATH].input_args; + if (cmd_truncate_args[WR_CMD_TRUNCATE_ARGS_PATH].convert_result != NULL) { + path = cmd_truncate_args[WR_CMD_TRUNCATE_ARGS_PATH].convert_result; + } + + int64 length; + status_t status = cm_str2bigint(cmd_truncate_args[WR_CMD_TRUNCATE_ARGS_LENGTH].input_args, &length); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR( + "length:%s is not a valid int64.\n", cmd_truncate_args[WR_CMD_TRUNCATE_ARGS_LENGTH].input_args); + return status; + } + + const char *input_args = cmd_truncate_args[WR_CMD_TRUNCATE_ARGS_UDS].input_args; + wr_conn_t *conn = wr_get_connection_opt(input_args); + if (conn == NULL) { + return CM_ERROR; + } + + int handle; + status = (status_t)wr_open_file_impl(conn, path, O_RDWR, &handle); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to truncate file, name is %s.\n", path); + return status; + } + + status = (status_t)wr_truncate_impl(conn, handle, length); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("Failed to truncate file, name is %s.\n", path); + (void)wr_close_file_impl(conn, handle); + return status; + } + WR_PRINT_INF("Success to truncate file, name is %s.\n", path); + + (void)wr_close_file_impl(conn, handle); + return status; +} + +// clang-format off +wr_admin_cmd_t g_wr_admin_cmd[] = { + {"mkdir", mkdir_help, mkdir_proc, &cmd_mkdir_args_set, true}, + {"touch", touch_help, touch_proc, &cmd_touch_args_set, true}, + {"ts", ts_help, ts_proc, &cmd_ts_args_set, false}, + {"ls", ls_help, ls_proc, &cmd_ls_args_set, false}, + {"rm", rm_help, rm_proc, &cmd_rm_args_set, true}, + {"rmdir", rmdir_help, rmdir_proc, &cmd_rmdir_args_set, true}, + {"inq", inq_help, inq_proc, &cmd_inq_args_set, false}, + {"inq_reg", inq_reg_help, inq_reg_proc, &cmd_inq_req_args_set, false}, + {"lscli", lscli_help, lscli_proc, &cmd_lscli_args_set, false}, + {"kickh", kickh_help, kickh_proc, &cmd_kickh_args_set, true}, + {"reghl", reghl_help, reghl_proc, &cmd_reghl_args_set, true}, + {"unreghl", unreghl_help, unreghl_proc, &cmd_unreghl_args_set, true}, + {"examine", examine_help, examine_proc, &cmd_examine_args_set, false}, + {"rename", rename_help, rename_proc, &cmd_rename_args_set, true}, + {"encrypt", encrypt_help, encrypt_proc, &cmd_encrypt_args_set, true}, + {"setcfg", setcfg_help, setcfg_proc, &cmd_setcfg_args_set, true}, + {"getcfg", getcfg_help, getcfg_proc, &cmd_getcfg_args_set, false}, + {"getstatus", getstatus_help, getstatus_proc, &cmd_getstatus_args_set, false}, + {"stopwr", stopwr_help, stopwr_proc, &cmd_stopwr_args_set, true}, + {"truncate", truncate_help, truncate_proc, &cmd_truncate_args_set, true} +}; + +void clean_cmd() +{ + wr_conn_opt_exit(); + wr_free_vg_info(); + ga_reset_app_pools(); +} + +// clang-format on +static void help(char *prog_name, wr_help_type help_type) +{ + (void)printf("Usage:%s [command] [OPTIONS]\n\n", prog_name); + (void)printf("Usage:%s %s/%s show help information of wrcmd\n", prog_name, HELP_SHORT, HELP_LONG); + (void)printf("Usage:%s %s/%s show all help information of wrcmd\n", prog_name, ALL_SHORT, ALL_LONG); + (void)printf("Usage:%s %s/%s show version information of wrcmd\n", prog_name, VERSION_SHORT, VERSION_LONG); + if (!g_run_interatively) { + (void)printf("Usage:%s -i/--interactive run wrcmd interatively\n", prog_name); + } + (void)printf("commands:\n"); + for (uint32 i = 0; i < sizeof(g_wr_admin_cmd) / sizeof(g_wr_admin_cmd[0]); ++i) { + g_wr_admin_cmd[i].help(prog_name, help_type); + } + cmd_print_interactive_help(prog_name, help_type); + (void)printf("\n\n"); +} + +static status_t execute_one_cmd(int argc, char **argv, uint32 cmd_idx) +{ + cmd_parse_init(g_wr_admin_cmd[cmd_idx].args_set->cmd_args, g_wr_admin_cmd[cmd_idx].args_set->args_size); + if (cmd_parse_args(argc, argv, g_wr_admin_cmd[cmd_idx].args_set) != CM_SUCCESS) { + int32 code; + const char *message; + cm_get_error(&code, &message); + if (code != 0) { + WR_PRINT_ERROR("\ncmd %s error:%d %s.\n", g_wr_admin_cmd[cmd_idx].cmd, code, message); + } + return CM_ERROR; + } + status_t ret = g_wr_admin_cmd[cmd_idx].proc(); + cmd_parse_clean(g_wr_admin_cmd[cmd_idx].args_set->cmd_args, g_wr_admin_cmd[cmd_idx].args_set->args_size); + return ret; +} + +static status_t wr_cmd_append_oper_log(char *log_buf, void *buf, uint32 *offset) +{ + uint32 len = (uint32)strlen(buf); + errno_t errcode = memcpy_s(log_buf + *offset, CM_MAX_LOG_CONTENT_LENGTH - *offset, buf, len); + if (errcode != EOK) { + LOG_RUN_ERR("Copying buf to log_buf failed.\n"); + return CM_ERROR; + } + *offset += len; + return CM_SUCCESS; +} + +static void wr_cmd_oper_log(int argc, char **argv, status_t status) +{ + char log_buf[CM_MAX_LOG_CONTENT_LENGTH] = {0}; + uint32 offset = 0; + + if (!LOG_OPER_ON) { + return; + } + + WR_RETURN_DRIECT_IFERR(wr_cmd_append_oper_log(log_buf, "wrcmd", &offset)); + + for (int i = 1; i < argc; i++) { + WR_RETURN_DRIECT_IFERR(wr_cmd_append_oper_log(log_buf, " ", &offset)); + WR_RETURN_DRIECT_IFERR(wr_cmd_append_oper_log(log_buf, argv[i], &offset)); + } + + char result[WR_MAX_PATH_BUFFER_SIZE]; + int32 ret = snprintf_s( + result, WR_MAX_PATH_BUFFER_SIZE, WR_MAX_PATH_BUFFER_SIZE - 1, ". execute result %d.", (int32)status); + if (ret == -1) { + return; + } + WR_RETURN_DRIECT_IFERR(wr_cmd_append_oper_log(log_buf, result, &offset)); + + if (offset + 1 > CM_MAX_LOG_CONTENT_LENGTH) { + WR_PRINT_ERROR("Oper log len %u exceeds max %u.\n", offset, CM_MAX_LOG_CONTENT_LENGTH); + return; + } + log_buf[offset + 1] = '\0'; + cm_write_oper_log(log_buf, offset); +} + +static bool32 get_cmd_idx(int argc, char **argv, uint32_t *idx) +{ + for (uint32 i = 0; i < sizeof(g_wr_admin_cmd) / sizeof(g_wr_admin_cmd[0]); ++i) { + if (strcmp(g_wr_admin_cmd[i].cmd, argv[WR_ARG_IDX_1]) == 0) { + *idx = i; + return CM_TRUE; + } + } + return CM_FALSE; +} + +bool8 cmd_check_run_interactive(int argc, char **argv) +{ + if (argc < CMD_ARGS_AT_LEAST) { + return CM_FALSE; + } + if (cm_str_equal(argv[1], "-i") || cm_str_equal(argv[1], "--interactive")) { + g_run_interatively = CM_TRUE; + return CM_TRUE; + } + return CM_FALSE; +} + +bool8 cmd_version_and_help(int argc, char **argv) +{ + if (cm_str_equal(argv[1], VERSION_SHORT) || cm_str_equal(argv[1], VERSION_LONG)) { + (void)printf("wrcmd %s\n", (char *)DEF_WR_VERSION); + return CM_TRUE; + } + if (cm_str_equal(argv[1], ALL_SHORT) || cm_str_equal(argv[1], ALL_LONG)) { + help(argv[0], WR_HELP_DETAIL); + return CM_TRUE; + } + if (cm_str_equal(argv[1], HELP_SHORT) || cm_str_equal(argv[1], HELP_LONG)) { + help(argv[0], WR_HELP_SIMPLE); + return CM_TRUE; + } + return CM_FALSE; +} + +void print_help_hint() +{ + (void)printf("wrcmd: Try \"wrcmd -h/--help\" for help information.\n"); + (void)printf("wrcmd: Try \"wrcmd -a/--all\" for detailed help information.\n"); +} + +int32 execute_help_cmd(int argc, char **argv, uint32_t *idx, bool8 *go_ahead) +{ + if (argc < CMD_ARGS_AT_LEAST) { + if (!g_run_interatively) { + (void)printf("wrcmd: no operation specified.\n"); + print_help_hint(); + } + *go_ahead = CM_FALSE; + return EXIT_FAILURE; + } + if (cmd_version_and_help(argc, argv)) { + *go_ahead = CM_FALSE; + return EXIT_SUCCESS; + } + if (!get_cmd_idx(argc, argv, idx)) { + (void)printf("wrcmd: command(%s) not found!\n", argv[WR_ARG_IDX_1]); + print_help_hint(); + *go_ahead = CM_FALSE; + return EXIT_FAILURE; + } + if (argc > WR_ARG_IDX_2 && + (strcmp(argv[WR_ARG_IDX_2], "-h") == 0 || strcmp(argv[WR_ARG_IDX_2], "--help") == 0)) { + g_wr_admin_cmd[*idx].help(argv[0], WR_HELP_DETAIL); + *go_ahead = CM_FALSE; + return EXIT_SUCCESS; + } + + *go_ahead = CM_TRUE; + return EXIT_SUCCESS; +} + +status_t execute_cmd(int argc, char **argv, uint32 idx) +{ + status_t status = execute_one_cmd(argc, argv, idx); + wr_cmd_oper_log(argc, argv, status); + return status; +} + +static bool32 is_log_necessary(int argc, char **argv) +{ + uint32_t cmd_idx; + if (get_cmd_idx(argc, argv, &cmd_idx) && g_wr_admin_cmd[cmd_idx].log_necessary) { + return true; + } + return false; +} + +static status_t wr_check_user_permit() +{ +#ifndef WIN32 + // check root + if (geteuid() == 0 || getuid() != geteuid()) { + (void)printf("The root user is not permitted to execute the wrcmd " + "and the real uids must be the same as the effective uids.\n"); + (void)fflush(stdout); + return CM_ERROR; + } + if (cm_regist_signal(SIGPIPE, SIG_IGN) != CM_SUCCESS) { + (void)printf("Can't assign function for SIGPIPE.\n"); + return CM_ERROR; + } +#endif + return CM_SUCCESS; +} + +int main(int argc, char **argv) +{ + WR_RETURN_IF_ERROR(wr_check_user_permit()); + uint32 idx = 0; + bool8 go_ahead = CM_TRUE; + bool8 is_interactive = cmd_check_run_interactive(argc, argv); + if (!is_interactive) { + int32 help_ret = execute_help_cmd(argc, argv, &idx, &go_ahead); + if (!go_ahead) { + exit(help_ret); + } + } + wr_config_t *inst_cfg = wr_get_g_inst_cfg(); + status_t ret = wr_set_cfg_dir(NULL, inst_cfg); + WR_RETURN_IFERR2(ret, WR_PRINT_ERROR("Environment variant WR_HOME not found!\n")); + ret = wr_load_local_server_config(inst_cfg); + WR_RETURN_IFERR2(ret, WR_PRINT_ERROR("Failed to load local server config, status(%d).\n", ret)); + ret = cm_start_timer(g_timer()); + WR_RETURN_IFERR2(ret, WR_PRINT_ERROR("Aborted due to starting timer thread.\n")); + ret = wr_init_loggers(inst_cfg, wr_get_cmd_log_def(), wr_get_cmd_log_def_count(), "wrcmd"); + if (ret != CM_SUCCESS && is_log_necessary(argc, argv)) { + WR_PRINT_ERROR("%s\nWR init loggers failed!\n", cm_get_errormsg(cm_get_error_code())); + return ret; + } + + do { + if (g_run_interatively) { + wr_cmd_run_interactively(); + ret = CM_SUCCESS; + break; + } + cm_reset_error(); + ret = execute_cmd(argc, argv, idx); + } while (0); + + clean_cmd(); + return ret; +} diff --git a/src/cmd/wrcmd.h b/src/cmd/wrcmd.h new file mode 100644 index 0000000000000000000000000000000000000000..23ca370053714cf66952b65daf7fb616febf6ccd --- /dev/null +++ b/src/cmd/wrcmd.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wrcmd.h + * + * + * IDENTIFICATION + * src/cmd/wrcmd.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WRCMD_H__ +#define __WRCMD_H__ + +#include "wr_defs.h" +#include "wr_interaction.h" + +int32 execute_help_cmd(int argc, char **argv, uint32_t *idx, bool8 *go_ahead); + +status_t execute_cmd(int argc, char **argv, uint32 idx); + +void clean_cmd(); + +#endif \ No newline at end of file diff --git a/src/cmd/wrcmd_conn_opt.c b/src/cmd/wrcmd_conn_opt.c new file mode 100644 index 0000000000000000000000000000000000000000..c6143760e85f63175ca6f4300d520ef61319fdb2 --- /dev/null +++ b/src/cmd/wrcmd_conn_opt.c @@ -0,0 +1,81 @@ +#include "wr_api_impl.h" +#include "wr_interaction.h" +#include "wrcmd.h" +#include "wrcmd_conn_opt.h" +#include "wr_cli_conn.h" + +#define WR_SUBSTR_UDS_PATH "UDS:" + +typedef struct { + wr_conn_t conn; + bool8 is_connected; + char server_locator[WR_MAX_PATH_BUFFER_SIZE]; +} wr_uds_conn_t; + +static wr_uds_conn_t g_wr_uds_conn = {}; /* global connection for wrCmd */ + +/** + * [brief] disconnect uds connection + * @param [IN] wr_conn + */ +void wr_disconnect_ex_conn() +{ + if (g_wr_uds_conn.is_connected) { + wr_disconnect_ex(&g_wr_uds_conn.conn); + g_wr_uds_conn.is_connected = false; + (void)memset_s(&g_wr_uds_conn.conn, sizeof(wr_conn_t), 0, sizeof(wr_conn_t)); + } +} + +/** + * [brief] disconnect all uds connection + * */ +void wr_conn_opt_exit() +{ + wr_disconnect_ex_conn(); +} + +/** + * [brief] setup a new connection + * @param [IN] server_locator + * @param [OUT] wr_conn + * @return + */ +static status_t wr_uds_set_up_connection(const char *server_locator, wr_uds_conn_t *wr_conn) +{ + status_t status = wr_connect_ex(server_locator, NULL, &wr_conn->conn); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to set up connect(url:%s)\n", server_locator); + return status; + } + wr_conn->is_connected = true; + return CM_SUCCESS; +} + +/** + * [brief] first setup a connection or use the exist connection + * @param [IN] input_args + * @return [OUT] uds connection + */ +wr_conn_t *wr_get_connection_opt(const char *input_args) +{ + if (g_wr_uds_conn.is_connected && input_args != NULL) { + (void)printf("You are about to changing connection, the operation is not allowed!(%s)\n", input_args); + return NULL; + } + /* use the connected conn if */ + if (g_wr_uds_conn.is_connected) { + return &g_wr_uds_conn.conn; + } + + status_t status = wr_uds_set_up_connection(g_wr_uds_conn.server_locator, &g_wr_uds_conn); + if (status != CM_SUCCESS) { + return NULL; + } + return &g_wr_uds_conn.conn; +} + +bool8 wr_get_connection_opt_status() +{ + return g_wr_uds_conn.is_connected; +} \ No newline at end of file diff --git a/src/cmd/wrcmd_conn_opt.h b/src/cmd/wrcmd_conn_opt.h new file mode 100644 index 0000000000000000000000000000000000000000..5919be7b22e8b522cc8fd07e33bbdbc6daca8656 --- /dev/null +++ b/src/cmd/wrcmd_conn_opt.h @@ -0,0 +1,13 @@ +#ifndef WR_CMD_CONN_OPT +#define WR_CMD_CONN_OPT + +/* get opt connection */ +wr_conn_t* wr_get_connection_opt(const char *input_args); + +/* get opt connection status */ +bool8 wr_get_connection_opt_status(); + +/* disconnection opt connection */ +void wr_conn_opt_exit(); + +#endif diff --git a/src/cmd/wrcmd_encrypt.c b/src/cmd/wrcmd_encrypt.c new file mode 100644 index 0000000000000000000000000000000000000000..d51f34e66479bc44dc1788b8f92c13a5918bd538 --- /dev/null +++ b/src/cmd/wrcmd_encrypt.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wrcmd_encrypt.c + * + * + * IDENTIFICATION + * src/cmd/wrcmd_encrypt.c + * + * ------------------------------------------------------------------------- + */ + +#include "wrcmd_encrypt.h" +#include "cm_utils.h" +#include "wr_malloc.h" +#ifdef WIN32 +#include +#else +#include +#endif + +static int32 wr_get_one_char() +{ +#ifdef WIN32 + return _getch(); +#else + size_t count; + int32 char_ascii; + struct termios oldt; + struct termios newt; + (void)tcgetattr(STDIN_FILENO, &oldt); + + count = sizeof(newt); + MEMS_RETURN_IFERR(memcpy_s(&newt, count, &oldt, count)); + newt.c_lflag &= ~(ECHO | ICANON | ECHOE | ECHOK | ECHONL | ICRNL); + newt.c_cc[VMIN] = 1; + newt.c_cc[VTIME] = 0; + (void)tcsetattr(STDIN_FILENO, TCSANOW, &newt); + char_ascii = getchar(); + /* Restore the old setting of terminal */ + (void)tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + return char_ascii; +#endif +} + +status_t wr_receive_info_from_terminal(char *buff, int32 buff_size, bool32 is_plain_text) +{ + int32 pos = 0; + char char_ascii; + int32 key = 0; + bool32 len_exceed = CM_FALSE; + CM_POINTER(buff); + do { + key = wr_get_one_char(); + if (key < 0) { + (void)printf("invalid char which may be EOF found"); + return CM_ERROR; + } + char_ascii = (char)key; +#ifdef WIN32 + if (char_ascii == KEY_BS) { +#else + if (char_ascii == KEY_BS || char_ascii == KEY_BS_LNX) { +#endif + if (pos > 0) { + buff[pos] = '\0'; + pos--; + /* + * Recv a key of backspace, print a '\b' backing a char + and printing + * a space replacing the char displayed to screen + with the space. + */ + (void)printf("\b"); + (void)printf(" "); + (void)printf("\b"); + } else { + continue; + } + } else if (char_ascii == KEY_LF || char_ascii == KEY_CR) { + break; + } else { + /* + * Only recv the limited length of pswd characters, on beyond, + * contine to get a next char entered by user. + */ + if (pos >= buff_size - 1) { + len_exceed = CM_TRUE; + continue; + } + if (is_plain_text) { + (void)printf("%c", char_ascii); + } else { + /* Faking a mask star * */ + (void)printf("*"); + } + buff[pos] = char_ascii; + pos++; + } + } while (CM_TRUE); + int32 end = pos < buff_size - 1 ? pos : buff_size - 1; + buff[end] = '\0'; + (void)printf("\n"); + if (len_exceed == CM_TRUE) { + (void)printf("invalid password, maximum length is %d\n", buff_size - 1); + return CM_ERROR; + } + return CM_SUCCESS; +} + +status_t wr_verify_password_str(const char *text, const char *rptext) +{ + uint32 len, rlen; + char *name = "sys"; + CM_POINTER2(text, rptext); + + // Verify input twice pswd + len = (uint32)strlen(text); + rlen = (uint32)strlen(rptext); + if (len != rlen || strcmp(text, rptext) != 0) { + (void)printf("Input twice passwords are inconsistent.\n"); + return CM_ERROR; + } + uint32 pwd_len = CM_PASSWD_MIN_LEN; + return cm_verify_password_str(name, text, pwd_len); +} + +// catch plain from terminal +status_t wr_catch_input_text(char *plain, uint32 plain_size) +{ + char first[CM_PASSWD_MAX_LEN + 1] = {0}; + char second[CM_PASSWD_MAX_LEN + 1] = {0}; + status_t ret; + errno_t errcode; + do { + (void)printf("Please enter password to encrypt: \n"); + ret = wr_receive_info_from_terminal(first, (int32)sizeof(first), CM_FALSE); + WR_BREAK_IF_ERROR(ret); + + (void)printf("Please input password again: \n"); + ret = wr_receive_info_from_terminal(second, (int32)sizeof(second), CM_FALSE); + WR_BREAK_IF_ERROR(ret); + + ret = wr_verify_password_str(first, second); + if (ret != CM_SUCCESS) { + (void)printf("1.password can't be more than 64 characters\n" + "2:password can't be less than %d characters\n" + "3.password should contain at least " + "three type the following characters:\n" + "A. at least one lowercase letter\n" + "B. at least one uppercase letter\n" + "C. at least one digit\n" + "D. at least one special character: `~!@#$%%^&*()-_=+\\|[{}]:\'\",<.>/? and space\n", + CM_PASSWD_MIN_LEN); + break; + } + + errcode = memcpy_s(plain, plain_size, first, CM_PASSWD_MAX_LEN + 1); + if (errcode != EOK) { + ret = CM_ERROR; + CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode); + break; + } + } while (0); + + MEMS_RETURN_IFERR(memset_s(first, CM_PASSWD_MAX_LEN + 1, 0, CM_PASSWD_MAX_LEN + 1)); + MEMS_RETURN_IFERR(memset_s(second, CM_PASSWD_MAX_LEN + 1, 0, CM_PASSWD_MAX_LEN + 1)); + return ret; +} diff --git a/src/cmd/wrcmd_encrypt.h b/src/cmd/wrcmd_encrypt.h new file mode 100644 index 0000000000000000000000000000000000000000..1d93b21af529616d6838786759021820a42a2763 --- /dev/null +++ b/src/cmd/wrcmd_encrypt.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wrcmd_encrypt.h + * + * + * IDENTIFICATION + * src/cmd/wrcmd_encrypt.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef WRCMD_ENCRYPT_H_ +#define WRCMD_ENCRYPT_H_ + +#include "wr_param.h" + +status_t wr_catch_input_text(char *plain, uint32 plain_size); +status_t wr_receive_info_from_terminal(char *buff, int32 buff_size, bool32 is_plain_text); +#endif diff --git a/src/cmd/wrcmd_inq.c b/src/cmd/wrcmd_inq.c new file mode 100644 index 0000000000000000000000000000000000000000..3fe711ba58477eb717b6c5a0fa62a0df49cc19b0 --- /dev/null +++ b/src/cmd/wrcmd_inq.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wrcmd_inq.c + * + * + * IDENTIFICATION + * src/cmd/wrcmd_inq.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_malloc.h" +#include "wr_latch.h" +#include "wrcmd_inq.h" + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef IOFENCE + +static void print_dev_info(ptlist_t *devs) +{ + return; +} + +static void print_reg_info(ptlist_t *regs) +{ + return; +} + +static status_t wr_modify_cluster_node_info( + wr_vg_info_item_t *vg_item, wr_config_t *inst_cfg, wr_inq_status_e inq_status, int64 host_id) +{ + return CM_SUCCESS; +} + +status_t wr_get_vg_non_entry_info( + wr_config_t *inst_cfg, wr_vg_info_item_t *vg_item, bool32 is_lock, bool32 check_redo) +{ + return CM_SUCCESS; +} + +status_t wr_inq_lun(const char *home) +{ + return CM_SUCCESS; +} + +status_t wr_inq_reg(const char *home) +{ + return CM_SUCCESS; +} + +bool32 is_register(iof_reg_in_t *reg, int64 host_id, int64 *iofence_key) +{ + return WR_FALSE; +} + +status_t wr_check_volume_register(char *entry_path, int64 host_id, bool32 *is_reg, int64 *iofence_key) +{ + return CM_SUCCESS; +} + +static status_t wr_reghl_inner(wr_vg_info_item_t *item, int64 host_id) +{ + return CM_SUCCESS; +} + +static void wr_printf_iofence_key(int64 *iofence_key) +{ + return; +} + +status_t wr_reghl_core(const char *home) +{ + return CM_SUCCESS; +} + +static status_t wr_unreghl_inner(wr_vg_info_item_t *item, int64 host_id) +{ + return CM_SUCCESS; +} + +status_t wr_unreghl_core(const char *home, bool32 is_lock) +{ + return CM_SUCCESS; +} + +static status_t wr_inq_reg_inner(wr_vg_info_t *vg_info, wr_config_t *inst_cfg, int64 host_id, int64 *iofence_key) +{ + return CM_PIPECLOSED; +} + +status_t wr_inq_reg_core(const char *home, int64 host_id) +{ + return CM_PIPECLOSED; +} + +static status_t wr_clean_inner(wr_vg_info_t *vg_info, wr_config_t *inst_cfg, int64 inst_id) +{ + return CM_SUCCESS; +} + +status_t wr_check_disk_latch_remain_inner( + int64 inst_id, wr_vg_info_t *vg_info, bool32 *is_remain, uint64 *latch_status) +{ + return CM_SUCCESS; +} + +status_t wr_check_lock_remain(wr_vg_info_t *vg_info, int32 wr_mode, int64 inst_id) +{ + return CM_SUCCESS; +} + +status_t wr_check_disk_latch_remain(int64 inst_id, wr_vg_info_t *vg_info) +{ + return CM_SUCCESS; +} + +static status_t wr_get_latch_flag(int64 type, uint64 *flags) +{ + return CM_SUCCESS; +} +status_t wr_query_latch_remain(const char *home, int64 inst_id, int64 type) +{ + return status; +} + +status_t wr_clean_vg_lock(const char *home, int64 inst_id) +{ + + return CM_SUCCESS; +} + +static status_t wr_kickh_inner(wr_vg_info_t *vg_info, wr_config_t *inst_cfg, int64 host_id, bool32 is_lock) +{ + return CM_SUCCESS; +} + +/* + * 1. get vg entry info + * 2. get vg non entry info without lock, then kick + * 3. get vg non entry info with lock, then kick + */ +status_t wr_kickh_core(const char *home, int64 host_id) +{ + return CM_SUCCESS; +} +#endif + +#ifdef __cplusplus +} +#endif diff --git a/src/cmd/wrcmd_inq.h b/src/cmd/wrcmd_inq.h new file mode 100644 index 0000000000000000000000000000000000000000..8c8bf193391d05c19dd6e6d1dcdf29fa0fdc3f0a --- /dev/null +++ b/src/cmd/wrcmd_inq.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wrcmd_inq.h + * + * + * IDENTIFICATION + * src/cmd/wrcmd_inq.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WRCMD_INQ_H__ +#define __WRCMD_INQ_H__ + +#include "wr_file_def.h" +#include "wr_io_fence.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef IOFENCE +typedef enum en_wr_inq_status { + WR_INQ_STATUS_REG = 0, + WR_INQ_STATUS_UNREG, +} wr_inq_status_e; + +typedef enum en_wr_latch_remain_status { + WR_NO_LATCH_STATUS = 0, + WR_LATCH_STATUS_X = 1, + WR_LATCH_STATUS_S = 2, +} wr_latch_remain_status_e; + +typedef enum en_wr_query_latch_type { + WR_LATCH_ALL = 0, + WR_VG_LATCH = 1, + WR_DISK_LATCH = 2, +} wr_query_latch_type_e; + +#define WR_VG_LATCH_FLAG 0x00000001 +#define WR_DISK_LATCH_FLAG 0x00000002 +#define WR_ALL_LATCH_FLAG (WR_VG_LATCH_FLAG | WR_DISK_LATCH_FLAG) + +status_t wr_inq_lun(const char *home); +status_t wr_inq_reg(const char *home); +status_t wr_check_volume_register(char *entry_path, int64 host_id, bool32 *is_reg, int64 *iofence_key); +status_t wr_unreghl_core(const char *home, bool32 is_lock); +status_t wr_reghl_core(const char *home); +status_t wr_inq_reg_core(const char *home, int64 host_id); +bool32 is_register(iof_reg_in_t *reg, int64 host_id, int64 *iofence_key); +status_t wr_clean_vg_lock(const char *home, int64 inst_id); +status_t wr_kickh_core(const char *home, int64 host_id); +status_t wr_get_vg_non_entry_info( + wr_config_t *inst_cfg, wr_vg_info_item_t *vg_item, bool32 is_lock, bool32 check_redo); +status_t wr_inq_alloc_vg_info(const char *home, wr_config_t *inst_cfg, wr_vg_info_t **vg_info); +void wr_inq_free_vg_info(wr_vg_info_t *vg_info); +status_t wr_query_latch_remain(const char *home, int64 inst_id, int64 type); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/cmd/wrcmd_interactive.c b/src/cmd/wrcmd_interactive.c new file mode 100644 index 0000000000000000000000000000000000000000..f5511c04bb4cecdb92a4c8180a52f1b45f9a95cf --- /dev/null +++ b/src/cmd/wrcmd_interactive.c @@ -0,0 +1,750 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wrcmd_interactive.c + * + * + * IDENTIFICATION + * src/cmd/wrcmd_interactive.c + * + * ------------------------------------------------------------------------- + */ + +#include +#include "wrcmd_interactive.h" +#include "wr_malloc.h" +#include "wr_file.h" +#include "wr_interaction.h" +#include "wr_api_impl.h" +#include "wrcmd_conn_opt.h" + +#ifndef WIN32 +#include +#include +#include +#include +#endif + +typedef struct st_wr_cmd_history_list { + uint32 nbytes; + uint32 nwidths; + char hist_buf[MAX_CMD_LEN]; +} wr_cmd_history_list_t; + +static wr_cmd_history_list_t g_hist_list[WR_CMD_MAX_HISTORY_SIZE + 1]; + +char g_cmd_buf[MAX_CMD_LEN]; + +bool8 g_run_interatively = CM_FALSE; + +char g_cur_path[WR_FILE_PATH_MAX_LENGTH] = {0}; + +bool8 cmd_check_need_convert_path(const char *input_path, uint32 *cur_path_len) +{ + if (!g_run_interatively) { + return CM_FALSE; + } + if (input_path[0] == '+') { + return CM_FALSE; + } + + *cur_path_len = strlen(g_cur_path); + if (*cur_path_len == 0) { + return CM_FALSE; + } + + return CM_TRUE; +} + +status_t cmd_check_convert_path(const char *input_args, void **convert_result, int *convert_size) +{ + status_t ret; + uint32 input_path_len; + uint32 cur_path_len; + char *convert_path; + uint32 convert_path_len; + + if (!cmd_check_need_convert_path(input_args, &cur_path_len)) { + return CM_SUCCESS; + } + + input_path_len = strlen(input_args); + convert_path_len = cur_path_len + input_path_len + 2; + + *convert_result = cm_malloc(convert_path_len); + if (*convert_result == NULL) { + WR_PRINT_ERROR("Malloc failed.\n"); + return CM_ERROR; + } + convert_path = (char *)*convert_result; + securec_check_ret(memcpy_s(convert_path, convert_path_len, g_cur_path, cur_path_len)); + convert_path[cur_path_len] = '/'; + securec_check_ret( + memcpy_s(convert_path + cur_path_len + 1, convert_path_len - cur_path_len - 1, input_args, input_path_len)); + convert_path[convert_path_len - 1] = '\0'; + + ret = wr_check_device_path(convert_path); + if (ret != CM_SUCCESS) { + free(*convert_result); + return ret; + } + + *convert_size = (int)convert_path_len; + return CM_SUCCESS; +} + +status_t wr_cmd_check_device_path(const char *path) +{ + uint32 cur_path_len; + + if (cmd_check_need_convert_path(path, &cur_path_len)) { + return CM_SUCCESS; + } + + return wr_check_device_path(path); +} + +void wr_cmd_exit_proc(int argc, char **args) +{ + if (argc != 2) { + WR_PRINT_ERROR("args num %d error.\n", argc - 1); + return; + } + + exit(EXIT_SUCCESS); +} + +status_t wr_cmd_check_path_exist(wr_conn_t *conn, char *path) +{ + bool32 exist = false; + gft_item_type_t type; + + WR_RETURN_IFERR2( + wr_exist_impl(conn, path, &exist, &type), WR_PRINT_ERROR("Failed to check the path %s exists.\n", path)); + if (!exist) { + WR_PRINT_ERROR("The path %s is not exist.\n", path); + return CM_ERROR; + } + if (type != GFT_PATH) { + WR_PRINT_ERROR("%s is not a directory.\n", path); + return CM_ERROR; + } + + return CM_SUCCESS; +} + +status_t wr_cmd_check_path(char *path) +{ + status_t status = wr_check_device_path(path); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("check path error.\n"); + return status; + } + + /* get connection from env of wr_home */ + wr_conn_t *conn = wr_get_connection_opt(NULL); + if (conn == NULL) { + WR_PRINT_ERROR("Failed to get uds connection.\n"); + return CM_ERROR; + } + + status = wr_cmd_check_path_exist(conn, path); + return status; +} + +status_t wr_cmd_format_path(char *org_path, char *out_path_buf, uint32 out_buf_len, uint32 *out_path_len) +{ + char *sub_path; + char *saved = NULL; + uint32 sub_path_len; + uint32 cur_len = 0; + + if (org_path == NULL || out_path_buf == NULL) { + return CM_ERROR; + } + + sub_path = strtok_r(org_path, "/", &saved); + sub_path_len = strlen(sub_path); + if (sub_path_len >= out_buf_len) { + WR_PRINT_ERROR("path is too long.\n"); + return CM_ERROR; + } + securec_check_ret(memcpy_s(out_path_buf, out_buf_len, sub_path, sub_path_len)); + cur_len += sub_path_len; + + while (sub_path != NULL) { + sub_path = strtok_r(NULL, "/", &saved); + if (sub_path == NULL) { + break; + } + sub_path_len = strlen(sub_path); + if (cur_len + sub_path_len + 1 >= out_buf_len) { + WR_PRINT_ERROR("path is too long.\n"); + return CM_ERROR; + } + out_path_buf[cur_len] = '/'; + cur_len += 1; + securec_check_ret(memcpy_s(out_path_buf + cur_len, out_buf_len - cur_len, sub_path, sub_path_len)); + cur_len += sub_path_len; + } + + out_path_buf[cur_len] = '\0'; + *out_path_len = cur_len; + return CM_SUCCESS; +} + +void wr_cmd_cd_proc(int argc, char **args) +{ + status_t ret; + char *path; + char *input_path = args[WR_ARG_IDX_2]; + char format_path[WR_FILE_PATH_MAX_LENGTH] = {0}; + char merged_path[WR_FILE_PATH_MAX_LENGTH] = {0}; + uint32 path_len; + uint32 format_path_len; + uint32 cur_path_len = strlen(g_cur_path); + + if (argc != 3) { + WR_PRINT_ERROR("args num %d error.\n", argc - 1); + return; + } + + if (input_path[0] == '/') { + WR_PRINT_ERROR("path should not start with /\n"); + return; + } + + ret = wr_cmd_format_path(input_path, format_path, WR_FILE_PATH_MAX_LENGTH, &format_path_len); + if (ret != CM_SUCCESS) { + return; + } + + errno_t err = 0; + if (input_path[0] == '+') { + path = format_path; + path_len = format_path_len; + } else { + if (format_path_len + cur_path_len + 1 >= WR_FILE_PATH_MAX_LENGTH) { + WR_PRINT_ERROR("path is too long.\n"); + return; + } + + err = memcpy_s(merged_path, WR_FILE_PATH_MAX_LENGTH, g_cur_path, cur_path_len); + if (err != EOK) { + WR_PRINT_ERROR("Error occured when copying current working directory, error code is %d.\n", err); + return; + } + merged_path[cur_path_len] = '/'; + err = memcpy_s( + merged_path + cur_path_len + 1, WR_FILE_PATH_MAX_LENGTH - cur_path_len - 1, format_path, format_path_len); + if (err != EOK) { + WR_PRINT_ERROR("Error occured when copying relative path error code is %d.\n", err); + return; + } + path_len = cur_path_len + format_path_len + 1; + merged_path[path_len] = '\0'; + path = merged_path; + } + + ret = wr_cmd_check_path(path); + if (ret != CM_SUCCESS) { + return; + } + + err = memcpy_s(g_cur_path, WR_FILE_PATH_MAX_LENGTH, path, path_len + 1); + if (err != EOK) { + WR_PRINT_ERROR("Error occured when copying new working directory, error code is %d.\n", err); + } +} + +void wr_cmd_pwd_proc(int argc, char **args) +{ + if (argc != 2) { + WR_PRINT_ERROR("args num %d error.\n", argc - 1); + return; + } + + WR_PRINT_INF("%s\n", g_cur_path); +} + +static void wr_cmd_exit_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s exit\n", prog_name); + (void)printf("[client command] exit wrcmd\n"); +} + +static void wr_cmd_cd_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s cd \n", prog_name); + (void)printf("[client command] change the current directory to path\n"); + if (print_flag == WR_HELP_SIMPLE) { + return; + } + (void)printf("path, , the path to change to\n"); +} + +static void wr_cmd_pwd_help(const char *prog_name, int print_flag) +{ + (void)printf("\nUsage:%s pwd\n", prog_name); + (void)printf("[client command] show current directory\n"); +} + +wr_interactive_cmd_t g_wr_interactive_cmd[] = { + {"cd", wr_cmd_cd_help, wr_cmd_cd_proc}, + {"pwd", wr_cmd_pwd_help, wr_cmd_pwd_proc}, + {"exit", wr_cmd_exit_help, wr_cmd_exit_proc}, +}; + +static bool32 get_interactive_cmd_idx(int argc, char **argv, uint32_t *idx) +{ + for (uint32 i = 0; i < sizeof(g_wr_interactive_cmd) / sizeof(g_wr_interactive_cmd[0]); ++i) { + if (strcmp(g_wr_interactive_cmd[i].cmd, argv[WR_ARG_IDX_1]) == 0) { + *idx = i; + return CM_TRUE; + } + } + return CM_FALSE; +} + +static uint32 wr_cmd_utf8_chr_widths(char *chr, uint32 c_bytes) +{ + wchar_t wchr; + uint32 c_widths = 0; + (void)mbtowc(&wchr, chr, c_bytes); +#ifndef WIN32 + c_widths = (uint32)wcwidth(wchr); +#endif + return c_widths; +} + +void wr_cmd_clean_line(uint32 line_widths) +{ + uint32 line_wid = line_widths; + while (line_wid--) { + wr_cmd_write(3, "\b \b"); + } +} + +int32 wr_utf8_chr_bytes(uint8 c, uint32 *bytes) +{ + uint8 chr = c; + // 1 byte character + if (chr < WR_UTF8_MULTI_BYTES_MASK) { + *bytes = 1; + return CM_SUCCESS; + } + + // 2-6 bytes character + *bytes = 0; + while (chr & WR_UTF8_MULTI_BYTES_MASK) { + (*bytes)++; + chr <<= 1; + } + + // begin with 10xxxxxx is invalid + if (*bytes >= 2 && *bytes <= 6) { + return CM_SUCCESS; + } else { + *bytes = 1; + return CM_ERROR; + } +} + +status_t wr_utf8_reverse_str_bytes(const char *str, uint32 len, uint32 *bytes) +{ + const char* cur_c = str; + + // 1 byte character + if (CM_IS_ASCII(*cur_c)) { + *bytes = 1; + return CM_SUCCESS; + } + + // 2-6 bytes character + *bytes = 1; + while ((*bytes < len) && IS_VALID_UTF8_CHAR(*cur_c)) { + (*bytes)++; + cur_c -= 1; + } + + return (*bytes >= 2 && *bytes <= 6 && *bytes < len) ? CM_SUCCESS : CM_ERROR; +} + +/* Calculate the position and total number of spaces used to space at the end of a line */ +void wr_cmd_set_endspace(wr_cmd_history_list_t hist_list, uint32 ws_col, uint32 welcome_width, + uint32 *spacenum, bool8 *endspace) +{ + uint32 offset = 0; + uint32 c_bytes = 0; + uint32 c_widths = 0; + uint32 nwidths = 0; + uint32 space_num = 0; + + (void)memset_s(endspace, MAX_CMD_LEN, 0, MAX_CMD_LEN); + while (offset < hist_list.nbytes) { + (void)wr_utf8_chr_bytes(hist_list.hist_buf[offset], &c_bytes); + c_widths = wr_cmd_utf8_chr_widths(hist_list.hist_buf + offset, c_bytes); + offset += c_bytes; + + if (c_widths == 2 && (nwidths + space_num + welcome_width + 1) % ws_col == 0) { + space_num++; + endspace[(nwidths + space_num + welcome_width + 1) / ws_col] = CM_TRUE; + } + nwidths += c_widths; + } + *spacenum = space_num; +} + +void wr_cmd_hist_turn_up(const int *hist_count, int *list_num, uint32 *nbytes, uint32 *nwidths, uint32 ws_col, + uint32 welcome_width, uint32 *spacenum, bool8 *endspace, char *cmd_buf, uint32 max_len) +{ + if (*list_num >= *hist_count) { + return; + } + wr_cmd_clean_line(*nwidths + *spacenum); + (*list_num)++; + + *nbytes = g_hist_list[*list_num].nbytes; + *nwidths = g_hist_list[*list_num].nwidths; + + errno_t err = memcpy_s(cmd_buf, max_len, g_hist_list[*list_num].hist_buf, *nbytes); + if (err != EOK) { + WR_PRINT_ERROR("Error occured when copying historical command.\n"); + return; + } + wr_cmd_write(*nbytes, g_hist_list[*list_num].hist_buf); + wr_cmd_write(2, " \b"); + wr_cmd_set_endspace(g_hist_list[*list_num], ws_col, welcome_width, spacenum, endspace); +} + +void wr_cmd_hist_turn_down(int *list_num, uint32 *nbytes, uint32 *nwidths, uint32 ws_col, uint32 welcome_width, + uint32 *spacenum, bool8 *endspace, char *cmd_buf, uint32 max_len) +{ + if (*list_num <= 1) { + return; + } + wr_cmd_clean_line(*nwidths + *spacenum); + (*list_num)--; + + *nbytes = g_hist_list[*list_num].nbytes; + *nwidths = g_hist_list[*list_num].nwidths; + + errno_t err = memcpy_s(cmd_buf, max_len, g_hist_list[*list_num].hist_buf, *nbytes); + if (err != EOK) { + WR_PRINT_ERROR("Error occured when copying historical command.\n"); + return; + } + wr_cmd_write(*nbytes, g_hist_list[*list_num].hist_buf); + wr_cmd_write(2, " \b"); + wr_cmd_set_endspace(g_hist_list[*list_num], ws_col, welcome_width, spacenum, endspace); +} + +void wr_cmd_push_history(uint32 cmd_bytes, uint32 cmd_width, int *hist_count, char *cmd_buf, uint32 max_len) +{ + if (cmd_bytes == 0) { + return; + } + + if (*hist_count < WR_CMD_MAX_HISTORY_SIZE) { + *hist_count += 1; + } + for (int i = *hist_count; i > 1; i--) { + (void)memcpy_s(&g_hist_list[i], sizeof(wr_cmd_history_list_t), + &g_hist_list[i - 1], sizeof(wr_cmd_history_list_t)); + } + errno_t err = memcpy_s(g_hist_list[1].hist_buf, MAX_CMD_LEN, cmd_buf, MAX_CMD_LEN); + if (err != EOK) { + WR_PRINT_ERROR("Error occured when copying historical command.\n"); + return; + } + g_hist_list[1].nbytes = cmd_bytes; + g_hist_list[1].nwidths = cmd_width; + return; +} + +#ifndef WIN32 +void wr_cmd_set_terminal(uint32 *ws_col, struct termios *oldt) +{ + struct winsize size; + status_t status = ioctl(STDIN_FILENO, TIOCGWINSZ, &size); + const uint32 DEFAULT_WS_COL = 80; + /* set default ws_col when ioctl fails */ + *ws_col = (status != CM_SUCCESS) ? DEFAULT_WS_COL : size.ws_col; + + struct termios newt; + (void)tcgetattr(STDIN_FILENO, oldt); + errno_t err = memcpy_s(&newt, sizeof(newt), oldt, sizeof(newt)); + if (err != EOK) { + WR_PRINT_ERROR("Error occured when copying termios.\n"); + return; + } + newt.c_lflag &= ~(ECHO | ICANON | ECHOE | ECHOK | ECHONL | ICRNL); + newt.c_cc[VMIN] = 1; + newt.c_cc[VTIME] = 0; + (void)tcsetattr(STDIN_FILENO, TCSANOW, &newt); // Set terminal input echo off. +} +#endif + +void wr_cmd_handle_backspace(char *cmd_buf, uint32 *nbytes, uint32 *nwidths, bool8 *endspace, + uint32 *spacenum, uint32 ws_col, uint32 welcome_width) +{ + char chr[WR_UTF8_CHR_SIZE]; + uint32 c_bytes = 0; + uint32 c_widths = 0; + uint32 tmp_nbytes = *nbytes; + uint32 tmp_nwidths = *nwidths; + uint32 tmp_spacenum = *spacenum; + + if (tmp_nbytes == 0) { + return; + } + + (void)wr_utf8_reverse_str_bytes(cmd_buf + tmp_nbytes - 1, tmp_nbytes, &c_bytes); + tmp_nbytes -= c_bytes; + errno_t err = memcpy_s(chr, WR_UTF8_CHR_SIZE, cmd_buf + tmp_nbytes, c_bytes); + if (err != EOK) { + WR_PRINT_ERROR("Error occured when copying command, error code is %d.\n", err); + return; + } + + c_widths = wr_cmd_utf8_chr_widths(chr, c_bytes); + for (int i = c_widths; i > 0; i--) { + wr_cmd_write(3, "\b \b"); + } + tmp_nwidths -= c_widths; + /* When there is a filled in space at the end of the line, one more space should be deleted. */ + if ((tmp_nwidths + tmp_spacenum + welcome_width) % ws_col == 0 && c_widths == 2 && + endspace[(tmp_nwidths + tmp_spacenum + welcome_width) / ws_col] == CM_TRUE) { + endspace[(tmp_nwidths + tmp_spacenum + welcome_width) / ws_col] = CM_FALSE; + tmp_spacenum--; + wr_cmd_write(3, "\b \b"); + } + + *nbytes = tmp_nbytes; + *nwidths = tmp_nwidths; + *spacenum = tmp_spacenum; +} + +void wr_cmd_handle_common_key(int32 input_key_char, char *cmd_buf, uint32 *nbytes, uint32 *nwidths, bool8 *endspace, + uint32 *spacenum, uint32 ws_col, uint32 welcome_width) +{ + int32 key_char = input_key_char; + char chr[WR_UTF8_CHR_SIZE]; + uint32 c_bytes = 0; + uint32 c_widths = 0; + uint32 tmp_nbytes = *nbytes; + uint32 tmp_nwidths = *nwidths; + uint32 tmp_spacenum = *spacenum; + + (void)wr_utf8_chr_bytes((uint8)key_char, &c_bytes); + if (tmp_nbytes + c_bytes > MAX_INPUT_LEN) { + return; + } + (void)memset_s(chr, WR_UTF8_CHR_SIZE, key_char, 1); + for (uint32 i = 1; i < c_bytes; i++) { + key_char = getchar(); + (void)memset_s(chr + i, WR_UTF8_CHR_SIZE - i, key_char, 1); + } + c_widths = wr_cmd_utf8_chr_widths(chr, c_bytes); + /* If the char is invisible, skip */ + if (c_widths == -1) { + return; + } + errno_t err = memcpy_s(cmd_buf + tmp_nbytes, MAX_CMD_LEN - tmp_nbytes, chr, c_bytes); + if (err != EOK) { + WR_PRINT_ERROR("Error occured when copying command error code is %d.\n", err); + return; + } + tmp_nbytes += c_bytes; + wr_cmd_write(c_bytes, chr); + /* UNIX console standard output requires special handling when the cursor is at the end of the line. + When the end of the line is exactly full of characters, the cursor needs to jump to the next line. + When there is only one space at the end of the line and the next character is full width, a space + needs to be filled in. */ + if (((tmp_nwidths + tmp_spacenum + welcome_width + 1) % ws_col == 0 && c_widths == 1) || + ((tmp_nwidths + tmp_spacenum + welcome_width + 2) % ws_col == 0 && c_widths == 2)) { + wr_cmd_write(2, " \b"); + } else if ((tmp_nwidths + tmp_spacenum + welcome_width + 1) % ws_col == 0 && c_widths == 2) { + tmp_spacenum++; + endspace[(tmp_nwidths + tmp_spacenum + welcome_width + 1) / ws_col] = CM_TRUE; + } + tmp_nwidths += c_widths; + + *nbytes = tmp_nbytes; + *nwidths = tmp_nwidths; + *spacenum = tmp_spacenum; +} + +bool8 wr_cmd_fgets(int *hist_count, int *list_num, uint32 welcome_width, char *cmd_buf, uint32 max_len) +{ + int32 key_char = 0; + int32 direction_key = 0; + uint32 nbytes = 0; + uint32 nwidths = 0; + uint32 spacenum = 0; // Record the number of spaces filled at the end of the line. + bool8 endspace[MAX_CMD_LEN] = {0}; // Record the line number with space at the end of the line. + uint32 ws_col = 0; + +#ifndef WIN32 + struct termios oldt; + wr_cmd_set_terminal(&ws_col, &oldt); +#endif + + while (key_char != CMD_KEY_ASCII_LF && key_char != CMD_KEY_ASCII_CR) { + key_char = getchar(); + WR_RETURN_STATUS_IF_TRUE((key_char < 0), CM_TRUE); + switch (key_char) { + case CMD_KEY_ESCAPE: + (void)getchar(); // '[' + direction_key = getchar(); + if (direction_key == CMD_KEY_UP) { + wr_cmd_hist_turn_up(hist_count, list_num, &nbytes, &nwidths, ws_col, welcome_width, &spacenum, + endspace, cmd_buf, max_len); + continue; + } else if (direction_key == CMD_KEY_DOWN) { + wr_cmd_hist_turn_down(list_num, &nbytes, &nwidths, ws_col, welcome_width, &spacenum, endspace, + cmd_buf, max_len); + continue; + } else if (direction_key == CMD_KEY_DEL) { + (void)getchar(); // '~' + } else { + continue; + } + + case CMD_KEY_ASCII_DEL: + case CMD_KEY_ASCII_BS: + wr_cmd_handle_backspace(cmd_buf, &nbytes, &nwidths, endspace, &spacenum, ws_col, welcome_width); + continue; + + case CMD_KEY_ASCII_CR: + case CMD_KEY_ASCII_LF: + *list_num = 0; + wr_cmd_write(1, "\n"); + continue; + + default: + wr_cmd_handle_common_key(key_char, cmd_buf, &nbytes, &nwidths, endspace, &spacenum, + ws_col, welcome_width); + continue; + } + } + + wr_cmd_push_history(nbytes, nwidths, hist_count, cmd_buf, max_len); + if (nbytes < max_len) { + cmd_buf[nbytes] = '\0'; + } + +#ifndef WIN32 + (void)tcsetattr(STDIN_FILENO, TCSANOW, &oldt); /* Set terminal input echo on */ +#endif + return CM_FALSE; +} + +uint32 wr_cmd_print_welcome() +{ + bool8 isConnected = wr_get_connection_opt_status(); + uint32 num = printf("wrcmd%s%s%s%s> ", isConnected ? "@connected" : "", + strcmp(g_cur_path, "") == CM_SUCCESS ? "" : "(", + strcmp(g_cur_path, "") == CM_SUCCESS ? "" : g_cur_path, + strcmp(g_cur_path, "") == CM_SUCCESS ? "" : ")"); + fflush(stdout); + return num; +} + +bool8 wr_exe_interactive_cmd(int argc, char **args) +{ + uint32_t idx; + + if (argc < CMD_ARGS_AT_LEAST) { + return CM_FALSE; + } + + if (get_interactive_cmd_idx(argc, args, &idx)) { + if (argc > WR_ARG_IDX_2 && + (strcmp(args[WR_ARG_IDX_2], "-h") == 0 || strcmp(args[WR_ARG_IDX_2], "--help") == 0)) { + g_wr_interactive_cmd[idx].help(args[0], WR_HELP_DETAIL); + } else { + g_wr_interactive_cmd[idx].proc(argc, args); + } + return CM_FALSE; + } + + return CM_TRUE; +} + +int wr_cmd_parse_args(char *cmd_buf, char **args, uint32 max_arg_num) +{ + char *tmpArg; + char *saved = NULL; + int argIdx = 1; + + args[0] = ""; + tmpArg = strtok_r(cmd_buf, " ", &saved); + while (tmpArg != NULL && argIdx < WR_MAX_ARG_NUM) { + args[argIdx] = tmpArg; + argIdx++; + tmpArg = strtok_r(NULL, " ", &saved); + } + + return argIdx; +} + +void cmd_print_interactive_help(char *prog_name, wr_help_type help_type) +{ + if (!g_run_interatively) { + return; + } + + for (uint32 i = 0; i < sizeof(g_wr_interactive_cmd) / sizeof(g_wr_interactive_cmd[0]); ++i) { + g_wr_interactive_cmd[i].help(prog_name, help_type); + } +} + +void wr_cmd_run_interactively() +{ + uint32 welcome_width = 0; + int hist_count = 0; + int list_num = 0; + char *args[WR_MAX_ARG_NUM] = {0}; + int argc; + uint32 cmd_idx; + bool8 go_ahead; + bool8 exit_cmd; + setlocale(LC_CTYPE, ""); + + while (!feof(stdin)) { + welcome_width = wr_cmd_print_welcome(); + + (void)memset_s(g_cmd_buf, MAX_CMD_LEN, 0, MAX_CMD_LEN); + exit_cmd = wr_cmd_fgets(&hist_count, &list_num, welcome_width, g_cmd_buf, MAX_CMD_LEN); + if (exit_cmd) { + break; + } + argc = wr_cmd_parse_args(g_cmd_buf, args, WR_MAX_ARG_NUM); + + cm_reset_error(); + go_ahead = wr_exe_interactive_cmd(argc, args); + if (!go_ahead) { + continue; + } + + execute_help_cmd(argc, args, &cmd_idx, &go_ahead); + if (!go_ahead) { + continue; + } + + (void)execute_cmd(argc, args, cmd_idx); + } +} diff --git a/src/cmd/wrcmd_interactive.h b/src/cmd/wrcmd_interactive.h new file mode 100644 index 0000000000000000000000000000000000000000..bd8c4a845614edd06faa3f8356e26d5c15d78990 --- /dev/null +++ b/src/cmd/wrcmd_interactive.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wrcmd_interactive.h + * + * + * IDENTIFICATION + * src/cmd/wrcmd_interactive.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WRCMD_INTERACTIVE_H__ +#define __WRCMD_INTERACTIVE_H__ + +#include "cm_utils.h" +#include "wr_defs.h" +#include "wr_args_parse.h" +#include "wrcmd.h" + +#define VERSION_SHORT (g_run_interatively ? "v" : "-v") +#define VERSION_LONG (g_run_interatively ? "version" : "--version") +#define ALL_SHORT (g_run_interatively ? "a" : "-a") +#define ALL_LONG (g_run_interatively ? "all" : "--all") +#define HELP_SHORT (g_run_interatively ? "h" : "-h") +#define HELP_LONG (g_run_interatively ? "help" : "--help") + +#define CMD_KEY_ASCII_BS 8 +#define CMD_KEY_ASCII_DEL 127 +#define CMD_KEY_ASCII_LF 10 +#define CMD_KEY_ASCII_CR 13 +#define CMD_KEY_ESCAPE 27 +#define CMD_KEY_UP 65 +#define CMD_KEY_DOWN 66 +#define CMD_KEY_DEL 51 + +#define MAX_INPUT_LEN 6144 +#define MAX_CMD_LEN MAX_INPUT_LEN + 1 +#define WR_MAX_ARG_NUM 30 +#define WR_UTF8_CHR_SIZE 6 +#define STDOUT 1 +#define WR_UTF8_MULTI_BYTES_MASK 0x80 +#define IS_VALID_UTF8_CHAR(c) (((c) & 0xC0) == 0x80) // 10xxxxxx +#define WR_CMD_MAX_HISTORY_SIZE 20 + +#define wr_cmd_write(len, fmt, ...) write(STDOUT, fmt, len) + +typedef void (*wr_interactive_cmd_proc)(int argc, char **args); + +typedef struct st_wr_interactive_cmd_t { + char cmd[CM_MAX_NAME_LEN]; + wr_admin_help help; + wr_interactive_cmd_proc proc; +} wr_interactive_cmd_t; + +extern char g_cur_path[WR_FILE_PATH_MAX_LENGTH]; + +extern bool8 g_run_interatively; + +status_t wr_cmd_check_device_path(const char *path); + +status_t cmd_check_convert_path(const char *input_args, void **convert_result, int *convert_size); + +void cmd_print_interactive_help(char *prog_name, wr_help_type help_type); + +void wr_cmd_run_interactively(); + +#endif \ No newline at end of file diff --git a/src/common/persist/README.md b/src/common/persist/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4f108996ba1676fe831a616b66f8a43f5b708825 --- /dev/null +++ b/src/common/persist/README.md @@ -0,0 +1,3 @@ +**Some C structs are defined firmly same as the structures of metadata on disk**. However, some OS architectures apply 4-byte alignment on C structs by default while others apply 8-byte alignment. As a result, metadata structures written to disks are different between these two kinds of systems, which is fatal for **compatibility**. + +Thus, all such C structs are compulsorily applied with **8-byte alignment**. To prevent possible ommissions, C structs defined for disk metadata must be defined under this directory, namely "src/common/persist". \ No newline at end of file diff --git a/src/common/persist/wr_alloc_unit.c b/src/common/persist/wr_alloc_unit.c new file mode 100644 index 0000000000000000000000000000000000000000..881433566c3e8c235fda427a74d654bf0cb8ae84 --- /dev/null +++ b/src/common/persist/wr_alloc_unit.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_alloc_unit.c + * + * + * IDENTIFICATION + * src/common/persist/wr_alloc_unit.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_defs.h" +#include "wr_alloc_unit.h" +#include "wr_file.h" +#include "wr_redo.h" +#include "wr_fs_aux.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void wr_init_au_root(wr_ctrl_t *wr_ctrl) +{ + CM_ASSERT(wr_ctrl != NULL); + wr_au_root_t *au_root = WR_GET_AU_ROOT(wr_ctrl); + au_root->count = 0; + au_root->free_root = CM_INVALID_ID64; + au_root->free_vol_id = 0; + + return; +} + +bool32 wr_can_alloc_from_recycle(const gft_node_t *root_node, bool32 is_before) +{ + if ((is_before && root_node->items.count >= WR_MIN_FILE_NUM_IN_RECYCLE) || + (!is_before && root_node->items.count > 0)) { + return WR_TRUE; + } + + return CM_FALSE; +} + +status_t wr_alloc_au_core(wr_session_t *session, wr_ctrl_t *wr_ctrl, wr_vg_info_item_t *vg_item, auid_t *auid) +{ + return CM_SUCCESS; +} + +bool32 wr_alloc_au_batch(wr_session_t *session, wr_vg_info_item_t *vg_item, auid_t *auid, uint32 count) +{ + return CM_TRUE; +} + +status_t wr_alloc_au(wr_session_t *session, wr_vg_info_item_t *vg_item, auid_t *auid) +{ + return CM_SUCCESS; +} + +status_t wr_get_core_version(wr_vg_info_item_t *item, uint64 *version) +{ + return CM_SUCCESS; +} + +// shoud lock in caller +status_t wr_load_core_ctrl(wr_vg_info_item_t *item, wr_core_ctrl_t *core) +{ + return CM_SUCCESS; +} + +void wr_update_core_ctrl( + wr_session_t *session, wr_vg_info_item_t *item, wr_core_ctrl_t *core, uint32 volume_id, bool32 is_only_root) +{ + CM_ASSERT(item != NULL); + CM_ASSERT(core != NULL); + + char *buf; + uint32 size; + + if (is_only_root) { + buf = (char *)core; + size = WR_DISK_UNIT_SIZE; + } else { + buf = (char *)core; + size = sizeof(wr_core_ctrl_t); + } + + // when update core ctrl ,handle should be valid. + wr_put_log(session, item, WR_RT_UPDATE_CORE_CTRL, buf, size); +} + +int64 wr_get_au_offset(wr_vg_info_item_t *item, auid_t auid) +{ + return (int64)((uint64)auid.au * (uint64)wr_get_vg_au_size(item->wr_ctrl)); +} + +status_t wr_get_au(wr_vg_info_item_t *item, auid_t auid, char *buf, int32 size) +{ + if (auid.volume >= WR_MAX_VOLUMES) { + return CM_ERROR; + } + + bool32 remote = CM_FALSE; + int64_t offset = wr_get_au_offset(item, auid); + return wr_check_read_volume(item, (uint32)auid.volume, offset, buf, size, &remote); +} + +status_t wr_get_au_head(wr_vg_info_item_t *item, auid_t auid, wr_au_head_t *au_head) +{ + CM_ASSERT(item != NULL); + CM_ASSERT(au_head != NULL); + + if (auid.volume >= WR_MAX_VOLUMES) { + return CM_ERROR; + } + + return wr_get_au(item, auid, (char *)au_head, sizeof(wr_au_head_t)); +} + +bool32 wr_cmp_auid(auid_t auid, uint64 id) +{ + return *(uint64 *)&auid == id; +} + +void wr_set_auid(auid_t *auid, uint64 id) +{ + *(uint64 *)auid = id; +} + +void wr_set_blockid(wr_block_id_t *blockid, uint64 id) +{ + *(uint64 *)blockid = id; +} + +bool32 wr_cmp_blockid(wr_block_id_t blockid, uint64 id) +{ + return *(uint64 *)&blockid == id; +} + +uint64 wr_get_au_id(wr_vg_info_item_t *item, uint64 offset) +{ + return offset / (uint64)wr_get_vg_au_size(item->wr_ctrl); +} + +status_t wr_get_volume_version(wr_vg_info_item_t *item, uint64 *version) +{ + CM_ASSERT(item != NULL); + CM_ASSERT(version != NULL); +#ifndef WIN32 + char temp[WR_DISK_UNIT_SIZE] __attribute__((__aligned__(WR_DISK_UNIT_SIZE))); +#else + char temp[WR_DISK_UNIT_SIZE]; +#endif + bool32 remote = CM_FALSE; + status_t status = + wr_load_vg_ctrl_part(item, (int64)WR_CTRL_VOLUME_OFFSET, temp, (int32)WR_DISK_UNIT_SIZE, &remote); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to load vg core version %s.", item->entry_path); + return status; + } + *version = ((wr_core_ctrl_t *)temp)->version; + return CM_SUCCESS; +} +#ifdef __cplusplus +} +#endif diff --git a/src/common/persist/wr_alloc_unit.h b/src/common/persist/wr_alloc_unit.h new file mode 100644 index 0000000000000000000000000000000000000000..73d32fe92871aabae5fff767d31400e0de1ee1b4 --- /dev/null +++ b/src/common/persist/wr_alloc_unit.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_alloc_unit.h + * + * + * IDENTIFICATION + * src/common/persist/wr_alloc_unit.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_ALLOC_UNIT_H__ +#define __WR_ALLOC_UNIT_H__ + +#include "cm_defs.h" +#include "wr_defs.h" +#include "wr_au.h" +#include "wr_diskgroup.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WR_GET_AU_ROOT(wr_ctrl_p) ((wr_au_root_t *)((wr_ctrl_p)->core.au_root)) +#define WR_MIN_FILE_NUM_IN_RECYCLE 32 + +typedef enum en_wr_au_type { + WR_AU_TYPE_FILE, + WR_AU_TYPE_META_FT, + WR_AU_TYPE_META_BITMAP, + WR_AU_TYPE_META_FREE, +} wr_au_type_t; + +#pragma pack(8) +typedef struct st_wr_au_t { + uint32_t checksum; + uint32_t type : 4; // au type:file,meta + uint32_t size : 28; + auid_t id; + auid_t next; // next free au + char reserve[488]; // 512 align +} wr_au_head_t; + +typedef struct st_wr_au_list_t { + uint32 count; + auid_t first; + auid_t last; +} wr_au_list_t; + +typedef struct st_wr_au_root_t { + uint64 version; + uint64 free_root; // .recycle ftid; + uint64 count; + uint32 free_vol_id; // the first volume that has free space. + uint32 reserve; + wr_au_list_t free_list; +} wr_au_root_t; +#pragma pack() + +bool32 wr_can_alloc_from_recycle(const gft_node_t *root_node, bool32 is_before); +void wr_init_au_root(wr_ctrl_t *wr_ctrl); +status_t wr_alloc_au(wr_session_t *session, wr_vg_info_item_t *vg_item, auid_t *auid); +bool32 wr_alloc_au_batch(wr_session_t *session, wr_vg_info_item_t *vg_item, auid_t *auid, uint32 count); + +status_t wr_get_core_version(wr_vg_info_item_t *item, uint64 *version); +status_t wr_load_core_ctrl(wr_vg_info_item_t *item, wr_core_ctrl_t *core); +void wr_update_core_ctrl( + wr_session_t *session, wr_vg_info_item_t *item, wr_core_ctrl_t *core, uint32 volume_id, bool32 is_only_root); +status_t wr_get_au_head(wr_vg_info_item_t *item, auid_t auid, wr_au_head_t *au_head); +status_t wr_get_au(wr_vg_info_item_t *item, auid_t auid, char *buf, int32 size); +bool32 wr_cmp_auid(auid_t auid, uint64 id); +void wr_set_auid(auid_t *auid, uint64 id); +int64 wr_get_au_offset(wr_vg_info_item_t *item, auid_t auid); +uint64 wr_get_au_id(wr_vg_info_item_t *item, uint64 offset); +void wr_set_blockid(wr_block_id_t *blockid, uint64 id); +bool32 wr_cmp_blockid(wr_block_id_t blockid, uint64 id); +status_t wr_get_volume_version(wr_vg_info_item_t *item, uint64 *version); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/persist/wr_au.c b/src/common/persist/wr_au.c new file mode 100644 index 0000000000000000000000000000000000000000..ab448cc9d069a7d9b4ece3dbc4bcf8e76f47c33a --- /dev/null +++ b/src/common/persist/wr_au.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_au.c + * + * + * IDENTIFICATION + * src/common/persist/wr_au.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_au.h" + +auid_t wr_invalid_auid = {.volume = 0x3ff, .au = 0x3ffffffff, .block = 0x1ffff, .item = 0x7}; +auid_t wr_set_inited_mask = {.volume = 0, .au = 0, .block = 0, .item = 0x1}; +auid_t wr_unset_inited_mask = {.volume = 0x3ff, .au = 0x3ffffffff, .block = 0x1ffff, .item = 0}; + +#define WR_DISPLAY_SIZE 75 + +#ifdef WIN32 +__declspec(thread) char g_display_buf[WR_DISPLAY_SIZE]; +#else +__thread char g_display_buf[WR_DISPLAY_SIZE]; +#endif + +char *wr_display_metaid(auid_t id) +{ + int ret = sprintf_s(g_display_buf, WR_DISPLAY_SIZE, "metaid:%llu (v:%u, au:%llu, block:%u, item:%u)", + WR_ID_TO_U64(id), (uint32)(id).volume, (uint64)(id).au, (uint32)(id).block, (uint32)(id).item); + if (ret < 0) { + g_display_buf[0] = '\0'; + } + return g_display_buf; +} diff --git a/src/common/persist/wr_au.h b/src/common/persist/wr_au.h new file mode 100644 index 0000000000000000000000000000000000000000..21ef930aa60c74bbe0e611029ec2225a7a4d4590 --- /dev/null +++ b/src/common/persist/wr_au.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_au.h + * + * + * IDENTIFICATION + * src/common/persist/wr_au.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_AU_H__ +#define __WR_AU_H__ + +#include "wr_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(8) +typedef struct st_auid_t { // id of allocation unit, 8 Bytes + uint64 volume : WR_MAX_BIT_NUM_VOLUME; + uint64 au : WR_MAX_BIT_NUM_AU; + uint64 block : WR_MAX_BIT_NUM_BLOCK; + uint64 item : WR_MAX_BIT_NUM_ITEM; +} auid_t; + +typedef struct st_wr_addr_t { + uint64 volumeid : 10; + uint64 offset : 54; +} wr_addr_t; + +#pragma pack() + +typedef auid_t wr_block_id_t; +typedef auid_t ftid_t; + +extern auid_t wr_invalid_auid; +#define WR_INVALID_AUID (wr_invalid_auid) +#define WR_INVALID_BLOCK_ID (wr_invalid_auid) +#define WR_INVALID_FTID (wr_invalid_auid) + +extern auid_t wr_set_inited_mask; +extern auid_t wr_unset_inited_mask; + +#define WR_AU_UNINITED_MARK 0x1 +static inline void wr_auid_set_uninit(auid_t *auid) +{ + auid->item |= WR_AU_UNINITED_MARK; +} + +static inline void wr_auid_unset_uninit(auid_t *auid) +{ + auid->item &= ~WR_AU_UNINITED_MARK; +} + +static inline bool32 wr_auid_is_uninit(auid_t *auid) +{ + return ((auid->item & WR_AU_UNINITED_MARK) != 0); +} + +#define WR_BLOCK_ID_SET_INITED(block_id) ((*(uint64 *)&block_id) & (*(uint64 *)&wr_unset_inited_mask)) +#define WR_BLOCK_ID_SET_UNINITED(block_id) ((*(uint64 *)&block_id) | (*(uint64 *)&wr_set_inited_mask)) +#define WR_BLOCK_ID_IGNORE_UNINITED(block_id) ((*(uint64 *)&block_id) & (*(uint64 *)&wr_unset_inited_mask)) +#define WR_BLOCK_ID_IS_INITED(block_id) (((block_id).item & WR_AU_UNINITED_MARK) == 0) + +#define WR_BLOCK_ID_SET_AUX(block_id) ((*(uint64 *)&block_id) | (*(uint64 *)&wr_set_inited_mask)) +#define WR_BLOCK_ID_SET_NOT_AUX(block_id) ((*(uint64 *)&block_id) & (*(uint64 *)&wr_unset_inited_mask)) +#define WR_BLOCK_ID_IS_AUX(block_id) (((block_id).item & WR_AU_UNINITED_MARK) == 1) + +char *wr_display_metaid(auid_t id); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/common/persist/wr_block_ctrl.h b/src/common/persist/wr_block_ctrl.h new file mode 100644 index 0000000000000000000000000000000000000000..3a4fff98ab7a8337e4040b24bc43a9d4dba8bcd7 --- /dev/null +++ b/src/common/persist/wr_block_ctrl.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_block_ctrl.h + * + * + * IDENTIFICATION + * src/common/persist/wr_block_ctrl.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_BLOCK_CTRL_H +#define __WR_BLOCK_CTRL_H + +#include "wr_defs.h" +#include "wr_au.h" +#include "cm_latch.h" +#include "cm_bilist.h" +#include "wr_shm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum en_wr_block_type { + WR_BLOCK_TYPE_FT, + WR_BLOCK_TYPE_FS, + WR_BLOCK_TYPE_FS_AUX, + WR_BLOCK_TYPE_MAX, // should be the end +} wr_block_type_t; + +#pragma pack(8) +typedef union st_wr_fs_block_cache_info { + // this for cache gft_node_t + struct { + char *entry_block_addr; + char *fs_block_addr; + char *fs_aux_addr; + uint64 entry_block_id; + uint64 fs_block_id; + uint64 fs_aux_block_id; + + // for find the owner vg and cache slot + uint32 owner_vg_id; + uint32 owner_ftid_cache_index; + }; + // this for cache fs_block_t and fs_aux_block_t + struct { + char *owner_node_addr; + uint64 owner_node_id; + }; +} wr_fs_block_cache_info_t; + +typedef struct st_wr_block_ctrl { + latch_t latch; + wr_block_type_t type; + wr_block_id_t block_id; + sh_mem_p hash_next; + sh_mem_p hash_prev; + uint32_t hash; + bool32 has_next; + bool32 has_prev; + ga_obj_id_t my_obj_id; + + // the follow data setted or unsetted by uplayer, not by meta buf + // the follow info need not to make sure be seen by cli-api, such as point + // this section indentify the block owner + // every bg task using the ctrl should check (node != NULL), (fid, file_ver) and (node->fid, node->file_ver) first + // with the latch + bool32 is_refresh_ftid; // just for wr_ft_block_t + uint64 fid; // it's the owner's gft_node_t.fid + uint64 ftid; + uint64 file_ver; // it's the owner's gft_node_t.file_ver + char *node; // it's the owner's gft_node_t mem pointer + + uint64 bg_task_ref_cnt; // every bg task should inc this cnt with the latch + bool32 reserve; + + // this section using for cache + wr_fs_block_cache_info_t fs_block_cache_info; // only save in ft block ctrl now + + // this section using for ctrl syn meta bg task + int64 syn_meta_ref_cnt; + bilist_node_t syn_meta_node; // for syn meta + + // this section using for ctrl recycle meta + int64 ref_hot; + bilist_node_t recycle_meta_node; + bool8 recycle_disable; +} wr_block_ctrl_t; + +typedef struct st_wr_block_ctrl_task_desc_t { + latch_t latch; + bilist_t bilist; + void *task_args; +} wr_block_ctrl_task_desc_t; +#pragma pack() + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/common/persist/wr_ctrl_def.h b/src/common/persist/wr_ctrl_def.h new file mode 100644 index 0000000000000000000000000000000000000000..5514b67bceb3de18ccceb5a1e32cb9fe4bfcc61c --- /dev/null +++ b/src/common/persist/wr_ctrl_def.h @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_ctrl_def.h + * + * + * IDENTIFICATION + * src/common/persist/wr_ctrl_def.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_CTRL_DEF_H__ +#define __WR_CTRL_DEF_H__ + +#include "wr_defs.h" +#include "wr_au.h" +#include "cm_spinlock.h" +#include "wr_hashmap.h" +#include "cm_latch.h" +#include "wr_ga.h" +#include "cm_date.h" +#include "cm_bilist.h" +#include "wr_shm_hashmap.h" +#include "wr_param.h" +#include "wr_stack.h" +#include "wr_shm.h" +#include "wr_block_ctrl.h" + +#define WR_GET_ROOT_BLOCK(wr_ctrl_p) ((wr_root_ft_block_t *)((wr_ctrl_p)->root)) +#define WR_MAX_FT_AU_NUM 10 +#define WR_GET_FT_AU_LIST(ft_au_list_p) ((wr_ft_au_list_t *)(ft_au_list_p)) +#define WR_GET_FS_BLOCK_ROOT(wr_ctrl_p) ((wr_fs_block_root_t *)((wr_ctrl_p)->core.fs_block_root)) +#define WR_MAX_VOLUME_GROUP_NUM (CM_HASH_SHM_MAX_ID) +#define WR_VG_ITEM_CACHE_NODE_MAX 16 +#define WR_RECYLE_DIR_NAME ".recycle" + +#define WR_CTRL_RESERVE_SIZE1 (SIZE_K(663)) +#define WR_CTRL_RESERVE_SIZE2 (SIZE_K(15) - 512) +#define WR_CTRL_RESERVE_SIZE3 (SIZE_K(32)) +#define WR_CTRL_RESERVE_SIZE4 512 + +#define WR_CTRL_CORE_OFFSET OFFSET_OF(wr_ctrl_t, core_data) +#define WR_CTRL_VOLUME_OFFSET OFFSET_OF(wr_ctrl_t, volume_data) +#define WR_CTRL_VG_DATA_OFFSET OFFSET_OF(wr_ctrl_t, vg_data) +#define WR_CTRL_VG_LOCK_OFFSET OFFSET_OF(wr_ctrl_t, lock) +#define WR_CTRL_ROOT_OFFSET OFFSET_OF(wr_ctrl_t, root) +#define WR_CTRL_GLOBAL_CTRL_OFFSET OFFSET_OF(wr_ctrl_t, global_data) +#define WR_CTRL_REDO_OFFSET OFFSET_OF(wr_ctrl_t, redo_ctrl_data) +#define WR_VG_LOCK_SHARE_DISK_OFFSET OFFSET_OF(wr_ctrl_t, disk_lock) + +#define WR_CTRL_BAK_ADDR SIZE_M(1) +#define WR_CTRL_BAK_CORE_OFFSET (WR_CTRL_BAK_ADDR + WR_CTRL_CORE_OFFSET) +#define WR_CTRL_BAK_VOLUME_OFFSET (WR_CTRL_BAK_ADDR + WR_CTRL_VOLUME_OFFSET) +#define WR_CTRL_BAK_VG_DATA_OFFSET (WR_CTRL_BAK_ADDR + WR_CTRL_VG_DATA_OFFSET) +#define WR_CTRL_BAK_VG_LOCK_OFFSET (WR_CTRL_BAK_ADDR + WR_CTRL_VG_LOCK_OFFSET) +#define WR_CTRL_BAK_ROOT_OFFSET (WR_CTRL_BAK_ADDR + WR_CTRL_ROOT_OFFSET) +#define WR_CTRL_BAK_GLOBAL_CTRL_OFFSET (WR_CTRL_BAK_ADDR + WR_CTRL_GLOBAL_CTRL_OFFSET) +#define WR_CTRL_BAK_REDO_OFFSET (WR_CTRL_BAK_ADDR + WR_CTRL_REDO_OFFSET) + +// Size of the volume header. 2MB is used to store vg_ctrl and its backup. The last 2MB is reserved. +#define WR_VOLUME_HEAD_SIZE SIZE_M(4) + +#define WR_VG_IS_VALID(ctrl_p) ((ctrl_p)->vg_info.valid_flag == WR_CTRL_VALID_FLAG) + +#define WR_STANDBY_CLUSTER (g_inst_cfg->params.cluster_run_mode == CLUSTER_STANDBY) +#define WR_IS_XLOG_VG(VG_ID) (VG_ID == g_inst_cfg->params.xlog_vg_id) +#define WR_STANDBY_CLUSTER_XLOG_VG(VG_ID) (WR_STANDBY_CLUSTER && WR_IS_XLOG_VG(VG_ID)) + +#define WR_FS_BLOCK_ROOT_SIZE 64 +#define WR_AU_ROOT_SIZE 64 + +typedef enum en_vg_info_type { + WR_VG_INFO_CORE_CTRL = 1, + WR_VG_INFO_VG_HEADER, + WR_VG_INFO_VOLUME_CTRL, + WR_VG_INFO_ROOT_FT_BLOCK, + WR_VG_INFO_GFT_NODE, + WR_VG_INFO_REDO_CTRL, + WR_VG_INFO_TYPE_END, +} wr_vg_info_type_e; + +#ifdef WIN32 +typedef HANDLE volume_handle_t; +#else +typedef int32 volume_handle_t; +#endif + +#define WR_VOLUME_DEF_RESVS 112 + +#define WR_FS_AUX_ROOT_SIZE 32 +#define WR_GET_FS_AUX_ROOT(wr_ctrl_p) ((wr_fs_aux_root_t *)((wr_ctrl_p)->core.fs_aux_root)) +#define WR_GET_FS_AUX_NUM_IN_AU(wr_ctrl) ((wr_get_vg_au_size(wr_ctrl)) / WR_FS_AUX_SIZE) +#define WR_CTRL_RESV_SIZE \ + ((((((WR_DISK_UNIT_SIZE) - (24)) - (WR_FS_BLOCK_ROOT_SIZE)) - (WR_AU_ROOT_SIZE)) - (WR_FS_AUX_ROOT_SIZE))) + +#pragma pack(8) +typedef struct st_wr_volume_def { + uint64 id : 16; + uint64 flag : 3; + uint64 reserve : 45; + uint64 version; + char name[WR_MAX_VOLUME_PATH_LEN]; + char code[WR_VOLUME_CODE_SIZE]; + char resv[WR_VOLUME_DEF_RESVS]; +} wr_volume_def_t; // CAUTION:If add/remove field ,please keep 256B total !!! Or modify rp_redo_add_or_remove_volume + +typedef enum en_volume_slot { + VOLUME_FREE = 0, // free + VOLUME_OCCUPY = 1, + VOLUME_PREPARE = 2, // not registered + VOLUME_ADD = 3, // add + VOLUME_REMOVE = 4, // remove + VOLUME_REPLACE = 5, // replace + VOLUME_FLAG_MAX, +} volume_slot_e; + +typedef struct st_wr_volume_attr { + uint64 reverse1 : 1; + uint64 id : 16; + uint64 reserve2 : 47; + uint64 size; + uint64 hwm; + uint64 free; +} wr_volume_attr_t; // CAUTION:If add/remove field ,please keep 32B total !!! Or modify rp_redo_add_or_remove_volume + +typedef enum wr_vg_device_Type { + WR_VOLUME_TYPE_RAW = 0 // default is raw device +} wr_vg_device_Type_e; + +typedef struct st_wr_volume { + char name[WR_MAX_VOLUME_PATH_LEN]; + char *name_p; + wr_volume_attr_t *attr; + uint32 id; + volume_handle_t handle; + volume_handle_t unaligned_handle; + wr_vg_device_Type_e vg_type; +} wr_volume_t; + +typedef struct st_wr_volume_disk { + wr_volume_def_t def; + wr_volume_attr_t attr; + uint32 id; +} wr_volume_disk_t; + +typedef struct st_wr_metablock_header_t { + wr_addr_t free_block_begin; + wr_addr_t free_block_end; + wr_addr_t first_block; +} wr_metablock_header_t; + +#define WR_VOLUME_TYPE_NORMAL 0x12345678 +#define WR_VOLUME_TYPE_MANAGER 0x12345679 +typedef struct st_wr_volume_type_t { + uint32 type; + uint32 id; + char entry_volume_name[WR_MAX_VOLUME_PATH_LEN]; +} wr_volume_type_t; + +typedef enum st_wr_bak_level_e { + WR_BAK_LEVEL_0 = 0, // super block only backed up on first volume, fs and ft do not backup + WR_BAK_LEVEL_1, // super block backed up on some specific volumes, fs and ft backed up at the end of each volume + WR_BAK_LEVEL_2, // super block backed up on all volumes, fs and ft backed up at the end of each volume +} wr_bak_level_e; + +#define WR_MAX_BAK_LEVEL WR_BAK_LEVEL_2 + +typedef enum en_wr_software_version { + WR_SOFTWARE_VERSION_0 = 0, /* version 0 */ + WR_SOFTWARE_VERSION_1 = 1, /* version 1 */ + WR_SOFTWARE_VERSION_2 = 2, /* version 2 */ +} wr_software_version_e; + +#define WR_SOFTWARE_VERSION WR_SOFTWARE_VERSION_2 + +#define WR_CTRL_VALID_FLAG 0x5f3759df +typedef struct st_wr_disk_group_header_t { + uint32 checksum; + wr_volume_type_t vol_type; + char vg_name[WR_MAX_NAME_LEN]; + uint32 valid_flag; + uint32 software_version; // for upgrade + timeval_t create_time; + wr_bak_level_e bak_level; + uint32 ft_node_ratio; // ft_node is created for every ft_node_ratio bytes of space + uint64 bak_ft_offset; // Start position of the backup ft_node array +} wr_vg_header_t; + +typedef wr_vg_header_t wr_volume_header_t; + +typedef struct st_wr_simple_handle_t { + uint32 id; + volume_handle_t handle; + volume_handle_t unaligned_handle; + uint64 version; + wr_vg_device_Type_e vg_type; +} wr_simple_volume_t; + +typedef struct st_wr_core_ctrl { + uint32 checksum; // NOTE:checksum can not change the position in the struct.wr_get_checksum need. + uint32 reserve; + uint64 version; + uint32 au_size; // allocation unit size,4M,8M,16M,32M,64M + uint32 volume_count; + char fs_block_root[WR_FS_BLOCK_ROOT_SIZE]; // wr_fs_block_root_t + char au_root[WR_AU_ROOT_SIZE]; // 512-24-64,wr_au_root_t, recycle space entry + char fs_aux_root[WR_FS_AUX_ROOT_SIZE]; // wr_fs_aux_root_t + char resv[WR_CTRL_RESV_SIZE]; + wr_volume_attr_t volume_attrs[WR_MAX_VOLUMES]; +} wr_core_ctrl_t; + +typedef struct st_wr_volume_ctrl { + uint32 checksum; // NOTE:can not change the position in the struct. + uint32 rsvd; + uint64 version; + char reserve[496]; + wr_volume_def_t defs[WR_MAX_VOLUMES]; +} wr_volume_ctrl_t; + +// struct for volume refresh +typedef struct st_refvol_ctrl { // UNUSED + wr_core_ctrl_t core; + wr_volume_ctrl_t volume; +} wr_refvol_ctrl_t; + +typedef struct st_wr_group_global_ctrl { + uint64 cluster_node_info; +} wr_group_global_ctrl_t; + +#define WR_MAX_EXTENDED_COUNT 8 +typedef struct st_wr_redo_ctrl { + uint32 checksum; + uint32 redo_index; + uint64 version; + uint64 offset; // redo offset + uint64 lsn; // redo lsn + auid_t redo_start_au[WR_MAX_EXTENDED_COUNT]; + uint32 redo_size[WR_MAX_EXTENDED_COUNT]; // except redo_size > 32KB + uint32 count; + char reserve[376]; +} wr_redo_ctrl_t; + +typedef struct st_wr_ctrl { + union { + wr_vg_header_t vg_info; + char vg_data[WR_VG_DATA_SIZE]; + }; + union { + wr_core_ctrl_t core; + char core_data[WR_CORE_CTRL_SIZE]; // 16K + }; + + union { + wr_volume_ctrl_t volume; + char volume_data[WR_VOLUME_CTRL_SIZE]; // 256K + }; + char root[WR_ROOT_FT_DISK_SIZE]; // wr_root_ft_block_t, 8KB + union { + wr_redo_ctrl_t redo_ctrl; + char redo_ctrl_data[WR_DISK_UNIT_SIZE]; // 512 + }; + char reserve1[WR_CTRL_RESERVE_SIZE1]; // 663K + char disk_latch[WR_INIT_DISK_LATCH_SIZE]; // INIT DISK LATCH 32KB + union { + struct { + char disk_lock[WR_LOCK_SHARE_DISK_SIZE]; // share disk lock, 32KB + 512, align with 8K + char reserve4[WR_CTRL_RESERVE_SIZE4]; // 512 + }; + struct { + char reserve3[WR_CTRL_RESERVE_SIZE3]; // 32KB + char lock[WR_DISK_LOCK_LEN]; // align with 16K + }; + }; + char reserve2[WR_CTRL_RESERVE_SIZE2]; + union { + wr_group_global_ctrl_t global_ctrl; + char global_data[WR_DISK_UNIT_SIZE]; // client disk info, size is 512 + }; +} wr_ctrl_t; + +static inline void wr_set_software_version(wr_vg_header_t *vg_header, uint32 version) +{ + CM_ASSERT(vg_header != NULL); + vg_header->software_version = version; +} + +static inline uint32 wr_get_software_version(wr_vg_header_t *vg_header) +{ + CM_ASSERT(vg_header != NULL); + return vg_header->software_version; +} + +typedef enum en_wr_vg_status { + WR_VG_STATUS_RECOVERY = 1, + WR_VG_STATUS_ROLLBACK, + WR_VG_STATUS_OPEN, +} wr_vg_status_e; + +#define WR_UNDO_LOG_NUM (WR_LOG_BUFFER_SIZE / 8) + +typedef enum en_latch_type { + LATCH_VG_HEADER = 0, + LATCH_CORE_CTRL, + LATCH_VOLUME_CTRL, + LATCH_FT_ROOT, + LATCH_COUNT, // must be last +} latch_type_t; + +typedef struct st_wr_vg_cache_node_t { + latch_t latch; + uint64 fid; + uint64 ftid; + char *node; +} wr_vg_cache_node_t; + +typedef enum en_wr_from_type { + FROM_SHM = 0, + FROM_BBOX, + FROM_DISK, +} wr_from_type_e; + +typedef struct st_wr_log_file_ctrl { + spinlock_t lock; + char *log_buf; // global log_buf + bool8 used; + uint32 index; + uint64 offset; + uint64 lsn; +} wr_log_file_ctrl_t; + +typedef struct st_wr_vg_info_item_t { + uint32 id; + char vg_name[WR_MAX_NAME_LEN]; + char entry_path[WR_MAX_VOLUME_PATH_LEN]; // the manager volume path + wr_vg_status_e status; + cm_oamap_t au_map; // UNUSED + wr_volume_t volume_handle[WR_MAX_VOLUMES]; + wr_shared_latch_t *vg_latch; + wr_ctrl_t *wr_ctrl; + shm_hashmap_t *buffer_cache; + char *align_buf; + wr_stack stack; + latch_t open_file_latch; + bilist_t open_file_list; // open file bilist. + latch_t disk_latch; // just for lock vg to lock the local instance. + latch_t latch[LATCH_COUNT]; + wr_from_type_e from_type; + wr_block_ctrl_task_desc_t syn_meta_desc; + wr_vg_cache_node_t vg_cache_node[WR_VG_ITEM_CACHE_NODE_MAX]; + wr_log_file_ctrl_t log_file_ctrl; // redo log ctrl + wr_block_ctrl_task_desc_t recycle_meta_desc; // for recycle meta + uint32 objectid; + uint32 space_alarm; +} wr_vg_info_item_t; + +typedef struct st_wr_vg_info_t { + wr_vg_info_item_t volume_group[WR_MAX_VOLUME_GROUP_NUM]; + uint32_t group_num; +} wr_vg_info_t; + +typedef struct st_wr_vol_handles_t { + wr_simple_volume_t volume_handle[WR_MAX_VOLUMES]; +} wr_vol_handles_t; + +typedef struct st_wr_cli_vg_handles_t { + wr_vol_handles_t vg_vols[WR_MAX_VOLUME_GROUP_NUM]; + uint32_t group_num; +} wr_cli_vg_handles_t; + +typedef struct st_wr_vg_conf_t { + char vg_name[WR_MAX_NAME_LEN]; + char entry_path[WR_MAX_VOLUME_PATH_LEN]; // the manager volume path +} wr_vg_conf_t; + +typedef struct st_wr_share_vg_item_t { + wr_shared_latch_t vg_latch; + shm_hashmap_t buffer_cache; + uint32 objectid; + uint32 id; + char reserve[412]; // align 512 + wr_ctrl_t wr_ctrl; +} wr_share_vg_item_t; + +#pragma pack() +#endif // __WR_CTRL_DEF_H__ diff --git a/src/common/persist/wr_defs_print.c b/src/common/persist/wr_defs_print.c new file mode 100644 index 0000000000000000000000000000000000000000..cc7c9ffd3b64446f7f099bebdc80b5d2077a2a2c --- /dev/null +++ b/src/common/persist/wr_defs_print.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_defs_print.c + * + * + * IDENTIFICATION + * src/common/persist/wr_defs_print.c + * + * ------------------------------------------------------------------------- + */ + +#include "cm_log.h" +#include "wr_malloc.h" +#include "wr_defs_print.h" + +uint8 g_print_level = 0; + +void printf_auid(const auid_t *first) +{ + char *tab = wr_get_print_tab(g_print_level); + (void)printf("%s auid = %llu\n", tab, *(uint64 *)first); + (void)printf("%s volume = %llu\n", tab, (uint64)first->volume); + (void)printf("%s au = %llu\n", tab, (long long unsigned int)(first->au)); + (void)printf("%s block = %llu\n", tab, (uint64)first->block); + (void)printf("%s item = %llu\n", tab, (uint64)first->item); +} + +void printf_wr_fs_block_list(wr_fs_block_list_t *free) +{ + (void)printf(" count = %llu\n", free->count); + + auid_t *first = &free->first; + (void)printf(" first = {\n"); + printf_auid(first); + (void)printf(" }\n"); + + auid_t *last = &free->last; + (void)printf(" last = {\n"); + printf_auid(last); + (void)printf(" }\n"); +} + +void printf_wr_fs_aux_root(wr_fs_aux_root_t *root) +{ + (void)printf(" version = %llu\n", root->version); + + wr_fs_block_list_t *free = &root->free; + (void)printf(" free = {\n"); + printf_wr_fs_block_list(free); + (void)printf(" }\n"); +} + +void printf_wr_fs_block_root(wr_fs_block_root_t *root) +{ + (void)printf(" version = %llu\n", root->version); + + wr_fs_block_list_t *free = &root->free; + (void)printf(" free = {\n"); + printf_wr_fs_block_list(free); + (void)printf(" }\n"); +} + +void printf_wr_volume_attr(const wr_volume_attr_t *volume_attrs) +{ + (void)printf(" id = %llu\n", (uint64)volume_attrs->id); + (void)printf(" size = %llu\n", volume_attrs->size); + (void)printf(" hwm = %llu\n", volume_attrs->hwm); + (void)printf(" free = %llu\n", volume_attrs->free); +} + +static void printf_wr_au_list(wr_au_list_t *free_list) +{ + (void)printf(" count = %u\n", free_list->count); + (void)printf(" frist = {\n"); + printf_auid(&free_list->first); + (void)printf(" }\n"); + (void)printf(" last = {\n"); + printf_auid(&free_list->last); + (void)printf(" }\n"); +} + +void printf_wr_au_root(wr_au_root_t *au_root) +{ + (void)printf(" version = %llu\n", au_root->version); + (void)printf(" free_root = %llu\n", au_root->free_root); + (void)printf(" count = %llu\n", au_root->count); + (void)printf(" free_vol_id = %u\n", au_root->free_vol_id); + (void)printf(" reserve = %u\n", au_root->reserve); + + wr_au_list_t *free_list = &au_root->free_list; + (void)printf(" free_list = {\n"); + printf_wr_au_list(free_list); + (void)printf(" }\n"); +} + +void wr_printf_core_ctrl_base(wr_core_ctrl_t *core_ctrl) +{ + (void)printf("core_ctrl = {\n"); + (void)printf(" checksum = %u\n", core_ctrl->checksum); + (void)printf(" reserve = %u\n", core_ctrl->reserve); + (void)printf(" version = %llu\n", core_ctrl->version); + (void)printf(" au_size = %u\n", core_ctrl->au_size); + (void)printf(" volume_count = %u\n", core_ctrl->volume_count); + (void)printf(" fs_block_root = {\n"); + + wr_fs_block_root_t *root = (wr_fs_block_root_t *)(core_ctrl->fs_block_root); + printf_wr_fs_block_root(root); + (void)printf(" }\n"); + (void)printf(" au_root = {\n"); + + wr_au_root_t *au_root = (wr_au_root_t *)(core_ctrl->au_root); + printf_wr_au_root(au_root); + (void)printf(" }\n"); + + wr_volume_attr_t *volume_attrs = core_ctrl->volume_attrs; + for (uint32 i = 0; i < WR_MAX_VOLUMES; ++i) { + if (i == 0 || volume_attrs->id != 0) { + (void)printf(" volume_attrs[%u] = {\n", i); + printf_wr_volume_attr(volume_attrs); + (void)printf(" }\n"); + } + volume_attrs++; + continue; + } + + (void)printf("}\n"); +} + +void printf_gft_list(gft_list_t *items) +{ + (void)printf(" count = %u\n", items->count); + (void)printf(" first = {\n"); + + ftid_t *first = &items->first; + printf_auid(first); + (void)printf(" }\n"); + (void)printf(" last = {\n"); + + ftid_t *last = &items->last; + printf_auid(last); + (void)printf(" }\n"); +} + +void printf_gft_root(gft_root_t *ft_root) +{ + (void)printf(" free_list = {\n"); + + gft_list_t *free_list = &ft_root->free_list; + printf_gft_list(free_list); + (void)printf(" }\n"); + (void)printf(" items = {\n"); + + gft_list_t *items = &ft_root->items; + printf_gft_list(items); + (void)printf(" }\n"); + (void)printf(" fid = %llu\n", ft_root->fid); + (void)printf(" first = {\n"); + + wr_block_id_t *block_id_first = &ft_root->first; + printf_auid(block_id_first); + (void)printf(" }\n"); + (void)printf(" last = {\n"); + + wr_block_id_t *block_id_last = &ft_root->last; + printf_auid(block_id_last); + (void)printf(" }\n"); +} + +void printf_gft_node(gft_node_t *gft_node, const char *tab) +{ + if (gft_node->type == GFT_PATH) { + (void)printf("%s type = GFT_PATH\n", tab); + gft_list_t *items = &gft_node->items; + (void)printf("%s items = {\n", tab); + printf_gft_list(items); + (void)printf("%s }\n", tab); + } else if (gft_node->type == GFT_FILE) { + (void)printf("%s type = GFT_FILE\n", tab); + wr_block_id_t *entry = &gft_node->entry; + (void)printf("%s entry = {\n", tab); + printf_auid(entry); + (void)printf("%s }\n", tab); + } + (void)printf("%s software_version = %u\n", tab, gft_node->software_version); + (void)printf("%s name = %s\n", tab, gft_node->name); + (void)printf("%s fid = %llu\n", tab, gft_node->fid); + (void)printf("%s flags = %u\n", tab, gft_node->flags); + (void)printf("%s size = %lld\n", tab, gft_node->size); + (void)printf("%s written_size = %llu\n", tab, gft_node->written_size); + (void)printf("%s parent = {\n", tab); + printf_auid(&gft_node->parent); + (void)printf("%s }\n", tab); + (void)printf("%s file_ver = %llu\n", tab, gft_node->file_ver); + (void)printf("%s min_inited_size = %llu\n", tab, gft_node->min_inited_size); + char time[512]; + (void)cm_time2str(gft_node->create_time, "YYYY-MM-DD HH24:mi:ss", time, sizeof(time)); + (void)printf("%s create_time = %s\n", tab, time); + (void)cm_time2str(gft_node->update_time, "YYYY-MM-DD HH24:mi:ss", time, sizeof(time)); + (void)printf("%s update_time = %s\n", tab, time); + + auid_t *id = &gft_node->id; + (void)printf("%s id = {\n", tab); + printf_auid(id); + (void)printf("%s }\n", tab); + + auid_t *next = &gft_node->next; + (void)printf("%s next= {\n", tab); + printf_auid(next); + (void)printf("%s }\n", tab); + + auid_t *prev = &gft_node->prev; + (void)printf("%s prev = {\n", tab); + printf_auid(prev); + (void)printf("%s }\n", tab); +} diff --git a/src/common/persist/wr_defs_print.h b/src/common/persist/wr_defs_print.h new file mode 100644 index 0000000000000000000000000000000000000000..abcd93e2dc33784fedcc27cdc197ca3396695084 --- /dev/null +++ b/src/common/persist/wr_defs_print.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_defs_print.h + * + * + * IDENTIFICATION + * src/common/persist/wr_defs_print.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_DEFS_PRINT_H__ +#define __WR_DEFS_PRINT_H__ + +#include "wr_diskgroup.h" +#include "wr_alloc_unit.h" +#include "wr_meta_buf.h" +#include "wr_file.h" +#include "wr_session.h" +#include "wr_fs_aux.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WR_SECOND_PRINT_LEVEL 2 +extern uint8 g_print_level; +void printf_auid(const auid_t *first); +void printf_wr_fs_block_list(wr_fs_block_list_t *free); +void printf_wr_fs_aux_root(wr_fs_aux_root_t *root); +void printf_wr_au_root(wr_au_root_t *au_root); +void printf_wr_fs_block_root(wr_fs_block_root_t *root); +void printf_wr_volume_attr(const wr_volume_attr_t *volume_attrs); +void wr_printf_core_ctrl_base(wr_core_ctrl_t *core_ctrl); +void printf_gft_root(gft_root_t *ft_root); +void printf_gft_node(gft_node_t *gft_node, const char *tab); +void printf_gft_list(gft_list_t *items); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/persist/wr_diskgroup.c b/src/common/persist/wr_diskgroup.c new file mode 100644 index 0000000000000000000000000000000000000000..5477e21655f0d5df167a55953f724e7ed4adda7b --- /dev/null +++ b/src/common/persist/wr_diskgroup.c @@ -0,0 +1,1346 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_diskgroup.c + * + * + * IDENTIFICATION + * src/common/persist/wr_diskgroup.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_api.h" +#include "wr_alloc_unit.h" +#include "wr_file.h" +#include "wr_malloc.h" +#include "cm_dlock.h" +#include "cm_disklock.h" +#include "cm_utils.h" +#include "wr_io_fence.h" +#include "wr_open_file.h" +#include "wr_diskgroup.h" + +#ifndef WIN32 +#include +#endif +#include "wr_meta_buf.h" +#include "wr_fs_aux.h" +#include "wr_syn_meta.h" +#include "wr_thv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WIN32 +#define WR_SIMUFILE_NAME "wr_vglock" +#define WR_FP_FREE (0) +#define WR_FP_INUSE (1) +typedef struct st_vglock_fp { + uint32 state; + char file_name[WR_MAX_FILE_LEN]; + FILE *fp; // each process has itself fp +} vglock_fp_t; + +vglock_fp_t g_fp_list[WR_MAX_OPEN_VG]; +#endif + +wr_vg_info_t *g_vgs_info = NULL; + +bool32 g_is_wr_server = WR_FALSE; +static wr_rdwr_type_e g_is_wr_readwrite = WR_STATUS_NORMAL; +static uint32 g_master_instance_id = WR_INVALID_ID32; +static const char *const g_wr_lock_vg_file = "wr_vg.lck"; +static int32 g_wr_lock_vg_fd = CM_INVALID_INT32; +static uint32 g_wr_recover_thread_id = 0; + +// CAUTION: wr_admin manager command just like wr_create_vg,cannot call it, + +wr_vg_info_t *wr_malloc_vg_info(void) +{ + if (g_vgs_info != NULL) { + return g_vgs_info; /* reuse memory of g_vgs_info */ + } + return (wr_vg_info_t *)cm_malloc(sizeof(wr_vg_info_t)); +} + +bool32 wr_is_server(void) +{ + return g_is_wr_server; +} + +bool32 wr_is_readwrite(void) +{ + return g_is_wr_readwrite == WR_STATUS_READWRITE; +} + +bool32 wr_is_readonly(void) +{ + return g_is_wr_readwrite == WR_STATUS_READONLY; +} + +uint32 wr_get_master_id() +{ + return g_master_instance_id; +} + +void wr_set_master_id(uint32 id) +{ + g_master_instance_id = id; + LOG_RUN_INF("set master id is %u.", id); +} + +void wr_set_server_flag(void) +{ + g_is_wr_server = WR_TRUE; +} + +int32 wr_get_server_status_flag(void) +{ + return (int32)g_is_wr_readwrite; +} + +void wr_set_server_status_flag(int32 wr_status) +{ + g_is_wr_readwrite = wr_status; +} + +void wr_set_recover_thread_id(uint32 thread_id) +{ + g_wr_recover_thread_id = thread_id; +} + +uint32 wr_get_recover_thread_id(void) +{ + return g_wr_recover_thread_id; +} + +wr_get_instance_status_proc_t get_instance_status_proc = NULL; +void regist_get_instance_status_proc(wr_get_instance_status_proc_t proc) +{ + get_instance_status_proc = proc; +} +void wr_checksum_vg_ctrl(wr_vg_info_item_t *vg_item); + +void vg_destroy_env(wr_vg_info_item_t *vg_item) +{ + cm_oamap_destroy(&vg_item->au_map); +} + +status_t wr_read_vg_config_file(const char *file_name, char *buf, uint32 *buf_len, bool32 read_only) +{ + int32 file_fd; + status_t status; + uint32 mode = (read_only) ? (O_RDONLY | O_BINARY) : (O_CREAT | O_RDWR | O_BINARY); + + if (!cm_file_exist(file_name)) { + WR_THROW_ERROR(ERR_WR_FILE_NOT_EXIST, file_name, "config"); + return CM_ERROR; + } + + WR_RETURN_IF_ERROR(cm_open_file(file_name, mode, &file_fd)); + + int64 size = cm_file_size(file_fd); + bool32 result = (bool32)(size != -1); + WR_RETURN_IF_FALSE3(result, cm_close_file(file_fd), WR_THROW_ERROR(ERR_SEEK_FILE, 0, SEEK_END, errno)); + + result = (bool32)(size <= (int64)(*buf_len)); + WR_RETURN_IF_FALSE3(result, cm_close_file(file_fd), WR_THROW_ERROR(ERR_WR_CONFIG_FILE_OVERSIZED, file_name)); + + result = (bool32)(cm_seek_file(file_fd, 0, SEEK_SET) == 0); + WR_RETURN_IF_FALSE3(result, cm_close_file(file_fd), WR_THROW_ERROR(ERR_SEEK_FILE, 0, SEEK_SET, errno)); + + status = cm_read_file(file_fd, buf, (int32)size, (int32 *)buf_len); + cm_close_file(file_fd); + return status; +} + +void wr_free_vg_info() +{ + LOG_RUN_INF("free g_vgs_info."); + WR_FREE_POINT(g_vgs_info) +} + +wr_vg_info_item_t *wr_find_vg_item(const char *vg_name) +{ + for (uint32_t i = 0; i < g_vgs_info->group_num; i++) { + if (strcmp(g_vgs_info->volume_group[i].vg_name, vg_name) == 0) { + return &g_vgs_info->volume_group[i]; + } + } + return NULL; +} + +wr_vg_info_item_t *wr_find_vg_item_by_id(uint32 vg_id) +{ + if (vg_id > g_vgs_info->group_num) { + return NULL; + } + return &g_vgs_info->volume_group[vg_id]; +} + +status_t wr_alloc_vg_item_redo_log_buf(wr_vg_info_item_t *vg_item) +{ + LOG_RUN_INF("Begin to alloc redo log buf of vg %s.", vg_item->vg_name); + char *log_buf = (char *)cm_malloc_align(WR_ALIGN_SIZE, WR_VG_LOG_SPLIT_SIZE); + if (log_buf == NULL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_ALLOC_MEMORY, WR_VG_LOG_SPLIT_SIZE, "global log buffer")); + } + errno_t rc = memset_s(log_buf, WR_DISK_UNIT_SIZE, 0, WR_DISK_UNIT_SIZE); + if (rc != EOK) { + WR_RETURN_IFERR4( + CM_ERROR, LOG_RUN_ERR("Memset failed."), WR_FREE_POINT(log_buf), CM_THROW_ERROR(ERR_SYSTEM_CALL, rc)); + } + vg_item->log_file_ctrl.log_buf = log_buf; + return CM_SUCCESS; +} + +status_t wr_check_entry_path(char *entry_path1, char *entry_path2, bool32 *result) +{ + if (cm_str_equal_ins(entry_path1, entry_path2)) { + *result = CM_TRUE; + return CM_SUCCESS; + } + char real_path1[WR_MAX_VOLUME_PATH_LEN]; + char real_path2[WR_MAX_VOLUME_PATH_LEN]; + CM_RETURN_IFERR(realpath_file(entry_path1, real_path1, WR_MAX_VOLUME_PATH_LEN)); + CM_RETURN_IFERR(realpath_file(entry_path2, real_path2, WR_MAX_VOLUME_PATH_LEN)); + if (cm_str_equal_ins(real_path1, real_path2)) { + *result = CM_TRUE; + return CM_SUCCESS; + } + *result = CM_FALSE; + return CM_SUCCESS; +} + +status_t wr_check_dup_vg(wr_vg_info_t *config, uint32 vg_no, bool32 *result) +{ + char *last_vg_name = config->volume_group[vg_no - 1].vg_name; + char *last_entry_path = config->volume_group[vg_no - 1].entry_path; + + for (uint32 i = 0; i < vg_no - 1; i++) { + if (cm_str_equal_ins(last_vg_name, config->volume_group[i].vg_name)) { + *result = CM_TRUE; + return CM_SUCCESS; + } + CM_RETURN_IFERR(wr_check_entry_path(last_entry_path, config->volume_group[i].entry_path, result)); + if (*result) { + return CM_SUCCESS; + } + } + *result = CM_FALSE; + return CM_SUCCESS; +} + +// NOTE:called after load vg ctrl and recovery. +void wr_checksum_vg_ctrl(wr_vg_info_item_t *vg_item) +{ + LOG_RUN_INF("Begin to checksum vg:%s ctrl.", vg_item->vg_name); + char *buf = vg_item->wr_ctrl->vg_data; + uint32 checksum = wr_get_checksum(buf, WR_VG_DATA_SIZE); + uint32 old_checksum = vg_item->wr_ctrl->vg_info.checksum; + wr_check_checksum(checksum, old_checksum); + + buf = vg_item->wr_ctrl->root; + checksum = wr_get_checksum(buf, WR_BLOCK_SIZE); + wr_common_block_t *block = (wr_common_block_t *)buf; + old_checksum = block->checksum; + wr_check_checksum(checksum, old_checksum); + LOG_RUN_INF("Succeed to checksum vg:%s ctrl.", vg_item->vg_name); +} + +// NOTE:only called initializing.no check redo and recovery. +status_t wr_load_vg_ctrl(wr_vg_info_item_t *vg_item, bool32 is_lock) +{ + CM_ASSERT(vg_item != NULL); + bool32 remote = CM_FALSE; + wr_config_t *inst_cfg = wr_get_inst_cfg(); + + if (vg_item->vg_name[0] == '\0' || vg_item->entry_path[0] == '\0') { + LOG_RUN_ERR("Failed to load vg ctrl, input parameter is invalid."); + return CM_ERROR; + } + LOG_RUN_INF("Begin to load vg %s ctrl.", vg_item->vg_name); + status_t status; + if (is_lock) { + if (wr_lock_vg_storage_r(vg_item, vg_item->entry_path, inst_cfg) != CM_SUCCESS) { + LOG_RUN_ERR("Failed to lock vg:%s.", vg_item->entry_path); + return CM_ERROR; + } + } + status = wr_load_vg_ctrl_part(vg_item, 0, vg_item->wr_ctrl, (int32)sizeof(wr_ctrl_t), &remote); + if (status != CM_SUCCESS) { + if (is_lock) { + (void)wr_unlock_vg_storage(vg_item, vg_item->entry_path, inst_cfg); + } + LOG_RUN_ERR("Failed to read volume %s.", vg_item->entry_path); + return status; + } + if (is_lock) { + if (wr_unlock_vg_storage(vg_item, vg_item->entry_path, inst_cfg) != CM_SUCCESS) { + return CM_ERROR; + } + } + if (!WR_VG_IS_VALID(vg_item->wr_ctrl)) { + WR_THROW_ERROR(ERR_WR_VG_CHECK_NOT_INIT); + LOG_RUN_ERR("Invalid vg %s ctrl", vg_item->vg_name); + return CM_ERROR; + } + + date_t date = cm_timeval2date(vg_item->wr_ctrl->vg_info.create_time); + time_t time = cm_date2time(date); + char create_time[512]; + status = cm_time2str(time, "YYYY-MM-DD HH24:mi:ss", create_time, sizeof(create_time)); + LOG_RUN_INF("The vg:%s info, create time:%s.", vg_item->vg_name, create_time); + + return status; +} + +status_t wr_load_vg_ctrl_part(wr_vg_info_item_t *vg_item, int64 offset, void *buf, int32 size, bool32 *remote) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(buf != NULL); + // todo close volume? + if (vg_item->volume_handle[0].handle == WR_INVALID_HANDLE) { + if (wr_open_volume(vg_item->entry_path, NULL, WR_INSTANCE_OPEN_FLAG, &vg_item->volume_handle[0]) != + CM_SUCCESS) { + LOG_RUN_ERR("Failed to open volume %s.", vg_item->entry_path); + return CM_ERROR; + } + } + LOG_DEBUG_INF( + "Begin to read volume %s when load vg ctrl part, offset:%lld,size:%d.", vg_item->entry_path, offset, size); + if (wr_read_volume_inst(vg_item, &vg_item->volume_handle[0], offset, buf, size, remote) != CM_SUCCESS) { + LOG_RUN_ERR("Failed to read volume %s,offset:%lld,size:%d.", vg_item->entry_path, offset, size); + return CM_ERROR; + } + + return CM_SUCCESS; +} + +void wr_lock_vg_mem_x(wr_vg_info_item_t *vg_item) +{ + wr_latch_x(&vg_item->disk_latch); +} + +void wr_lock_vg_mem_x2ix(wr_vg_info_item_t *vg_item) +{ + latch_statis_t *stat = NULL; + wr_latch_x2ix(&vg_item->disk_latch, WR_DEFAULT_SESSIONID, stat); +} + +void wr_lock_vg_mem_ix2x(wr_vg_info_item_t *vg_item) +{ + latch_statis_t *stat = NULL; + wr_latch_ix2x(&vg_item->disk_latch, WR_DEFAULT_SESSIONID, stat); +} + +void wr_lock_vg_mem_s(wr_vg_info_item_t *vg_item) +{ + wr_latch_s(&vg_item->disk_latch); +} + +void wr_lock_vg_mem_degrade(wr_vg_info_item_t *vg_item) +{ + wr_latch_degrade(&vg_item->disk_latch, WR_DEFAULT_SESSIONID, NULL); +} + +void wr_lock_vg_mem_s_force(wr_vg_info_item_t *vg_item) +{ + wr_latch_s2(&vg_item->disk_latch, WR_DEFAULT_SESSIONID, CM_TRUE, NULL); +} + +void wr_unlock_vg_mem(wr_vg_info_item_t *vg_item) +{ + wr_unlatch(&vg_item->disk_latch); +} + +static void wr_free_vglock_fp(const char *lock_file, FILE *fp) +{ + int32 i; + for (i = 0; i < WR_MAX_OPEN_VG; i++) { + if (g_fp_list[i].state == WR_FP_FREE) { + continue; + } + if (g_fp_list[i].fp != fp) { + continue; + } + if (strcmp(g_fp_list[i].file_name, lock_file) == 0) { + g_fp_list[i].state = WR_FP_FREE; + g_fp_list[i].fp = NULL; + g_fp_list[i].file_name[0] = '\0'; + } + } +} + +static FILE *wr_get_vglock_fp(const char *lock_file, bool32 need_new) +{ + int32 i; + int32 ifree = -1; + for (i = 0; i < WR_MAX_OPEN_VG; i++) { + if (g_fp_list[i].state == WR_FP_FREE) { + ifree = (ifree == -1) ? i : ifree; + continue; + } + if (strcmp(g_fp_list[i].file_name, lock_file) == 0) { + return g_fp_list[i].fp; + } + } + + if (!need_new) { + return NULL; + } + + if (ifree == -1) { + return NULL; + } + + uint32 len = (uint32)strlen(lock_file); + int32 ret = memcpy_sp(g_fp_list[ifree].file_name, WR_MAX_FILE_LEN, lock_file, len); + WR_SECUREC_RETURN_IF_ERROR(ret, NULL); + g_fp_list[ifree].file_name[len] = '\0'; + g_fp_list[ifree].fp = fopen(lock_file, "w"); + if (g_fp_list[ifree].fp == NULL) { + char cmd[WR_MAX_CMD_LEN]; + ret = snprintf_s(cmd, WR_MAX_CMD_LEN, WR_MAX_CMD_LEN - 1, "touch %s", lock_file); + WR_SECUREC_SS_RETURN_IF_ERROR(ret, NULL); + (void)system(cmd); + g_fp_list[ifree].fp = fopen(lock_file, "w"); + } + + if (g_fp_list[ifree].fp == NULL) { + return NULL; + } + g_fp_list[ifree].state = WR_FP_INUSE; + return g_fp_list[ifree].fp; +} + +static status_t wr_pre_lockfile_name(const char *entry_path, char *lock_file, wr_config_t *inst_cfg) +{ + char *home = inst_cfg->params.disk_lock_file_path; + char superblock[WR_MAX_FILE_LEN]; + text_t pname, sub; + pname.len = (uint32)strlen(entry_path); + pname.str = (char *)entry_path; + if (!cm_fetch_rtext(&pname, '/', '\0', &sub)) { + pname = sub; + } + + int32 iret_snprintf; + if (pname.len == 0) { + iret_snprintf = snprintf_s(lock_file, WR_MAX_FILE_LEN, WR_MAX_FILE_LEN - 1, "%s/%s", home, WR_SIMUFILE_NAME); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + } else { + if (cm_text2str(&pname, superblock, WR_MAX_FILE_LEN) != CM_SUCCESS) { + return CM_ERROR; + } + + iret_snprintf = snprintf_s( + lock_file, WR_MAX_FILE_LEN, WR_MAX_FILE_LEN - 1, "%s/%s_%s", home, WR_SIMUFILE_NAME, superblock); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + } + return CM_SUCCESS; +} + +status_t wr_file_lock_vg(wr_config_t *inst_cfg, struct flock *lk) +{ + char file_name[CM_FILE_NAME_BUFFER_SIZE]; + int iret_snprintf; + + iret_snprintf = snprintf_s( + file_name, CM_FILE_NAME_BUFFER_SIZE, CM_FILE_NAME_BUFFER_SIZE - 1, "%s/%s", inst_cfg->home, g_wr_lock_vg_file); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + + if (cm_open_file(file_name, O_CREAT | O_RDWR | O_BINARY, &g_wr_lock_vg_fd) != CM_SUCCESS) { + return CM_ERROR; + } + + if (cm_fcntl(g_wr_lock_vg_fd, F_SETLK, lk, CM_WAIT_FOREVER) != CM_SUCCESS) { + cm_close_file(g_wr_lock_vg_fd); + g_wr_lock_vg_fd = CM_INVALID_INT32; + CM_THROW_ERROR(ERR_LOCK_FILE, errno); + return CM_ERROR; + } + return CM_SUCCESS; +} + +status_t wr_file_lock_vg_w(wr_config_t *inst_cfg) +{ + struct flock lk; + lk.l_type = F_WRLCK; + lk.l_whence = SEEK_SET; + lk.l_start = lk.l_len = 0; + if (wr_file_lock_vg(inst_cfg, &lk) != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to file write lock vg."); + return CM_ERROR; + } + + return CM_SUCCESS; +} + +status_t wr_file_lock_vg_r(wr_config_t *inst_cfg) +{ + struct flock lk; + lk.l_type = F_RDLCK; + lk.l_whence = SEEK_SET; + lk.l_start = lk.l_len = 0; + if (wr_file_lock_vg(inst_cfg, &lk) != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to file read lock vg."); + return CM_ERROR; + } + + return CM_SUCCESS; +} + +void wr_file_unlock_vg(void) +{ + if (g_wr_lock_vg_fd != CM_INVALID_INT32) { + (void)cm_unlock_fd(g_wr_lock_vg_fd); + cm_close_file(g_wr_lock_vg_fd); + g_wr_lock_vg_fd = CM_INVALID_INT32; + } +} + +status_t wr_lock_disk_vg(const char *entry_path, wr_config_t *inst_cfg) +{ + dlock_t lock; + status_t status; + + status = cm_alloc_dlock(&lock, WR_CTRL_VG_LOCK_OFFSET, inst_cfg->params.inst_id); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to alloc lock."); + return CM_ERROR; + } + + // if get the timeout(ERR_SCSI_LOCK_OCCUPIED) error from scsi lock, we'll try lock vg again + for (;;) { + status = cm_init_dlock(&lock, WR_CTRL_VG_LOCK_OFFSET, inst_cfg->params.inst_id); + WR_RETURN_IFERR3(status, cm_destory_dlock(&lock), LOG_DEBUG_ERR("Failed to init lock.")); + + status = cm_disk_timed_lock_s( + &lock, entry_path, WR_LOCK_VG_TIMEOUT, inst_cfg->params.lock_interval, inst_cfg->params.dlock_retry_count); + if (status == CM_SUCCESS) { + LOG_DEBUG_INF("Lock vg succ, entry path %s.", entry_path); + cm_destory_dlock(&lock); + return CM_SUCCESS; + } + if (status == CM_TIMEDOUT) { + LOG_DEBUG_INF("Lock vg timeout, get current lock info, entry_path %s.", entry_path); + // get old lock info from disk + status_t ret = cm_get_dlock_info_s(&lock, entry_path); + WR_RETURN_IFERR3( + ret, cm_destory_dlock(&lock), LOG_DEBUG_ERR("Failed to get old lock info, entry path %s.", entry_path)); + + // Get the status of the instance that owns the lock + LOG_DEBUG_INF("The node that owns the lock is online, inst_id(disk) %lld, inst_id(lock) %lld.", + LOCKR_INST_ID(lock), LOCKW_INST_ID(lock)); + if (wr_is_server()) { + continue; + } + } + LOG_DEBUG_ERR("Failed to lock %s, status %d.", entry_path, status); + cm_destory_dlock(&lock); + return status; + } +} + +status_t wr_dl_dealloc(unsigned int lock_id) +{ + int ret = cm_dl_dealloc(lock_id); + if (ret != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to dealloc lock %u, ret %d", lock_id, ret); + return CM_ERROR; + } + return CM_SUCCESS; +} + +status_t wr_lock_share_disk_vg(const char *entry_path, wr_config_t *inst_cfg) +{ + unsigned int lock_id; + unsigned long long disk_inst_id; + int ret; + + lock_id = cm_dl_alloc(entry_path, WR_VG_LOCK_SHARE_DISK_OFFSET, (unsigned long long)inst_cfg->params.inst_id); + if (lock_id == CM_INVALID_LOCK_ID) { + LOG_DEBUG_ERR("Failed to alloc lock."); + return CM_ERROR; + } + + for (;;) { + ret = cm_dl_lock(lock_id, WR_LOCK_VG_TIMEOUT_MS); + if (ret == CM_SUCCESS) { + LOG_DEBUG_INF("Lock vg succ, entry path %s.", entry_path); + WR_RETURN_IF_ERROR(wr_dl_dealloc(lock_id)); + return CM_SUCCESS; + } + if (ret == CM_DL_ERR_TIMEOUT) { + LOG_DEBUG_INF("Lock vg timeout, get current lock info, entry_path %s.", entry_path); + status_t status = cm_dl_getowner(lock_id, &disk_inst_id); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to get old lock info, entry path %s.", entry_path); + WR_RETURN_IF_ERROR(wr_dl_dealloc(lock_id)); + return status; + } + + LOG_DEBUG_INF("The node that owns the lock is online, inst_id(disk) %lld, inst_id(lock) %lld.", + disk_inst_id, inst_cfg->params.inst_id); + if (wr_is_server()) { + continue; + } + } + LOG_DEBUG_ERR("Failed to lock %s, status %d.", entry_path, ret); + WR_RETURN_IF_ERROR(wr_dl_dealloc(lock_id)); + return ret; + } +} + +status_t wr_lock_vg_storage_core(wr_vg_info_item_t *vg_item, const char *entry_path, wr_config_t *inst_cfg) +{ + LOG_DEBUG_INF("Lock vg storage, lock vg:%s.", entry_path); + int32 wr_mode = wr_storage_mode(inst_cfg); + if (wr_mode == WR_MODE_DISK) { + char lock_file[WR_MAX_FILE_LEN]; + if (wr_pre_lockfile_name(entry_path, lock_file, inst_cfg) != CM_SUCCESS) { + return CM_ERROR; + } + + FILE *vglock_fp = wr_get_vglock_fp(lock_file, WR_TRUE); + if (vglock_fp == NULL) { + WR_THROW_ERROR(ERR_WR_VG_LOCK, entry_path); + return CM_ERROR; + } + flock(vglock_fp->_fileno, LOCK_EX); // use flock to exclusive + LOG_DEBUG_INF("DISK MODE, lock vg:%s, lock file:%s.", entry_path, lock_file); + } else if (wr_mode == WR_MODE_SHARE_DISK) { + if (wr_lock_share_disk_vg(entry_path, inst_cfg) != CM_SUCCESS) { + WR_THROW_ERROR(ERR_WR_VG_LOCK, entry_path); + LOG_DEBUG_ERR("Failed to lock share disk vg, entry path %s.", entry_path); + return CM_ERROR; + } + } else { + /* in standby cluster, we do not need try to lock(scsi3) xlog vg, xlog vg is a read only disk */ + if (WR_STANDBY_CLUSTER_XLOG_VG(vg_item->id)) { + return CM_SUCCESS; + } + if (wr_lock_disk_vg(entry_path, inst_cfg) != CM_SUCCESS) { + WR_THROW_ERROR(ERR_WR_VG_LOCK, entry_path); + LOG_DEBUG_ERR("Failed to lock vg, entry path %s.", entry_path); + return CM_ERROR; + } + } + return CM_SUCCESS; +} + +status_t wr_lock_vg_storage_r(wr_vg_info_item_t *vg_item, const char *entry_path, wr_config_t *inst_cfg) +{ + if (wr_file_lock_vg_r(inst_cfg) != CM_SUCCESS) { + LOG_RUN_ERR("Failed to file read lock vg."); + return CM_ERROR; + } + if (wr_lock_vg_storage_core(vg_item, entry_path, inst_cfg) != CM_SUCCESS) { + LOG_RUN_ERR("Failed to lock vg, entry path %s.", entry_path); + wr_file_unlock_vg(); + return CM_ERROR; + } + + return CM_SUCCESS; +} + +status_t wr_lock_vg_storage_w(wr_vg_info_item_t *vg_item, const char *entry_path, wr_config_t *inst_cfg) +{ + if (wr_file_lock_vg_w(inst_cfg) != CM_SUCCESS) { + return CM_ERROR; + } + if (wr_lock_vg_storage_core(vg_item, entry_path, inst_cfg) != CM_SUCCESS) { + wr_file_unlock_vg(); + return CM_ERROR; + } + + return CM_SUCCESS; +} + +status_t wr_unlock_vg_raid(wr_vg_info_item_t *vg_item, const char *entry_path, int64 inst_id) +{ + dlock_t lock; + status_t status = cm_alloc_dlock(&lock, WR_CTRL_VG_LOCK_OFFSET, inst_id); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to alloc dlock for %lld.", inst_id); + return CM_ERROR; + } + status = cm_disk_unlock_s(&lock, entry_path); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to unlock %s the first time, inst id %llu, just try again.", entry_path, inst_id); + status = cm_disk_unlock_s(&lock, entry_path); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to unlock %s the second time, inst id %llu.", entry_path, inst_id); + cm_destory_dlock(&lock); + return CM_ERROR; + } + } + LOG_DEBUG_INF("unLock vg succ, entry path %s.", entry_path); + cm_destory_dlock(&lock); + return CM_SUCCESS; +} + +status_t wr_unlock_vg_share_disk(wr_vg_info_item_t *vg_item, const char *entry_path, int64 inst_id) +{ + unsigned int lock_id; + status_t status; + + lock_id = cm_dl_alloc(entry_path, WR_VG_LOCK_SHARE_DISK_OFFSET, (unsigned long long)inst_id); + if (lock_id == CM_INVALID_LOCK_ID) { + LOG_RUN_ERR("Failed to alloc %s, inst id %llu.", entry_path, inst_id); + return CM_ERROR; + } + status = cm_dl_unlock(lock_id); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to unlock %s the first time, inst id %llu, just try again.", entry_path, inst_id); + status = cm_dl_unlock(lock_id); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to unlock %s the second time, inst id %llu.", entry_path, inst_id); + status = wr_dl_dealloc(lock_id); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to dealloc %s, inst id %llu.", entry_path, inst_id); + } + return CM_ERROR; + } + } + LOG_DEBUG_INF("unLock vg succ, entry path %s.", entry_path); + status = wr_dl_dealloc(lock_id); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to dealloc %s, inst id %llu.", entry_path, inst_id); + return CM_ERROR; + } + return CM_SUCCESS; +} + +status_t wr_unlock_vg(int32 wr_mode, wr_vg_info_item_t *vg_item, const char *entry_path, int64 inst_id) +{ + if (wr_mode == WR_MODE_SHARE_DISK) { + return wr_unlock_vg_share_disk(vg_item, entry_path, inst_id); + } else { + return wr_unlock_vg_raid(vg_item, entry_path, inst_id); + } +} + +status_t wr_unlock_vg_storage_core(wr_vg_info_item_t *vg_item, const char *entry_path, wr_config_t *inst_cfg) +{ + LOG_DEBUG_INF("Unlock vg storage, lock vg:%s.", entry_path); + int32 wr_mode = wr_storage_mode(inst_cfg); + if (wr_mode == WR_MODE_DISK) { + char lock_file[WR_MAX_FILE_LEN]; + if (wr_pre_lockfile_name(entry_path, lock_file, inst_cfg) != CM_SUCCESS) { + LOG_RUN_ERR("Failed to get lock file %s.", entry_path); + return CM_ERROR; + } + + FILE *vglock_fp = wr_get_vglock_fp(lock_file, CM_FALSE); + if (vglock_fp == NULL) { + LOG_RUN_ERR("Failed to get vglock fp %s.", lock_file); + return CM_ERROR; + } + + flock(vglock_fp->_fileno, LOCK_UN); + wr_free_vglock_fp(lock_file, vglock_fp); + fclose(vglock_fp); + LOG_DEBUG_INF("ulock vg:%s, lock file:%s.", entry_path, lock_file); + } else { + if (wr_unlock_vg(wr_mode, vg_item, entry_path, inst_cfg->params.inst_id) != CM_SUCCESS) { + LOG_RUN_ERR("Failed to unlock vg %s.", vg_item->vg_name); + return CM_ERROR; + } + } + return CM_SUCCESS; +} + +status_t wr_unlock_vg_storage(wr_vg_info_item_t *vg_item, const char *entry_path, wr_config_t *inst_cfg) +{ + if (wr_unlock_vg_storage_core(vg_item, entry_path, inst_cfg) != CM_SUCCESS) { + wr_file_unlock_vg(); + return CM_ERROR; + } + wr_file_unlock_vg(); + return CM_SUCCESS; +} + +status_t wr_check_lock_remain_share_disk( + wr_vg_info_item_t *vg_item, const char *entry_path, int64 inst_id, bool32 *is_remain) +{ + unsigned int lock_id; + *is_remain = CM_TRUE; + lock_id = cm_dl_alloc(entry_path, WR_VG_LOCK_SHARE_DISK_OFFSET, (unsigned long long)inst_id); + if (lock_id == CM_INVALID_LOCK_ID) { + LOG_DEBUG_ERR("Failed to alloc lock."); + return CM_ERROR; + } + if (cm_dl_check_lock_remain(lock_id, (unsigned long long)inst_id, (unsigned int *)is_remain) != CM_SUCCESS) { + (void)wr_dl_dealloc(lock_id); + return CM_ERROR; + } + return wr_dl_dealloc(lock_id); +} + +status_t wr_check_lock_remain_cluster_raid( + wr_vg_info_item_t *vg_item, const char *entry_path, int64 inst_id, bool32 *is_remain) +{ + int32 fd = 0; + dlock_t lock; + *is_remain = CM_TRUE; + status_t status = cm_alloc_dlock(&lock, WR_CTRL_VG_LOCK_OFFSET, inst_id); + if (status != CM_SUCCESS) { + return CM_ERROR; + } + fd = open(entry_path, O_RDWR | O_DIRECT | O_SYNC); + if (fd < 0) { + cm_destory_dlock(&lock); + return CM_ERROR; + } + status = cm_check_dlock_remain(&lock, fd, is_remain); + if (status != CM_SUCCESS) { + (void)close(fd); + cm_destory_dlock(&lock); + return CM_ERROR; + } + (void)close(fd); + cm_destory_dlock(&lock); + return CM_SUCCESS; +} +status_t wr_check_lock_remain_inner( + int32 wr_mode, wr_vg_info_item_t *vg_item, const char *entry_path, int64 inst_id, bool32 *is_remain) +{ + if (wr_mode == WR_MODE_SHARE_DISK) { + return wr_check_lock_remain_share_disk(vg_item, entry_path, inst_id, is_remain); + } else if (wr_mode == WR_MODE_CLUSTER_RAID) { + return wr_check_lock_remain_cluster_raid(vg_item, entry_path, inst_id, is_remain); + } + LOG_DEBUG_ERR("Invalid wr mode %d when check lock remain.", wr_mode); + return CM_ERROR; +} + +status_t wr_write_ctrl_to_disk(wr_vg_info_item_t *vg_item, int64 offset, void *buf, uint32 size) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(buf != NULL); + status_t status; + + if (vg_item->volume_handle[0].handle != WR_INVALID_HANDLE) { + return wr_write_volume_inst(vg_item, &vg_item->volume_handle[0], offset, buf, size); + } + + wr_volume_t volume; + status = wr_open_volume(vg_item->entry_path, NULL, WR_INSTANCE_OPEN_FLAG, &volume); + if (status != CM_SUCCESS) { + return status; + } + status = wr_write_volume_inst(vg_item, &volume, offset, buf, size); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to read write file, offset:%lld, size:%u.", offset, size); + return status; + } + + vg_item->volume_handle[0] = volume; + + return CM_SUCCESS; +} + +status_t wr_update_core_ctrl_disk(wr_vg_info_item_t *vg_item) +{ + status_t status; + vg_item->wr_ctrl->core.version++; + vg_item->wr_ctrl->core.checksum = wr_get_checksum(&vg_item->wr_ctrl->core, WR_CORE_CTRL_SIZE); + LOG_DEBUG_INF( + "[REDO]Try to update vg core:%s, version:%llu to disk.", vg_item->vg_name, vg_item->wr_ctrl->core.version); + int64 offset = (int64)WR_CTRL_CORE_OFFSET; + status = wr_write_ctrl_to_disk(vg_item, offset, &vg_item->wr_ctrl->core, WR_CORE_CTRL_SIZE); + if (status == CM_SUCCESS) { + // write to backup area + status = wr_write_ctrl_to_disk( + vg_item, (int64)WR_CTRL_BAK_CORE_OFFSET, &vg_item->wr_ctrl->core, WR_CORE_CTRL_SIZE); + LOG_DEBUG_INF( + "[REDO]End to update vg core:%s, version:%llu to disk.", vg_item->vg_name, vg_item->wr_ctrl->core.version); + } + return status; +} + +status_t wr_update_volume_ctrl(wr_vg_info_item_t *vg_item) +{ + status_t status; + vg_item->wr_ctrl->volume.version++; + vg_item->wr_ctrl->volume.checksum = wr_get_checksum(&vg_item->wr_ctrl->volume, WR_VOLUME_CTRL_SIZE); + status = wr_write_ctrl_to_disk( + vg_item, (int64)WR_CTRL_VOLUME_OFFSET, &vg_item->wr_ctrl->volume, WR_VOLUME_CTRL_SIZE); + if (status == CM_SUCCESS) { + // write to backup area + status = wr_write_ctrl_to_disk( + vg_item, (int64)WR_CTRL_BAK_VOLUME_OFFSET, &vg_item->wr_ctrl->volume, WR_VOLUME_CTRL_SIZE); + } + return status; +} + +status_t wr_update_redo_ctrl(wr_vg_info_item_t *vg_item, uint32 index, uint64 offset, uint64 lsn) +{ + status_t status; + wr_redo_ctrl_t *redo_ctrl = &vg_item->wr_ctrl->redo_ctrl; + redo_ctrl->redo_index = index; + redo_ctrl->offset = offset; + redo_ctrl->lsn = lsn; + redo_ctrl->version++; + redo_ctrl->checksum = wr_get_checksum(redo_ctrl, WR_DISK_UNIT_SIZE); + status = wr_write_ctrl_to_disk(vg_item, (int64)WR_CTRL_REDO_OFFSET, redo_ctrl, WR_DISK_UNIT_SIZE); + if (status == CM_SUCCESS) { + // write to backup area + status = wr_write_ctrl_to_disk(vg_item, (int64)WR_CTRL_BAK_REDO_OFFSET, redo_ctrl, WR_DISK_UNIT_SIZE); + } + return status; +} + +status_t wr_update_volume_id_info(wr_vg_info_item_t *vg_item, uint32 id) +{ + WR_RETURN_IF_ERROR(wr_update_core_ctrl_disk(vg_item)); + WR_RETURN_IF_ERROR(wr_update_volume_ctrl(vg_item) != CM_SUCCESS); + + uint64 attr_offset = id * sizeof(wr_volume_attr_t); + char *align_buf = + (char *)vg_item->wr_ctrl->core.volume_attrs + (attr_offset / WR_DISK_UNIT_SIZE) * WR_DISK_UNIT_SIZE; + int64 offset = align_buf - (char *)vg_item->wr_ctrl; + if (wr_write_ctrl_to_disk(vg_item, offset, align_buf, WR_DISK_UNIT_SIZE) != CM_SUCCESS) { + return CM_ERROR; + } + // write to backup area + WR_RETURN_IF_ERROR(wr_write_ctrl_to_disk(vg_item, WR_CTRL_BAK_ADDR + offset, align_buf, WR_DISK_UNIT_SIZE)); + + attr_offset = id * sizeof(wr_volume_def_t); + align_buf = (char *)vg_item->wr_ctrl->volume.defs + (attr_offset / WR_DISK_UNIT_SIZE) * WR_DISK_UNIT_SIZE; + offset = align_buf - (char *)vg_item->wr_ctrl; + WR_RETURN_IF_ERROR(wr_write_ctrl_to_disk(vg_item, offset, align_buf, WR_DISK_UNIT_SIZE)); + // write to backup area + return wr_write_ctrl_to_disk(vg_item, WR_CTRL_BAK_ADDR + offset, align_buf, WR_DISK_UNIT_SIZE); +} + +status_t wr_write_volume_inst( + wr_vg_info_item_t *vg_item, wr_volume_t *volume, int64 offset, const void *buf, uint32 size) +{ + void *temp_buf = (void *)buf; + CM_ASSERT(offset % WR_DISK_UNIT_SIZE == 0); + CM_ASSERT(size % WR_DISK_UNIT_SIZE == 0); + if (((uint64)temp_buf) % WR_DISK_UNIT_SIZE != 0 && size <= WR_FILE_SPACE_BLOCK_SIZE) { +#ifndef WIN32 + char align_buf[WR_FILE_SPACE_BLOCK_SIZE] __attribute__((__aligned__(WR_DISK_UNIT_SIZE))); +#else + char align_buf[WR_FILE_SPACE_BLOCK_SIZE]; +#endif + // some redo logs about free can not align. rp_redo_free_fs_block + errno_t errcode = memcpy_s(align_buf, size, buf, size); + securec_check_ret(errcode); + return wr_write_volume(volume, offset, align_buf, (int32)size); + } + CM_ASSERT(((uint64)temp_buf) % WR_DISK_UNIT_SIZE == 0); + return wr_write_volume(volume, offset, temp_buf, (int32)size); +} + +uint32_t wr_find_free_volume_id(const wr_vg_info_item_t *vg_item) +{ + for (uint32_t i = 0; i < WR_MAX_VOLUMES; i++) { + if (vg_item->wr_ctrl->volume.defs[i].flag == VOLUME_FREE) { + return i; + } + } + return CM_INVALID_ID32; +} + +status_t wr_gen_volume_head( + wr_volume_header_t *vol_head, wr_vg_info_item_t *vg_item, const char *volume_name, uint32 id) +{ + vol_head->vol_type.id = id; + errno_t errcode = strcpy_s(vol_head->vol_type.entry_volume_name, WR_MAX_VOLUME_PATH_LEN, volume_name); + WR_SECUREC_SS_RETURN_IF_ERROR(errcode, CM_ERROR); + vol_head->vol_type.type = WR_VOLUME_TYPE_NORMAL; + vol_head->valid_flag = WR_CTRL_VALID_FLAG; + errcode = strcpy_s(vol_head->vg_name, WR_MAX_NAME_LEN, vg_item->vg_name); + WR_SECUREC_SS_RETURN_IF_ERROR(errcode, CM_ERROR); + wr_set_software_version((wr_vg_header_t *)vol_head, (uint32)WR_SOFTWARE_VERSION); + (void)cm_gettimeofday(&vol_head->create_time); + vol_head->checksum = wr_get_checksum((char *)vol_head, WR_VG_DATA_SIZE); + return CM_SUCCESS; +} + +status_t wr_cmp_volume_head(wr_vg_info_item_t *vg_item, const char *volume_name, uint32 id) +{ +#ifndef WIN32 + char buf[WR_ALIGN_SIZE] __attribute__((__aligned__(WR_DISK_UNIT_SIZE))); +#else + char buf[WR_ALIGN_SIZE]; +#endif + status_t status = CM_ERROR; + wr_volume_header_t *vol_cmp_head = (wr_volume_header_t *)buf; + do { + WR_BREAK_IF_ERROR(wr_read_volume(&vg_item->volume_handle[id], 0, vol_cmp_head, (int32)WR_ALIGN_SIZE)); + if (vol_cmp_head->valid_flag == WR_CTRL_VALID_FLAG) { + // cannot add a exists volume + WR_THROW_ERROR( + ERR_WR_VOLUME_ADD, volume_name, "please check volume is used in cluster, if not need to dd manually"); + break; + } + status = CM_SUCCESS; + } while (0); + return status; +} + +status_t wr_add_volume_vg_ctrl( + wr_ctrl_t *vg_ctrl, uint32 id, uint64 vol_size, const char *volume_name, volume_slot_e volume_flag) +{ + errno_t errcode = strcpy_s(vg_ctrl->volume.defs[id].name, WR_MAX_VOLUME_PATH_LEN, volume_name); + WR_SECUREC_SS_RETURN_IF_ERROR(errcode, CM_ERROR); + vg_ctrl->volume.defs[id].flag = volume_flag; + vg_ctrl->volume.defs[id].id = id; + vg_ctrl->core.volume_attrs[id].id = id; + vg_ctrl->core.volume_attrs[id].hwm = CM_CALC_ALIGN(WR_VOLUME_HEAD_SIZE, wr_get_vg_au_size(vg_ctrl)); + vg_ctrl->core.volume_attrs[id].size = vol_size; + if (vol_size <= vg_ctrl->core.volume_attrs[id].hwm) { + WR_THROW_ERROR(ERR_WR_VOLUME_ADD, volume_name, "volume size is too small"); + return CM_ERROR; + } + vg_ctrl->core.volume_attrs[id].free = vol_size - vg_ctrl->core.volume_attrs[id].hwm; + LOG_RUN_INF("Add volume refresh core, old core version:%llu, volume version:%llu, volume def version:%llu.", + vg_ctrl->core.version, vg_ctrl->volume.version, vg_ctrl->volume.defs[id].version); + vg_ctrl->volume.defs[id].version++; + vg_ctrl->core.volume_count++; + vg_ctrl->core.version++; + vg_ctrl->volume.version++; + return CM_SUCCESS; +} + +static status_t wr_add_volume_impl_generate_redo( + wr_session_t *session, wr_vg_info_item_t *vg_item, const char *volume_name, uint32 id) +{ + wr_redo_volhead_t redo; + wr_volume_header_t *vol_head = (wr_volume_header_t *)redo.head; + + CM_RETURN_IFERR(wr_cmp_volume_head(vg_item, volume_name, id)); + CM_RETURN_IFERR(wr_gen_volume_head(vol_head, vg_item, volume_name, id)); + + int32 ret = snprintf_s(redo.name, WR_MAX_NAME_LEN, strlen(volume_name), "%s", volume_name); + bool32 result = (bool32)(ret != -1); + WR_RETURN_IF_FALSE2(result, WR_THROW_ERROR(ERR_SYSTEM_CALL, ret)); + wr_put_log(session, vg_item, WR_RT_UPDATE_VOLHEAD, &redo, sizeof(redo)); + return CM_SUCCESS; +} + +static status_t wr_add_volume_record_log(wr_session_t *session, wr_vg_info_item_t *vg_item, uint32 id) +{ + wr_ctrl_t *vg_ctrl = vg_item->wr_ctrl; + wr_redo_volop_t volop_redo; + volop_redo.volume_count = vg_ctrl->core.volume_count; + volop_redo.core_version = vg_ctrl->core.version; + volop_redo.volume_version = vg_ctrl->volume.version; + volop_redo.is_add = WR_TRUE; + + LOG_RUN_INF("Refresh core, old version:%llu, disk version:%llu.", vg_ctrl->core.version - 1, vg_ctrl->core.version); + + errno_t errcode = + memcpy_sp(volop_redo.attr, WR_DISK_UNIT_SIZE, &vg_ctrl->core.volume_attrs[id], sizeof(wr_volume_attr_t)); + WR_SECUREC_RETURN_IF_ERROR(errcode, CM_ERROR); + errcode = memcpy_sp(volop_redo.def, WR_DISK_UNIT_SIZE, &vg_ctrl->volume.defs[id], sizeof(wr_volume_def_t)); + WR_SECUREC_RETURN_IF_ERROR(errcode, CM_ERROR); + wr_put_log(session, vg_item, WR_RT_ADD_OR_REMOVE_VOLUME, &volop_redo, sizeof(volop_redo)); + return CM_SUCCESS; +} + +static status_t wr_add_volume_impl( + wr_session_t *session, wr_vg_info_item_t *vg_item, const char *volume_name, volume_slot_e volume_flag) +{ + uint32 id = wr_find_free_volume_id(vg_item); + bool32 result = (bool32)(id < WR_MAX_VOLUMES); + WR_RETURN_IF_FALSE2( + result, LOG_DEBUG_ERR("[VOL][ADV] Failed to add volume, exceed max volumes %d.", WR_MAX_VOLUMES)); + + CM_RETURN_IFERR(wr_open_volume(volume_name, NULL, WR_INSTANCE_OPEN_FLAG, &vg_item->volume_handle[id])); + status_t status = wr_add_volume_impl_generate_redo(session, vg_item, volume_name, id); + uint64 vol_size = wr_get_volume_size(&vg_item->volume_handle[id]); + wr_close_volume(&vg_item->volume_handle[id]); + if (status != CM_SUCCESS) { + return status; + } + + result = (bool32)(vol_size != WR_INVALID_64); + WR_RETURN_IF_FALSE2( + result, LOG_DEBUG_ERR("[VOL][ADV] Failed to get volume size when add volume:%s.", volume_name)); + status = wr_add_volume_vg_ctrl(vg_item->wr_ctrl, id, vol_size, volume_name, volume_flag); + if (status != CM_SUCCESS) { + return status; + } + return wr_add_volume_record_log(session, vg_item, id); +} + +uint32_t wr_find_volume(wr_vg_info_item_t *vg_item, const char *volume_name) +{ + for (uint32_t i = 0; i < WR_MAX_VOLUMES; i++) { + if (vg_item->wr_ctrl->volume.defs[i].flag == VOLUME_FREE) { + // not been used + continue; + } + + if (strcmp(vg_item->wr_ctrl->volume.defs[i].name, volume_name) == 0) { + return i; + } + } + + return CM_INVALID_ID32; +} + +status_t wr_add_volume_core( + wr_session_t *session, wr_vg_info_item_t *vg_item, const char *volume_name, wr_config_t *inst_cfg) +{ + if (wr_refresh_vginfo(vg_item) != CM_SUCCESS) { + LOG_DEBUG_ERR("[VOL][ADV] %s refresh vginfo failed.", "wr_add_volume"); + return CM_ERROR; + } + if (wr_find_volume(vg_item, volume_name) != CM_INVALID_ID32) { + WR_THROW_ERROR(ERR_WR_VOLUME_EXISTED, volume_name, vg_item->vg_name); + return CM_ERROR; + } + if (wr_add_volume_impl(session, vg_item, volume_name, VOLUME_PREPARE) != CM_SUCCESS) { + return CM_ERROR; + } + + if (wr_process_redo_log(session, vg_item) != CM_SUCCESS) { + wr_unlock_vg_mem_and_shm(session, vg_item); + (void)wr_unlock_vg_storage(vg_item, vg_item->entry_path, inst_cfg); + LOG_RUN_ERR("[WR] ABORT INFO: redo log process failed, errcode:%d, OS errno:%d, OS errmsg:%s.", + cm_get_error_code(), errno, strerror(errno)); + cm_fync_logfile(); + wr_exit(1); + } + return CM_SUCCESS; +} + +status_t wr_refresh_meta_info(wr_session_t *session) +{ + return CM_SUCCESS; +} + +uint64 wr_get_vg_latch_shm_offset(wr_vg_info_item_t *vg_item) +{ + cm_shm_key_t key = ga_object_key(GA_INSTANCE_POOL, vg_item->objectid); + sh_mem_p offset = cm_trans_shm_offset(key, vg_item->vg_latch); + return offset; +} + +// shoud lock in caller +status_t wr_load_volume_ctrl(wr_vg_info_item_t *vg_item, wr_volume_ctrl_t *volume_ctrl) +{ + return CM_SUCCESS; +} + +status_t wr_check_refresh_core(wr_vg_info_item_t *vg_item) +{ + if (!WR_STANDBY_CLUSTER && wr_is_readwrite()) { + WR_ASSERT_LOG(wr_need_exec_local(), "only masterid %u can be readwrite.", wr_get_master_id()); + return CM_SUCCESS; + } +#ifndef WIN32 + char buf[WR_DISK_UNIT_SIZE] __attribute__((__aligned__(WR_DISK_UNIT_SIZE))); +#else + char buf[WR_DISK_UNIT_SIZE]; +#endif + bool32 remote = CM_FALSE; + uint64 core_version = vg_item->wr_ctrl->core.version; + wr_fs_block_root_t *fs_root = (wr_fs_block_root_t *)vg_item->wr_ctrl->core.fs_block_root; + uint64 fs_version = fs_root->version; + wr_fs_aux_root_t *fs_aux_root = (wr_fs_aux_root_t *)vg_item->wr_ctrl->core.fs_aux_root; + uint64 fs_aux_version = fs_aux_root->version; + + status_t status = wr_load_vg_ctrl_part(vg_item, (int64)WR_CTRL_CORE_OFFSET, buf, WR_DISK_UNIT_SIZE, &remote); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to load vg core version %s.", vg_item->entry_path); + return status; + } + + wr_core_ctrl_t *new_core = (wr_core_ctrl_t *)buf; + if (wr_compare_version(new_core->version, core_version)) { + LOG_RUN_INF("Refresh core, old version:%llu, disk version:%llu.", core_version, new_core->version); + status = wr_load_vg_ctrl_part( + vg_item, (int64)WR_CTRL_CORE_OFFSET, &vg_item->wr_ctrl->core, (int32)WR_CORE_CTRL_SIZE, &remote); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to load vg core %s.", vg_item->entry_path); + return status; + } + } else { + fs_root = (wr_fs_block_root_t *)new_core->fs_block_root; + fs_aux_root = (wr_fs_aux_root_t *)new_core->fs_aux_root; + if (wr_compare_version(fs_root->version, fs_version) || + wr_compare_version(fs_aux_root->version, fs_aux_version)) { + LOG_RUN_INF("Refresh core head, old version:%llu, disk version:%llu.", fs_version, fs_root->version); + errno_t errcode = memcpy_s(&vg_item->wr_ctrl->core, WR_DISK_UNIT_SIZE, buf, WR_DISK_UNIT_SIZE); + securec_check_ret(errcode); + } + } + return CM_SUCCESS; +} + +// NOTE:use in server. +status_t wr_check_volume(wr_vg_info_item_t *vg_item, uint32 volumeid) +{ + return CM_SUCCESS; +} + +// first check volume is valid. +status_t wr_check_write_volume(wr_vg_info_item_t *vg_item, uint32 volumeid, int64 offset, void *buf, uint32 size) +{ + wr_volume_t *volume; + WR_RETURN_IF_ERROR(wr_check_volume(vg_item, volumeid)); + volume = &vg_item->volume_handle[volumeid]; + return wr_write_volume_inst(vg_item, volume, offset, buf, size); +} + +// first check volume is valid. +status_t wr_check_read_volume( + wr_vg_info_item_t *vg_item, uint32 volumeid, int64 offset, void *buf, int32 size, bool32 *remote) +{ + wr_volume_t *volume; + WR_RETURN_IF_ERROR(wr_check_volume(vg_item, volumeid)); + volume = &vg_item->volume_handle[volumeid]; + LOG_DEBUG_INF("Begin to read volume %s when check, offset:%lld,size:%d.", vg_item->entry_path, offset, size); + return wr_read_volume_inst(vg_item, volume, offset, buf, size, remote); +} + +wr_remote_read_proc_t remote_read_proc = NULL; +void regist_remote_read_proc(wr_remote_read_proc_t proc) +{ + remote_read_proc = proc; +} + +static inline bool32 wr_need_load_remote(int size) +{ + return ((remote_read_proc != NULL) && (!wr_need_exec_local()) && (size <= (int32)WR_LOADDISK_BUFFER_SIZE)); +} + +bool32 wr_need_exec_local(void) +{ + wr_config_t *cfg = wr_get_inst_cfg(); + uint32 master_id = wr_get_master_id(); + uint32 curr_id = (uint32)(cfg->params.inst_id); + return ((curr_id == master_id)); +} + +status_t wr_read_volume_inst( + wr_vg_info_item_t *vg_item, wr_volume_t *volume, int64 offset, void *buf, int32 size, bool32 *remote_chksum) +{ + status_t status = CM_ERROR; + CM_ASSERT(offset % WR_DISK_UNIT_SIZE == 0); + CM_ASSERT(size % WR_DISK_UNIT_SIZE == 0); + CM_ASSERT(((uint64)buf) % WR_DISK_UNIT_SIZE == 0); + while (get_instance_status_proc != NULL && get_instance_status_proc() != WR_STATUS_RECOVERY && + wr_need_load_remote(size) == CM_TRUE && status != CM_SUCCESS) { + if (size == (int32)sizeof(wr_ctrl_t)) { + LOG_RUN_INF("Try to load wrctrl from remote."); + } + status = remote_read_proc(vg_item->vg_name, volume, offset, buf, size); + if (status != CM_SUCCESS) { + if (status == WR_READ4STANDBY_ERR || get_instance_status_proc() == WR_STATUS_PREPARE) { + LOG_RUN_ERR("Failed to load disk(%s) data from the active node, result:%d", volume->name_p, status); + return CM_ERROR; + } + LOG_RUN_WAR("Failed to load disk(%s) data from the active node, result:%d", volume->name_p, status); + cm_sleep(WR_READ_REMOTE_INTERVAL); + continue; + } + + if (*remote_chksum == CM_TRUE) { + if (wr_read_remote_checksum(buf, size) != CM_TRUE) { + LOG_RUN_WAR("Failed to load disk(%s) data from the active node, checksum error", volume->name_p); + status = CM_ERROR; + continue; + } + } + return status; + } + + if (wr_is_server()) { + uint32 recover_thread_id = wr_get_recover_thread_id(); + uint32 curr_thread_id = wr_get_current_thread_id(); + uint32 recover_status = get_instance_status_proc(); + if (recover_status != WR_STATUS_OPEN && recover_thread_id != curr_thread_id && + vg_item->status == WR_VG_STATUS_OPEN) { + WR_THROW_ERROR(ERR_WR_RECOVER_CAUSE_BREAK); + LOG_RUN_INF("Read volume inst break by recovery"); + return CM_ERROR; + } + } + + *remote_chksum = CM_FALSE; + status = wr_read_volume(volume, offset, buf, size); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to load disk(%s) data, result:%d", volume->name_p, status); + return status; + } + + return CM_SUCCESS; +} + +status_t wr_read_volume_4standby(const char *vg_name, uint32 volume_id, int64 offset, void *buf, uint32 size) +{ + wr_vg_info_item_t *vg_item = wr_find_vg_item(vg_name); + if (vg_item == NULL) { + LOG_RUN_ERR("Read volume for standby failed, find vg(%s) error.", vg_name); + return CM_ERROR; + } + + if (volume_id >= WR_MAX_VOLUMES) { + LOG_RUN_ERR("Read volume for standby failed, vg(%s) volume id[%u] error.", vg_name, volume_id); + return CM_ERROR; + } + + wr_volume_t *volume = &vg_item->volume_handle[volume_id]; + if (volume->handle == WR_INVALID_HANDLE) { + if (wr_open_volume(volume->name_p, NULL, WR_INSTANCE_OPEN_FLAG, volume) != CM_SUCCESS) { + LOG_RUN_ERR("Read volume for standby failed, failed to open volume(%s).", volume->name_p); + return CM_ERROR; + } + } + + uint64 volumesize = vg_item->wr_ctrl->core.volume_attrs[volume_id].size; + if (((uint64)offset > volumesize) || ((uint64)size > (volumesize - (uint64)offset))) { + LOG_RUN_ERR( + "Read volume for standby failed, params err, vg(%s) voiume id[%u] offset[%llu] size[%u] volume size[%llu].", + vg_name, volume_id, offset, size, volumesize); + return CM_ERROR; + } + + if (wr_read_volume(volume, offset, buf, (int32)size) != CM_SUCCESS) { + LOG_RUN_ERR("Read volume for standby failed, failed to load disk(%s) data.", volume->name_p); + return CM_ERROR; + } + + LOG_DEBUG_INF("load disk(%s) data for standby success.", volume->name_p); + return CM_SUCCESS; +} + +bool32 wr_meta_syn(wr_session_t *session, wr_bg_task_info_t *bg_task_info) +{ + bool32 finish = CM_TRUE; + for (uint32_t i = bg_task_info->vg_id_beg; i < bg_task_info->vg_id_end; i++) { + bool32 cur_finish = wr_syn_buffer_cache(session, &g_vgs_info->volume_group[i]); + if (!cur_finish && !finish) { + finish = CM_FALSE; + } + } + return finish; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/common/persist/wr_diskgroup.h b/src/common/persist/wr_diskgroup.h new file mode 100644 index 0000000000000000000000000000000000000000..ab978e785546a3d3028b465cfc4a82b3401e1541 --- /dev/null +++ b/src/common/persist/wr_diskgroup.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_diskgroup.h + * + * + * IDENTIFICATION + * src/common/persist/wr_diskgroup.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_DISK_GROUP_H__ +#define __WR_DISK_GROUP_H__ + +#include "wr_defs.h" +#include "wr_volume.h" +#include "cm_types.h" +#include "wr_hashmap.h" +#include "wr_latch.h" +#include "cm_checksum.h" +#include "wr_file_def.h" +#include "cm_checksum.h" +#include "wr_log.h" +#include "wr_stack.h" +#include "wr_session.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WR_READ4STANDBY_ERR (int32)3 + +/* + 1、when the node is standby, just send message to primary to read volume + 2、if the primary is just in recovery or switch, may wait the read request + 3、if read failed, just retry. + 4、may be standby switch to primary, just read volume from self; + 5、may be primary just change to standby, just read volume from new primary; +*/ +#define WR_READ_REMOTE_INTERVAL 50 + +#pragma pack(8) +// for lsvg +typedef struct wr_volume_space_info_t { + char volume_name[WR_MAX_VOLUME_PATH_LEN]; + double volume_free; + double volume_size; + double volume_used; +} volume_space_info_t; + +typedef struct wr_vg_space_info_t { + double wr_vg_free; + double wr_vg_size; +} vg_space_info_t; + +typedef struct wr_vg_vlm_space_info_t { + char vg_name[WR_MAX_NAME_LEN]; + volume_space_info_t volume_space_info[WR_MAX_VOLUMES]; + vg_space_info_t vg_space_info; + uint32 volume_count; +} vg_vlm_space_info_t; + +typedef struct st_wr_allvg_vlm_space_t { + vg_vlm_space_info_t volume_group[WR_MAX_VOLUME_GROUP_NUM]; + uint32_t group_num; +} wr_allvg_vlm_space_t; +#pragma pack() + +typedef handle_t wr_directory_t; // wr_vfs_t + +void wr_free_vg_info(); +wr_vg_info_item_t *wr_find_vg_item(const char *vg_name); +wr_vg_info_item_t *wr_find_vg_item_by_id(uint32 vg_id); + +status_t wr_load_vg_ctrl(wr_vg_info_item_t *vg_item, bool32 is_lock); + +status_t wr_load_vg_ctrl_part(wr_vg_info_item_t *vg_item, int64 offset, void *buf, int32 size, bool32 *remote); +status_t wr_check_refresh_core(wr_vg_info_item_t *vg_item); + +void wr_lock_vg_mem_x(wr_vg_info_item_t *vg_item); +void wr_lock_vg_mem_x2ix(wr_vg_info_item_t *vg_item); +void wr_lock_vg_mem_ix2x(wr_vg_info_item_t *vg_item); +void wr_lock_vg_mem_s(wr_vg_info_item_t *vg_item); +void wr_lock_vg_mem_s_force(wr_vg_info_item_t *vg_item); +void wr_lock_vg_mem_degrade(wr_vg_info_item_t *vg_item); +void wr_unlock_vg_mem(wr_vg_info_item_t *vg_item); + +status_t wr_file_lock_vg_w(wr_config_t *inst_cfg); +void wr_file_unlock_vg(void); + +status_t wr_lock_disk_vg(const char *entry_path, wr_config_t *inst_cfg); +status_t wr_lock_share_disk_vg(const char *entry_path, wr_config_t *inst_cfg); + +status_t wr_unlock_vg_raid(wr_vg_info_item_t *vg_item, const char *entry_path, int64 inst_id); +status_t wr_unlock_vg_share_disk(wr_vg_info_item_t *vg_item, const char *entry_path, int64 inst_id); +status_t wr_unlock_vg(int32 wr_mode, wr_vg_info_item_t *vg_item, const char *entry_path, int64 inst_id); +status_t wr_lock_vg_storage_r(wr_vg_info_item_t *vg_item, const char *entry_path, wr_config_t *inst_cfg); +status_t wr_lock_vg_storage_w(wr_vg_info_item_t *vg_item, const char *entry_path, wr_config_t *inst_cfg); +status_t wr_unlock_vg_storage(wr_vg_info_item_t *vg_item, const char *entry_path, wr_config_t *inst_cfg); +status_t wr_lock_vg_storage_core(wr_vg_info_item_t *vg_item, const char *entry_path, wr_config_t *inst_cfg); +status_t wr_unlock_vg_storage_core(wr_vg_info_item_t *vg_item, const char *entry_path, wr_config_t *inst_cfg); +status_t wr_add_volume(wr_session_t *session, const char *vg_name, const char *volume_name); +status_t wr_remove_volume(wr_session_t *session, const char *vg_name, const char *volume_name); +status_t wr_refresh_meta_info(wr_session_t *session); +status_t wr_load_volume_ctrl(wr_vg_info_item_t *vg_item, wr_volume_ctrl_t *volume_ctrl); + +status_t wr_write_ctrl_to_disk(wr_vg_info_item_t *vg_item, int64 offset, void *buf, uint32 size); +status_t wr_update_core_ctrl_disk(wr_vg_info_item_t *vg_item); +status_t wr_update_volume_ctrl(wr_vg_info_item_t *vg_item); +status_t wr_update_volume_id_info(wr_vg_info_item_t *vg_item, uint32 id); + +status_t wr_write_volume_inst( + wr_vg_info_item_t *vg_item, wr_volume_t *volume, int64 offset, const void *buf, uint32 size); +status_t wr_read_volume_inst( + wr_vg_info_item_t *vg_item, wr_volume_t *volume, int64 offset, void *buf, int32 size, bool32 *remote); +status_t wr_init_vol_handle(wr_vg_info_item_t *vg_item, int32 flags, wr_vol_handles_t *vol_handles); +void wr_destroy_vol_handle(wr_vg_info_item_t *vg_item, wr_vol_handles_t *vol_handles, uint32 size); +extern wr_vg_info_t *g_vgs_info; +#define VGS_INFO (g_vgs_info) +status_t wr_check_volume(wr_vg_info_item_t *vg_item, uint32 volumeid); +uint32_t wr_find_volume(wr_vg_info_item_t *vg_item, const char *volume_name); +uint32_t wr_find_free_volume_id(const wr_vg_info_item_t *vg_item); +status_t wr_cmp_volume_head(wr_vg_info_item_t *vg_item, const char *volume_name, uint32 id); +status_t wr_check_lock_remain_inner( + int32 wr_mode, wr_vg_info_item_t *vg_item, const char *entry_path, int64 inst_id, bool32 *is_remain); +static inline wr_vg_info_item_t *wr_get_first_vg_item() +{ + return &g_vgs_info->volume_group[0]; +} + +static inline uint64 wr_get_redo_log_lsn(wr_vg_info_item_t *vg_item) +{ + return vg_item->wr_ctrl->redo_ctrl.lsn; +} + +static inline uint64 wr_inc_redo_log_lsn(wr_vg_info_item_t *vg_item) +{ + uint64 lsn = wr_get_redo_log_lsn(vg_item); + lsn++; + return lsn; +} + +// NOTE:has minus checksum field. +static inline uint32 wr_get_checksum(void *data, uint32 len) +{ + char *buf = (char *)data; + buf = buf + sizeof(uint32); // checksum field + CM_ASSERT(len - sizeof(uint32) > 0); + uint32 size = (uint32)(len - sizeof(uint32)); + return cm_get_checksum(buf, size); +} + +static inline void wr_check_checksum(uint32 checksum0, uint32 checksum1) +{ + if (checksum0 != checksum1) { + LOG_RUN_ERR("Failed to check checksum:%u,%u.", checksum0, checksum1); + cm_panic(0); + } +} + +static inline bool32 wr_read_remote_checksum(void *buf, int32 size) +{ + uint32 sum1 = *(uint32 *)buf; + uint32 sum2 = wr_get_checksum(buf, (uint32)size); + LOG_DEBUG_INF("read remote checksum, checksum1 is %u, checksum2 is %u.", sum1, sum2); + return sum1 == sum2; +} + +uint64 wr_get_vg_latch_shm_offset(wr_vg_info_item_t *vg_item); + +static inline uint64 wr_get_vg_au_size(wr_ctrl_t *ctrl) +{ + return (uint64)(ctrl->core.au_size); +} + +static inline void wr_set_vg_au_size(wr_ctrl_t *ctrl, uint32 au_size) +{ + CM_ASSERT(au_size <= WR_MAX_AU_SIZE); + ctrl->core.au_size = au_size; +} + +static inline bool32 wr_check_volume_is_used(wr_vg_info_item_t *vg_item, uint32 vid) +{ + return (CM_CALC_ALIGN(WR_VOLUME_HEAD_SIZE, wr_get_vg_au_size(vg_item->wr_ctrl)) < + vg_item->wr_ctrl->core.volume_attrs[vid].hwm); +} + +static inline bool32 wr_compare_version(uint64 disk_version, uint64 mem_version) +{ + return (disk_version > mem_version); +} + +uint32 wr_get_master_id(); +void wr_set_master_id(uint32 id); +bool32 wr_is_server(void); +bool32 wr_is_readwrite(void); +bool32 wr_is_readonly(void); +void wr_set_server_flag(void); +bool32 wr_need_exec_local(void); +wr_vg_info_t *wr_malloc_vg_info(void); + +typedef wr_instance_status_e (*wr_get_instance_status_proc_t)(void); +extern wr_get_instance_status_proc_t get_instance_status_proc; +void regist_get_instance_status_proc(wr_get_instance_status_proc_t proc); + +int32 wr_get_server_status_flag(void); +void wr_set_server_status_flag(int32 wr_status); +void wr_set_recover_thread_id(uint32 thread_id); +uint32 wr_get_recover_thread_id(void); + +status_t wr_check_write_volume(wr_vg_info_item_t *vg_item, uint32 volumeid, int64 offset, void *buf, uint32 size); +status_t wr_check_read_volume( + wr_vg_info_item_t *vg_item, uint32 volumeid, int64 offset, void *buf, int32 size, bool32 *remote); +typedef status_t (*wr_remote_read_proc_t)( + const char *vg_name, wr_volume_t *volume, int64 offset, void *buf, int size); +void regist_remote_read_proc(wr_remote_read_proc_t proc); +status_t wr_read_volume_4standby(const char *vg_name, uint32 volume_id, int64 offset, void *buf, uint32 size); +status_t wr_add_volume_vg_ctrl( + wr_ctrl_t *vg_ctrl, uint32 id, uint64 vol_size, const char *volume_name, volume_slot_e volume_flag); +status_t wr_gen_volume_head( + wr_volume_header_t *vol_head, wr_vg_info_item_t *vg_item, const char *volume_name, uint32 id); +status_t wr_check_remove_volume(wr_vg_info_item_t *vg_item, const char *volume_name, uint32 *volume_id); +void wr_remove_volume_vg_ctrl(wr_ctrl_t *vg_ctrl, uint32 id); +bool32 wr_meta_syn(wr_session_t *session, wr_bg_task_info_t *bg_task_info); +status_t wr_update_redo_ctrl(wr_vg_info_item_t *vg_item, uint32 index, uint64 offset, uint64 lsn); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/common/persist/wr_file_def.h b/src/common/persist/wr_file_def.h new file mode 100644 index 0000000000000000000000000000000000000000..450c20ba3cf81680f7e5e4076d69b46a5095aa4d --- /dev/null +++ b/src/common/persist/wr_file_def.h @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_file_def.h + * + * + * IDENTIFICATION + * src/common/persist/wr_file_def.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_FILE_DEF_H__ +#define __WR_FILE_DEF_H__ + +#include "wr_ctrl_def.h" +#include "wr_session.h" +// gft_node_t flag +#define WR_FT_NODE_FLAG_SYSTEM 0x00000001 +#define WR_FT_NODE_FLAG_DEL 0x00000002 +#define WR_FT_NODE_FLAG_NORMAL 0x00000004 +#define WR_FT_NODE_FLAG_INVALID_FS_META 0x00000008 +#define WR_FT_NODE_FLAG_INNER_INITED 0x80000000 + +#define WR_IS_FILE_INNER_INITED(flag) ((uint64)(flag)&WR_FT_NODE_FLAG_INNER_INITED) + +#define WR_GFT_PATH_STR "PATH" +#define WR_GFT_FILE_STR "FILE" +#define WR_GFT_INVALID_STR "INVALID_TYPE" + +#ifdef WR_TEST +#define WR_INSTANCE_OPEN_FLAG (O_RDWR | O_SYNC) +#define WR_CLI_OPEN_FLAG (O_RDWR | O_SYNC) +#else +#define WR_INSTANCE_OPEN_FLAG (O_RDWR | O_SYNC | O_DIRECT) +#define WR_CLI_OPEN_FLAG (O_RDWR | O_SYNC | O_DIRECT) +#define WR_NOD_OPEN_FLAG (O_RDWR | O_SYNC) +#endif + +#define WR_BLOCK_ID_INIT (uint64)0xFFFFFFFFFFFFFFFE +#define WR_GET_COMMON_BLOCK_HEAD(au) ((wr_common_block_t *)((char *)(au))) +#define WR_GET_FS_BLOCK_FROM_AU(au, block_id) \ + ((wr_fs_block_t *)((char *)(au) + WR_FILE_SPACE_BLOCK_SIZE * (block_id))) +#define WR_GET_FT_BLOCK_FROM_AU(au, block_id) ((wr_ft_block_t *)((char *)(au) + WR_BLOCK_SIZE * (block_id))) +#define WR_GET_FT_BLOCK_NUM_IN_AU(wr_ctrl) ((wr_get_vg_au_size(wr_ctrl)) / WR_BLOCK_SIZE) +#define WR_GET_FS_BLOCK_NUM_IN_AU(wr_ctrl) ((wr_get_vg_au_size(wr_ctrl)) / WR_FILE_SPACE_BLOCK_SIZE) +#define WR_FILE_SPACE_BLOCK_BITMAP_COUNT (WR_FILE_SPACE_BLOCK_SIZE - sizeof(wr_fs_block_header)) / sizeof(auid_t) +#define WR_ENTRY_FS_INDEX 0xFFFD +#define WR_FS_INDEX_INIT 0xFFFE +#define WR_FILE_CONTEXT_FLAG_USED 1 +#define WR_FILE_CONTEXT_FLAG_FREE 0 + +#pragma pack(8) + +// GFT mean WR File Table +typedef enum en_zft_item_type { + GFT_PATH, // path + GFT_FILE, +} gft_item_type_t; + +typedef struct st_zft_list { + uint32 count; + ftid_t first; + ftid_t last; +} gft_list_t; + +// used for ft node parent and fs block ftid init, +typedef union st_gft_node { + struct { + gft_item_type_t type; + time_t create_time; + time_t update_time; + uint32 software_version; + uint32 flags; + atomic_t size; // Actually uint64, use atomic_get for client read and atomic_set for server modify. + union { + wr_block_id_t entry; // for file and link + gft_list_t items; // for dir + }; + ftid_t id; + ftid_t next; + ftid_t prev; + char name[WR_MAX_NAME_LEN]; + uint64 fid; + uint64 written_size; + ftid_t parent; + uint64 file_ver; // the current ver of the file, when create, it's zero, when truncate the content of the file + // to small size, update it by in old file_ver with step 1 + uint64 min_inited_size; // before this ,must has written data + }; + char ft_node[256]; // to ensure that the structure size is 256 +} gft_node_t; + +typedef struct st_gft_block_info { + gft_node_t *ft_node; +} gft_block_info_t; + +typedef struct st_wr_check_dir_param_t { + wr_vg_info_item_t *vg_item; + gft_node_t *p_node; + gft_node_t *last_node; + gft_node_t *link_node; + bool8 is_skip_delay_file; + bool8 not_exist_err; + bool8 is_find_link; + bool8 last_is_link; +} wr_check_dir_param_t; + +typedef struct st_wr_check_dir_output_t { + gft_node_t **out_node; + wr_vg_info_item_t **item; + gft_node_t **parent_node; + bool8 is_lock_x; +} wr_check_dir_output_t; + +typedef enum en_wr_block_flag { + WR_BLOCK_FLAG_RESERVE, + WR_BLOCK_FLAG_FREE, + WR_BLOCK_FLAG_USED, + WR_BLOCK_FLAG_MAX, +} wr_block_flag_e; + +typedef struct st_wr_common_block_t { + uint32_t checksum; + uint32_t type; + uint64 version; + wr_block_id_t id; + uint8_t flags; + uint8_t reserve[7]; +} wr_common_block_t; + +typedef union st_wr_ft_block { + struct { + wr_common_block_t common; + uint32_t node_num; + uint32_t reserve; + wr_block_id_t next; + }; + char ft_block[256]; // to ensure that the structure size is 256 +} wr_ft_block_t; + +typedef struct st_wr_fs_block_list_t { + uint64 count; + wr_block_id_t first; + wr_block_id_t last; +} wr_fs_block_list_t; + +typedef struct st_wr_fs_root_t { + uint64 version; + wr_fs_block_list_t free; +} wr_fs_block_root_t; + +typedef struct st_wr_block_header { + wr_common_block_t common; + wr_block_id_t next; + wr_block_id_t ftid; + uint16_t used_num; + uint16_t total_num; + uint16_t index; + uint16_t reserve; +} wr_fs_block_header; + +// file space block +typedef struct st_wr_fs_block_t { + wr_fs_block_header head; + wr_block_id_t bitmap[0]; +} wr_fs_block_t; + +#define WR_FS_BLOCK_ITEM_NUM ((WR_FILE_SPACE_BLOCK_SIZE - sizeof(wr_fs_block_header)) / sizeof(auid_t)) +typedef struct st_gft_root_t { + gft_list_t free_list; // free file table node list + gft_list_t items; // not used for now + uint64 fid; // the current max file id in the system; + wr_block_id_t first; // the first allocated block. + wr_block_id_t last; +} gft_root_t; + +typedef struct st_wr_root_ft_header { + wr_common_block_t common; + uint32_t node_num; + uint32_t reserve; + wr_block_id_t next; + char reserver2[8]; +} wr_root_ft_header_t; + +typedef union st_wr_root_ft_block { + struct { + wr_root_ft_header_t ft_block; + gft_root_t ft_root; + }; + char root_ft_block[256]; // to ensure that the structure size is 256 +} wr_root_ft_block_t; + +#pragma pack() + +typedef enum en_wr_file_mode { + WR_FILE_MODE_READ = 0x00000001, + WR_FILE_MODE_WRITE = 0x00000002, + WR_FILE_MODE_RDWR = WR_FILE_MODE_READ | WR_FILE_MODE_WRITE, +} wr_file_mode_e; + +typedef struct st_wr_file_context { + latch_t latch; + gft_node_t *node; + uint32 next; + uint32 flag : 2; // WR_FILE_CONTEXT_FLAG_USED,WR_FILE_CONTEXT_FLAG_FREE + uint32 tid : 22; // 64-bit OS: pid_max [0, 2^22] + uint32 reserve : 8; + int64 offset; + int64 vol_offset; + wr_vg_info_item_t *vg_item; + uint64 fid; + char vg_name[WR_MAX_NAME_LEN]; + uint32 vgid; + uint32 id; + wr_file_mode_e mode; +} wr_file_context_t; + +typedef struct st_wr_file_context_group_t { + wr_file_context_t *files_group[WR_MAX_FILE_CONTEXT_GROUP_NUM]; + uint32_t group_num; +} wr_file_context_group_t; + +typedef struct st_wr_ft_au_list_t { + void *au_addr[WR_MAX_FT_AU_NUM]; + uint32_t count; +} wr_ft_au_list_t; + +typedef struct st_wr_file_run_ctx { + uint32 max_open_file; + uint32 has_opened_files; + uint32 file_free_first; // the first free file context. + wr_file_context_group_t files; +} wr_file_run_ctx_t; + +typedef struct st_wr_env { + latch_t latch; + bool32 initialized; + uint32 instance_id; + latch_t conn_latch; + uint32 conn_count; + thread_t thread_heartbeat; + wr_config_t inst_cfg; +#ifdef ENABLE_WRTEST + pid_t inittor_pid; +#endif + wr_file_run_ctx_t file_run_ctx; +} wr_env_t; + +typedef struct st_wr_dir_t { + wr_vg_info_item_t *vg_item; + uint64 version; + ftid_t cur_ftid; + gft_node_t cur_node; + ftid_t pftid; // path ftid +} wr_vfs_t; + +typedef struct st_wr_find_node_t { + ftid_t ftid; + char vg_name[WR_MAX_NAME_LEN]; +} wr_find_node_t; + +#endif // __WR_FILE_DEF_H__ diff --git a/src/common/persist/wr_fs_aux.c b/src/common/persist/wr_fs_aux.c new file mode 100644 index 0000000000000000000000000000000000000000..5d86840253da1a97882b7441a91dc8f749b281c4 --- /dev/null +++ b/src/common/persist/wr_fs_aux.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_fs_aux.c + * + * + * IDENTIFICATION + * src/common/persist/wr_fs_aux.c + * + * ------------------------------------------------------------------------- + */ +#include "wr_file.h" +#include "wr_fs_aux.h" +#include "wr_zero.h" +#include "wr_syn_meta.h" +#include "wr_defs_print.h" + +#ifdef __cplusplus +extern "C" { +#endif +// range is [beg, end) + +// end for redo +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/common/persist/wr_fs_aux.h b/src/common/persist/wr_fs_aux.h new file mode 100644 index 0000000000000000000000000000000000000000..44acca87a270fa096b6d6dc6464ec3634086ebe2 --- /dev/null +++ b/src/common/persist/wr_fs_aux.h @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_fs_aux.h + * + * + * IDENTIFICATION + * src/common/persist/wr_fs_aux.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_FS_AUX_H__ +#define __WR_FS_AUX_H__ + +#include "wr_file_def.h" +#include "wr_file.h" +#include "wr_redo.h" +#include "wr_latch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(8) +#define WR_REFRESH_FS_AUX_BATCH_MAX 8U +typedef struct st_wr_fs_aux_root_t { + uint64 version; + wr_fs_block_list_t free; +} wr_fs_aux_root_t; + +typedef struct st_wr_fs_aux_header_t { + wr_common_block_t common; + wr_block_id_t next; + wr_block_id_t ftid; + wr_block_id_t data_id; // when data_id.item & 0x1 is 1, means the au is parted write + // when data_id.item & 0x1 is 0, means the au is fully write + uint32 bitmap_num; + uint16_t index; + uint16_t resv; +} wr_fs_aux_header_t; + +typedef struct st_wr_fs_aux_t { + wr_fs_aux_header_t head; + uchar bitmap[0]; +} wr_fs_aux_t; + +typedef struct st_wr_fs_aux_pos_desc_t { + uint32 byte_index; + uint8 bit_index; + uint8 rsv[3]; +} wr_fs_aux_pos_desc_t; + +typedef struct st_wr_fs_aux_range_desc_t { + wr_fs_aux_pos_desc_t beg; + wr_fs_aux_pos_desc_t end; +} wr_fs_aux_range_desc_t; + +typedef struct st_wr_fs_pos_desc { + bool32 is_valid; + bool32 is_exist_aux; + wr_fs_block_t *entry_fs_block; + wr_fs_block_t *second_fs_block; + wr_fs_aux_t *fs_aux; + uint32 block_count; + uint32 block_au_count; + uint32 au_offset; + wr_block_id_t data_auid; +} wr_fs_pos_desc_t; + +// for redo ------------------------------ +typedef struct st_wr_redo_format_fs_aux_t { + auid_t auid; + uint32 obj_id; + uint32 count; + wr_fs_block_list_t old_free_list; +} wr_redo_format_fs_aux_t; + +typedef struct st_wr_redo_free_fs_aux_t { + wr_block_id_t id; + wr_block_id_t next; + wr_fs_aux_root_t root; +} wr_redo_free_fs_aux_t; + +typedef struct st_wr_redo_alloc_fs_aux_t { + wr_block_id_t id; + wr_block_id_t ftid; + uint16 index; + wr_fs_aux_root_t root; +} wr_redo_alloc_fs_aux_t; + +typedef struct st_wr_redo_init_fs_aux_t { + wr_block_id_t id; + wr_block_id_t data_id; + wr_block_id_t ftid; + wr_block_id_t parent_id; + uint16 reserve[2]; +} wr_redo_init_fs_aux_t; + +typedef struct st_wr_redo_updt_fs_block_t { + wr_block_id_t id; + wr_block_id_t data_id; + uint16 index; + uint16 reserve; +} wr_redo_updt_fs_block_t; + +#pragma pack() +// end for redo<----------------- + +void wr_check_fs_aux_affiliation(wr_fs_aux_header_t *block, ftid_t id, uint16_t index); + +static inline bool32 wr_is_fs_aux_valid(gft_node_t *node, wr_fs_aux_t *fs_aux) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(fs_aux); + return ((node->fid == block_ctrl->fid) && (node->file_ver == block_ctrl->file_ver) && + (block_ctrl->ftid == WR_ID_TO_U64(node->id))); +} + +static inline bool32 wr_is_fs_aux_valid_all(gft_node_t *node, wr_fs_aux_t *fs_aux, uint16_t index) +{ + bool32 is_valid_shm = wr_is_fs_aux_valid(node, fs_aux); + if (is_valid_shm) { + wr_check_fs_aux_affiliation(&fs_aux->head, node->id, index); + } + return is_valid_shm; +} + +static inline void wr_updt_fs_aux_file_ver(gft_node_t *node, wr_fs_aux_t *fs_aux) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(fs_aux); + block_ctrl->fid = node->fid; + block_ctrl->file_ver = node->file_ver; + block_ctrl->ftid = WR_ID_TO_U64(node->id); + block_ctrl->node = (char *)node; +} + +static inline uint64 wr_get_fs_aux_fid(wr_fs_aux_t *fs_aux) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(fs_aux); + return block_ctrl->fid; +} + +static inline uint64 wr_get_fs_aux_file_ver(wr_fs_aux_t *fs_aux) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(fs_aux); + return block_ctrl->file_ver; +} + +static inline void wr_latch_fs_aux_init(wr_fs_aux_t *fs_aux) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(fs_aux); + cm_latch_init(&block_ctrl->latch); +} + +static inline void wr_latch_s_fs_aux(wr_session_t *session, wr_fs_aux_t *fs_aux, latch_statis_t *stat) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(fs_aux); + wr_latch_s2(&block_ctrl->latch, WR_SESSIONID_IN_LOCK(session->id), CM_FALSE, stat); +} + +static inline void wr_latch_x_fs_aux(wr_session_t *session, wr_fs_aux_t *fs_aux, latch_statis_t *stat) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(fs_aux); + cm_latch_x(&block_ctrl->latch, WR_SESSIONID_IN_LOCK(session->id), stat); +} + +static inline void wr_unlatch_fs_aux(wr_fs_aux_t *fs_aux) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(fs_aux); + wr_unlatch(&block_ctrl->latch); +} + +void wr_calc_fs_aux_pos(uint64 au_size, int64 offset, wr_fs_aux_pos_desc_t *pos, bool32 is_end); +void wr_calc_fs_aux_range(wr_vg_info_item_t *vg_item, int64 offset, int64 size, wr_fs_aux_range_desc_t *range); +void wr_calc_fs_aux_bitmap_value(uint8 bit_beg, uint8 bit_end, uint8 *value); + +status_t wr_format_fs_aux(wr_session_t *session, wr_vg_info_item_t *vg_item, auid_t auid); +status_t wr_alloc_fs_aux(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, + wr_alloc_fs_block_info_t *info, wr_fs_aux_t **block); +void wr_free_fs_aux(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_fs_aux_t *block, wr_fs_aux_root_t *root); + +void wr_init_fs_aux(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_fs_aux_t *block, wr_block_id_t data_id, + wr_block_id_t ftid); +wr_fs_aux_t *wr_find_fs_aux(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, + wr_block_id_t block_id, bool32 check_version, ga_obj_id_t *out_obj_id, uint16 index); +status_t wr_updt_fs_aux(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, int64 offset, + int64 size, bool32 is_init_tail); + +bool32 wr_check_fs_aux_inited(wr_vg_info_item_t *vg_item, wr_fs_aux_t *fs_aux, int64 offset, int64 size); + +void wr_get_inited_size_with_fs_aux( + wr_vg_info_item_t *vg_item, wr_fs_aux_t *fs_aux, int64 offset, int32 size, int32 *inited_size); + +status_t wr_try_find_data_au_batch(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, + wr_fs_block_t *second_block, uint32 block_au_count_beg); +status_t wr_find_data_au_by_offset( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, int64 offset, wr_fs_pos_desc_t *fs_pos); +status_t wr_read_volume_with_fs_aux(wr_vg_info_item_t *vg_item, gft_node_t *node, wr_fs_aux_t *fs_aux, + wr_volume_t *volume, int64 vol_offset, int64 offset, void *buf, int32 size); + +status_t wr_get_gft_node_with_cache( + wr_session_t *session, wr_vg_info_item_t *vg_item, uint64 fid, wr_block_id_t ftid, gft_node_t **node_out); +status_t wr_get_entry_block_with_cache( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, wr_fs_block_t **fs_block_out); +status_t wr_get_fs_aux_with_cache(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, + wr_block_id_t block_id, uint32 block_au_count, wr_fs_aux_t **fs_aux_out); +void wr_check_fs_aux_free(wr_fs_aux_header_t *block); +void wr_init_fs_aux_head(wr_fs_aux_t *fs_aux, wr_block_id_t ftid, uint16 index); +// for redo +status_t rp_redo_format_fs_aux(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry); +status_t rb_redo_format_fs_aux(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry); +status_t rp_redo_alloc_fs_aux(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry); +status_t rb_redo_alloc_fs_aux(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry); +status_t rp_redo_free_fs_aux(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry); +status_t rb_redo_free_fs_aux(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry); +status_t rp_redo_init_fs_aux(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry); +status_t rb_redo_init_fs_aux(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry); +status_t rb_reload_fs_aux_root(wr_vg_info_item_t *vg_item); +void print_redo_format_fs_aux(wr_redo_entry_t *entry); +void print_redo_alloc_fs_aux(wr_redo_entry_t *entry); +void print_redo_free_fs_aux(wr_redo_entry_t *entry); +void print_redo_init_fs_aux(wr_redo_entry_t *entry); +status_t wr_update_fs_aux_bitmap2disk(wr_vg_info_item_t *item, wr_fs_aux_t *block, uint32 size, bool32 had_checksum); +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/common/persist/wr_redo.c b/src/common/persist/wr_redo.c new file mode 100644 index 0000000000000000000000000000000000000000..653bf7638a3ef5ea083a2556de7a87133c59ba66 --- /dev/null +++ b/src/common/persist/wr_redo.c @@ -0,0 +1,1232 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_redo.c + * + * + * IDENTIFICATION + * src/common/persist/wr_redo.c + * + * ------------------------------------------------------------------------- + */ + +#include "cm_debug.h" +#include "wr_ga.h" +#include "cm_hash.h" +#include "wr_defs.h" +#include "wr_errno.h" +#include "wr_file.h" +#include "wr_malloc.h" +#include "wr_redo.h" +#include "wr_fs_aux.h" +#include "wr_syn_meta.h" +#include "wr_defs_print.h" + +status_t wr_reset_log_slot_head(uint32 vg_id, char *log_buf) +{ + CM_ASSERT(vg_id < WR_MAX_VOLUME_GROUP_NUM); + wr_vg_info_item_t *first_vg_item = wr_get_first_vg_item(); + uint64 redo_start = wr_get_redo_log_v0_start(first_vg_item->wr_ctrl, vg_id); + errno_t errcode = memset_s(log_buf, WR_DISK_UNIT_SIZE, 0, WR_DISK_UNIT_SIZE); + securec_check_ret(errcode); + status_t status = wr_write_redolog_to_disk(first_vg_item, 0, (int64)redo_start, log_buf, WR_DISK_UNIT_SIZE); + if (status != CM_SUCCESS) { + LOG_RUN_ERR( + "[REDO][RESET]Failed to reset redo log, offset is %lld, size is %u.", redo_start, WR_DISK_UNIT_SIZE); + return status; + } + LOG_DEBUG_INF( + "[REDO][RESET] Reset head of redo log, first vg is %s, actural vg id is %u, offset is %lld, size is %u.", + first_vg_item->vg_name, vg_id, redo_start, WR_DISK_UNIT_SIZE); + return status; +} +void wr_put_log(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_type_t type, void *data, uint32 size) +{ + return; +} + +status_t wr_write_redolog_to_disk(wr_vg_info_item_t *vg_item, uint32 volume_id, int64 offset, char *buf, uint32 size) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(buf != NULL); + status_t status; + if (vg_item->volume_handle[volume_id].handle != WR_INVALID_HANDLE) { + return wr_write_volume_inst(vg_item, &vg_item->volume_handle[volume_id], offset, buf, size); + } + status = wr_open_volume(vg_item->wr_ctrl->volume.defs[volume_id].name, NULL, WR_INSTANCE_OPEN_FLAG, + &vg_item->volume_handle[volume_id]); + if (status != CM_SUCCESS) { + return status; + } + status = wr_write_volume_inst(vg_item, &vg_item->volume_handle[volume_id], offset, buf, size); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to read write file, offset:%lld, size:%u.", offset, size); + return status; + } + return CM_SUCCESS; +} + +status_t wr_flush_log_v0_inner(wr_vg_info_item_t *vg_item, char *log_buf, uint32 flush_size) +{ + wr_vg_info_item_t *first_vg_item = wr_get_first_vg_item(); + uint64 redo_start = wr_get_redo_log_v0_start(first_vg_item->wr_ctrl, vg_item->id); + if (flush_size > WR_INSTANCE_LOG_SPLIT_SIZE) { + LOG_RUN_ERR("redo log size %u is bigger than %u", flush_size, (uint32)WR_INSTANCE_LOG_SPLIT_SIZE); + return CM_ERROR; + } + status_t status = wr_write_redolog_to_disk(first_vg_item, 0, redo_start, log_buf, flush_size); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to flush redo log, offset is %lld, size is %u.", redo_start, flush_size); + return status; + } + return status; +} + +status_t wr_flush_log_inner(wr_vg_info_item_t *vg_item, char *log_buf, uint32 flush_size) +{ + wr_ctrl_t *wr_ctrl = vg_item->wr_ctrl; + wr_redo_ctrl_t *redo_ctrl = &wr_ctrl->redo_ctrl; + uint32 redo_index = redo_ctrl->redo_index; + auid_t redo_au = redo_ctrl->redo_start_au[redo_index]; + uint64 redo_size = (uint64)redo_ctrl->redo_size[redo_index]; + uint32 count = redo_ctrl->count; + CM_ASSERT(flush_size < WR_VG_LOG_SPLIT_SIZE); + uint64 log_start = wr_get_vg_au_size(wr_ctrl) * redo_au.au; + uint64 offset = redo_ctrl->offset; + uint64 log_offset = log_start + offset; + wr_log_file_ctrl_t *log_ctrl = &vg_item->log_file_ctrl; + status_t status; + // redo_au0 | redo_au1 | redo_au2 |...|redo_aun + if (offset + flush_size > redo_size) { + uint64 flush_size_2 = (flush_size + offset) % redo_size; + uint64 flush_size_1 = flush_size - flush_size_2; + auid_t redo_au_next; + if (redo_index == count - 1) { + redo_au_next = redo_ctrl->redo_start_au[0]; + log_ctrl->index = 0; + } else { + redo_au_next = redo_ctrl->redo_start_au[redo_index + 1]; + log_ctrl->index = redo_index + 1; + } + uint64 log_start_next = wr_get_vg_au_size(wr_ctrl) * redo_au_next.au; + LOG_DEBUG_INF("Begin to flush redo log, offset is %lld, size is %llu.", offset, flush_size_1); + status = wr_write_redolog_to_disk(vg_item, redo_au.volume, (int64)log_offset, log_buf, (uint32)flush_size_1); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to flush redo log, offset is %lld, size is %u.", log_offset, (uint32)flush_size_1); + return status; + } + LOG_DEBUG_INF("Begin to flush redo log, offset is %d, size is %llu.", 0, flush_size_2); + status = wr_write_redolog_to_disk( + vg_item, redo_au_next.volume, (int64)log_start_next, log_buf + flush_size_1, (uint32)flush_size_2); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to flush redo log, offset is %d, size is %u.", 0, (uint32)flush_size_2); + return status; + } + log_ctrl->offset = flush_size_2; + return status; + } + LOG_DEBUG_INF("Begin to flush redo log, offset is %lld, size is %u.", offset, flush_size); + status = wr_write_redolog_to_disk(vg_item, redo_au.volume, (int64)log_offset, log_buf, flush_size); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to flush redo log, offset is %llu, size is %u.", log_offset, flush_size); + return status; + } + if (offset + flush_size == redo_size) { + log_ctrl->index = (redo_index == count - 1) ? 0 : redo_index + 1; + log_ctrl->offset = 0; + } else { + log_ctrl->index = redo_index; + log_ctrl->offset = offset + flush_size; + } + return status; +} + +status_t wr_flush_log(wr_vg_info_item_t *vg_item, char *log_buf) +{ + errno_t errcode = 0; + wr_redo_batch_t *batch = (wr_redo_batch_t *)(log_buf); + uint32 data_size; + uint32 flush_size; + if (batch->size == sizeof(wr_redo_batch_t) || vg_item->status == WR_VG_STATUS_RECOVERY) { + return CM_SUCCESS; + } + data_size = batch->size - sizeof(wr_redo_batch_t); + batch->hash_code = cm_hash_bytes((uint8 *)log_buf + sizeof(wr_redo_batch_t), data_size, INFINITE_HASH_RANGE); + batch->time = cm_now(); + flush_size = CM_CALC_ALIGN(batch->size + sizeof(wr_redo_batch_t), WR_DISK_UNIT_SIZE); // align with 512 + // batch_head|entry1|entry2|reserve|batch_tail --align with 512 + uint64 tail = (uint64)(flush_size - sizeof(wr_redo_batch_t)); + errcode = memcpy_s(log_buf + tail, sizeof(wr_redo_batch_t), batch, sizeof(wr_redo_batch_t)); + securec_check_ret(errcode); + uint32 software_version = wr_get_software_version(&vg_item->wr_ctrl->vg_info); + LOG_DEBUG_INF("[REDO] Before flush log, batch size is %u, count is %d, flush size is %u.", batch->size, + batch->count, flush_size); + if (software_version < WR_SOFTWARE_VERSION_2) { + return wr_flush_log_v0_inner(vg_item, log_buf, flush_size); + } + status_t status = wr_flush_log_inner(vg_item, log_buf, flush_size); + return status; +} + +static status_t rp_redo_update_volhead(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ +#ifndef WIN32 + char align_buf[WR_DISK_UNIT_SIZE] __attribute__((__aligned__(WR_DISK_UNIT_SIZE))); +#else + char align_buf[WR_DISK_UNIT_SIZE]; +#endif + wr_redo_volhead_t *redo = (wr_redo_volhead_t *)entry->data; + if (entry->size == 0) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_REDO_ILL, "invalid entry log size 0.")); + } + int32 errcode = memcpy_sp(align_buf, WR_DISK_UNIT_SIZE, redo->head, WR_DISK_UNIT_SIZE); + securec_check_ret(errcode); + wr_volume_t volume; + if (wr_open_volume(redo->name, NULL, WR_INSTANCE_OPEN_FLAG, &volume) != CM_SUCCESS) { + return CM_ERROR; + } + status_t status = wr_write_volume(&volume, 0, align_buf, (int32)WR_ALIGN_SIZE); + wr_close_volume(&volume); + return status; +} + +static status_t rp_redo_add_or_remove_volume( + wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + errno_t errcode = 0; + wr_redo_volop_t *redo = (wr_redo_volop_t *)entry->data; + if (entry->size == 0) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_REDO_ILL, "invalid entry log size 0.")); + } + wr_volume_attr_t *attr = (wr_volume_attr_t *)redo->attr; + uint32 id = attr->id; + + if (vg_item->status == WR_VG_STATUS_RECOVERY) { + if (wr_refresh_vginfo(vg_item) != CM_SUCCESS) { + WR_RETURN_IFERR2( + CM_ERROR, LOG_DEBUG_ERR("[REDO][REPLAY][ADD_OR_REMOVE_VOLUME] %s", "refresh vginfo failed.")); + } + + // in recovery + if (redo->is_add) { + CM_ASSERT((vg_item->wr_ctrl->core.volume_count + 1 == redo->volume_count) || + (vg_item->wr_ctrl->core.volume_count == redo->volume_count)); + } else { + CM_ASSERT((vg_item->wr_ctrl->core.volume_count - 1 == redo->volume_count) || + (vg_item->wr_ctrl->core.volume_count == redo->volume_count)); + } + + errcode = memcpy_s(&vg_item->wr_ctrl->core.volume_attrs[id], sizeof(wr_volume_attr_t), redo->attr, + sizeof(wr_volume_attr_t)); + securec_check_ret(errcode); + errcode = memcpy_s( + &vg_item->wr_ctrl->volume.defs[id], sizeof(wr_volume_def_t), redo->def, sizeof(wr_volume_def_t)); + securec_check_ret(errcode); + + LOG_RUN_INF("[REDO][REPLAY][ADD_OR_REMOVE_VOLUME] recovery add volume core\n" + "[before]core version:%llu, volume version:%llu, volume count:%u.\n" + "[after]core version:%llu, volume version:%llu, volume count:%u.", + vg_item->wr_ctrl->core.version, vg_item->wr_ctrl->volume.version, vg_item->wr_ctrl->core.volume_count, + redo->core_version, redo->volume_version, redo->volume_count); + + vg_item->wr_ctrl->core.version = redo->core_version; + vg_item->wr_ctrl->core.volume_count = redo->volume_count; + vg_item->wr_ctrl->volume.version = redo->volume_version; + } + status_t status = wr_update_volume_id_info(vg_item, id); + WR_RETURN_IFERR2(status, + LOG_DEBUG_ERR("[REDO][REPLAY][ADD_OR_REMOVE_VOLUME] Failed to update core ctrl and volume to disk, vg:%s.", + vg_item->vg_name)); + WR_LOG_DEBUG_OP("[REDO][REPLAY][ADD_OR_REMOVE_VOLUME] Succeed to replay add or remove volume:%u.", id); + return CM_SUCCESS; +} + +static status_t rb_redo_update_volhead(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + // no need to update volume head. + return CM_SUCCESS; +} + +static void print_redo_update_volhead(wr_redo_entry_t *entry) +{ + wr_redo_volhead_t *redo = (wr_redo_volhead_t *)entry->data; + (void)printf(" redo_volhead = {\n"); + (void)printf(" head = %s\n", redo->head); + (void)printf(" name = %s\n", redo->name); + (void)printf(" }\n"); +} +static status_t rb_redo_add_or_remove_volume( + wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + bool32 remote = CM_FALSE; + wr_redo_volop_t *redo = (wr_redo_volop_t *)entry->data; + WR_LOG_DEBUG_OP( + "[REDO][ROLLBACK][ADD_OR_REMOVE_VOL] rollback %s volume operate", (redo->is_add) ? "add" : "remove"); + return wr_load_vg_ctrl_part(vg_item, (int64)WR_CTRL_CORE_OFFSET, vg_item->wr_ctrl->core_data, + (int32)(WR_CORE_CTRL_SIZE + WR_VOLUME_CTRL_SIZE), &remote); +} + +static void print_redo_add_or_remove_volume(wr_redo_entry_t *entry) +{ + wr_redo_volop_t *data = (wr_redo_volop_t *)entry->data; + (void)printf(" redo_volop = {\n"); + (void)printf(" attr = %s\n", data->attr); + (void)printf(" def = %s\n", data->def); + (void)printf(" is_add = %u\n", data->is_add); + (void)printf(" volume_count = %u\n", data->volume_count); + (void)printf(" core_version = %llu\n", data->core_version); + (void)printf(" volume_version = %llu\n", data->volume_version); + (void)printf(" }\n"); +} + +static status_t rp_update_core_ctrl(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + errno_t errcode = 0; + wr_core_ctrl_t *data = (wr_core_ctrl_t *)entry->data; + if (entry->size != 0 && vg_item->status == WR_VG_STATUS_RECOVERY) { + errcode = + memcpy_s(vg_item->wr_ctrl->core_data, WR_CORE_CTRL_SIZE, data, entry->size - sizeof(wr_redo_entry_t)); + securec_check_ret(errcode); + } + LOG_DEBUG_INF("[REDO] replay to update core ctrl, hwm:%llu.", vg_item->wr_ctrl->core.volume_attrs[0].hwm); + status_t status = wr_update_core_ctrl_disk(vg_item); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("[REDO] Failed to update core ctrl to disk, vg:%s.", vg_item->vg_name)); + WR_LOG_DEBUG_OP("[REDO] Succeed to replay update core ctrl:%s.", vg_item->vg_name); + return CM_SUCCESS; +} + +static status_t rb_update_core_ctrl(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + bool32 remote = CM_FALSE; + WR_LOG_DEBUG_OP( + "[REDO][ROLLBACK] rollback update core ctrl, hwm:%llu.", vg_item->wr_ctrl->core.volume_attrs[0].hwm); + return wr_load_vg_ctrl_part( + vg_item, (int64)WR_CTRL_CORE_OFFSET, vg_item->wr_ctrl->core_data, (int32)WR_CORE_CTRL_SIZE, &remote); +} + +static void print_redo_update_core_ctrl(wr_redo_entry_t *entry) +{ + wr_core_ctrl_t *data = (wr_core_ctrl_t *)entry->data; + wr_printf_core_ctrl_base(data); +} + +void rp_init_block_addr_history(wr_block_addr_his_t *addr_his) +{ + CM_ASSERT(addr_his != NULL); + addr_his->count = 0; +} +void rp_insert_block_addr_history(wr_block_addr_his_t *addr_his, void *block) +{ + CM_ASSERT(addr_his != NULL); + CM_ASSERT(block != NULL); + CM_ASSERT(addr_his->count < WR_MAX_BLOCK_ADDR_NUM); + addr_his->addrs[addr_his->count] = block; + addr_his->count++; +} + +bool32 rp_check_block_addr(const wr_block_addr_his_t *addr_his, const void *block) +{ + CM_ASSERT(addr_his != NULL); + CM_ASSERT(block != NULL); + + for (uint32 i = 0; i < addr_his->count; i++) { + if (addr_his->addrs[i] == block) { + return CM_TRUE; + } + } + return CM_FALSE; +} +static status_t rp_redo_alloc_ft_node_core(wr_session_t *session, wr_vg_info_item_t *vg_item, + wr_redo_alloc_ft_node_t *data, wr_root_ft_block_t *ft_block, bool32 check_version) +{ + bool32 cmp; + status_t status; + gft_node_t *node; + wr_ft_block_t *cur_block; + wr_block_addr_his_t addr_his; + rp_init_block_addr_history(&addr_his); + rp_insert_block_addr_history(&addr_his, ft_block); + for (uint32 i = 0; i < WR_REDO_ALLOC_FT_NODE_NUM; i++) { + cmp = wr_cmp_auid(data->node[i].id, CM_INVALID_ID64); + if (cmp) { + continue; + } + node = wr_get_ft_node_by_ftid(session, vg_item, data->node[i].id, check_version, CM_FALSE); + if (node == NULL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FNODE_CHECK, "invalid ft node.")); + } + cur_block = wr_get_ft_by_node(node); + if (vg_item->status == WR_VG_STATUS_RECOVERY) { + *node = data->node[i]; + if (i == WR_REDO_ALLOC_FT_NODE_SELF_INDEX) { + cur_block->common.flags = WR_BLOCK_FLAG_USED; + } + } + + LOG_DEBUG_INF("[REDO] replay alloc file table node, name:%s.", node->name); + + cur_block = wr_get_ft_by_node(node); + if (rp_check_block_addr(&addr_his, cur_block) && vg_item->status != WR_VG_STATUS_RECOVERY) { + continue; // already update the block to disk + } + status = wr_update_ft_block_disk(vg_item, cur_block, data->node[i].id); + WR_RETURN_IF_ERROR(status); + rp_insert_block_addr_history(&addr_his, cur_block); + } + return CM_SUCCESS; +} + +static status_t rp_redo_alloc_ft_node(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(entry != NULL); + status_t status; + wr_redo_alloc_ft_node_t *data = (wr_redo_alloc_ft_node_t *)entry->data; + wr_root_ft_block_t *ft_block = WR_GET_ROOT_BLOCK(vg_item->wr_ctrl); + gft_root_t *gft = &ft_block->ft_root; + bool32 check_version = CM_FALSE; + + if (entry->size == 0) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_REDO_ILL, "invalid entry log size 0.")); + } + if (vg_item->status == WR_VG_STATUS_RECOVERY) { + status = wr_refresh_root_ft(vg_item, CM_TRUE, CM_FALSE); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("[REDO] Failed to refresh file table root, vg:%s.", vg_item->vg_name); + return status; + } + + *gft = data->ft_root; + check_version = CM_TRUE; + LOG_DEBUG_INF("[REDO] replay alloc file table node when recovery."); + } + + status = wr_update_ft_root(vg_item); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_REDO_ILL, "Failed to update file table root.")); + WR_RETURN_IF_ERROR(rp_redo_alloc_ft_node_core(session, vg_item, data, ft_block, check_version)); + LOG_DEBUG_INF("[REDO] Succeed to replay alloc ft node, vg name:%s.", vg_item->vg_name); + return CM_SUCCESS; +} + +static status_t rb_rollback_ft_block( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, uint32 node_num) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(node != NULL); + status_t status; + bool32 check_version = CM_FALSE; + bool32 remote = CM_FALSE; + + status = wr_load_vg_ctrl_part( + vg_item, (int64)WR_CTRL_ROOT_OFFSET, vg_item->wr_ctrl->root, (int32)WR_BLOCK_SIZE, &remote); + if (status != CM_SUCCESS) { + return status; + } + + gft_node_t *cur_node; + wr_ft_block_t *cur_block = NULL; + bool32 cmp; + int64 offset = 0; + for (uint32 i = 0; i < node_num; i++) { + cmp = wr_cmp_auid(node[i].id, CM_INVALID_ID64); + if (cmp) { + continue; + } + cur_node = wr_get_ft_node_by_ftid(session, vg_item, node[i].id, check_version, CM_FALSE); + if (!cur_node) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FNODE_CHECK, "invalid ft node.")); + } + + cur_block = wr_get_ft_by_node(cur_node); + offset = wr_get_ft_block_offset(vg_item, node[i].id); + status = + wr_get_block_from_disk(vg_item, node[i].id, (char *)cur_block, offset, (int32)WR_BLOCK_SIZE, CM_TRUE); + if (status != CM_SUCCESS) { + return status; + } + } + return CM_SUCCESS; +} + +static status_t rb_redo_alloc_ft_node(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(entry != NULL); + wr_redo_alloc_ft_node_t *data = (wr_redo_alloc_ft_node_t *)entry->data; + + if (entry->size == 0) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_REDO_ILL, "invalid entry log size 0.")); + } + + return rb_rollback_ft_block(session, vg_item, data->node, WR_REDO_ALLOC_FT_NODE_NUM); +} + +static void print_redo_alloc_ft_node(wr_redo_entry_t *entry) +{ + wr_redo_alloc_ft_node_t *data = (wr_redo_alloc_ft_node_t *)entry->data; + (void)printf(" alloc_ft_node = {\n"); + (void)printf(" ft_root = {\n"); + printf_gft_root(&data->ft_root); + (void)printf(" }\n"); + for (uint32 i = 0; i < WR_REDO_ALLOC_FT_NODE_NUM; i++) { + if (wr_cmp_auid(data->node[i].id, CM_INVALID_ID64)) { + continue; + } + (void)printf(" gft_node[%u] = {\n", i); + printf_gft_node(&data->node[i], " "); + (void)printf(" }\n"); + } + (void)printf(" }\n"); +} + +static status_t wr_update_ft_info(wr_vg_info_item_t *vg_item, wr_ft_block_t *block, wr_redo_format_ft_t *data) +{ + status_t status = wr_update_ft_block_disk(vg_item, block, data->old_last_block); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR( + "[REDO] Failed to update file table block to disk, %s.", wr_display_metaid(data->old_last_block)); + return status; + } + status = wr_update_ft_root(vg_item); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("[REDO] Failed to update file table root, vg:%s.", vg_item->vg_name)); + return CM_SUCCESS; +} + +static status_t rp_redo_format_ft_node(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL && entry != NULL); + + status_t status; + wr_redo_format_ft_t *data = (wr_redo_format_ft_t *)entry->data; + wr_ft_block_t *block = NULL; + if (vg_item->status == WR_VG_STATUS_RECOVERY) { + status = wr_refresh_root_ft(vg_item, CM_TRUE, CM_FALSE); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("[REDO] Failed to refresh file table root, vg:%s.", vg_item->vg_name)); + // note:first load + block = (wr_ft_block_t *)wr_get_ft_block_by_ftid(session, vg_item, data->old_last_block); + if (block == NULL) { + WR_RETURN_IFERR2(CM_ERROR, LOG_DEBUG_ERR("[REDO]Failed to get last file table block, blockid: %s.", + wr_display_metaid(data->old_last_block))); + } + wr_root_ft_block_t *root_block = WR_GET_ROOT_BLOCK(vg_item->wr_ctrl); + root_block->ft_root.free_list = data->old_free_list; + root_block->ft_root.last = data->old_last_block; + status = wr_format_ft_node(session, vg_item, data->auid); + WR_RETURN_IFERR2( + status, LOG_DEBUG_ERR("[REDO] Failed to format file table node, %s.", wr_display_metaid(data->auid))); + } + // when recover, has load old last block. + if (vg_item->status != WR_VG_STATUS_RECOVERY) { // just find the block, it has already in memory. + block = (wr_ft_block_t *)wr_get_ft_block_by_ftid(session, vg_item, data->old_last_block); + if (block == NULL) { + WR_RETURN_IFERR2(CM_ERROR, LOG_DEBUG_ERR("[REDO]Failed to get last file table block, blockid: %s.", + wr_display_metaid(data->old_last_block))); + } + } + CM_RETURN_IFERR(wr_update_ft_info(vg_item, block, data)); + wr_block_id_t first = data->auid; + ga_obj_id_t obj_id; + status = wr_find_block_objid_in_shm(session, vg_item, first, WR_BLOCK_TYPE_FT, &obj_id); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("[REDO] Failed to find block: %s.", wr_display_metaid(first))); + status = wr_update_au_disk(vg_item, data->auid, GA_8K_POOL, obj_id.obj_id, data->count, WR_BLOCK_SIZE); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("[REDO] Failed to update au to disk, %s.", wr_display_metaid(data->auid))); + WR_LOG_DEBUG_OP("[REDO] Succeed to replay formate ft node: %s , obj_id:%u, count:%u.", + wr_display_metaid(data->auid), data->obj_id, data->count); + LOG_DEBUG_INF("[REDO] old_last_block: %s", wr_display_metaid(data->old_last_block)); + return CM_SUCCESS; +} + +static status_t rb_redo_format_ft_node(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + // format file table node only when new au, if fail, just free the memory, no need to rollback. + return CM_SUCCESS; +} + +static void print_redo_format_ft_node(wr_redo_entry_t *entry) +{ + wr_redo_format_ft_t *data = (wr_redo_format_ft_t *)entry->data; + (void)printf(" format_ft = {\n"); + (void)printf(" auid = {\n"); + printf_auid(&data->auid); + (void)printf(" }\n"); + (void)printf(" obj_id = %u\n", data->obj_id); + (void)printf(" count = %u\n", data->count); + (void)printf(" old_last_block = {\n"); + printf_auid(&data->old_last_block); + (void)printf(" }\n"); + (void)printf(" old_free_list = {\n"); + printf_gft_list(&data->old_free_list); + (void)printf(" }\n"); + (void)printf(" obj_id = %u\n", data->obj_id); + (void)printf(" }\n"); +} + +static status_t rp_redo_free_fs_block(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(entry != NULL); + + status_t status; + wr_redo_free_fs_block_t *data = (wr_redo_free_fs_block_t *)entry->data; + + wr_fs_block_t *block; + wr_fs_block_t *log_block = (wr_fs_block_t *)data->head; + if (vg_item->status == WR_VG_STATUS_RECOVERY) { + ga_obj_id_t obj_id; + block = (wr_fs_block_t *)wr_find_block_in_shm( + session, vg_item, log_block->head.common.id, WR_BLOCK_TYPE_FS, CM_TRUE, &obj_id, CM_FALSE); + if (block == NULL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FNODE_CHECK, "invalid block")); + } + block->head.next = log_block->head.next; + block->head.index = WR_FS_INDEX_INIT; + block->head.common.flags = WR_BLOCK_FLAG_FREE; + wr_set_auid(&block->head.ftid, WR_BLOCK_ID_INIT); + status = wr_update_fs_bitmap_block_disk(vg_item, block, WR_DISK_UNIT_SIZE, CM_FALSE); + WR_RETURN_IF_ERROR(status); + wr_unregister_buffer_cache(session, vg_item, log_block->head.common.id); + ga_free_object(obj_id.pool_id, obj_id.obj_id); + return CM_SUCCESS; + } + + status = wr_update_fs_bitmap_block_disk(vg_item, log_block, WR_DISK_UNIT_SIZE, CM_TRUE); + WR_RETURN_IFERR2(status, + LOG_DEBUG_ERR("[REDO] Failed to update fs bitmap block: %s.", wr_display_metaid(log_block->head.common.id))); + LOG_DEBUG_INF("[REDO] Succeed to replay free fs block: %s, vg name:%s.", + wr_display_metaid(log_block->head.common.id), vg_item->vg_name); + return CM_SUCCESS; +} + +status_t rb_redo_free_fs_block(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(entry != NULL); + + wr_redo_free_fs_block_t *data = (wr_redo_free_fs_block_t *)entry->data; + wr_fs_block_t *log_block = (wr_fs_block_t *)data->head; + + return wr_load_fs_block_by_blockid(session, vg_item, log_block->head.common.id, (int32)WR_FILE_SPACE_BLOCK_SIZE); +} +static void print_redo_free_fs_block(wr_redo_entry_t *entry) +{ + wr_redo_free_fs_block_t *data = (wr_redo_free_fs_block_t *)entry->data; + (void)printf(" free_fs_block = {\n"); + (void)printf(" head = %s\n", data->head); + (void)printf(" }\n"); +} +static status_t rp_redo_alloc_fs_block(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(entry != NULL); + + status_t status; + wr_redo_alloc_fs_block_t *data = (wr_redo_alloc_fs_block_t *)entry->data; + wr_fs_block_root_t *root = WR_GET_FS_BLOCK_ROOT(vg_item->wr_ctrl); + wr_fs_block_t *block = NULL; + + if (vg_item->status == WR_VG_STATUS_RECOVERY) { + status = wr_check_refresh_core(vg_item); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("[REDO] Failed to refresh vg core:%s.", vg_item->vg_name)); + block = (wr_fs_block_t *)wr_find_block_in_shm( + session, vg_item, data->id, WR_BLOCK_TYPE_FS, CM_TRUE, NULL, CM_FALSE); + if (block == NULL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FNODE_CHECK, "invalid block")); + } + + wr_init_fs_block_head(block); + block->head.ftid = data->ftid; + block->head.index = data->index; + block->head.common.flags = WR_BLOCK_FLAG_USED; + *root = data->root; + } + status = wr_update_core_ctrl_disk(vg_item); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("[REDO] Failed to update vg core:%s to disk.", vg_item->vg_name)); + + if (block == NULL) { + block = (wr_fs_block_t *)wr_find_block_in_shm( + session, vg_item, data->id, WR_BLOCK_TYPE_FS, CM_FALSE, NULL, CM_FALSE); + } + + if (block == NULL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FNODE_CHECK, "invalid block")); + } + + status = wr_update_fs_bitmap_block_disk(vg_item, block, WR_FILE_SPACE_BLOCK_SIZE, CM_FALSE); + WR_RETURN_IFERR2( + status, LOG_DEBUG_ERR("[REDO] Failed to update fs bitmap block: %s.", wr_display_metaid(data->id))); + LOG_DEBUG_INF( + "[REDO] Succeed to replay alloc fs block: %s, vg name:%s.", wr_display_metaid(data->id), vg_item->vg_name); + return CM_SUCCESS; +} + +static status_t rb_redo_alloc_fs_block(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(entry != NULL); + + status_t status; + bool32 remote = CM_FALSE; + wr_redo_alloc_fs_block_t *data = (wr_redo_alloc_fs_block_t *)entry->data; + + ga_obj_id_t obj_id; + wr_fs_block_t *block = (wr_fs_block_t *)wr_find_block_in_shm( + session, vg_item, data->id, WR_BLOCK_TYPE_FS, CM_FALSE, &obj_id, CM_FALSE); + CM_ASSERT(block != NULL); + wr_unregister_buffer_cache(session, vg_item, block->head.common.id); + ga_free_object(obj_id.pool_id, obj_id.obj_id); + status = wr_load_vg_ctrl_part( + vg_item, (int64)WR_CTRL_CORE_OFFSET, vg_item->wr_ctrl->core_data, WR_DISK_UNIT_SIZE, &remote); + CM_ASSERT(status == CM_SUCCESS); + return status; +} + +static void print_redo_alloc_fs_block(wr_redo_entry_t *entry) +{ + wr_redo_alloc_fs_block_t *data = (wr_redo_alloc_fs_block_t *)entry->data; + (void)printf(" alloc_fs_block = {\n"); + (void)printf(" id = {\n"); + printf_auid(&data->id); + (void)printf(" }\n"); + (void)printf(" ftid = {\n"); + printf_auid(&data->ftid); + (void)printf(" }\n"); + (void)printf(" root = {\n"); + printf_wr_fs_block_root(&data->root); + (void)printf(" }\n"); + (void)printf(" index = %hu\n", data->index); + (void)printf(" }\n"); +} +status_t rp_redo_init_fs_block(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(entry != NULL); + + status_t status; + wr_redo_init_fs_block_t *data = (wr_redo_init_fs_block_t *)entry->data; + + wr_fs_block_t *block = NULL; + + if (vg_item->status == WR_VG_STATUS_RECOVERY) { + block = (wr_fs_block_t *)wr_find_block_in_shm( + session, vg_item, data->id, WR_BLOCK_TYPE_FS, CM_TRUE, NULL, CM_FALSE); + if (block == NULL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FNODE_CHECK, "invalid block")); + } + block->bitmap[data->index] = data->second_id; + block->head.used_num = data->used_num; + } + + if (block == NULL) { + block = (wr_fs_block_t *)wr_find_block_in_shm( + session, vg_item, data->id, WR_BLOCK_TYPE_FS, CM_FALSE, NULL, CM_FALSE); + if (block == NULL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FNODE_CHECK, "invalid block")); + } + } + + status = wr_update_fs_bitmap_block_disk(vg_item, block, WR_FILE_SPACE_BLOCK_SIZE, CM_FALSE); + WR_RETURN_IFERR2( + status, LOG_DEBUG_ERR("[REDO] Failed to update fs bitmap block: %s to disk.", wr_display_metaid(data->id))); + LOG_DEBUG_INF( + "[REDO] Succeed to replay init fs block: %s, vg name:%s.", wr_display_metaid(data->id), vg_item->vg_name); + return CM_SUCCESS; +} + +status_t rb_redo_init_fs_block(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(entry != NULL); + + wr_redo_init_fs_block_t *data = (wr_redo_init_fs_block_t *)entry->data; + + wr_fs_block_t *block = (wr_fs_block_t *)wr_find_block_in_shm( + session, vg_item, data->id, WR_BLOCK_TYPE_FS, CM_FALSE, NULL, CM_FALSE); + if (block == NULL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FNODE_CHECK, "invalid block")); + } + + wr_set_blockid(&block->bitmap[data->index], CM_INVALID_ID64); + block->head.used_num = 0; + + return CM_SUCCESS; +} +static void print_redo_init_fs_block(wr_redo_entry_t *entry) +{ + wr_redo_init_fs_block_t *data = (wr_redo_init_fs_block_t *)entry->data; + (void)printf(" init_fs_block = {\n"); + (void)printf(" id = {\n"); + printf_auid(&data->id); + (void)printf(" }\n"); + (void)printf(" second_id = {\n"); + printf_auid(&data->second_id); + (void)printf(" }\n"); + (void)printf(" index = %hu\n", data->index); + (void)printf(" used_num = %hu\n", data->used_num); + (void)printf(" }\n"); +} +status_t rp_redo_rename_file(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(entry != NULL); + + if (entry->size == 0) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_REDO_ILL, "invalid entry log size 0.")); + } + + bool32 check_version = CM_FALSE; + if (vg_item->status == WR_VG_STATUS_RECOVERY) { + check_version = CM_TRUE; + } + + wr_redo_rename_t *data = (wr_redo_rename_t *)entry->data; + if (wr_cmp_auid(data->node.id, CM_INVALID_ID64)) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FNODE_CHECK, "invalid node 0xFFFFFFFF")); + } + + gft_node_t *node = wr_get_ft_node_by_ftid(session, vg_item, data->node.id, check_version, CM_FALSE); + if (!node) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FNODE_CHECK, "invalid node")); + } + + if (vg_item->status == WR_VG_STATUS_RECOVERY) { + int32 ret = snprintf_s(node->name, WR_MAX_NAME_LEN, strlen(data->name), "%s", data->name); + WR_SECUREC_SS_RETURN_IF_ERROR(ret, CM_ERROR); + } + + wr_ft_block_t *cur_block = wr_get_ft_by_node(node); + if (cur_block == NULL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FNODE_CHECK, "invalid block")); + } + + status_t status = wr_update_ft_block_disk(vg_item, cur_block, data->node.id); + WR_RETURN_IFERR2( + status, LOG_DEBUG_ERR("[REDO] Failed to update fs block: %s to disk.", wr_display_metaid(data->node.id))); + + LOG_DEBUG_INF( + "Succeed to replay rename file:%s, old_name:%s, name:%s.", data->name, data->old_name, vg_item->vg_name); + return CM_SUCCESS; +} +status_t rb_redo_rename_file(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(entry != NULL); + + wr_redo_rename_t *data = (wr_redo_rename_t *)entry->data; + bool32 check_version = CM_FALSE; + + if (entry->size == 0) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_REDO_ILL, "invalid entry log size 0.")); + } + if (vg_item->status == WR_VG_STATUS_RECOVERY) { + check_version = CM_TRUE; + } + + if (wr_cmp_auid(data->node.id, CM_INVALID_ID64)) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FNODE_CHECK, "invalid node 0xFFFFFFFF")); + } + + gft_node_t *node = wr_get_ft_node_by_ftid(session, vg_item, data->node.id, check_version, CM_FALSE); + if (!node) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FNODE_CHECK, "invalid node")); + } + + int32 ret = snprintf_s(node->name, WR_MAX_NAME_LEN, strlen(data->old_name), "%s", data->old_name); + WR_SECUREC_SS_RETURN_IF_ERROR(ret, CM_ERROR); + return CM_SUCCESS; +} +static void print_redo_rename_file(wr_redo_entry_t *entry) +{ + wr_redo_rename_t *data = (wr_redo_rename_t *)entry->data; + (void)printf(" set_file_size = {\n"); + (void)printf(" node = {\n"); + printf_gft_node(&data->node, " "); + (void)printf(" }\n"); + (void)printf(" name = %s\n", data->name); + (void)printf(" old_name = %s\n", data->old_name); + (void)printf(" }\n"); +} +status_t rp_redo_set_fs_block(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(entry != NULL); + + status_t status; + wr_redo_set_fs_block_t *data = (wr_redo_set_fs_block_t *)entry->data; + + bool32 check_version = CM_FALSE; + if (vg_item->status == WR_VG_STATUS_RECOVERY) { + check_version = CM_TRUE; + } + + wr_fs_block_t *block = (wr_fs_block_t *)wr_find_block_in_shm( + session, vg_item, data->id, WR_BLOCK_TYPE_FS, check_version, NULL, CM_FALSE); + if (block == NULL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FNODE_CHECK, "invalid block")); + } + + if (vg_item->status == WR_VG_STATUS_RECOVERY) { + block->bitmap[data->index] = data->value; + block->head.used_num = data->used_num; + } + + status = wr_update_fs_bitmap_block_disk(vg_item, block, WR_FILE_SPACE_BLOCK_SIZE, CM_FALSE); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to update fs block: %s to disk.", wr_display_metaid(data->id))); + + LOG_DEBUG_INF("[REDO] Succeed to replay set fs block: %s, used_num:%hu, vg name:%s.", wr_display_metaid(data->id), + block->head.used_num, vg_item->vg_name); + return CM_SUCCESS; +} + +status_t rb_redo_set_fs_block(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(entry != NULL); + + wr_redo_set_fs_block_t *data = (wr_redo_set_fs_block_t *)entry->data; + + wr_fs_block_t *block; + bool32 check_version = CM_FALSE; + + block = (wr_fs_block_t *)wr_find_block_in_shm( + session, vg_item, data->id, WR_BLOCK_TYPE_FS, check_version, NULL, CM_FALSE); + if (block == NULL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FNODE_CHECK, "invalid block")); + } + + block->bitmap[data->index] = data->old_value; + block->head.used_num = data->old_used_num; + + return CM_SUCCESS; +} + +static void print_redo_set_fs_block(wr_redo_entry_t *entry) +{ + wr_redo_set_fs_block_t *data = (wr_redo_set_fs_block_t *)entry->data; + (void)printf(" set_fs_block = {\n"); + (void)printf(" id = {\n"); + printf_auid(&data->id); + (void)printf(" }\n"); + (void)printf(" value = {\n"); + printf_auid(&data->value); + (void)printf(" }\n"); + (void)printf(" old_value = {\n"); + printf_auid(&data->old_value); + (void)printf(" }\n"); + (void)printf(" index = %hu\n", data->index); + (void)printf(" used_num = %hu\n", data->used_num); + (void)printf(" old_used_num = %hu\n", data->old_used_num); + (void)printf(" }\n"); +} + +static status_t rp_redo_free_ft_node_core(wr_session_t *session, wr_vg_info_item_t *vg_item, + wr_root_ft_block_t *ft_block, wr_redo_free_ft_node_t *data, bool32 check_version) +{ + return CM_SUCCESS; +} + +status_t rp_redo_free_ft_node(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(entry != NULL); + + wr_redo_free_ft_node_t *data = (wr_redo_free_ft_node_t *)entry->data; + wr_root_ft_block_t *ft_block = WR_GET_ROOT_BLOCK(vg_item->wr_ctrl); + gft_root_t *gft = &ft_block->ft_root; + bool32 check_version = CM_FALSE; + + if (entry->size == 0) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_REDO_ILL, "invalid entry log size 0.")); + } + if (vg_item->status == WR_VG_STATUS_RECOVERY) { + CM_RETURN_IFERR_EX(wr_refresh_root_ft(vg_item, CM_TRUE, CM_FALSE), + LOG_DEBUG_ERR("[REDO] Failed to refresh file table root, vg:%s.", vg_item->vg_name)); + + *gft = data->ft_root; + check_version = CM_TRUE; + } + return rp_redo_free_ft_node_core(session, vg_item, ft_block, data, check_version); +} + +status_t rb_redo_free_ft_node(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(entry != NULL); + + wr_redo_free_ft_node_t *data = (wr_redo_free_ft_node_t *)entry->data; + + if (entry->size == 0) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_REDO_ILL, "invalid entry log size 0.")); + } + + return rb_rollback_ft_block(session, vg_item, data->node, WR_REDO_FREE_FT_NODE_NUM); +} + +static void print_redo_free_ft_node(wr_redo_entry_t *entry) +{ + wr_redo_free_ft_node_t *data = (wr_redo_free_ft_node_t *)entry->data; + (void)printf(" free_ft_node = {\n"); + (void)printf(" ft_root = {\n"); + printf_gft_root(&data->ft_root); + (void)printf(" }\n"); + for (uint32 i = 0; i < WR_REDO_FREE_FT_NODE_NUM; i++) { + if (wr_cmp_auid(data->node[i].id, CM_INVALID_ID64)) { + continue; + } + (void)printf(" gft_node[%u] = {\n", i); + printf_gft_node(&data->node[i], " "); + (void)printf(" }\n"); + } + (void)printf(" }\n"); +} + +status_t rp_redo_recycle_ft_node(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + return CM_SUCCESS; +} + +status_t rb_redo_recycle_ft_node(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + return CM_SUCCESS; +} + +static void print_redo_recycle_ft_node(wr_redo_entry_t *entry) +{ + wr_redo_recycle_ft_node_t *data = (wr_redo_recycle_ft_node_t *)entry->data; + (void)printf(" recycle_ft_node = {\n"); + for (uint32 i = 0; i < WR_REDO_RECYCLE_FT_NODE_NUM; i++) { + if (wr_cmp_auid(data->node[i].id, CM_INVALID_ID64)) { + continue; + } + (void)printf(" gft_node[%u] = {\n", i); + printf_gft_node(&data->node[i], " "); + (void)printf(" }\n"); + } + (void)printf(" }\n"); +} + +status_t rp_redo_set_file_size(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + return CM_SUCCESS; +} + +static status_t rb_redo_get_ft_node( + wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry, ftid_t ftid, gft_node_t **node) +{ + return CM_SUCCESS; +} + +status_t rb_redo_set_file_size(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(entry != NULL); + wr_redo_set_file_size_t *data = (wr_redo_set_file_size_t *)entry->data; + gft_node_t *node; + WR_RETURN_IF_ERROR(rb_redo_get_ft_node(session, vg_item, entry, data->ftid, &node)); + node->size = data->oldsize; + return CM_SUCCESS; +} + +static void print_redo_set_file_size(wr_redo_entry_t *entry) +{ + wr_redo_set_file_size_t *data = (wr_redo_set_file_size_t *)entry->data; + (void)printf(" set_file_size = {\n"); + (void)printf(" ftid = {\n"); + printf_auid(&data->ftid); + (void)printf(" }\n"); + (void)printf(" size = %llu\n", data->size); + (void)printf(" oldsize = %llu\n", data->oldsize); + (void)printf(" }\n"); +} + +status_t rp_redo_format_fs_block(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + return CM_SUCCESS; +} + +void rb_redo_clean_resource( + wr_session_t *session, wr_vg_info_item_t *item, auid_t auid, ga_pool_id_e pool_id, uint32 first, uint32 count) +{ + wr_fs_block_header *block; + uint32 obj_id = first; + uint32 last = first; + CM_ASSERT(count > 0); + for (uint32 i = 0; i < count; i++) { + block = (wr_fs_block_header *)wr_buffer_get_meta_addr(pool_id, obj_id); + CM_ASSERT(block != NULL); + wr_unregister_buffer_cache(session, item, block->common.id); + if (i == count - 1) { + last = obj_id; + } + obj_id = ga_next_object(pool_id, obj_id); + } + ga_queue_t queue; + queue.count = count; + queue.first = first; + queue.last = last; + ga_free_object_list(pool_id, &queue); +} + +status_t rb_redo_format_fs_block(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + return CM_SUCCESS; +} + +static void print_redo_format_fs_block(wr_redo_entry_t *entry) +{ + wr_redo_format_fs_t *data = (wr_redo_format_fs_t *)entry->data; + (void)printf(" format_fs = {\n"); + (void)printf(" auid = {\n"); + printf_auid(&data->auid); + (void)printf(" }\n"); + (void)printf(" obj_id = %u\n", data->obj_id); + (void)printf(" count = %u\n", data->count); + (void)printf(" old_free_list = {\n"); + printf_wr_fs_block_list(&data->old_free_list); + (void)printf(" }\n"); + (void)printf(" }\n"); +} + +static status_t rp_redo_set_node_flag(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + return CM_SUCCESS; +} + +static status_t rb_redo_set_node_flag(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + return CM_SUCCESS; +} + +static void print_redo_set_node_flag(wr_redo_entry_t *entry) +{ + wr_redo_set_file_flag_t *data = (wr_redo_set_file_flag_t *)entry->data; + (void)printf(" set_file_flag = {\n"); + (void)printf(" id = {\n"); + printf_auid(&data->ftid); + (void)printf(" }\n"); + (void)printf(" flags = %u\n", data->flags); + (void)printf(" old_flags = %u\n", data->old_flags); + (void)printf(" }\n"); +} + +status_t rp_redo_set_fs_block_batch(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + return CM_SUCCESS; +} + +status_t rb_redo_set_fs_block_batch(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + return CM_SUCCESS; +} + +status_t rp_redo_set_fs_aux_block_batch_in_recovery(wr_session_t *session, wr_vg_info_item_t *vg_item, + wr_redo_entry_t *entry, wr_fs_block_t *second_block, gft_node_t *node) +{ + return CM_SUCCESS; +} + +status_t rp_redo_set_fs_aux_block_batch_inner(wr_session_t *session, wr_vg_info_item_t *vg_item, + wr_redo_entry_t *entry, wr_fs_block_t *second_block, gft_node_t *node) +{ + return CM_SUCCESS; +} + +status_t rp_redo_set_fs_aux_block_batch(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + return CM_SUCCESS; +} + +status_t rb_redo_set_fs_aux_block_batch(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + return CM_SUCCESS; +} + +status_t rp_redo_truncate_fs_block_batch(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + return CM_SUCCESS; +} + +status_t rb_redo_truncate_fs_block_batch(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry) +{ + return CM_SUCCESS; +} + +static wr_redo_handler_t g_wr_handlers[] = { + {WR_RT_UPDATE_CORE_CTRL, rp_update_core_ctrl, rb_update_core_ctrl, print_redo_update_core_ctrl}, + {WR_RT_ADD_OR_REMOVE_VOLUME, rp_redo_add_or_remove_volume, rb_redo_add_or_remove_volume, + print_redo_add_or_remove_volume}, + {WR_RT_UPDATE_VOLHEAD, rp_redo_update_volhead, rb_redo_update_volhead, print_redo_update_volhead}, + // ft_au initializes multiple ft_blocks and mounts them to gft->free_list + {WR_RT_FORMAT_AU_FILE_TABLE, rp_redo_format_ft_node, rb_redo_format_ft_node, print_redo_format_ft_node}, + // mount a gft_node to a directory + {WR_RT_ALLOC_FILE_TABLE_NODE, rp_redo_alloc_ft_node, rb_redo_alloc_ft_node, print_redo_alloc_ft_node}, + // recycle gft_node to gft->free_list + {WR_RT_FREE_FILE_TABLE_NODE, rp_redo_free_ft_node, rb_redo_free_ft_node, print_redo_free_ft_node}, + // recycle gft_node to wr_ctrl->core.au_root->free_root + {WR_RT_RECYCLE_FILE_TABLE_NODE, rp_redo_recycle_ft_node, rb_redo_recycle_ft_node, print_redo_recycle_ft_node}, + {WR_RT_SET_FILE_SIZE, rp_redo_set_file_size, rb_redo_set_file_size, print_redo_set_file_size}, + {WR_RT_RENAME_FILE, rp_redo_rename_file, rb_redo_rename_file, print_redo_rename_file}, + + // bitmap_au is initialized to multiple fs_blocks and mounted to wr_ctrl->core.fs_block_root + {WR_RT_FORMAT_AU_FILE_SPACE, rp_redo_format_fs_block, rb_redo_format_fs_block, print_redo_format_fs_block}, + // allocate an idle fs_block from the wr_ctrl->core.fs_block_root + {WR_RT_ALLOC_FS_BLOCK, rp_redo_alloc_fs_block, rb_redo_alloc_fs_block, print_redo_alloc_fs_block}, + // recycle fs_block to wr_ctrl->core.fs_block_root->free + {WR_RT_FREE_FS_BLOCK, rp_redo_free_fs_block, rb_redo_free_fs_block, print_redo_free_fs_block}, + // initialize fs_block on gft_node + {WR_RT_INIT_FILE_FS_BLOCK, rp_redo_init_fs_block, rb_redo_init_fs_block, print_redo_init_fs_block}, + // adds or removes a managed object of fs_block + {WR_RT_SET_FILE_FS_BLOCK, rp_redo_set_fs_block, rb_redo_set_fs_block, print_redo_set_fs_block}, + {WR_RT_SET_NODE_FLAG, rp_redo_set_node_flag, rb_redo_set_node_flag, print_redo_set_node_flag}, +}; + +void wr_print_redo_entry(wr_redo_entry_t *entry) +{ + (void)printf(" redo entry type = %u\n", entry->type); + (void)printf(" redo entry size = %u\n", entry->size); + wr_redo_handler_t *handler = &g_wr_handlers[entry->type]; + handler->print(entry); +} + +// apply log to update meta +status_t wr_apply_log(wr_session_t *session, wr_vg_info_item_t *vg_item, char *log_buf) +{ + + return CM_SUCCESS; +} + +status_t wr_update_redo_info(wr_vg_info_item_t *vg_item, char *log_buf) +{ + return CM_SUCCESS; +} + +status_t wr_process_redo_log_inner(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + return CM_SUCCESS; +} + +status_t wr_process_redo_log(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + return CM_SUCCESS; +} + +status_t wr_rollback_log(wr_session_t *session, wr_vg_info_item_t *vg_item, char *log_buf) +{ + return CM_SUCCESS; +} + +void wr_rollback_mem_update(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + return; +} diff --git a/src/common/persist/wr_redo.h b/src/common/persist/wr_redo.h new file mode 100644 index 0000000000000000000000000000000000000000..b1faa0e6f8769231f54624d74fcf189435baec13 --- /dev/null +++ b/src/common/persist/wr_redo.h @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_redo.h + * + * + * IDENTIFICATION + * src/common/persist/wr_redo.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_REDO_H__ +#define __WR_REDO_H__ + +#include "cm_defs.h" +#include "cm_date.h" +#include "wr_diskgroup.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WR_LOG_OFFSET OFFSET_OF(wr_ctrl_t, log_buf) + +#define WR_INSTANCE_LOG_BUFFER_SIZE_V0 SIZE_M(8) +#define WR_LOG_BUF_SLOT_COUNT_V0 16 +#define WR_INSTANCE_LOG_SPLIT_SIZE_V0 ((WR_INSTANCE_LOG_BUFFER_SIZE_V0) / (WR_LOG_BUF_SLOT_COUNT_V0)) +#define WR_INSTANCE_LOG_SPLIT_SIZE \ + ((WR_INSTANCE_LOG_BUFFER_SIZE_V0) / (WR_MAX_VOLUME_GROUP_NUM) / (WR_DISK_UNIT_SIZE) * \ + (WR_DISK_UNIT_SIZE)) // 126KB +#define WR_VG_LOG_SPLIT_SIZE SIZE_K(64) +#define WR_VG_LOG_BUFFER_SIZE SIZE_M(64) + +#pragma pack(8) + +typedef enum en_wr_redo_type { + // wr_ctrl + WR_RT_UPDATE_CORE_CTRL = 0, // start with 0, step 1, type id as index of handler array + // volume + WR_RT_ADD_OR_REMOVE_VOLUME, + WR_RT_UPDATE_VOLHEAD, + // ft_block && gft_node + WR_RT_FORMAT_AU_FILE_TABLE, + WR_RT_ALLOC_FILE_TABLE_NODE, + WR_RT_FREE_FILE_TABLE_NODE, + WR_RT_RECYCLE_FILE_TABLE_NODE, + WR_RT_SET_FILE_SIZE, + WR_RT_RENAME_FILE, + // fs_block + WR_RT_FORMAT_AU_FILE_SPACE, + WR_RT_ALLOC_FS_BLOCK, + WR_RT_FREE_FS_BLOCK, + WR_RT_INIT_FILE_FS_BLOCK, + WR_RT_SET_FILE_FS_BLOCK, + + // gft_node + WR_RT_SET_NODE_FLAG, + + // fs aux + WR_RT_ALLOC_FS_AUX, + WR_RT_FREE_FS_AUX, + WR_RT_INIT_FS_AUX, + WR_RT_SET_FS_BLOCK_BATCH, + WR_RT_SET_FS_AUX_BLOCK_BATCH, + WR_RT_TRUNCATE_FS_BLOCK_BATCH, +} wr_redo_type_t; + +// redo struct allocate file table node +typedef enum st_wr_redo_alloc_ft_node_index { + WR_REDO_ALLOC_FT_NODE_SELF_INDEX = 0, + WR_REDO_ALLOC_FT_NODE_PREV_INDEX = 1, + WR_REDO_ALLOC_FT_NODE_PARENT_INDEX = 2, + WR_REDO_ALLOC_FT_NODE_NUM = 3 +} wr_redo_alloc_ft_node_index_e; +typedef struct st_wr_redo_alloc_ft_node_t { + gft_root_t ft_root; + gft_node_t node[WR_REDO_ALLOC_FT_NODE_NUM]; +} wr_redo_alloc_ft_node_t; + +typedef enum st_wr_redo_free_ft_node_index { + WR_REDO_FREE_FT_NODE_PARENT_INDEX = 0, + WR_REDO_FREE_FT_NODE_PREV_INDEX = 1, + WR_REDO_FREE_FT_NODE_NEXT_INDEX = 2, + WR_REDO_FREE_FT_NODE_SELF_INDEX = 3, + WR_REDO_FREE_FT_NODE_NUM = 4 +} wr_redo_free_ft_node_index_e; +typedef struct st_wr_redo_free_ft_node_t { + gft_root_t ft_root; + gft_node_t node[WR_REDO_FREE_FT_NODE_NUM]; +} wr_redo_free_ft_node_t; + +typedef enum st_wr_redo_recycle_ft_node_index { + WR_REDO_RECYCLE_FT_NODE_SELF_INDEX = 0, + WR_REDO_RECYCLE_FT_NODE_LAST_INDEX = 1, + WR_REDO_RECYCLE_FT_NODE_RECYCLE_INDEX = 2, + WR_REDO_RECYCLE_FT_NODE_NUM = 3 +} wr_redo_recycle_ft_node_index_e; +typedef struct st_wr_redo_recycle_ft_node_t { + gft_node_t node[WR_REDO_RECYCLE_FT_NODE_NUM]; +} wr_redo_recycle_ft_node_t; + +typedef struct st_wr_redo_format_ft_t { + auid_t auid; + uint32 obj_id; + uint32 count; + wr_block_id_t old_last_block; + gft_list_t old_free_list; +} wr_redo_format_ft_t; + +typedef struct st_wr_redo_free_fs_block_t { + char head[WR_DISK_UNIT_SIZE]; +} wr_redo_free_fs_block_t; + +typedef struct st_wr_redo_alloc_fs_block_t { + wr_block_id_t id; + wr_block_id_t ftid; + wr_fs_block_root_t root; + uint16_t index; + uint16_t reserve; +} wr_redo_alloc_fs_block_t; + +typedef struct st_wr_redo_rename_t { + gft_node_t node; + char name[WR_MAX_NAME_LEN]; + char old_name[WR_MAX_NAME_LEN]; +} wr_redo_rename_t; + +typedef struct st_wr_redo_volhead_t { + char head[WR_DISK_UNIT_SIZE]; + char name[WR_MAX_NAME_LEN]; +} wr_redo_volhead_t; + +typedef struct st_wr_redo_volop_t { + char attr[WR_DISK_UNIT_SIZE]; + char def[WR_DISK_UNIT_SIZE]; + bool32 is_add; + uint32 volume_count; + uint64 core_version; + uint64 volume_version; +} wr_redo_volop_t; + +typedef struct st_wr_redo_format_fs_t { + auid_t auid; + uint32 obj_id; + uint32 count; + wr_fs_block_list_t old_free_list; +} wr_redo_format_fs_t; + +typedef struct st_wr_redo_init_fs_block_t { + wr_block_id_t id; + wr_block_id_t second_id; + uint16 index; + uint16 used_num; + uint16 reserve[2]; +} wr_redo_init_fs_block_t; + +typedef struct st_wr_redo_set_fs_block_t { + wr_block_id_t id; + wr_block_id_t value; + wr_block_id_t old_value; + uint16 index; + uint16 used_num; + uint16 old_used_num; + uint16 reserve; +} wr_redo_set_fs_block_t; + +typedef struct st_wr_redo_set_fs_block_batch_t { + wr_block_id_t id; + uint16 used_num; + uint16 old_used_num; + uint16 reserve; + wr_block_id_t id_set[WR_FILE_SPACE_BLOCK_BITMAP_COUNT]; +} wr_redo_set_fs_block_batch_t; + +typedef struct st_wr_redo_set_fs_aux_block_batch_t { + wr_block_id_t fs_block_id; + auid_t first_batch_au; + ftid_t node_id; + uint16 old_used_num; + uint16 batch_count; + wr_fs_block_list_t new_free_list; + wr_block_id_t id_set[WR_FILE_SPACE_BLOCK_BITMAP_COUNT]; +} wr_redo_set_fs_aux_block_batch_t; + +typedef struct st_wr_redo_truncate_fs_block_batch_t { + wr_block_id_t src_id; + wr_block_id_t dst_id; + uint16 src_begin; + uint16 dst_begin; + uint16 src_old_used_num; + uint16 dst_old_used_num; + uint16 count; + uint16 reserve; + wr_block_id_t id_set[WR_FILE_SPACE_BLOCK_BITMAP_COUNT]; +} wr_redo_truncate_fs_block_batch_t; +typedef struct st_wr_redo_set_file_size_t { + ftid_t ftid; + uint64 size; + uint64 oldsize; // old size +} wr_redo_set_file_size_t; + +typedef struct st_wr_redo_set_fs_block_list_t { + wr_block_id_t id; + wr_block_id_t next; + uint16 reserve[4]; +} wr_redo_set_fs_block_list_t; + +typedef struct st_wr_redo_set_file_flag_t { + ftid_t ftid; + uint32 flags; + uint32 old_flags; +} wr_redo_set_file_flag_t; + +typedef struct st_wr_redo_entry { + wr_redo_type_t type; + uint32 size; + char data[0]; +} wr_redo_entry_t; + +#define WR_REDO_ENTRY_HEAD_SIZE OFFSET_OF(wr_redo_entry_t, data) + +// sizeof(wr_redo_batch_t) should be eight-byte aligned +typedef struct st_wr_redo_batch { + uint32 size; + uint32 hash_code; + date_t time; + uint64 lsn; + uint32 count; // entry count; + char reverse[4]; + char data[0]; +} wr_redo_batch_t; +#pragma pack() + +// todo: deleteredo log begin in disk +static inline uint64 wr_get_redo_log_v0_start(wr_ctrl_t *wr_ctrl, uint32 vg_id) +{ + uint64 au_size = wr_get_vg_au_size(wr_ctrl); + uint64 redo_start = CM_CALC_ALIGN(WR_VOLUME_HEAD_SIZE, au_size) + vg_id * WR_INSTANCE_LOG_SPLIT_SIZE; + return redo_start; +} + +static inline uint32 wr_get_log_size(uint64 au_size) +{ + if (au_size < WR_VG_LOG_BUFFER_SIZE && au_size > 0) { + uint64 m = WR_VG_LOG_BUFFER_SIZE / au_size; + uint64 n = WR_VG_LOG_BUFFER_SIZE % au_size; + return (n == 0) ? (uint32)WR_VG_LOG_BUFFER_SIZE : (uint32)((m + 1) * au_size); + } + return (uint32)au_size; +} + +#define WR_REDO_BATCH_HEAD_SIZE OFFSET_OF(wr_redo_batch_t, data) +#define WR_REDO_PRINT_HEAD "wr redo detail:" + +typedef status_t (*wr_replay_proc)(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry); +typedef status_t (*wr_rollback_proc)(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_entry_t *entry); +typedef status_t (*wr_flush_proc)(wr_session_t *session, wr_vg_info_item_t *vg_item, void *data, uint32 size); +typedef void (*wr_print_proc)(wr_redo_entry_t *entry); + +typedef struct st_wr_redo_handler { + wr_redo_type_t type; + wr_replay_proc replay; + wr_rollback_proc rollback; // only rollback memory operation. + wr_print_proc print; +} wr_redo_handler_t; + +#define WR_MAX_BLOCK_ADDR_NUM 10 +typedef struct st_wr_block_addr_his_t { + void *addrs[WR_MAX_BLOCK_ADDR_NUM]; + uint32 count; +} wr_block_addr_his_t; +void rp_init_block_addr_history(wr_block_addr_his_t *addr_his); +void rp_insert_block_addr_history(wr_block_addr_his_t *addr_his, void *block); +bool32 rp_check_block_addr(const wr_block_addr_his_t *addr_his, const void *block); + +status_t wr_write_redolog_to_disk(wr_vg_info_item_t *item, uint32 volume_id, int64 offset, char *buf, uint32 size); +void wr_put_log(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_redo_type_t type, void *data, uint32 size); +status_t wr_flush_log(wr_vg_info_item_t *vg_item, char *log_buf); +status_t wr_apply_log(wr_session_t *session, wr_vg_info_item_t *vg_item, char *log_buf); +status_t wr_process_redo_log(wr_session_t *session, wr_vg_info_item_t *vg_item); +status_t wr_reset_log_slot_head(uint32 vg_id, char *log_buf); +void wr_rollback_mem_update(wr_session_t *session, wr_vg_info_item_t *vg_item); +void rb_redo_clean_resource( + wr_session_t *session, wr_vg_info_item_t *item, auid_t auid, ga_pool_id_e pool_id, uint32 first, uint32 count); +status_t wr_update_redo_info(wr_vg_info_item_t *vg_item, char *log_buf); +void wr_print_redo_entry(wr_redo_entry_t *entry); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/wr_args_parse.c b/src/common/wr_args_parse.c new file mode 100644 index 0000000000000000000000000000000000000000..49eceee2d8adf3ac5e82572f62ad860538877878 --- /dev/null +++ b/src/common/wr_args_parse.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_args_parse.c + * + * + * IDENTIFICATION + * src/common/wr_args_parse.c + * + * ------------------------------------------------------------------------- + */ + +#include "cm_base.h" +#include "cm_config.h" +#include "cm_dlock.h" +#include "cm_list.h" +#include "cm_system.h" +#include "cm_cipher.h" +#include "cm_encrypt.h" +#include "cm_utils.h" +#include "cm_signal.h" +#include "cm_sec_file.h" + +#include "wr_log.h" +#include "wr_defs.h" +#include "wr_errno.h" +#include "wr_param.h" +#include "wr_file.h" +#include "wr_args_parse.h" +#ifdef __cplusplus +extern "C" { +#endif + +status_t cmd_parse_check(wr_args_t *cmd_args_set, int set_size) +{ + for (int i = 0; i < set_size; i++) { + if (cmd_args_set[i].required && !cmd_args_set[i].inputed) { + WR_PRINT_ERROR( + "args [-%c|--%s] needs input value.\n", cmd_args_set[i].short_name, cmd_args_set[i].long_name); + return CM_ERROR; + } + } + return CM_SUCCESS; +} + +static status_t cmd_parse_short_name_args(int argc, char **argv, int *argc_idx, wr_args_t *cmd_args_set, int set_size) +{ + int i = *argc_idx; + int j; + for (j = 0; j < set_size; j++) { + // not hit short name + if (cmd_args_set[j].short_name != argv[i][WR_ARG_IDX_1]) { + continue; + } + + // repeat args + if (cmd_args_set[j].inputed) { + WR_PRINT_ERROR("%s repeat args.\n", argv[i]); + return CM_ERROR; + } + + // input -f and -f needs no args + if (!cmd_args_set[j].required_args) { + // input -fx + if (argv[i][WR_ARG_IDX_2] != 0x0) { + WR_PRINT_ERROR("%s should not with args.\n", argv[i]); + return CM_ERROR; + } + } else { + // input -f, and -f needs args + if (argv[i][WR_ARG_IDX_2] == 0x0 && (i + 1 >= argc)) { + WR_PRINT_ERROR("%s should with args.\n", argv[i]); + return CM_ERROR; + } + + if (argv[i][WR_ARG_IDX_2] != 0x0) { + // input -fx + cmd_args_set[j].input_args = &argv[i][WR_ARG_IDX_2]; + } else { + // input -f x + i++; + cmd_args_set[j].input_args = argv[i]; + } + + // need to check args input + if (cmd_args_set[j].check_args != NULL && + cmd_args_set[j].check_args(cmd_args_set[j].input_args) != CM_SUCCESS) { + return CM_ERROR; + } + if (cmd_args_set[j].convert_args != NULL && + cmd_args_set[j].convert_args(cmd_args_set[j].input_args, &cmd_args_set[j].convert_result, + &cmd_args_set[j].convert_result_size) != CM_SUCCESS) { + return CM_ERROR; + } + } + cmd_args_set[j].inputed = CM_TRUE; + break; + } + + // no args hit + if (j == set_size) { + WR_PRINT_ERROR("input %s hit no args.\n", argv[i]); + return CM_ERROR; + } + *argc_idx = i; + return CM_SUCCESS; +} + +static status_t cmd_parse_long_name_args(int argc, char **argv, int *argc_idx, wr_args_t *cmd_args_set, int set_size) +{ + int i = *argc_idx; + int j; + for (j = 0; j < set_size; j++) { + // hit long name + if (cmd_args_set[j].long_name == NULL || strcmp(cmd_args_set[j].long_name, &argv[i][WR_ARG_IDX_2]) != 0) { + continue; + } + + // repeat args + if (cmd_args_set[j].inputed) { + WR_PRINT_ERROR("%s repeat args.\n", argv[i]); + return CM_ERROR; + } + + // input --format args + if (cmd_args_set[j].required_args) { + // input --format , and no more args + if (i + 1 >= argc) { + WR_PRINT_ERROR("%s should with args.\n", argv[i]); + return CM_ERROR; + } + i++; + cmd_args_set[j].input_args = argv[i]; + + // need to check args input + if (cmd_args_set[j].check_args != NULL && + cmd_args_set[j].check_args(cmd_args_set[j].input_args) != CM_SUCCESS) { + return CM_ERROR; + } + // + if (cmd_args_set[j].convert_args != NULL && + cmd_args_set[j].convert_args(cmd_args_set[j].input_args, &cmd_args_set[j].convert_result, + &cmd_args_set[j].convert_result_size) != CM_SUCCESS) { + return CM_ERROR; + } + } + cmd_args_set[j].inputed = CM_TRUE; + break; + } + + // no args hit + if (j == set_size) { + WR_PRINT_ERROR("input %s hit no args.\n", argv[i]); + return CM_ERROR; + } + *argc_idx = i; + return CM_SUCCESS; +} + +status_t cmd_parse_args(int argc, char **argv, wr_args_set_t *args_set) +{ + if (argc < CMD_ARGS_AT_LEAST || (args_set->args_size == 0 && argc > CMD_ARGS_AT_LEAST)) { + WR_PRINT_ERROR("args num %d error.\n", argc); + return CM_ERROR; + } + // allow the cmd needs no args + if (args_set->args_size == 0) { + return CM_SUCCESS; + } + for (int i = CMD_ARGS_AT_LEAST; i < argc; i++) { + if (argv[i][WR_ARG_IDX_0] != '-') { + WR_PRINT_ERROR("%s should begin with -.\n", argv[i]); + return CM_ERROR; + } + status_t status; + if (argv[i][WR_ARG_IDX_1] != '-') { + status = cmd_parse_short_name_args(argc, argv, &i, args_set->cmd_args, args_set->args_size); + } else { + status = cmd_parse_long_name_args(argc, argv, &i, args_set->cmd_args, args_set->args_size); + } + if (status != CM_SUCCESS) { + return status; + } + } + if (args_set->args_check != NULL) { + return args_set->args_check(args_set->cmd_args, args_set->args_size); + } + return cmd_parse_check(args_set->cmd_args, args_set->args_size); +} + +// just for cmd exist for much cmd at once +void cmd_parse_init(wr_args_t *cmd_args_set, int set_size) +{ + for (int i = 0; i < set_size; i++) { + cmd_args_set[i].inputed = CM_FALSE; + cmd_args_set[i].input_args = NULL; + cmd_args_set[i].convert_result = NULL; + cmd_args_set[i].convert_result_size = 0; + } +} + +void cmd_parse_clean(wr_args_t *cmd_args_set, int set_size) +{ + for (int i = 0; i < set_size; i++) { + cmd_args_set[i].inputed = CM_FALSE; + cmd_args_set[i].input_args = NULL; + if (cmd_args_set[i].clean_convert_args != NULL) { + cmd_args_set[i].clean_convert_args(cmd_args_set[i].convert_result, cmd_args_set[i].convert_result_size); + } + cmd_args_set[i].convert_result = NULL; + cmd_args_set[i].convert_result_size = 0; + } +} + +status_t cmd_check_au_size(const char *au_size_str) +{ + uint32 min_multiple = WR_MIN_AU_SIZE / SIZE_K(1); + uint32 max_multiple = WR_MAX_AU_SIZE / SIZE_K(1); + uint32 au_size; + status_t ret = cm_str2uint32(au_size_str, &au_size); + if (ret != CM_SUCCESS) { + WR_PRINT_ERROR("au_size %s is error!\n", au_size_str); + return CM_ERROR; + } + if (au_size == 0 || au_size < min_multiple || au_size > max_multiple) { + WR_PRINT_ERROR( + "au_size %u is error, au_size cannot be 0, must greater than 2MB, smaller than 64MB!\n", au_size); + return CM_ERROR; + } + return CM_SUCCESS; +} + +status_t cmd_check_wr_home(const char *wr_home) +{ + return wr_check_path(wr_home); +} + +status_t cmd_realpath_home(const char *input_args, char **convert_result, int *convert_size) +{ + uint32 len = (uint32)strlen(input_args); + if (len == 0 || len >= CM_FILE_NAME_BUFFER_SIZE) { + WR_PRINT_ERROR("the len of path is invalid.\n"); + return CM_ERROR; + } + *convert_result = (char *)malloc(CM_FILE_NAME_BUFFER_SIZE); + if (*convert_result == NULL) { + WR_PRINT_ERROR("Malloc failed.\n"); + return CM_ERROR; + } + status_t status = realpath_file(input_args, *convert_result, CM_FILE_NAME_BUFFER_SIZE); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("path is insecure, home: %s.\n", input_args); + free(*convert_result); + *convert_result = NULL; + return status; + } + *convert_size = (int)CM_FILE_NAME_BUFFER_SIZE; + return status; +} + +status_t cmd_check_convert_wr_home(const char *input_args, void **convert_result, int *convert_size) +{ + if (input_args == NULL) { + *convert_result = NULL; + *convert_size = 0; + return CM_SUCCESS; + } + status_t status = cmd_realpath_home(input_args, (char **)convert_result, convert_size); + if (status != CM_SUCCESS) { + WR_PRINT_ERROR("home realpth failed, home: %s.\n", input_args); + return status; + } + return CM_SUCCESS; +} + +void cmd_clean_check_convert(char *convert_result, int convert_size) +{ + if (convert_result != NULL) { + CM_FREE_PTR(convert_result); + } +} +status_t cmd_check_uint64(const char *str) +{ + uint64 num; + status_t status = cm_str2uint64(str, &num); + if (status == CM_ERROR) { + WR_PRINT_ERROR("%s is not a valid uint64\n", str); + return CM_ERROR; + } + return CM_SUCCESS; +} + +status_t set_config_info(char *home, wr_config_t *inst_cfg) +{ + status_t status; + status = wr_set_cfg_dir(home, inst_cfg); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Environment variant WR_HOME not found!\n"); + return status; + } + + status = wr_load_config(inst_cfg); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to load parameters!\n"); + return status; + } + return CM_SUCCESS; +} + +status_t wr_get_vg_item(wr_vg_info_item_t **vg_item, const char *vg_name) +{ + wr_vg_info_item_t *tmp_vg_item = wr_find_vg_item(vg_name); + if (tmp_vg_item == NULL) { + LOG_DEBUG_ERR("vg_name %s is not exist.\n", vg_name); + return CM_ERROR; + } + *vg_item = tmp_vg_item; + return CM_SUCCESS; +} + +config_item_t g_wr_admin_parameters[] = { + // name (30B) isdefault readonly defaultvalue value runtime_value description range datatype + // comment + // ------------- --------- -------- ------------ ----- ------------- ----------- ----- -------- + // ----- + /* log */ + {"LOG_HOME", CM_TRUE, ATTR_READONLY, "", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 0, EFFECT_REBOOT, CFG_INS, + NULL, NULL}, + {"_LOG_BACKUP_FILE_COUNT", CM_TRUE, ATTR_NONE, "20", NULL, NULL, "-", "[0,128]", "GS_TYPE_INTEGER", NULL, 1, + EFFECT_REBOOT, CFG_INS, NULL, NULL}, + {"_LOG_MAX_FILE_SIZE", CM_TRUE, ATTR_NONE, "256M", NULL, NULL, "-", "[1M,4G]", "GS_TYPE_INTEGER", NULL, 2, + EFFECT_REBOOT, CFG_INS, NULL, NULL}, + {"_LOG_FILE_PERMISSIONS", CM_TRUE, ATTR_READONLY, "600", NULL, NULL, "-", "[600-777]", "GS_TYPE_INTEGER", NULL, 3, + EFFECT_REBOOT, CFG_INS, NULL, NULL}, + {"_LOG_PATH_PERMISSIONS", CM_TRUE, ATTR_READONLY, "700", NULL, NULL, "-", "[700-777]", "GS_TYPE_INTEGER", NULL, 4, + EFFECT_REBOOT, CFG_INS, NULL, NULL}, + {"_LOG_LEVEL", CM_TRUE, ATTR_NONE, "519", NULL, NULL, "-", "[0,4087]", "GS_TYPE_INTEGER", NULL, 5, EFFECT_REBOOT, + CFG_INS, NULL, NULL, NULL, NULL}, + {"_AUDIT_BACKUP_FILE_COUNT", CM_TRUE, ATTR_NONE, "20", NULL, NULL, "-", "[0,128]", "GS_TYPE_INTEGER", NULL, 6, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"_AUDIT_MAX_FILE_SIZE", CM_TRUE, ATTR_NONE, "256M", NULL, NULL, "-", "[1M,4G]", "GS_TYPE_INTEGER", NULL, 7, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"_AUDIT_LEVEL", CM_TRUE, ATTR_NONE, "1", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 9, EFFECT_REBOOT, CFG_INS, + NULL, NULL, NULL, NULL}, + {"CLUSTER_RUN_MODE", CM_TRUE, ATTR_NONE, "cluster_primary", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 10, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + { "LOG_COMPRESSED", CM_TRUE, ATTR_READONLY, "FALSE", NULL, NULL, "-", "[FALSE,TRUE]", "GS_TYPE_BOOLEAN", NULL, + 11, EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, +}; + +static status_t wr_load_local_server_config_core( + wr_config_t *inst_cfg, config_item_t *client_parameters, uint32 item_count) +{ + char file_name[CM_MAX_PATH_LEN]; + char *home = wr_get_cfg_dir(inst_cfg); + status_t res; + + if (snprintf_s(file_name, CM_MAX_PATH_LEN, CM_MAX_PATH_LEN - 1, "%s/cfg/%s", home, WR_CFG_NAME) == -1) { + cm_panic(0); + } + cm_init_config(client_parameters, item_count, &inst_cfg->config); + inst_cfg->config.ignore = CM_TRUE; /* ignore unknown parameters */ + if (!cm_file_exist(file_name)) { + return CM_SUCCESS; + } + res = cm_read_config(file_name, &inst_cfg->config); + if (res != CM_SUCCESS) { + LOG_DEBUG_ERR("Read config from %s failed.\n", file_name); + } + return res; +} + +status_t wr_load_local_server_config(wr_config_t *inst_cfg) +{ + return wr_load_local_server_config_core( + inst_cfg, g_wr_admin_parameters, sizeof(g_wr_admin_parameters) / sizeof(config_item_t)); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/common/wr_args_parse.h b/src/common/wr_args_parse.h new file mode 100644 index 0000000000000000000000000000000000000000..d18731cc18f747bd06c6d60b147fd68dc45d3a90 --- /dev/null +++ b/src/common/wr_args_parse.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_args_parse.h + * + * + * IDENTIFICATION + * src/common/wr_args_parse.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef WR_ARGS_PARSE_H_ +#define WR_ARGS_PARSE_H_ + +#include "cm_base.h" +#include "wr_ctrl_def.h" + +typedef status_t (*cmd_parser_check_args_t)(const char *input_args); +typedef status_t (*cmd_parser_convert_args_t)(const char *input_args, void **convert_result, int *convert_size); +typedef void (*cmd_parser_clean_convert_args_t)(char *convert_result, int convert_size); +typedef struct st_wr_args_t { + char short_name; // args short name + const char *long_name; // args long name ,can be null + int32 required; // CM_TRUE required, CM_FALSE optional + int32 required_args; // CM_TRUE required, CM_FALSE not need + cmd_parser_check_args_t check_args; // if want to check input_args, set it, can be NULL + cmd_parser_convert_args_t convert_args; + cmd_parser_clean_convert_args_t clean_convert_args; + int32 inputed; // CM_TRUE input-ed by user, CM_FALSE not input + char *input_args; // if required_args is CM_TRUE, should get value from user + void *convert_result; + int32 convert_result_size; +} wr_args_t; + +typedef status_t (*cmd_parse_check_t)(wr_args_t *cmd_args_set, int set_size); +typedef struct st_wr_args_set_t { + wr_args_t *cmd_args; + int32 args_size; + cmd_parse_check_t args_check; +} wr_args_set_t; + +typedef void (*wr_admin_help)(const char *prog_name, int print_flag); +typedef status_t (*wr_admin_cmd_proc)(void); +typedef struct st_wr_admin_cmd_t { + char cmd[CM_MAX_NAME_LEN]; + wr_admin_help help; + wr_admin_cmd_proc proc; + wr_args_set_t *args_set; + bool8 log_necessary; // Logs are necessary for commands which write disks, and unnecessary for others. +} wr_admin_cmd_t; + +typedef enum en_wr_help_type { + WR_HELP_DETAIL = 0, + WR_HELP_SIMPLE, +} wr_help_type; + +#define WR_ARG_IDX_0 0 +#define WR_ARG_IDX_1 1 +#define WR_ARG_IDX_2 2 +#define WR_ARG_IDX_3 3 +#define WR_ARG_IDX_4 4 +#define WR_ARG_IDX_5 5 +#define WR_ARG_IDX_6 6 +#define WR_ARG_IDX_7 7 +#define WR_ARG_IDX_8 8 +#define WR_ARG_IDX_9 9 +#define WR_ARG_IDX_10 10 +#define CMD_ARGS_AT_LEAST 2 + +status_t cmd_parse_args(int argc, char **argv, wr_args_set_t *args_set); +void cmd_parse_init(wr_args_t *cmd_args_set, int set_size); +void cmd_parse_clean(wr_args_t *cmd_args_set, int set_size); +status_t cmd_check_au_size(const char *au_size_str); +status_t wr_load_local_server_config(wr_config_t *inst_cfg); +status_t cmd_check_uint64(const char *lsn_str); +status_t cmd_check_wr_home(const char *wr_home); +status_t cmd_check_convert_wr_home(const char *input_args, void **convert_result, int *convert_size); +status_t cmd_realpath_home(const char *input_args, char **convert_result, int *convert_size); +void cmd_clean_check_convert(char *convert_result, int convert_size); +status_t set_config_info(char *home, wr_config_t *inst_cfg); +status_t wr_get_vg_item(wr_vg_info_item_t **vg_item, const char *vg_name); +status_t wr_check_meta_type(const char *type); +status_t wr_check_meta_id(const char *intput); +status_t cmd_parse_check(wr_args_t *cmd_args_set, int set_size); +#endif \ No newline at end of file diff --git a/src/common/wr_defs.h b/src/common/wr_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..d797d4aed41c5701f8757ef087532cbf83975ffc --- /dev/null +++ b/src/common/wr_defs.h @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_defs.h + * + * + * IDENTIFICATION + * src/common/wr_defs.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_DEFS_H__ +#define __WR_DEFS_H__ + +#include "cm_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WR_FALSE (uint8)0 +#define WR_TRUE (uint8)1 + +#define WR_FILE_NAME_BUFFER_SIZE (uint32)256 +#define WR_FILE_PATH_MAX_LENGTH (SIZE_K(1) + 1) +#define WR_FKEY_FILENAME "server.key.rand" +#define WR_MAX_AUDIT_PATH_LENGTH (SIZE_K(2) + 512) + +#define WR_VG_ALARM_CHECK_COUNT 10 +#define WR_VG_USAGE_MIN 0 +#define WR_VG_USAGE_MAX 100 + +/* invalid id */ +#define WR_INVALID_INT8 ((int8)(-1)) +#define WR_INVALID_ID8 (uint8)0xFF +#define WR_INVALID_OFFSET16 (uint16)0xFFFF +#define WR_INVALID_ID16 (uint16)0xFFFF +#define WR_INVALID_ID24 (uint32)0xFFFFFF +#define WR_INVALID_ID32 (uint32)0xFFFFFFFF +#define WR_INVALID_OFFSET32 (uint32)0xFFFFFFFF +#define WR_INVALID_ID64 (uint64)0xFFFFFFFFFFFFFFFF +#define WR_INFINITE32 (uint32)0xFFFFFFFF +#define WR_NULL_VALUE_LEN (uint16)0xFFFF +#define WR_INVALID_ASN (uint32)0 +#define WR_INVALID_INT32 (uint32)0x7FFFFFFF +#define WR_INVALID_INT64 (int64)0x7FFFFFFFFFFFFFFF +#define WR_INVALID_FILEID WR_INVALID_ID16 +#define WR_INVALID_CHECKSUM (uint16)0 + +#define WR_ULL_MAX (uint64)0xFFFFFFFFFFFFFFFF + +#ifdef WIN32 +#define WR_INVALID_HANDLE NULL +#else +#define WR_INVALID_HANDLE (-1) +#endif + +#define WR_DEFAULT_AU_SIZE SIZE_M(8) +#define WR_MAX_AU_SIZE SIZE_M(64) +#define WR_MIN_AU_SIZE SIZE_M(2) + +#define WR_MAX_VOLUMES 256 +#define WR_CTRL_SIZE WR_DEFAULT_AU_SIZE +#define WR_LOG_BUFFER_SIZE SIZE_K(512) +#define WR_CORE_CTRL_SIZE SIZE_K(16) +#define WR_VOLUME_CTRL_SIZE SIZE_K(256) +#define WR_VG_DATA_SIZE 512 +#define WR_MIN_BUFFER_BLOCKS 32 +#define WR_MIN_SESSIONID 0 +#define WR_MAX_SESSIONS 16320 +#define WR_SESSION_NUM_PER_GROUP 128 +#define WR_MIN_SESSIONID_CFG 16 // allow config min sessionid in wr_inst.ini +#define WR_MIN_INST_ID 0 +#define WR_MAX_INST_ID WR_MAX_INSTANCES +#define WR_LOCK_VG_TIMEOUT 1000000 // usecs +#define WR_LOCK_VG_TIMEOUT_MS (WR_LOCK_VG_TIMEOUT / 1000) // ms +#define WR_LOKC_ALIGN_SIZE_512 512 +#define WR_MIN_LOCK_INTERVAL 1 +#define WR_MAX_LOCK_INTERVAL 600000 +#define WR_MIN_DLOCK_RETRY_COUNT 1 +#define WR_MAX_DLOCK_RETRY_COUNT 500000 +#define WR_MIN_DELAY_CLEAN_INTERVAL 5 +#define WR_MAX_DELAY_CLEAN_INTERVAL 1000000 +#define WR_MIN_SHM_KEY 1 +#define WR_MAX_SHM_KEY 64 +#define WR_MAX_SHM_KEY_BITS 8 + +#define WR_MAX_NAME_LEN 64 +#define WR_MAX_VOLUME_PATH_LEN 64 +#define WR_MAX_CMD_LEN (512) +#define WR_MAX_FILE_LEN (256) +#define WR_MAX_OPEN_VG (WR_MAX_VOLUME_GROUP_NUM) + +#define WR_BLOCK_SIZE 512 +#define WR_ROOT_FT_DISK_SIZE SIZE_K(8) +#define WR_LOCK_SHARE_DISK_SIZE (SIZE_K(32) + 512) +#define WR_INIT_DISK_LATCH_SIZE (SIZE_K(32)) + +#define WR_NAME_BUFFER_SIZE (uint32)68 +#define WR_NAME_USER_BUFFER_SIZE (WR_NAME_BUFFER_SIZE - 16) // reserve 16 bytes for system +#define WR_VOLUME_CODE_SIZE 64 + +#define WR_DISK_LOCK_LEN 1024 + +#define WR_FILE_SPACE_BLOCK_SIZE SIZE_K(16) // unit:K +#define WR_BLOCK_CTRL_SIZE 512 +#define WR_LOADDISK_BUFFER_SIZE SIZE_M(1) +#define WR_MAX_META_BLOCK_SIZE (SIZE_K(16) + 512) + +#define WR_INVALID_64 WR_INVALID_ID64 + +#define WR_DISK_UNIT_SIZE 512 + +#define WR_MAX_OPEN_FILES 1000000 +#define WR_DEFAULT_OPEN_FILES_NUM 10000 +#define WR_FILE_CONTEXT_PER_GROUP 1000 +#define WR_MAX_FILE_CONTEXT_GROUP_NUM 1000 + +#define WR_STATIC_ASSERT(condition) ((void)sizeof(char[1 - 2 * (int32)(!(condition))])) + +#define WR_MAX_BIT_NUM_VOLUME 10 +#define WR_MAX_BIT_NUM_AU 34 +#define WR_MAX_BIT_NUM_BLOCK 17 +#define WR_MAX_BIT_NUM_ITEM 3 +#define WR_MAX_VOLUME_SIZE ((1 << WR_MAX_BIT_NUM_AU) * WR_DEFAULT_AU_SIZE) + +#define WR_INIT_HASH_MAP_SIZE SIZE_K(16) + +#define WR_CFG_NAME "wr_inst.ini" + +#define WR_MAX_MEM_BLOCK_SIZE SIZE_M(8) + +#define WR_BLOCK_HASH_SIZE SIZE_M(1) + +#define WR_MAX_FILE_SIZE SIZE_T(8) + +#define WR_USOCKET_PERMSSION (S_IRUSR | S_IWUSR) + +#define WR_ID_TO_U64(id) (*(uint64 *)&(id)) + +#define WR_MAX_STACK_BUF_SIZE SIZE_K(512) + +#define WR_CMS_RES_TYPE "wr" + +#define WR_FILE_HASH_SIZE (uint32)5000 + +#define WR_MAX_PATH_BUFFER_SIZE (uint32)(WR_FILE_NAME_BUFFER_SIZE - WR_NAME_BUFFER_SIZE) + +#define WR_PROTO_CODE *(uint32 *)"\xFE\xDC\xBA\x98" +#define WR_UNIX_PATH_MAX (uint32)108 +#define WR_MAX_INSTANCES 64 +#define WR_VERSION_MAX_LEN 256 +#define WR_WAIT_TIMEOUT 5 + +#define WR_ENV_HOME (char *)"WR_HOME" + +/* file */ +#define WR_MAX_CONFIG_FILE_SIZE SIZE_K(64) /* 64K */ +#define WR_MAX_CONFIG_BUFF_SIZE SIZE_M(1) +#define WR_MAX_CONFIG_LINE_SIZE SIZE_K(2) +#define WR_MAX_SQL_FILE_SIZE SIZE_M(2) +#define WR_MIN_SYSTEM_DATAFILE_SIZE SIZE_M(128) +#define WR_MIN_USER_DATAFILE_SIZE SIZE_M(1) +#define WR_DFLT_CTRL_BLOCK_SIZE SIZE_K(16) +#define WR_DFLT_LOG_BLOCK_SIZE (uint32)512 +#define WR_MAX_ARCH_FILES_SIZE SIZE_T(32) + +#define GSDB_UDS_EMERG_CLIENT "gsdb_uds_emerg.client" +#define GSDB_UDS_EMERG_SERVER "gsdb_uds_emerg.server" + +#define CM_MAX_UDS_FILE_PERMISSIONS (uint16)777 +#define CM_DEF_UDS_FILE_PERMISSIONS (uint16)600 + +#define WR_MAX_PACKET_SIZE (uint32)2136 /* sizeof(wr_packet_head_t) + CM_ALIGN4(WR_FILE_PATH_MAX_LENGTH + 1) */ +#define WR_MAX_PACKET_DATA_SIZE (((WR_MAX_PACKET_SIZE) - sizeof(wr_packet_head_t)) - sizeof(uint32)) + +#define WR_PARAM_BUFFER_SIZE (uint32)1024 +#define WR_ALIGN_SIZE (uint32)512 +#define WR_MIN_PORT (uint32)1024 +#define CM_ALIGN_512(size) (((size) + 0x000001FF) & 0xFFFFFE00) +#define WR_DEFAULT_NULL_VALUE (uint32)0xFFFFFFFF +#define WR_UDS_CONNECT_TIMEOUT (int32)(30000) /* 30 seconds */ +#define WR_UDS_SOCKET_TIMEOUT (int32)0x4FFFFFFF +#define WR_SEEK_MAXWR 3 /* Used for seek actual file size for openGauss */ + +#define WR_MIN_IOTHREADS_CFG 1 +#define WR_MAX_IOTHREADS_CFG 8 +#define WR_MIN_WORKTHREADS_CFG 16 +#define WR_MAX_WORKTHREADS_CFG 128 + +#define WR_DIR_PARENT ".." +#define WR_DIR_SELF "." + +#define WR_RETURN_IF_ERROR(ret) \ + do { \ + int _status_ = (ret); \ + if (_status_ != CM_SUCCESS) { \ + return _status_; \ + } \ + } while (0) + +#define WR_RETURN_IFERR2(func, hook) \ + do { \ + int _status_ = (func); \ + if (SECUREC_UNLIKELY(_status_ != CM_SUCCESS)) { \ + hook; \ + return _status_; \ + } \ + } while (0) + +#define WR_RETURN_IFERR3(func, hook1, hook2) \ + do { \ + int _status_ = (func); \ + if (SECUREC_UNLIKELY(_status_ != CM_SUCCESS)) { \ + hook1; \ + hook2; \ + return _status_; \ + } \ + } while (0) + +#define WR_RETURN_IF_FALSE2(ret, hook) \ + do { \ + if (SECUREC_UNLIKELY((ret) != CM_TRUE)) { \ + hook; \ + return CM_ERROR; \ + } \ + } while (0) + +#define WR_RETURN_IFERR4(func, hook1, hook2, hook3) \ + do { \ + int _status_ = (func); \ + if (SECUREC_UNLIKELY(_status_ != CM_SUCCESS)) { \ + hook1; \ + hook2; \ + hook3; \ + return _status_; \ + } \ + } while (0) + +#define WR_RETURN_IF_FALSE3(ret, hook1, hook2) \ + do { \ + if (SECUREC_UNLIKELY((ret) != CM_TRUE)) { \ + hook1; \ + hook2; \ + return CM_ERROR; \ + } \ + } while (0) + +#define WR_RETURN_IF_SUCCESS(ret) \ + do { \ + int _status_ = (ret); \ + if (_status_ == CM_SUCCESS) { \ + return _status_; \ + } \ + } while (0) + +#define WR_RETURN_STATUS_IF_TRUE(cond, status) \ + do { \ + int _status_ = (status); \ + if ((cond) == CM_TRUE) { \ + return _status_; \ + } \ + } while (0) + +#define WR_SECUREC_RETURN_IF_ERROR(err, ret) \ + { \ + if ((err) != EOK) { \ + CM_THROW_ERROR(ERR_SYSTEM_CALL, (err)); \ + return ret; \ + } \ + } + +#define WR_SECUREC_RETURN_IF_ERROR2(err, hook, ret) \ + { \ + if ((err) != EOK) { \ + hook; \ + CM_THROW_ERROR(ERR_SYSTEM_CALL, (err)); \ + return ret; \ + } \ + } + +#define WR_SECUREC_SS_RETURN_IF_ERROR(err, ret) \ + { \ + if ((err) == -1) { \ + CM_THROW_ERROR(ERR_SYSTEM_CALL, (err)); \ + return ret; \ + } \ + } + +#define WR_RETURN_IF_NULL(ret) \ + do { \ + if ((ret) == NULL) { \ + return CM_ERROR; \ + } \ + } while (0) + +#define WR_BREAK_IF_ERROR(ret) \ + if ((ret) != CM_SUCCESS) { \ + break; \ + } + +#define WR_BREAK_IFERR2(func, hook) \ + if (SECUREC_UNLIKELY((func) != CM_SUCCESS)) { \ + hook; \ + break; \ + } + +#define WR_BREAK_IFERR3(func, hook1, hook2) \ + if (SECUREC_UNLIKELY((func) != CM_SUCCESS)) { \ + hook1; \ + hook2; \ + break; \ + } + +#define WR_RETURN_DRIECT_IFERR(ret) \ + do { \ + if ((ret) != CM_SUCCESS) { \ + return; \ + } \ + } while (0) + +#ifdef WIN32 +#define WR_LOG_WITH_OS_MSG(user_fmt_str, ...) \ + do { \ + char os_errmsg_buf[64]; \ + (void)snprintf_s( \ + os_errmsg_buf, sizeof(os_errmsg_buf), sizeof(os_errmsg_buf) - 1, "Unknown error %d", GetLastError()); \ + strerror_s(os_errmsg_buf, sizeof(os_errmsg_buf), GetLastError()); \ + LOG_DEBUG_ERR(user_fmt_str ", OS errno=%d, OS errmsg=%s", __VA_ARGS__, GetLastError(), os_errmsg_buf); \ + } while (0) +#else +#define WR_LOG_WITH_OS_MSG(user_fmt_str, ...) \ + do { \ + char os_errmsg_buf[64]; \ + (void)snprintf_s(os_errmsg_buf, sizeof(os_errmsg_buf), sizeof(os_errmsg_buf) - 1, "Unknown error %d", errno); \ + /* here we use GNU version of strerror_r, make sure _GNU_SOURCE is defined */ \ + LOG_DEBUG_ERR(user_fmt_str ", OS errno=%d, OS errmsg=%s", __VA_ARGS__, errno, \ + strerror_r(errno, os_errmsg_buf, sizeof(os_errmsg_buf))); \ + } while (0) +#endif + +#define WR_ASSERT_LOG(condition, format, ...) \ + do { \ + if (SECUREC_UNLIKELY(!(condition))) { \ + LOG_RUN_ERR(format, ##__VA_ARGS__); \ + LOG_RUN_ERR("Assertion throws an exception at line %u", (uint32)__LINE__); \ + cm_fync_logfile(); \ + CM_ASSERT(0); \ + } \ + } while (0) + +#define WR_BYTE_BITS_SIZE 8 + +// if want change the default, compile the wr with set WR_PAGE_SIZE=page_size_you_want +#ifndef WR_PAGE_SIZE +#define WR_PAGE_SIZE 8192 +#endif + +#if WR_PAGE_SIZE != 4096 && WR_PAGE_SIZE != 8192 && WR_PAGE_SIZE != 16384 && WR_PAGE_SIZE != 32768 +#error "WR_PAGE_SIZE only can be one of [4096, 8192, 16384, 32768]" +#endif + +#define WR_FS_AUX_HEAD_SIZE_MAX WR_DISK_UNIT_SIZE + +#define WR_FS_AUX_BITMAP_SIZE(au_size) (((au_size) / WR_PAGE_SIZE) / WR_BYTE_BITS_SIZE) +#define WR_MAX_FS_AUX_BITMAP_SIZE (WR_FS_AUX_BITMAP_SIZE(WR_MAX_AU_SIZE)) +#define WR_MIN_FS_AUX_BITMAP_SIZE (WR_FS_AUX_BITMAP_SIZE(WR_MIN_AU_SIZE)) +// default is 1.5k +#define WR_FS_AUX_SIZE (WR_MAX_FS_AUX_BITMAP_SIZE + WR_FS_AUX_HEAD_SIZE_MAX) + +#define WR_FREE_POINT(pointer) \ + { \ + if ((pointer) != NULL) { \ + free(pointer); \ + (pointer) = NULL; \ + } \ + } + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/wr_fault_injection.h b/src/common/wr_fault_injection.h new file mode 100644 index 0000000000000000000000000000000000000000..c9e3077f1ba484ba7eff475f8fa5daf80ee3a984 --- /dev/null +++ b/src/common/wr_fault_injection.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_fault_injection.h + * the ways to perform fault injection: + * compile DEBUG, which registers all FI triggers at cfg para SS_FI_ + * + * ------------------------------------------------------------------------- + */ +#ifndef WR_FAULT_INJECTION_H +#define WR_FAULT_INJECTION_H + +#include "ddes_fault_injection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WR_FI_MAX_PROBABILTY (uint32)100 + +typedef enum en_wr_fi_point_name { + WR_FI_ENTRY_BEGIN = 4000, + WR_FI_MES_PROC_ENTER = WR_FI_ENTRY_BEGIN, + WR_FI_ENTRY_END = 6000, +} wr_fi_point_name_e; + +#ifdef __cplusplus +} +#endif + +#endif // WR_FAULT_INJECTION_H \ No newline at end of file diff --git a/src/common/wr_file.c b/src/common/wr_file.c new file mode 100644 index 0000000000000000000000000000000000000000..f5468e318e3eb299a9033bec182e1882c5509aa8 --- /dev/null +++ b/src/common/wr_file.c @@ -0,0 +1,2408 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_file.c + * + * + * IDENTIFICATION + * src/common/wr_file.c + * + * ------------------------------------------------------------------------- + */ + +#include "cm_date.h" +#include "wr_ga.h" +#include "cm_hash.h" +#include "wr_defs.h" +#include "wr_hashmap.h" +#include "wr_shm.h" +#include "wr_alloc_unit.h" +#include "wr_io_fence.h" +#include "wr_malloc.h" +#include "wr_open_file.h" +#include "wr_redo.h" +#include "cm_system.h" +#include "wr_latch.h" +#include "wr_session.h" +#include "wr_fs_aux.h" +#include "wr_zero.h" +#include "wr_syn_meta.h" +#include "wr_thv.h" + +wr_env_t g_wr_env; +wr_env_t *wr_get_env(void) +{ + return &g_wr_env; +} +// CAUTION: wr_admin manager command just like wr_create_vg,cannot call it, +wr_config_t *wr_get_inst_cfg(void) +{ + if (wr_is_server()) { + return g_inst_cfg; + } else { + wr_env_t *wr_env = wr_get_env(); + return &wr_env->inst_cfg; + } +} +// return 1 is letter +// return 0 is not letter +int is_letter(char c) +{ + return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); +} + +// return 1 is number +// return 0 is not number +int is_number(char c) +{ + return (c >= '0' && c <= '9'); +} + +static inline bool32 compare_auid(auid_t a, auid_t b) +{ + return ((a.volume == b.volume) && (a.au == b.au) && (a.block == b.block) && (a.item == b.item)); +} + +static status_t wr_is_valid_name_char(char name) +{ + if (!is_number(name) && !is_letter(name) && name != '_' && name != '.' && name != '-') { + return CM_ERROR; + } + + return CM_SUCCESS; +} + +static status_t wr_is_valid_path_char(char name) +{ + if (name != '/' && wr_is_valid_name_char(name) != CM_SUCCESS) { + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t wr_check_name_is_valid(const char *name, uint32 path_max_size) +{ + if (strlen(name) >= path_max_size) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, name, ", name is too long")); + } + if (cm_str_equal(name, WR_DIR_PARENT) || cm_str_equal(name, WR_DIR_SELF)) { + WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, name, ", cannot be '..' or '.'"); + return CM_ERROR; + } + + for (uint32 i = 0; i < strlen(name); i++) { + status_t status = wr_is_valid_name_char(name[i]); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, name, ", name should be [0~9,a~z,A~Z,-,_,.]")); + } + return CM_SUCCESS; +} + +static status_t wr_check_path_is_valid(const char *path, uint32 path_max_size) +{ + if (strlen(path) >= path_max_size) { + WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, path, ", path is too long\n"); + return CM_ERROR; + } + + for (uint32 i = 0; i < strlen(path); i++) { + if (wr_is_valid_path_char(path[i]) != CM_SUCCESS) { + WR_RETURN_IFERR2( + CM_ERROR, WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, path, ", path should be [0~9,a~z,A~Z,-,_,/,.]")); + } + } + return CM_SUCCESS; +} + +status_t wr_check_name(const char *name) +{ + if (name == NULL || strlen(name) == 0) { + WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, "[null]", ", name cannot be a null string."); + return CM_ERROR; + } + + return wr_check_name_is_valid(name, WR_MAX_NAME_LEN); +} + +status_t wr_check_path(const char *path) +{ + if (path == NULL || strlen(path) == 0) { + WR_RETURN_IFERR2( + CM_ERROR, WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, "[null]", ", path cannot be a null string.")); + } + + return wr_check_path_is_valid(path, WR_FILE_PATH_MAX_LENGTH); +} + +status_t wr_check_volume_path(const char *path) +{ + if (path == NULL || strlen(path) == 0) { + WR_RETURN_IFERR2( + CM_ERROR, WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, "[null]", ", path cannot be a null string.")); + } + + return wr_check_path_is_valid(path, WR_MAX_VOLUME_PATH_LEN); +} + +status_t wr_check_device_path(const char *path) +{ + if (path == NULL || strlen(path) == 0) { + WR_RETURN_IFERR2( + CM_ERROR, WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, "[null]", ", path cannot be a null string.")); + } + + return wr_check_path_is_valid(path + 1, (WR_FILE_PATH_MAX_LENGTH - 1)); +} + +status_t wr_check_path_both(const char *path) +{ + if (path == NULL || strlen(path) == 0) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, "[null]", "path cannot be a null string.")); + } + + if (path[0] == '+') { + return wr_check_path_is_valid(path + 1, WR_FILE_PATH_MAX_LENGTH - 1); + } else { + return wr_check_path_is_valid(path, WR_FILE_PATH_MAX_LENGTH); + } +} + +status_t wr_get_name_from_path(const char *path, uint32_t *beg_pos, char *name) +{ + CM_ASSERT(path != NULL); + CM_ASSERT(beg_pos != NULL); + CM_ASSERT(name != NULL); + uint32_t name_len = 0; + size_t len = strlen(path); + if (len == 0) { + WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, "[null]", "path cannot be a null string."); + return CM_ERROR; + } + if (*beg_pos > len) { + WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, path, "begin pos is larger than string length."); + return CM_ERROR; + } + if (path[*beg_pos] == '/' || (*beg_pos == 0 && path[*beg_pos] == '+')) { + (*beg_pos)++; + if (path[*beg_pos - 1] == '/') { + while (path[*beg_pos] == '/') { + (*beg_pos)++; + } + } + while (path[*beg_pos] != '/' && path[*beg_pos] != 0) { + name[name_len] = path[*beg_pos]; + if (wr_is_valid_name_char(name[name_len]) != CM_SUCCESS) { + WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, path, ", name should be [0~9,a~z,A~Z,-,_,.]"); + return CM_ERROR; + } + (*beg_pos)++; + name_len++; + if (name_len >= WR_MAX_NAME_LEN) { + char *err_msg = "name length should less than 64."; + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, (char *)path + *beg_pos, err_msg)); + } + } + name[name_len] = 0; + } else if (path[*beg_pos] == 0) { + name[0] = 0; + } else { + WR_RETURN_IFERR2( + CM_ERROR, WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, path, ", name should be [0~9,a~z,A~Z,-,_,.]")); + } + return CM_SUCCESS; +} + +status_t wr_find_vg_by_dir(const char *dir_path, char *name, wr_vg_info_item_t **vg_item) +{ + status_t status; + uint32_t beg_pos = 0; + + status = wr_get_name_from_path(dir_path, &beg_pos, name); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to get name from path %s,%d.", dir_path, status); + return status; + } + + if (name[0] == 0) { + WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, dir_path, ", get vg name is NULL."); + return CM_ERROR; + } + + *vg_item = wr_find_vg_item(name); + if (*vg_item == NULL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_VG_NOT_EXIST, name)); + } + + return CM_SUCCESS; +} + +void wr_lock_vg_mem_s_and_shm_x(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + wr_lock_vg_mem_s(vg_item); + wr_enter_shm_x(session, vg_item); +} + +void wr_lock_vg_mem_and_shm_x(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + wr_lock_vg_mem_x(vg_item); + wr_enter_shm_x(session, vg_item); +} + +void wr_lock_vg_mem_and_shm_x2ix(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + wr_lock_shm_meta_x2ix(session, vg_item->vg_latch); + wr_lock_vg_mem_x2ix(vg_item); +} + +void wr_lock_vg_mem_and_shm_ix2x(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + wr_lock_vg_mem_ix2x(vg_item); + wr_lock_shm_meta_ix2x(session, vg_item->vg_latch); +} + +void wr_lock_vg_mem_and_shm_degrade(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + wr_lock_vg_mem_degrade(vg_item); + wr_lock_shm_meta_degrade(session, vg_item->vg_latch); +} + +void wr_lock_vg_mem_and_shm_s(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + wr_lock_vg_mem_s(vg_item); + wr_enter_shm_s(session, vg_item, CM_FALSE, SPIN_WAIT_FOREVER); +} + +void wr_lock_vg_mem_and_shm_s_force(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + wr_lock_vg_mem_s_force(vg_item); + wr_enter_shm_s(session, vg_item, CM_TRUE, SPIN_WAIT_FOREVER); +} + +void wr_unlock_vg_mem_and_shm(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + wr_leave_shm(session, vg_item); + wr_unlock_vg_mem(vg_item); +} + +void wr_lock_vg_mem_and_shm_ex_s(wr_session_t *session, char *vg_name) +{ + wr_vg_info_item_t *vg_item = wr_find_vg_item(vg_name); + if (vg_item != NULL) { + wr_lock_vg_mem_and_shm_s_force(session, vg_item); + } +} + +void wr_unlock_vg_mem_and_shm_ex(wr_session_t *session, char *vg_name) +{ + wr_vg_info_item_t *vg_item = wr_find_vg_item(vg_name); + if (vg_item != NULL) { + wr_unlock_vg_mem_and_shm(session, vg_item); + } +} + +static status_t wr_exist_item_core( + wr_session_t *session, const char *dir_path, bool32 *result, gft_item_type_t *output_type) +{ + return CM_SUCCESS; +} + +status_t wr_check_dir(wr_session_t *session, const char *dir_path, gft_item_type_t type, + wr_check_dir_output_t *output_info, bool32 is_throw_err) +{ + return CM_SUCCESS; +} + +status_t wr_open_dir(wr_session_t *session, const char *dir_path, bool32 is_refresh, wr_find_node_t *find_info) +{ + return CM_SUCCESS; +} + +void wr_close_dir(wr_session_t *session, char *vg_name, uint64 ftid) +{ + return; +} + +int64 wr_get_fs_block_offset(wr_vg_info_item_t *vg_item, wr_block_id_t blockid) +{ + return wr_get_block_offset(vg_item, WR_FILE_SPACE_BLOCK_SIZE, blockid.block, blockid.au); +} + +void wr_init_fs_block_head(wr_fs_block_t *fs_block) +{ + CM_ASSERT(fs_block != NULL); + wr_set_blockid(&fs_block->head.next, CM_INVALID_ID64); + fs_block->head.used_num = 0; + wr_set_blockid(&fs_block->bitmap[0], CM_INVALID_ID64); +} + +status_t wr_alloc_fs_block_inter(wr_session_t *session, wr_vg_info_item_t *vg_item, bool32 check_version, + char **block, wr_alloc_fs_block_info_t *info) +{ + return CM_SUCCESS; +} + +status_t wr_alloc_fs_block( + wr_session_t *session, wr_vg_info_item_t *vg_item, char **block, wr_alloc_fs_block_info_t *info) +{ + return CM_SUCCESS; +} + +status_t wr_exist_item(wr_session_t *session, const char *item, bool32 *result, gft_item_type_t *output_type) +{ + CM_ASSERT(item != NULL); + status_t status; + *result = CM_FALSE; + wr_vg_info_item_t *vg_item = NULL; + char name[WR_MAX_NAME_LEN]; + CM_RETURN_IFERR(wr_find_vg_by_dir(item, name, &vg_item)); + wr_lock_vg_mem_and_shm_s(session, vg_item); + + status = CM_ERROR; + do { + WR_BREAK_IF_ERROR(wr_check_file(vg_item)); + status = wr_exist_item_core(session, item, result, output_type); + if (status != CM_SUCCESS) { + if (status == ERR_WR_FILE_NOT_EXIST) { + LOG_DEBUG_INF("Reset error %d when check dir failed.", status); + cm_reset_error(); + } else { + WR_BREAK_IFERR2(CM_ERROR, LOG_DEBUG_ERR("Failed to check item, errcode:%d.", status)); + } + } + status = CM_SUCCESS; + } while (0); + + wr_unlock_vg_mem_and_shm(session, vg_item); + return status; +} + +static void wr_get_dir_path(char *dir_path, uint32 buf_size, const char *full_path) +{ + char *p = NULL; + size_t path_len = strlen(full_path); + errno_t ret = strncpy_s(dir_path, buf_size, full_path, path_len); + if (ret != EOK) { + WR_THROW_ERROR(ERR_SYSTEM_CALL, (ret)); + return; + } + p = strrchr(dir_path, '/'); + if (p == NULL) { + return; + } + *p = '\0'; +} + +static uint32_t wr_get_last_delimiter(const char *path, char delimiter) +{ + uint32_t len = (uint32_t)strlen(path); + for (uint32_t i = len - 1; i > 0; i--) { + if (path[i] == delimiter) { + return i; + } + } + return len; +} + +static status_t wr_check_node_delete(gft_node_t *node) +{ + if ((node->flags & WR_FT_NODE_FLAG_DEL) == 0) { + return CM_SUCCESS; + } + WR_THROW_ERROR(ERR_WR_FILE_NOT_EXIST, node->name, "wr"); + LOG_DEBUG_ERR("The file node:%s is deleted", node->name); + return CM_ERROR; +} + +gft_node_t *wr_get_gft_node_by_path( + wr_session_t *session, wr_vg_info_item_t *vg_item, const char *path, wr_vg_info_item_t **dir_vg_item) +{ + gft_node_t *parent_node = NULL; + gft_node_t *node = NULL; + status_t status = CM_ERROR; + char name[WR_MAX_NAME_LEN]; + char dir_path[WR_FILE_PATH_MAX_LENGTH]; + do { + WR_BREAK_IF_ERROR(wr_check_file(vg_item)); + wr_get_dir_path(dir_path, WR_FILE_PATH_MAX_LENGTH, path); + *dir_vg_item = vg_item; + wr_check_dir_output_t output_info = {&parent_node, dir_vg_item, NULL, CM_FALSE}; + status = wr_check_dir(session, dir_path, GFT_PATH, &output_info, CM_TRUE); + WR_BREAK_IF_ERROR(status); + uint32_t pos = wr_get_last_delimiter(path, '/'); + status = wr_get_name_from_path(path, &pos, name); + WR_BREAK_IF_ERROR(status); + if (name[0] == 0) { + LOG_DEBUG_INF("get root node ftid"); + return parent_node; + } + node = wr_find_ft_node(session, *dir_vg_item, parent_node, name, CM_TRUE); + if (node == NULL) { + status = CM_ERROR; + WR_BREAK_IFERR3( + status, WR_THROW_ERROR(ERR_WR_FILE_NOT_EXIST, name, path), LOG_DEBUG_ERR("path:%s not exist", path)); + } + WR_BREAK_IF_ERROR(wr_check_node_delete(node)); + LOG_DEBUG_INF("Success to get ft_node:%s by path:%s", wr_display_metaid(node->id), path); + status = CM_SUCCESS; + } while (0); + if (status == CM_SUCCESS) { + return node; + } + return NULL; +} + +status_t wr_get_ftid_by_path(wr_session_t *session, const char *path, ftid_t *ftid, wr_vg_info_item_t **dir_vg_item) +{ + CM_ASSERT(path != NULL); + wr_vg_info_item_t *vg_item = NULL; + char name[WR_MAX_NAME_LEN]; + CM_RETURN_IFERR(wr_find_vg_by_dir(path, name, &vg_item)); + wr_lock_vg_mem_and_shm_s(session, vg_item); + status_t status = CM_ERROR; + gft_node_t *node = wr_get_gft_node_by_path(session, vg_item, path, dir_vg_item); + if (node != NULL) { + *ftid = node->id; + LOG_DEBUG_INF("Success to get ftid:%s by path:%s", wr_display_metaid(*ftid), path); + status = CM_SUCCESS; + } + wr_unlock_vg_mem_and_shm(session, vg_item); + return status; +} + +status_t wr_check_file(wr_vg_info_item_t *vg_item) +{ + status_t status = wr_check_refresh_ft(vg_item); + WR_RETURN_IFERR2( + status, LOG_DEBUG_ERR("Failed to check and update file table %s.", vg_item->wr_ctrl->vg_info.vg_name)); + return CM_SUCCESS; +} + +status_t wr_open_file_check_s( + wr_session_t *session, const char *file, wr_vg_info_item_t **vg_item, gft_item_type_t type, gft_node_t **out_node) +{ + status_t status = wr_check_file(*vg_item); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to check file, errcode:%d.", cm_get_error_code())); + wr_vg_info_item_t *file_vg_item = *vg_item; + wr_check_dir_output_t output_info = {out_node, &file_vg_item, NULL, CM_FALSE}; + status = wr_check_dir(session, file, type, &output_info, CM_TRUE); + WR_RETURN_IFERR2( + status, LOG_DEBUG_ERR("Failed to check dir when open file read, errcode:%d.", cm_get_error_code())); + if (file_vg_item->id != (*vg_item)->id) { + wr_unlock_vg_mem_and_shm(session, *vg_item); + LOG_DEBUG_INF( + "Unlock vg:%s and then lock vg:%s, session id:%u", (*vg_item)->vg_name, file_vg_item->vg_name, session->id); + *vg_item = file_vg_item; + wr_lock_vg_mem_and_shm_s(session, *vg_item); + } + return CM_SUCCESS; +} + +static status_t wr_open_file_find_block_and_insert_index( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *out_node) +{ + status_t status; + if (wr_cmp_blockid(out_node->entry, CM_INVALID_ID64)) { + LOG_RUN_ERR("Failed to open fs block,errcode:%d.", cm_get_error_code()); + WR_THROW_ERROR(ERR_WR_INVALID_ID, "node entry", WR_ID_TO_U64(out_node->entry)); + return ERR_WR_INVALID_ID; + } + // check the entry and load + char *entry_block = + wr_find_block_in_shm(session, vg_item, out_node->entry, WR_BLOCK_TYPE_FS, CM_TRUE, NULL, CM_FALSE); + if (entry_block == NULL) { + WR_RETURN_IFERR2( + CM_ERROR, LOG_DEBUG_ERR("Failed to find block:%s in cache", wr_display_metaid(out_node->entry))); + } + + status = wr_insert_open_file_index( + session, vg_item, WR_ID_TO_U64(out_node->id), session->cli_info.cli_pid, session->cli_info.start_time); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to insert open file index.")); + return CM_SUCCESS; +} + +static status_t wr_open_file_core( + wr_session_t *session, const char *path, uint32 type, gft_node_t **out_node, wr_find_node_t *find_info) +{ + CM_ASSERT(path != NULL); + wr_vg_info_item_t *vg_item = NULL; + errno_t errno; + char name[WR_MAX_NAME_LEN]; + CM_RETURN_IFERR(wr_find_vg_by_dir(path, name, &vg_item)); + wr_lock_vg_mem_and_shm_s(session, vg_item); + + status_t status = wr_open_file_check_s(session, path, &vg_item, type, out_node); + WR_RETURN_IFERR2(status, wr_unlock_vg_mem_and_shm(session, vg_item)); + if (*out_node == NULL) { + wr_unlock_vg_mem_and_shm(session, vg_item); + cm_panic(0); + } + + if (((*out_node)->flags & WR_FT_NODE_FLAG_DEL) && ((*out_node)->type == GFT_FILE)) { + WR_RETURN_IFERR3(CM_ERROR, WR_THROW_ERROR(ERR_WR_FILE_NOT_EXIST, path, "wr"), + wr_unlock_vg_mem_and_shm(session, vg_item)); + } + + status = wr_open_file_find_block_and_insert_index(session, vg_item, *out_node); + WR_RETURN_IFERR3(status, wr_rollback_mem_update(session, vg_item), wr_unlock_vg_mem_and_shm(session, vg_item)); + + find_info->ftid = (*out_node)->id; + errno = strncpy_sp(find_info->vg_name, WR_MAX_NAME_LEN, vg_item->vg_name, WR_MAX_NAME_LEN - 1); + bool32 result = (bool32)(errno == EOK); + WR_RETURN_IF_FALSE3( + result, wr_rollback_mem_update(session, vg_item), wr_unlock_vg_mem_and_shm(session, vg_item)); + status = wr_process_redo_log(session, vg_item); + + if (status != CM_SUCCESS) { + wr_unlock_vg_mem_and_shm(session, vg_item); + LOG_RUN_ERR("[WR] ABORT INFO : redo log process failed, errcode:%d, OS errno:%d, OS errmsg:%s.", + cm_get_error_code(), errno, strerror(errno)); + cm_fync_logfile(); + wr_exit(1); + } + wr_unlock_vg_mem_and_shm(session, vg_item); + return CM_SUCCESS; +} + +status_t wr_open_file(wr_session_t *session, const char *file, int32_t flag, wr_find_node_t *find_info) +{ + WR_LOG_DEBUG_OP("Begin to open file:%s, session id:%u.", file, session->id); + gft_node_t *out_node = NULL; + CM_RETURN_IFERR(wr_open_file_core(session, file, GFT_FILE, &out_node, find_info)); + uint64 fid = out_node->fid; + WR_LOG_DEBUG_OP("Succeed to open file:%s, fid:%llu, ftid:%s, session:%u.", file, fid, + wr_display_metaid(out_node->id), session->id); + return CM_SUCCESS; +} + +status_t wr_close_file(wr_session_t *session, wr_vg_info_item_t *vg_item, uint64 ftid) +{ + status_t status = + wr_delete_open_file_index(session, vg_item, ftid, session->cli_info.cli_pid, session->cli_info.start_time); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to delete open file index, ftid:%llu.", ftid)); + return CM_SUCCESS; +} + +status_t wr_check_rm_file( + wr_session_t *session, wr_vg_info_item_t *vg_item, ftid_t ftid, bool32 *should_rm_file, gft_node_t **file_node) +{ + return CM_SUCCESS; +} + +static void wr_init_ft_node( + wr_ft_block_t *ft_block, gft_node_t *first_node, gft_root_t *gft, uint32_t block_id, auid_t auid) +{ + gft_node_t *node; + for (uint32 i = 0; i < ft_block->node_num; i++) { + node = &first_node[i]; + if (i != 0) { + node->prev = auid; + node->prev.block = block_id; + node->prev.item = (uint16)i - 1; + } + node->id = auid; + node->id.block = block_id; + node->id.item = i; + wr_set_auid(&node->parent, WR_BLOCK_ID_INIT); + + if (i == ft_block->node_num - 1) { + gft->free_list.last = auid; + gft->free_list.last.block = block_id; + gft->free_list.last.item = i; + wr_set_auid(&node->next, WR_INVALID_64); + } else { + node->next = auid; + node->next.block = block_id; + node->next.item = (uint16)i + 1; + } + } +} + +status_t wr_init_ft_block( + wr_session_t *session, wr_vg_info_item_t *vg_item, char *block, uint32_t block_id, auid_t auid) +{ + char *root = vg_item->wr_ctrl->root; + gft_root_t *gft = &((wr_root_ft_block_t *)(root))->ft_root; + + wr_ft_block_t *ft_block = (wr_ft_block_t *)block; + ft_block->node_num = (WR_BLOCK_SIZE - sizeof(wr_ft_block_t)) / sizeof(gft_node_t); + ft_block->common.id = auid; + ft_block->common.id.block = block_id; + ft_block->common.type = WR_BLOCK_TYPE_FT; + ft_block->common.flags = WR_BLOCK_FLAG_FREE; + + gft_node_t *first_node = (gft_node_t *)(block + sizeof(wr_ft_block_t)); + gft_node_t *node; + gft_node_t *last_node = NULL; + if (ft_block->node_num > 0) { + node = &first_node[0]; + node->prev = gft->free_list.last; + bool32 cmp = wr_cmp_auid(gft->free_list.last, WR_INVALID_64); + if (!cmp) { + last_node = wr_get_ft_node_by_ftid(session, vg_item, gft->free_list.last, CM_FALSE, CM_FALSE); + if (last_node == NULL) { + LOG_DEBUG_ERR( + "[FT][FORMAT] Failed to get file table node:%s.", wr_display_metaid(gft->free_list.last)); + return CM_ERROR; + } + + last_node->next = auid; + last_node->next.block = block_id; + last_node->next.item = 0; + } + } + wr_init_ft_node(ft_block, first_node, gft, block_id, auid); + gft->free_list.count = gft->free_list.count + ft_block->node_num; + if (wr_cmp_auid(gft->free_list.first, WR_INVALID_64)) { + gft->free_list.first = auid; + gft->free_list.first.block = block_id; + gft->free_list.first.item = 0; + } + WR_LOG_DEBUG_OP("[FT][FORMAT] wr_init_ft_block blockid:%s.", wr_display_metaid(ft_block->common.id)); + return CM_SUCCESS; +} + +void wr_init_bitmap_block(wr_ctrl_t *wr_ctrl, char *block, uint32_t block_id, auid_t auid) +{ + wr_fs_block_root_t *block_root = WR_GET_FS_BLOCK_ROOT(wr_ctrl); + wr_fs_block_header *fs_block = (wr_fs_block_header *)block; + if (memset_s(fs_block, WR_FILE_SPACE_BLOCK_SIZE, -1, WR_FILE_SPACE_BLOCK_SIZE) != EOK) { + cm_panic(0); + } + fs_block->common.type = WR_BLOCK_TYPE_FS; + fs_block->common.flags = WR_BLOCK_FLAG_FREE; + fs_block->common.version = 0; + fs_block->used_num = 0; + fs_block->total_num = WR_FILE_SPACE_BLOCK_BITMAP_COUNT; + fs_block->index = WR_FS_INDEX_INIT; + fs_block->common.id.au = auid.au; + fs_block->common.id.volume = auid.volume; + fs_block->common.id.block = block_id; + fs_block->common.id.item = 0; + wr_set_auid(&fs_block->ftid, WR_BLOCK_ID_INIT); + + block_root->free.count++; + wr_block_id_t first = block_root->free.first; + block_root->free.first = fs_block->common.id; + fs_block->next = first; + + bool32 cmp = wr_cmp_auid(block_root->free.last, WR_INVALID_64); + if (cmp) { + block_root->free.last = fs_block->common.id; + } + LOG_DEBUG_INF("[FS][FORMAT] Init bitmap block, free count:%llu, first:%s.", block_root->free.count, + wr_display_metaid(first)); + LOG_DEBUG_INF("[FS][FORMAT] Fs block id:%s", wr_display_metaid(fs_block->common.id)); +} + +status_t wr_update_au_disk( + wr_vg_info_item_t *vg_item, auid_t auid, ga_pool_id_e pool_id, uint32 first, uint32 count, uint32 size) +{ + CM_ASSERT(vg_item != NULL); + status_t status; + char *buf; + CM_ASSERT(vg_item->volume_handle[auid.volume].handle != WR_INVALID_HANDLE); + int64_t offset = wr_get_au_offset(vg_item, auid); + int64_t block_offset = offset; + uint32 obj_id = first; + for (uint32 i = 0; i < count; i++) { + buf = wr_buffer_get_meta_addr(pool_id, obj_id); + WR_ASSERT_LOG(buf != NULL, "buf is NULL when update au disk, auid:%s", wr_display_metaid(auid)); + wr_common_block_t *block = (wr_common_block_t *)buf; + block->version++; + block->checksum = wr_get_checksum(buf, size); + LOG_DEBUG_INF( + "wr_update_au_disk checksum:%u, %s, count:%u.", block->checksum, wr_display_metaid(block->id), i); + + block_offset = offset + i * size; + status = wr_write_volume_inst(vg_item, &vg_item->volume_handle[auid.volume], block_offset, buf, size); + if (status != CM_SUCCESS) { + return status; + } + obj_id = ga_next_object(pool_id, obj_id); + } + return CM_SUCCESS; +} + +status_t wr_format_ft_node_core( + wr_session_t *session, wr_vg_info_item_t *vg_item, ga_queue_t queue, auid_t auid, gft_root_t *gft) +{ + status_t status = CM_SUCCESS; + uint32 rollback_count = 0; + uint32 block_num = (uint32)WR_GET_FT_BLOCK_NUM_IN_AU(vg_item->wr_ctrl); + uint32 obj_id = queue.first; + ga_obj_id_t ga_obj_id = {.pool_id = GA_8K_POOL, .obj_id = 0}; + gft_list_t bk_list = gft->free_list; + wr_ft_block_t *block = (wr_ft_block_t *)wr_get_ft_block_by_ftid(session, vg_item, gft->last); + CM_ASSERT(block != NULL); + block->next = auid; + for (uint32 i = 0; i < block_num; i++) { + block = (wr_ft_block_t *)wr_buffer_get_meta_addr(GA_8K_POOL, obj_id); + errno_t err = memset_sp((char *)block, WR_BLOCK_SIZE, 0, WR_BLOCK_SIZE); + cm_panic(err == EOK); + block->common.id = auid; + block->common.id.block = i; + if (i != block_num - 1) { + block->next = auid; + block->next.block = i + 1; + } else { + wr_set_blockid(&block->next, CM_INVALID_ID64); + } + gft->last = block->common.id; + + ga_obj_id.obj_id = obj_id; + do { + status = wr_register_buffer_cache( + session, vg_item, block->common.id, ga_obj_id, (char *)block, WR_BLOCK_TYPE_FT); + if (status != CM_SUCCESS) { + rollback_count = i; + WR_BREAK_IFERR2(status, + LOG_DEBUG_ERR("[FT][FORMAT] Failed to register block:%s.", wr_display_metaid(block->common.id))); + } + + status = wr_init_ft_block(session, vg_item, (char *)block, i, auid); + if (status != CM_SUCCESS) { + rollback_count = i + 1; + WR_BREAK_IFERR2(status, + LOG_DEBUG_ERR("[FT][FORMAT] Failed to initialize block:%s.", wr_display_metaid(block->common.id))); + } + } while (0); + if (status != CM_SUCCESS) { + for (uint32 j = 0; j < rollback_count; ++j) { + wr_block_id_t block_id = auid; + block_id.block = j; + wr_unregister_buffer_cache(session, vg_item, block_id); + } + ga_free_object_list(GA_8K_POOL, &queue); + gft->free_list = bk_list; // rollback free_list + LOG_DEBUG_ERR("[FT][FORMAT] Rollback the format ft node when fail, i:%u.", i); + return status; + } + + obj_id = ga_next_object(GA_8K_POOL, obj_id); + } + return CM_SUCCESS; +} + +status_t wr_format_ft_node(wr_session_t *session, wr_vg_info_item_t *vg_item, auid_t auid) +{ + CM_ASSERT(vg_item != NULL); + wr_ctrl_t *wr_ctrl = vg_item->wr_ctrl; + char *root = wr_ctrl->root; + wr_root_ft_block_t *ft_block = (wr_root_ft_block_t *)(root); + gft_root_t *gft = &ft_block->ft_root; + status_t status = CM_SUCCESS; + + gft_list_t bk_list = gft->free_list; + uint32 block_num = (uint32)WR_GET_FT_BLOCK_NUM_IN_AU(wr_ctrl); + ga_queue_t queue; + status = ga_alloc_object_list(GA_8K_POOL, block_num, &queue); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("[FT][FORMAT] Failed to alloc object list, block_num:%u.", block_num)); + + wr_block_id_t old_last = gft->last; + status = wr_format_ft_node_core(session, vg_item, queue, auid, gft); + if (status != CM_SUCCESS) { + return status; + } + + wr_redo_format_ft_t redo; + redo.auid = auid; + redo.obj_id = queue.first; + redo.count = block_num; + redo.old_last_block = old_last; + redo.old_free_list = bk_list; + wr_put_log(session, vg_item, WR_RT_FORMAT_AU_FILE_TABLE, &redo, sizeof(wr_redo_format_ft_t)); + return CM_SUCCESS; +} + +status_t wr_format_bitmap_node(wr_session_t *session, wr_vg_info_item_t *vg_item, auid_t auid) +{ + wr_ctrl_t *wr_ctrl = vg_item->wr_ctrl; + status_t status; + + wr_fs_block_root_t *block_root = WR_GET_FS_BLOCK_ROOT(wr_ctrl); + wr_fs_block_list_t bk_list = block_root->free; + wr_fs_block_header *block; + uint32 block_num = (uint32)WR_GET_FS_BLOCK_NUM_IN_AU(wr_ctrl); + ga_queue_t queue; + status = ga_alloc_object_list(GA_16K_POOL, block_num, &queue); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("[FS][FORMAT] Failed to alloc object list, block num is %u.", block_num)); + uint32 obj_id = queue.first; + ga_obj_id_t ga_obj_id; + ga_obj_id.pool_id = GA_16K_POOL; + for (uint32 i = 0; i < block_num; i++) { + block = (wr_fs_block_header *)wr_buffer_get_meta_addr(GA_16K_POOL, obj_id); + CM_ASSERT(block != NULL); + block->common.id = auid; + block->common.id.block = i; + block->common.id.item = 0; + ga_obj_id.obj_id = obj_id; + + status = + wr_register_buffer_cache(session, vg_item, block->common.id, ga_obj_id, (char *)block, WR_BLOCK_TYPE_FS); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("[FS][FORMAT] Failed to register block:%s, obj is %u.", + wr_display_metaid(block->common.id), obj_id)); + + wr_init_bitmap_block(wr_ctrl, (char *)block, i, auid); + obj_id = ga_next_object(GA_16K_POOL, obj_id); + } + + wr_redo_format_fs_t redo; + redo.auid = auid; + redo.count = block_num; + redo.old_free_list = bk_list; + wr_put_log(session, vg_item, WR_RT_FORMAT_AU_FILE_SPACE, &redo, sizeof(wr_redo_format_fs_t)); + + return CM_SUCCESS; +} + +static void format_ft_block_when_create_vg( + wr_vg_info_item_t *vg_item, gft_list_t *plist, wr_ft_block_t *block, uint32 index, auid_t auid) +{ + uint32 blk_count = (uint32)WR_GET_FT_BLOCK_NUM_IN_AU(vg_item->wr_ctrl); + uint32 item_count = (WR_BLOCK_SIZE - sizeof(wr_ft_block_t)) / sizeof(gft_node_t); + gft_node_t *node = NULL; + + block->common.type = WR_BLOCK_TYPE_FT; + block->common.flags = WR_BLOCK_FLAG_FREE; + block->node_num = item_count; + + for (uint32 j = 0; j < item_count; j++) { + node = (gft_node_t *)((char *)block + sizeof(wr_ft_block_t) + sizeof(gft_node_t) * j); + node->id = auid; + node->id.block = index; + node->id.item = j; + wr_set_auid(&node->parent, WR_BLOCK_ID_INIT); + + // set the prev ftid_t + if (j == 0) { + if (index == 0) { + *(uint64 *)(&node->prev) = WR_INVALID_64; + } else { + // the prev ft block + node->prev = auid; + node->prev.block = index - 1; + node->prev.item = item_count - 1; + } + } else { + // the same ft block + node->prev = auid; + node->prev.block = index; + node->prev.item = j - 1; + } + + // set the next ftid_t + if (j == item_count - 1) { + if (index == blk_count - 1) { + *(uint64 *)(&node->next) = WR_INVALID_64; + } else { + // the next ft block + node->next = auid; + node->next.block = index + 1; + node->next.item = 0; + } + } else { + // the same ft block + node->next = auid; + node->next.block = index; + node->next.item = j + 1; + } + + // add to gft node free list + if (*(uint64 *)(&plist->first) == WR_INVALID_64) { + plist->first = node->id; + } + plist->last = node->id; + plist->count++; + } +} + +/* + * NOTE: this function is used only in creating vg. + * you can't use block memory cache and must flush block to disk manually. + */ +static status_t format_ft_au_when_create_vg(wr_vg_info_item_t *vg_item, auid_t auid) +{ + LOG_DEBUG_INF("[FT][FORMAT] Begin to format ft au when create vg."); + status_t status; + wr_ctrl_t *wr_ctrl = vg_item->wr_ctrl; + uint64 au_size = wr_get_vg_au_size(wr_ctrl); + char *au_buf = (char *)cm_malloc_align(WR_DISK_UNIT_SIZE, (uint32)au_size); + if (au_buf == NULL) { + WR_RETURN_IFERR2(CM_ERROR, LOG_DEBUG_ERR("[FT][FORMAT] Failed to alloc %d memory", (int32)au_size)); + } + int64 offset; + wr_ft_block_t *block = NULL; + errno_t err = memset_sp(au_buf, au_size, 0, au_size); + if (err != EOK) { + free(au_buf); + LOG_DEBUG_ERR("[FT][FORMAT] Failed to memset:%d", err); + return CM_ERROR; + } + + uint32 blk_count = (uint32)WR_GET_FT_BLOCK_NUM_IN_AU(wr_ctrl); + + gft_list_t new_list; + new_list.count = 0; + *(uint64 *)&new_list.first = WR_INVALID_64; + *(uint64 *)&new_list.last = WR_INVALID_64; + + for (uint32 i = 0; i < blk_count; i++) { + block = (wr_ft_block_t *)(au_buf + (i * WR_BLOCK_SIZE)); + block->common.id = auid; + block->common.id.block = i; + + // set ft block next + if (i == blk_count - 1) { + *(uint64 *)(&block->next) = WR_INVALID_64; + } else { + block->next = auid; + block->next.block = i + 1; + } + format_ft_block_when_create_vg(vg_item, &new_list, block, i, auid); + block->common.version++; + block->common.checksum = wr_get_checksum(block, WR_BLOCK_SIZE); + } + + wr_root_ft_block_t *root_ft = WR_GET_ROOT_BLOCK(wr_ctrl); + gft_root_t *root_gft = &root_ft->ft_root; + root_ft->ft_block.next = ((wr_ft_block_t *)au_buf)->common.id; // first block + root_gft->last = ((wr_ft_block_t *)(au_buf + au_size - WR_BLOCK_SIZE))->common.id; // last block + + // link the gft_node and free_list + root_gft->free_list = new_list; + // flush ft block to disk manually + block = (wr_ft_block_t *)(au_buf); + offset = wr_get_ft_block_offset(vg_item, block->common.id); + status = wr_check_write_volume(vg_item, block->common.id.volume, offset, au_buf, (uint32)au_size); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("[FT][FORMAT] Failed to check write volume."); + free(au_buf); + return status; + } + status = wr_update_ft_root(vg_item); + free(au_buf); + return status; +} + +status_t wr_alloc_ft_au(wr_session_t *session, wr_vg_info_item_t *vg_item, ftid_t *id) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(id != NULL); + status_t status; + + status = wr_alloc_au(session, vg_item, id); + WR_RETURN_IFERR2( + status, LOG_DEBUG_ERR("[FT][ALLOC] Failed allocate au for file table from vg:%s.", vg_item->vg_name)); + + wr_au_root_t *au_root = WR_GET_AU_ROOT(vg_item->wr_ctrl); + if (au_root->free_root == WR_INVALID_64) { + /* when we are creating vg, .recycle directory hasn't been initialized yet! */ + status = format_ft_au_when_create_vg(vg_item, *(auid_t *)id); + } else { + CM_ASSERT(session != NULL); + status = wr_format_ft_node(session, vg_item, *id); + } + + WR_RETURN_IFERR2(status, + LOG_DEBUG_ERR("[FT][ALLOC] Failed format ft au:%s from vg:%s.", wr_display_metaid(*id), vg_item->vg_name)); + LOG_DEBUG_INF("[FT][ALLOC] Succeed to allocate ft au:%s from vg:%s.", wr_display_metaid(*id), vg_item->vg_name); + return status; +} + +static void wr_init_alloc_ft_node(gft_root_t *gft, gft_node_t *node, uint32 flags, gft_node_t *parent_node) +{ + node->create_time = cm_current_time(); + node->update_time = node->create_time; + (void)cm_atomic_set(&node->size, 0); + node->written_size = 0; + node->min_inited_size = 0; + node->prev = parent_node->items.last; + node->fid = gft->fid++; + node->flags = flags; +#ifdef WR_DEFAULT_FILE_FLAG_INNER_INITED + if (node->type == GFT_FILE) { + node->flags |= WR_FT_NODE_FLAG_INNER_INITED; + } +#endif + node->parent = parent_node->id; + wr_set_auid(&node->next, CM_INVALID_ID64); + + wr_block_ctrl_t *block_ctrl = wr_get_block_ctrl_by_node(node); + if (node->type == GFT_FILE && block_ctrl != NULL) { + wr_init_wr_fs_block_cache_info(&block_ctrl->fs_block_cache_info); + } +} + +void wr_set_ft_node(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *parent_node, gft_node_t *node, + gft_root_t *gft, gft_node_t *prev_node) +{ + wr_redo_alloc_ft_node_t redo_node; + redo_node.node[WR_REDO_ALLOC_FT_NODE_SELF_INDEX] = *node; + if (prev_node != NULL) { + redo_node.node[WR_REDO_ALLOC_FT_NODE_PREV_INDEX] = *prev_node; + } else { + wr_set_auid(&redo_node.node[WR_REDO_ALLOC_FT_NODE_PREV_INDEX].id, WR_INVALID_64); + } + redo_node.node[WR_REDO_ALLOC_FT_NODE_PARENT_INDEX] = *parent_node; + + redo_node.ft_root = *gft; + wr_put_log(session, vg_item, WR_RT_ALLOC_FILE_TABLE_NODE, &redo_node, sizeof(wr_redo_alloc_ft_node_t)); + char *prev_name; + if (prev_node) { + prev_name = prev_node->name; + } else { + prev_name = "NULL"; + } + WR_LOG_DEBUG_OP("[FT] Alloc ft node, type:%u, name:%s, prev name:%s, %s, free count:%u.", node->type, node->name, + prev_name, wr_display_metaid(node->id), gft->free_list.count); +} + +void wr_ft_node_link_list(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *parent_node, ftid_t id, + gft_node_t *node, gft_root_t *gft) +{ + gft_node_t *prev_node = NULL; + bool32 cmp = wr_cmp_auid(parent_node->items.last, CM_INVALID_ID64); + if (!cmp) { + /* + * when current thread modify prev_node's next pointer, + * another thread may be modify prev_node's size by extend space + * so here we need file lock to avoid concurrency scenario. + */ + prev_node = wr_get_ft_node_by_ftid(session, vg_item, parent_node->items.last, CM_TRUE, CM_FALSE); + if (prev_node != NULL) { + prev_node->next = id; + } + } + + parent_node->items.count++; + parent_node->items.last = id; + cmp = wr_cmp_auid(parent_node->items.first, CM_INVALID_ID64); + if (cmp) { + parent_node->items.first = id; + } + + wr_set_ft_node(session, vg_item, parent_node, node, gft, prev_node); +} + +/* + * NOTE: this function is called only in creating vg. + * because there is no block buffer for use, you can't call wr_find_block_in_mem + * or ga_alloc_object_list, redo log etc. You must flush buffer to disk manually. + */ +status_t wr_alloc_ft_node_when_create_vg( + wr_vg_info_item_t *vg_item, gft_node_t *parent_node, const char *name, gft_item_type_t type, uint32 flags) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(parent_node != NULL); + CM_ASSERT(name != NULL); + /* parent_node must be the root directory */ + CM_ASSERT(parent_node->id.au == 0 && parent_node->id.block == 0 && parent_node->id.item == 0); + + status_t status; + ftid_t id; + wr_ctrl_t *wr_ctrl = vg_item->wr_ctrl; + char *root = wr_ctrl->root; + wr_root_ft_block_t *ft_block = (wr_root_ft_block_t *)(root); + gft_root_t *gft = &ft_block->ft_root; + if (gft->free_list.count == 0) { + status = wr_alloc_ft_au(NULL, vg_item, &id); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("[FT][ALLOC] Failed to allocate au when allocating file table node."); + return status; + } + LOG_RUN_INF("[FT][ALLOC] Succeed to allocate au:%s when allocating file table node.", wr_display_metaid(id)); + } + + id = gft->free_list.first; + char *buf = (char *)cm_malloc_align(WR_DISK_UNIT_SIZE, WR_BLOCK_SIZE); + if (buf == NULL) { + LOG_RUN_ERR("[FT][ALLOC] Failed to allocate buf."); + return CM_ERROR; + } + + /* read ft block from disk, because there's no cache in hands */ + wr_block_id_t block_id = id; + block_id.item = 0; + int64 offset = wr_get_block_offset(vg_item, WR_BLOCK_SIZE, block_id.block, block_id.au); + if (wr_get_block_from_disk(vg_item, block_id, buf, offset, WR_BLOCK_SIZE, CM_TRUE) != CM_SUCCESS) { + WR_FREE_POINT(buf); + LOG_RUN_ERR("[FT][ALLOC] Failed to load ft block %s.", wr_display_metaid(block_id)); + return CM_ERROR; + } + gft_node_t *node = (gft_node_t *)(buf + sizeof(wr_ft_block_t) + sizeof(gft_node_t) * id.item); + gft->free_list.first = node->next; + bool32 cmp = wr_cmp_auid(gft->free_list.first, CM_INVALID_ID64); + if (cmp) { + gft->free_list.last = gft->free_list.first; + } + gft->free_list.count--; + node->type = type; + node->parent = parent_node->id; + if (type == GFT_PATH) { + node->items.count = 0; + wr_set_auid(&node->items.first, CM_INVALID_ID64); + wr_set_auid(&node->items.last, CM_INVALID_ID64); + } else { + /* file or link */ + wr_set_blockid(&node->entry, CM_INVALID_ID64); + } + if (strcpy_s(node->name, sizeof(node->name), name) != EOK) { + cm_panic(0); + } + wr_init_alloc_ft_node(gft, node, flags, parent_node); + parent_node->items.first = node->id; + parent_node->items.last = node->id; + parent_node->items.count = 1; + ((wr_ft_block_t *)buf)->common.flags = WR_BLOCK_FLAG_USED; + do { + /* flush ft block to disk manually */ + status = wr_update_ft_block_disk(vg_item, (wr_ft_block_t *)buf, id); + WR_BREAK_IF_ERROR(status); + status = wr_update_ft_root(vg_item); // parent_node must be root directory like `+data` + } while (0); + if (status == CM_SUCCESS) { + LOG_RUN_INF("Succeed to create recycle file, node id is %s.", wr_display_metaid(node->id)); + } + WR_FREE_POINT(buf); + return status; +} + +status_t wr_alloc_ft_au_when_no_free( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_root_t *gft, bool32 *check_version) +{ + if (gft->free_list.count == 0) { + LOG_DEBUG_INF("[FT][ALLOC] There is no free au, begin to allocate au in vg:%s", vg_item->vg_name); + ftid_t id; + status_t status = wr_alloc_ft_au(session, vg_item, &id); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("[FT][ALLOC] Failed to allocate au when allocating file table node.")); + *check_version = CM_FALSE; + WR_LOG_DEBUG_OP( + "[FT][ALLOC] Succeed to allocate au:%s when allocating file table node, ", wr_display_metaid(id)); + } + return CM_SUCCESS; +} + +static void wr_get_prev_and_next_node(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *parent_node, + gft_node_t *node, gft_block_info_t *prev_info, gft_block_info_t *next_info) +{ + node->update_time = cm_current_time(); + if (*(uint64 *)(&parent_node->items.first) == *(uint64 *)(&node->id)) { + parent_node->items.first = node->next; + bool32 cmp = wr_cmp_blockid(parent_node->items.first, CM_INVALID_ID64); + if (cmp) { + CM_ASSERT(parent_node->items.count == 1); + parent_node->items.last = parent_node->items.first; + } else { + next_info->ft_node = wr_get_ft_node_by_ftid(session, vg_item, parent_node->items.first, CM_TRUE, CM_FALSE); + CM_ASSERT(next_info->ft_node != NULL); + wr_set_blockid(&next_info->ft_node->prev, CM_INVALID_ID64); + } + } else if (*(uint64 *)(&parent_node->items.last) == *(uint64 *)(&node->id)) { + parent_node->items.last = node->prev; + prev_info->ft_node = wr_get_ft_node_by_ftid(session, vg_item, parent_node->items.last, CM_TRUE, CM_FALSE); + CM_ASSERT(prev_info->ft_node != NULL); + wr_set_blockid(&prev_info->ft_node->next, CM_INVALID_ID64); + } else { + prev_info->ft_node = wr_get_ft_node_by_ftid(session, vg_item, node->prev, CM_TRUE, CM_FALSE); + CM_ASSERT(prev_info->ft_node != NULL); + prev_info->ft_node->next = node->next; + next_info->ft_node = wr_get_ft_node_by_ftid(session, vg_item, node->next, CM_TRUE, CM_FALSE); + CM_ASSERT(next_info->ft_node != NULL); + next_info->ft_node->prev = node->prev; + } + parent_node->items.count--; +} + +void wr_free_ft_node_inner( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *parent_node, gft_node_t *node, bool32 real_del) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(parent_node != NULL); + CM_ASSERT(node != NULL); + gft_block_info_t prev_info = {0}; + gft_block_info_t next_info = {0}; + node->update_time = cm_current_time(); + wr_get_prev_and_next_node(session, vg_item, parent_node, node, &prev_info, &next_info); + + wr_ctrl_t *wr_ctrl = vg_item->wr_ctrl; + char *root = wr_ctrl->root; + wr_root_ft_block_t *ft_block = (wr_root_ft_block_t *)(root); + gft_root_t *gft = &ft_block->ft_root; + if (real_del) { + wr_ft_block_t *block = wr_get_ft_by_node(node); + block->common.flags = WR_BLOCK_FLAG_FREE; + node->next = gft->free_list.first; + wr_set_blockid(&node->parent, WR_BLOCK_ID_INIT); + wr_set_blockid(&node->prev, WR_INVALID_64); + wr_set_blockid(&node->entry, WR_INVALID_64); + gft->free_list.first = node->id; + gft->free_list.count++; + } + + wr_redo_free_ft_node_t redo_node; + redo_node.node[WR_REDO_FREE_FT_NODE_PARENT_INDEX] = *parent_node; + if (prev_info.ft_node != NULL) { + redo_node.node[WR_REDO_FREE_FT_NODE_PREV_INDEX] = *prev_info.ft_node; + WR_LOG_DEBUG_OP("Free ft node, prev_node name:%s, prev_node id:%s.", prev_info.ft_node->name, + wr_display_metaid(prev_info.ft_node->id)); + } else { + wr_set_auid(&redo_node.node[WR_REDO_FREE_FT_NODE_PREV_INDEX].id, CM_INVALID_ID64); + } + if (next_info.ft_node != NULL) { + redo_node.node[WR_REDO_FREE_FT_NODE_NEXT_INDEX] = *next_info.ft_node; + WR_LOG_DEBUG_OP("Free ft node, next_node name:%s, next_node id:%s.", next_info.ft_node->name, + wr_display_metaid(next_info.ft_node->id)); + } else { + wr_set_auid(&redo_node.node[WR_REDO_FREE_FT_NODE_NEXT_INDEX].id, CM_INVALID_ID64); + } + redo_node.node[WR_REDO_FREE_FT_NODE_SELF_INDEX] = *node; + redo_node.ft_root = *gft; + wr_put_log(session, vg_item, WR_RT_FREE_FILE_TABLE_NODE, &redo_node, sizeof(wr_redo_free_ft_node_t)); + WR_LOG_DEBUG_OP("[FT][FREE] Free ft node, name:%s, %s, free count:%u, real delete:%u", node->name, + wr_display_metaid(node->id), gft->free_list.count, real_del); +} + +// remove ftn from parent +void wr_free_ft_node( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *parent_node, gft_node_t *node, bool32 real_del) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(parent_node != NULL); + CM_ASSERT(node != NULL); + wr_free_ft_node_inner(session, vg_item, parent_node, node, real_del); +} + +gft_node_t *wr_find_ft_node_core( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *parent_node, const char *name, bool32 skip_del) +{ + bool32 check_version = wr_is_server(); + ftid_t id = parent_node->items.first; + + for (uint32 i = 0; i < parent_node->items.count; i++) { + if (wr_cmp_blockid(id, CM_INVALID_ID64)) { + // may be find uncommitted node when standby + LOG_DEBUG_ERR("Get invalid id in parent name:%s, %s, count:%u, when find node name:%s, index:%u.", + parent_node->name, wr_display_metaid(parent_node->id), parent_node->items.count, name, i); + return NULL; + } + gft_node_t *node = wr_get_ft_node_by_ftid(session, vg_item, id, check_version, CM_FALSE); + if (node == NULL) { + LOG_DEBUG_ERR( + "Can not get node:%s, File name %s type:%u.", wr_display_metaid(id), name, parent_node->type); + return NULL; + } + if (skip_del && (node->flags & WR_FT_NODE_FLAG_DEL)) { + id = node->next; + LOG_DEBUG_INF("Skip del the node, next node:%s", wr_display_metaid(id)); + continue; + } + if (strcmp(node->name, name) == 0) { + return node; + } + + id = node->next; + } + return NULL; +} + +gft_node_t *wr_find_ft_node( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *parent_node, const char *name, bool8 skip_del) +{ + CM_ASSERT(name != NULL); + ftid_t id; + if (parent_node == NULL) { + memset_s(&id, sizeof(id), 0, sizeof(id)); + return wr_get_ft_node_by_ftid(session, vg_item, id, wr_is_server(), CM_FALSE); + } + + if (parent_node->type != GFT_PATH) { + LOG_DEBUG_ERR("File name %s, its parent's type:%u is invalid.", name, parent_node->type); + return NULL; + } + + if (parent_node->items.count == 0) { + LOG_DEBUG_INF("File name %s, its parent's sub item count:%u.", name, parent_node->items.count); + return NULL; + } + timeval_t begin_tv; + wr_begin_stat(&begin_tv); + gft_node_t *node = wr_find_ft_node_core(session, vg_item, parent_node, name, skip_del); + wr_session_end_stat(session, &begin_tv, WR_FIND_FT_ON_SERVER); + if (node != NULL) { + return node; + } + + LOG_DEBUG_INF("File name %s, its parent's sub item count:%u.", name, parent_node->items.count); + return NULL; +} + +status_t wr_refresh_root_ft_inner(wr_vg_info_item_t *vg_item) +{ + bool32 remote = CM_TRUE; + wr_ctrl_t *wr_ctrl = vg_item->wr_ctrl; + char *root = wr_ctrl->root; + status_t status = wr_load_vg_ctrl_part(vg_item, (int64)WR_CTRL_ROOT_OFFSET, root, (int32)WR_BLOCK_SIZE, &remote); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to get the whole root.")); + if (remote == CM_FALSE) { + uint32 checksum = wr_get_checksum(root, WR_BLOCK_SIZE); + wr_common_block_t *block = (wr_common_block_t *)root; + wr_check_checksum(checksum, block->checksum); + } + return CM_SUCCESS; +} + +status_t wr_refresh_root_ft(wr_vg_info_item_t *vg_item, bool32 check_version, bool32 active_refresh) +{ + if (!wr_is_server()) { + return CM_SUCCESS; + } + if (!WR_STANDBY_CLUSTER && wr_is_readwrite() && !active_refresh) { + WR_ASSERT_LOG(wr_need_exec_local(), "only masterid %u can be readwrite.", wr_get_master_id()); + return CM_SUCCESS; + } + wr_ctrl_t *wr_ctrl = vg_item->wr_ctrl; + char *root = wr_ctrl->root; + wr_root_ft_block_t *ft_block = (wr_root_ft_block_t *)(root); + if (check_version) { + uint64 version = ft_block->ft_block.common.version; + uint64 disk_version; + status_t status = wr_get_root_version(vg_item, &disk_version); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to get the root version."); + return status; + } + + if (wr_compare_version(disk_version, version)) { + WR_LOG_DEBUG_OP( + "The root version is changed, refresh it, version:%llu, new version:%llu.", version, disk_version); + status = wr_refresh_root_ft_inner(vg_item); + WR_RETURN_IF_ERROR(status); + } + } + return CM_SUCCESS; +} + +gft_node_t *wr_get_ft_node_by_ftid( + wr_session_t *session, wr_vg_info_item_t *vg_item, ftid_t id, bool32 check_version, bool32 active_refresh) +{ + wr_ctrl_t *wr_ctrl = vg_item->wr_ctrl; + if (is_ft_root_block(id)) { + char *root = wr_ctrl->root; + wr_root_ft_block_t *ft_block = (wr_root_ft_block_t *)(root); + if (wr_refresh_root_ft(vg_item, check_version, active_refresh) != CM_SUCCESS) { + return NULL; + } + + if (id.item < ft_block->ft_block.node_num) { + return (gft_node_t *)((root + sizeof(wr_root_ft_block_t)) + id.item * sizeof(gft_node_t)); + } + } else { + wr_block_id_t block_id = id; + block_id.item = 0; + wr_ft_block_t *ft_block = (wr_ft_block_t *)wr_find_block_in_shm( + session, vg_item, block_id, WR_BLOCK_TYPE_FT, check_version, NULL, active_refresh); + if (ft_block == NULL) { + LOG_DEBUG_ERR("Failed to find block:%s in mem.", wr_display_metaid(block_id)); + return NULL; + } + + if (ft_block->node_num <= id.item) { + LOG_DEBUG_ERR("The block is wrong, node_num:%u, item:%u.", ft_block->node_num, (uint32)id.item); + return NULL; + } + + gft_node_t *node = (gft_node_t *)(((char *)ft_block + sizeof(wr_ft_block_t)) + id.item * sizeof(gft_node_t)); + if (!wr_is_server() || wr_is_ft_block_valid(node, ft_block)) { + return node; + } + + LOG_DEBUG_INF("block:%llu fid:%llu, file ver:%llu is not same as node:%llu, fid:%llu, file ver:%llu", + WR_ID_TO_U64(block_id), wr_get_ft_block_fid(ft_block), wr_get_ft_block_file_ver(ft_block), + WR_ID_TO_U64(node->id), node->fid, node->file_ver); + wr_set_ft_block_file_ver(node, ft_block); + LOG_DEBUG_INF("block:%llu fid:%llu, file ver:%llu setted with node:%llu, fid:%llu, file ver:%llu", + WR_ID_TO_U64(block_id), wr_get_ft_block_fid(ft_block), wr_get_ft_block_file_ver(ft_block), + WR_ID_TO_U64(node->id), node->fid, node->file_ver); + return node; + } + return NULL; +} + +gft_node_t *wr_get_ft_node_by_ftid_no_refresh(wr_session_t *session, wr_vg_info_item_t *vg_item, ftid_t id) +{ + wr_ctrl_t *wr_ctrl = vg_item->wr_ctrl; + if (is_ft_root_block(id)) { + char *root = wr_ctrl->root; + wr_root_ft_block_t *ft_block = (wr_root_ft_block_t *)(root); + if (id.item < ft_block->ft_block.node_num) { + return (gft_node_t *)((root + sizeof(wr_root_ft_block_t)) + id.item * sizeof(gft_node_t)); + } + } else { + wr_block_id_t block_id = id; + block_id.item = 0; + wr_ft_block_t *block = (wr_ft_block_t *)wr_find_block_in_shm_no_refresh(session, vg_item, block_id, NULL); + if (block == NULL) { + LOG_DEBUG_ERR("Failed to find block:%s in mem.", wr_display_metaid(block_id)); + return NULL; + } + + if (block->node_num <= id.item) { + LOG_DEBUG_ERR("The block is wrong, node_num:%u, item:%u.", block->node_num, (uint32)id.item); + return NULL; + } + + return (gft_node_t *)(((char *)block + sizeof(wr_ft_block_t)) + id.item * sizeof(gft_node_t)); + } + return NULL; +} + +gft_node_t *wr_get_ft_node_by_ftid_from_disk_and_refresh_shm( + wr_session_t *session, wr_vg_info_item_t *vg_item, ftid_t id) +{ + wr_ctrl_t *wr_ctrl = vg_item->wr_ctrl; + if (is_ft_root_block(id)) { + char *root = wr_ctrl->root; + wr_root_ft_block_t *ft_block = (wr_root_ft_block_t *)(root); + if (wr_refresh_root_ft_inner(vg_item) != CM_SUCCESS) { + return NULL; + } + if (id.item < ft_block->ft_block.node_num) { + return (gft_node_t *)((root + sizeof(wr_root_ft_block_t)) + id.item * sizeof(gft_node_t)); + } + } else { + wr_block_id_t block_id = id; + block_id.item = 0; + wr_ft_block_t *ft_block = (wr_ft_block_t *)wr_find_block_from_disk_and_refresh_shm( + session, vg_item, block_id, WR_BLOCK_TYPE_FT, NULL); + if (ft_block == NULL) { + LOG_DEBUG_ERR("Failed to find block:%s from disk and refresh shm.", wr_display_metaid(block_id)); + return NULL; + } + if (ft_block->node_num <= id.item) { + LOG_DEBUG_ERR("Wrong block, node_num:%u, item:%u.", ft_block->node_num, (uint32)id.item); + return NULL; + } + gft_node_t *node = (gft_node_t *)(((char *)ft_block + sizeof(wr_ft_block_t)) + id.item * sizeof(gft_node_t)); + if (!wr_is_server() || wr_is_ft_block_valid(node, ft_block)) { + return node; + } + LOG_DEBUG_INF("block:%llu, fid:%llu, file ver:%llu is not same as node:%llu, fid:%llu, file ver:%llu", + WR_ID_TO_U64(block_id), wr_get_ft_block_fid(ft_block), wr_get_ft_block_file_ver(ft_block), + WR_ID_TO_U64(node->id), node->fid, node->file_ver); + wr_set_ft_block_file_ver(node, ft_block); + LOG_DEBUG_INF("block:%llu, fid:%llu, file ver:%llu setted with node:%llu, fid:%llu, file ver:%llu", + WR_ID_TO_U64(block_id), wr_get_ft_block_fid(ft_block), wr_get_ft_block_file_ver(ft_block), + WR_ID_TO_U64(node->id), node->fid, node->file_ver); + return node; + } + return NULL; +} + +char *wr_get_ft_block_by_ftid(wr_session_t *session, wr_vg_info_item_t *vg_item, ftid_t id) +{ + wr_ctrl_t *wr_ctrl = vg_item->wr_ctrl; + if (is_ft_root_block(id)) { + char *root = wr_ctrl->root; + // NOTE:when recover just return root, must not be load from disk.Because format ft node is logic recovery, + // its gft info only use redo log info. + if (vg_item->status == WR_VG_STATUS_RECOVERY) { + return root; + } + + if (wr_refresh_root_ft(vg_item, CM_TRUE, CM_FALSE) != CM_SUCCESS) { + return NULL; + } + return root; + } + return wr_find_block_in_shm(session, vg_item, id, WR_BLOCK_TYPE_FT, CM_TRUE, NULL, CM_FALSE); +} + +static void wr_init_ft_root_core(char *root, wr_root_ft_block_t *ft_block, gft_root_t *gft) +{ + wr_set_blockid(&ft_block->ft_block.next, WR_INVALID_64); + wr_set_blockid(&gft->first, 0); + wr_set_blockid(&gft->last, 0); + + gft->items.count = 0; + *(uint64_t *)(&gft->items.first) = WR_INVALID_64; + *(uint64_t *)(&gft->items.last) = WR_INVALID_64; + gft->free_list.count = 0; + *(uint64 *)(&gft->free_list.first) = WR_INVALID_64; + *(uint64 *)(&gft->free_list.last) = WR_INVALID_64; + // item_count is always 1 + uint32 item_count = (WR_BLOCK_SIZE - sizeof(wr_root_ft_block_t)) / sizeof(gft_node_t); + ft_block->ft_block.node_num = item_count; + gft_node_t *first_free_node = (gft_node_t *)(root + sizeof(wr_root_ft_block_t)); + gft_node_t *node = NULL; + + // the first gft_node_t is used for vg name (like: `/`) + for (uint32 i = 1; i < item_count; i++) { + node = first_free_node + i; + wr_set_auid(&node->id, 0); + node->id.block = 0; + node->id.item = i; + + if (i == 1) { + *(uint64_t *)(&node->prev) = WR_INVALID_64; + gft->free_list.first = node->id; + } else { + *(uint64_t *)(&node->prev) = 0; + node->prev.block = 0; + node->prev.item = (uint16)i - 1; + } + + if (i == item_count - 1) { + *(uint64_t *)(&node->next) = WR_INVALID_64; + gft->free_list.last = node->id; + } else { + *(uint64_t *)(&node->next) = 0; + node->next.block = 0; + node->next.item = (uint16)i + 1; + } + + gft->free_list.count++; + } +} + +static void wr_init_first_node(wr_ctrl_t *wr_ctrl, gft_node_t *first_node) +{ + first_node->type = GFT_PATH; + if (strcpy_s(first_node->name, WR_MAX_NAME_LEN, wr_ctrl->vg_info.vg_name) != EOK) { + cm_panic(0); + } + first_node->create_time = cm_current_time(); + first_node->size = 0; + first_node->written_size = 0; + first_node->items.count = 0; + wr_set_auid(&first_node->items.first, WR_INVALID_64); + wr_set_auid(&first_node->items.last, WR_INVALID_64); + wr_set_auid(&first_node->prev, WR_INVALID_64); + wr_set_auid(&first_node->next, WR_INVALID_64); + wr_set_auid(&first_node->id, 0); + first_node->id.block = 0; + first_node->id.item = 0; +} + +void wr_init_ft_root(wr_ctrl_t *wr_ctrl, gft_node_t **out_node) +{ + CM_ASSERT(wr_ctrl != NULL); + char *root = wr_ctrl->root; + wr_root_ft_block_t *ft_block = (wr_root_ft_block_t *)(root); + gft_root_t *gft = &ft_block->ft_root; + wr_init_ft_root_core(root, ft_block, gft); + + gft_node_t *first_node = (gft_node_t *)(root + sizeof(wr_root_ft_block_t)); + wr_init_first_node(wr_ctrl, first_node); + + gft->items.count = 1; + gft->items.first = first_node->id; + gft->items.last = first_node->id; + if (out_node) { + *out_node = first_node; + } + return; +} + +status_t wr_update_ft_root(wr_vg_info_item_t *vg_item) +{ + status_t status; + wr_ctrl_t *wr_ctrl = vg_item->wr_ctrl; + wr_root_ft_block_t *block = WR_GET_ROOT_BLOCK(wr_ctrl); + block->ft_block.common.version++; + block->ft_block.common.checksum = wr_get_checksum(block, WR_BLOCK_SIZE); + CM_ASSERT(vg_item->volume_handle[0].handle != WR_INVALID_HANDLE); + WR_LOG_DEBUG_OP("Update node table root, version:%llu, checksum:%u.", block->ft_block.common.version, + block->ft_block.common.checksum); + status = wr_write_volume_inst( + vg_item, &vg_item->volume_handle[0], (int64)WR_CTRL_ROOT_OFFSET, wr_ctrl->root, WR_BLOCK_SIZE); + if (status == CM_SUCCESS) { + // write to backup area + status = wr_write_volume_inst( + vg_item, &vg_item->volume_handle[0], (int64)WR_CTRL_BAK_ROOT_OFFSET, wr_ctrl->root, WR_BLOCK_SIZE); + } + return status; +} + +status_t wr_check_refresh_fs_block( + wr_vg_info_item_t *vg_item, wr_block_id_t blockid, char *block, bool32 *is_changed) +{ + if (!WR_STANDBY_CLUSTER && wr_is_readwrite()) { + WR_ASSERT_LOG(wr_need_exec_local(), "only masterid %u can be readwrite.", wr_get_master_id()); + return CM_SUCCESS; + } + status_t status = wr_check_refresh_core(vg_item); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to check and refresh core, %s.", vg_item->entry_path)); + + return wr_check_block_version(vg_item, blockid, WR_BLOCK_TYPE_FS, block, is_changed, CM_FALSE); +} + +// refresh file table +status_t wr_refresh_ft(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + if (!WR_STANDBY_CLUSTER && wr_is_readwrite()) { + WR_ASSERT_LOG(wr_need_exec_local(), "only masterid %u can be readwrite.", wr_get_master_id()); + return CM_SUCCESS; + } + bool32 remote = CM_FALSE; + status_t status = wr_load_vg_ctrl_part( + vg_item, (int64)WR_CTRL_ROOT_OFFSET, vg_item->wr_ctrl->root, (int32)WR_BLOCK_SIZE, &remote); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to load vg core part %s.", vg_item->entry_path)); + + uint64 count = 0; + char *root = vg_item->wr_ctrl->root; + wr_root_ft_block_t *ft_block = (wr_root_ft_block_t *)(root); + wr_block_id_t block_id = ft_block->ft_block.next; + bool32 cmp = wr_cmp_blockid(block_id, CM_INVALID_ID64); + while (!cmp) { + ft_block = (wr_root_ft_block_t *)wr_get_ft_block_by_ftid(session, vg_item, block_id); + if (ft_block) { + block_id = ft_block->ft_block.next; + cmp = wr_cmp_blockid(block_id, CM_INVALID_ID64); + } else { + WR_RETURN_IFERR2( + CM_ERROR, LOG_DEBUG_ERR("Failed to get file table block when refresh ft %s.", vg_item->entry_path)); + } + count++; + } + WR_LOG_DEBUG_OP("Succeed to refresh ft %s, count:%llu.", vg_item->entry_path, count); + return CM_SUCCESS; +} + +status_t wr_get_root_version(wr_vg_info_item_t *vg_item, uint64 *version) +{ + CM_ASSERT(vg_item != NULL); + CM_ASSERT(version != NULL); + +#ifndef WIN32 + char temp[WR_DISK_UNIT_SIZE] __attribute__((__aligned__(WR_DISK_UNIT_SIZE))); +#else + char temp[WR_DISK_UNIT_SIZE]; +#endif + bool32 remote = CM_FALSE; + status_t status = wr_load_vg_ctrl_part(vg_item, (int64)WR_CTRL_ROOT_OFFSET, temp, WR_DISK_UNIT_SIZE, &remote); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to load vg core version %s.", vg_item->entry_path); + return status; + } + *version = ((wr_common_block_t *)temp)->version; + return CM_SUCCESS; +} + +status_t wr_check_refresh_ft(wr_vg_info_item_t *vg_item) +{ + if (!wr_is_server()) { + return CM_SUCCESS; + } + if (!WR_STANDBY_CLUSTER && wr_is_readwrite()) { + WR_ASSERT_LOG(wr_need_exec_local(), "only masterid %u can be readwrite.", wr_get_master_id()); + return CM_SUCCESS; + } + uint64 disk_version; + bool32 remote = CM_FALSE; + status_t status = wr_get_root_version(vg_item, &disk_version); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to get root version %s.", vg_item->entry_path)); + + wr_root_ft_block_t *ft_block_m = WR_GET_ROOT_BLOCK(vg_item->wr_ctrl); + if (wr_compare_version(disk_version, ft_block_m->ft_block.common.version)) { + status = wr_load_vg_ctrl_part( + vg_item, (int64)WR_CTRL_ROOT_OFFSET, vg_item->wr_ctrl->root, (int32)WR_BLOCK_SIZE, &remote); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to load vg core part %s.", vg_item->entry_path)); + } + WR_LOG_DEBUG_OP( + "wr_check_refresh_ft version:%llu, disk version:%llu.", ft_block_m->ft_block.common.version, disk_version); + return CM_SUCCESS; +} + +status_t wr_update_ft_block_disk(wr_vg_info_item_t *vg_item, wr_ft_block_t *block, ftid_t id) +{ + uint32 volume_id = (uint32)id.volume; + int64 offset = wr_get_ft_block_offset(vg_item, id); + + block->common.version++; + block->common.checksum = wr_get_checksum(block, WR_BLOCK_SIZE); + CM_ASSERT(vg_item->volume_handle[volume_id].handle != WR_INVALID_HANDLE); + return wr_check_write_volume(vg_item, volume_id, offset, block, WR_BLOCK_SIZE); +} + +int64 wr_get_ft_block_offset(wr_vg_info_item_t *vg_item, ftid_t id) +{ + if ((id.au) == 0) { + return (int64)WR_CTRL_ROOT_OFFSET; + } + return wr_get_block_offset(vg_item, WR_BLOCK_SIZE, id.block, id.au); +} + +status_t wr_update_fs_bitmap_block_disk( + wr_vg_info_item_t *item, wr_fs_block_t *block, uint32 size, bool32 had_checksum) +{ + CM_ASSERT(item != NULL); + CM_ASSERT(block != NULL); + uint32 volume_id = (uint32)block->head.common.id.volume; + int64 offset = wr_get_fs_block_offset(item, block->head.common.id); + + if (!had_checksum) { + block->head.common.version++; + block->head.common.checksum = wr_get_checksum(block, WR_FILE_SPACE_BLOCK_SIZE); + } + + WR_LOG_DEBUG_OP("[FS] update_fs_bitmap_block_disk checksum:%u, fsid:%s, version:%llu, size:%u.", + block->head.common.checksum, wr_display_metaid(block->head.common.id), block->head.common.version, size); + + CM_ASSERT(item->volume_handle[volume_id].handle != WR_INVALID_HANDLE); + status_t status = wr_check_write_volume(item, volume_id, offset, block, size); + if (status != CM_SUCCESS) { + return status; + } + return CM_SUCCESS; +} + +static status_t wr_get_block_entry(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_config_t *inst_cfg, + uint64 fid, ftid_t ftid, gft_node_t **node_out, wr_fs_block_t **entry_out) +{ + return CM_SUCCESS; +} + +status_t wr_get_fs_block_info_by_offset( + int64 offset, uint64 au_size, uint32 *block_count, uint32 *block_au_count, uint32 *au_offset) +{ + WR_ASSERT_LOG(au_size != 0, "The au size cannot be zero."); + + // two level bitmap, ~2k block ids per entry FSB + uint64 au_count = WR_FILE_SPACE_BLOCK_BITMAP_COUNT; // 2043 2nd FSBs + uint64 block_len = au_count * au_size; // [4G, 128G] per 2nd-level FSB, with AU range [2MB, 64MB] + int64 temp = (offset / (int64)block_len); + if (temp > (int64)au_count) { // Total [8T, 256T] per file, to be verified + LOG_DEBUG_ERR( + "Invalid offset, offset:%lld, real block count:%lld, max block count:%llu.", offset, temp, au_count); + return CM_ERROR; + } + *block_count = (uint32)(temp); // index of secondary FSB(id) in entry FSB's bitmap + int64 block_offset = offset % (int64)block_len; // offset within FSB + *block_au_count = (uint32)(block_offset / (int64)au_size); // index of AU within FSB + if (au_offset != NULL) { + *au_offset = (uint32)(block_offset % (int64)au_size); // offset within AU + } + + return CM_SUCCESS; +} +status_t wr_alloc_fs_aux_batch_prepare(wr_session_t *session, wr_vg_info_item_t *vg_item, uint32 batch_count) +{ + return CM_SUCCESS; +} + +status_t wr_extend_fs_aux_batch_inner(wr_session_t *session, wr_vg_info_item_t *vg_item, auid_t batch_first, + gft_node_t *node, uint32 block_au_count, uint32 batch_count, wr_fs_block_t *second_block, + uint64 old_aux_root_free_count) +{ + return CM_SUCCESS; +} + +status_t wr_extend_fs_aux_batch(wr_session_t *session, wr_vg_info_item_t *vg_item, auid_t batch_first, + gft_node_t *node, uint32 block_au_count, uint32 batch_count, wr_fs_block_t *second_block) +{ + return CM_SUCCESS; +} + +status_t wr_extend_fs_aux(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, + wr_block_id_t second_fs_block_id, wr_alloc_fs_block_info_t *info, auid_t *data_auid) +{ + return CM_SUCCESS; +} + +status_t wr_extend_fs_batch(wr_session_t *session, wr_vg_info_item_t *vg_item, auid_t batch_first, + uint32 block_au_count, uint32 batch_count, wr_fs_block_t *second_block) +{ + return CM_SUCCESS; +} + +status_t wr_extend_batch_inner(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, uint64 align_beg, + uint64 align_end, bool32 *finish) +{ + return CM_SUCCESS; +} + +status_t wr_extend_batch( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, wr_node_data_t *node_data, bool32 *finish) +{ + return CM_SUCCESS; +} + +status_t wr_extend_inner(wr_session_t *session, wr_node_data_t *node_data) +{ + return CM_SUCCESS; +} + +status_t wr_extend_from_offset( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, wr_node_data_t *node_data) +{ + return CM_SUCCESS; +} + +static status_t wr_extend_with_updt_written_size( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, wr_node_data_t *node_data) +{ + return CM_SUCCESS; +} + +status_t wr_extend(wr_session_t *session, wr_node_data_t *node_data) +{ + return CM_SUCCESS; +} + +status_t wr_do_fallocate(wr_session_t *session, wr_node_data_t *node_data) +{ + status_t status; + if (node_data->size < 0) { + WR_THROW_ERROR(ERR_WR_FILE_INVALID_SIZE, node_data->offset, node_data->size); + LOG_DEBUG_ERR("Invalid fallocate offset:%lld, size:%lld.", node_data->offset, node_data->size); + return CM_ERROR; + } + + if (node_data->mode != 0) { + WR_RETURN_IFERR3(CM_ERROR, LOG_DEBUG_ERR("Failed to check mode,vg id %d.", node_data->mode), + WR_THROW_ERROR(ERR_WR_INVALID_ID, "fallocate mode", (uint64)node_data->mode)); + } + + wr_vg_info_item_t *vg_item = wr_find_vg_item_by_id(node_data->vgid); + if (vg_item == NULL) { + WR_RETURN_IFERR3(CM_ERROR, LOG_DEBUG_ERR("Failed to find vg, vg id:%u.", node_data->vgid), + WR_THROW_ERROR(ERR_WR_INVALID_ID, "vg id", (uint64)node_data->vgid)); + } + node_data->vg_name = (char *)vg_item->vg_name; + + wr_lock_vg_mem_and_shm_x(session, vg_item); + gft_node_t *node = wr_get_ft_node_by_ftid(session, vg_item, node_data->ftid, CM_TRUE, CM_FALSE); + if (node == NULL) { + wr_unlock_vg_mem_and_shm(session, vg_item); + WR_RETURN_IFERR2( + CM_ERROR, LOG_DEBUG_ERR("Failed to find ftid, ftid:%s.", wr_display_metaid(node_data->ftid))); + } + + status = wr_extend_with_updt_written_size(session, vg_item, node, node_data); + wr_unlock_vg_mem_and_shm(session, vg_item); + + return status; +} + +/* validate params, lock VG and process recovery for truncate */ +static status_t wr_prepare_truncate(wr_session_t *session, wr_vg_info_item_t *vg_item, int64 length) +{ + wr_lock_vg_mem_and_shm_x(session, vg_item); + + status_t status = wr_check_file(vg_item); + if (status != CM_SUCCESS) { + WR_RETURN_IFERR3(CM_ERROR, wr_unlock_vg_mem_and_shm(session, vg_item), + LOG_DEBUG_ERR("Failed to check file,errcode:%d.", cm_get_error_code())); + } + return CM_SUCCESS; +} + +static void wr_truncate_set_size(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, int64 length) +{ + uint64 old_size = (uint64)node->size; + uint64 align_length = CM_CALC_ALIGN((uint64)length, wr_get_vg_au_size(vg_item->wr_ctrl)); + (void)cm_atomic_set(&node->size, (int64)align_length); + node->written_size = (uint64)length < node->written_size ? (uint64)length : node->written_size; + node->min_inited_size = (uint64)align_length < node->min_inited_size ? (uint64)align_length : node->min_inited_size; + wr_redo_set_file_size_t redo_size; + redo_size.ftid = node->id; + redo_size.size = (uint64)node->size; + redo_size.oldsize = old_size; + wr_put_log(session, vg_item, WR_RT_SET_FILE_SIZE, &redo_size, sizeof(redo_size)); +} + +status_t truncate_to_extend(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, int64 size) +{ + wr_node_data_t node_data; + node_data.fid = node->fid; + node_data.ftid = node->id; + node_data.vgid = vg_item->id; + node_data.vg_name = (char *)vg_item->vg_name; + node_data.offset = 0; + node_data.size = size; + + return wr_extend_with_updt_written_size(session, vg_item, node, &node_data); +} + +void wr_set_node_flag( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, bool32 is_set, uint32 flags) +{ + wr_redo_set_file_flag_t file_flag; + file_flag.ftid = node->id; + file_flag.old_flags = node->flags; + + if (is_set) { + node->flags |= flags; + } else { + node->flags &= ~flags; + } + file_flag.flags = node->flags; + if (wr_need_exec_local()) { + wr_put_log(session, vg_item, WR_RT_SET_NODE_FLAG, &file_flag, sizeof(wr_redo_set_file_flag_t)); + LOG_DEBUG_INF("Successfully put the set flag redo log flags:%u, curr flags:%u, node:%s, name %s", flags, + node->flags, wr_display_metaid(node->id), node->name); + } else { + LOG_DEBUG_INF("Dont put the set flag redo log flags:%u, curr flags:%u, node:%s, name %s", flags, node->flags, + wr_display_metaid(node->id), node->name); + } +} + +void wr_validate_fs_meta(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node) +{ + +} + +wr_invalidate_other_nodes_proc_t invalidate_other_nodes_proc = NULL; +wr_broadcast_check_file_open_proc_t broadcast_check_file_open_proc = NULL; + +status_t wr_invalidate_other_nodes_proc( + wr_vg_info_item_t *vg_item, char *meta_info, uint32 meta_info_size, bool32 *cmd_ack) +{ + return CM_SUCCESS; +} + +void regist_invalidate_other_nodes_proc(wr_invalidate_other_nodes_proc_t proc) +{ + invalidate_other_nodes_proc = proc; +} + +void regist_broadcast_check_file_open_proc(wr_broadcast_check_file_open_proc_t proc) +{ + broadcast_check_file_open_proc = proc; +} + +status_t wr_invalidate_fs_meta(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node) +{ + return CM_SUCCESS; +} + +status_t wr_truncate_small_init_tail(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node) +{ + if (!WR_IS_FILE_INNER_INITED(node->flags)) { + LOG_DEBUG_INF("normal file:%s fid:%llu not bitmap type, skip extend fs aux", node->name, node->fid); + return CM_SUCCESS; + } + if ((uint64)node->size == node->written_size) { + LOG_DEBUG_INF("No need to init tail to zero for file:%s, fid:%llu, ftid:%s, size:%llu, written_size:%llu", + node->name, node->fid, wr_display_metaid(node->id), (uint64)node->size, node->written_size); + return CM_SUCCESS; + } + return wr_try_write_zero_one_au("truncate small", session, vg_item, node, (int64)node->written_size); +} + +static status_t wr_truncate_to_recycle( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, wr_fs_block_t *entry_block, int64 length) +{ + return CM_SUCCESS; +} + +status_t wr_truncate_inner(wr_session_t *session, uint64 fid, ftid_t ftid, int64 length, wr_vg_info_item_t *vg_item) +{ + CM_RETURN_IFERR(wr_prepare_truncate(session, vg_item, length)); + + // update props on FT, generate new FT node in recycle with props, check v3 usage on truncate + status_t status = CM_SUCCESS; + gft_node_t *node = NULL; + wr_fs_block_t *entry_block = NULL; + wr_config_t *inst_cfg = wr_get_inst_cfg(); + + uint64 au_size = wr_get_vg_au_size(vg_item->wr_ctrl); + uint64 align_length = CM_CALC_ALIGN((uint64)length, au_size); + CM_RETURN_IFERR(wr_get_block_entry(session, vg_item, inst_cfg, fid, ftid, &node, &entry_block)); + + uint64 written_size = (uint64)length; + if ((written_size == node->written_size) && (align_length == (uint64)node->size)) { + LOG_DEBUG_INF("No truncate file:%s, size:%llu, written_size:%llu", node->name, node->size, node->written_size); + wr_unlock_vg_mem_and_shm(session, vg_item); + return CM_SUCCESS; + } + + // need to truncate to bigger + if (written_size > node->written_size) { + /* to extend the file */ + LOG_DEBUG_INF("start truncate to extend"); + status = truncate_to_extend(session, vg_item, node, length); + wr_unlock_vg_mem_and_shm(session, vg_item); + return status; + } + + wr_block_ctrl_t *block_ctrl = wr_get_block_ctrl_by_node(node); + wr_init_wr_fs_block_cache_info(&block_ctrl->fs_block_cache_info); + + // need to truncate to smaller + if (wr_invalidate_fs_meta(session, vg_item, node) != CM_SUCCESS) { + LOG_RUN_ERR("[WR] Invalid file:%s in vg:%s fail.", node->name, vg_item->vg_name); + wr_unlock_vg_mem_and_shm(session, vg_item); + return CM_ERROR; + } + + /* + * Key idea: what to check when determining that we've reached EOF during R/W? we must make sure no out-of-bound + * R/W on truncated file. Answer is the second file space block id at the truncate point should be invalid64. + * More importantly, truncated space must be recycled for re-use, meaning the metadata in .recycle must be + * generated accordingly, associated with the file space block(s) taken from the truncated file. + */ + + uint64 align_origin_length = CM_CALC_ALIGN((uint64)node->size, au_size); + bool32 need_recycle = (align_length < align_origin_length); + LOG_DEBUG_INF("To truncate %s from %lld(aligned %llu) to %lld(aligned %llu), a recycle file is %s needed.", + node->name, node->size, align_origin_length, length, align_length, (need_recycle ? "" : "not")); + if (need_recycle) { + if (wr_truncate_to_recycle(session, vg_item, node, entry_block, length) != CM_SUCCESS) { + wr_validate_fs_meta(session, vg_item, node); + wr_unlock_vg_mem_and_shm(session, vg_item); + return CM_ERROR; + } + } + wr_truncate_set_size(session, vg_item, node, length); + + if (wr_truncate_small_init_tail(session, vg_item, node) != CM_SUCCESS) { + wr_unlock_vg_mem_and_shm(session, vg_item); + LOG_RUN_ERR("[WR] ABORT INFO:truncate small init tail failed, errcode:%d, OS errno:%d, OS errmsg:%s.", + cm_get_error_code(), errno, strerror(errno)); + cm_fync_logfile(); + wr_exit(1); + } + + /* Truncating file space block completed. */ + if (wr_process_redo_log(session, vg_item) != CM_SUCCESS) { + wr_unlock_vg_mem_and_shm(session, vg_item); + LOG_RUN_ERR("[WR] ABORT INFO: redo log process failed, errcode:%d, OS errno:%d, OS errmsg:%s.", + cm_get_error_code(), errno, strerror(errno)); + cm_fync_logfile(); + wr_exit(1); + } + + // update the file ver for entry block + wr_set_fs_block_file_ver(node, entry_block); + + // re-valid the file after the truncate has been done + wr_validate_fs_meta(session, vg_item, node); + + // release resources + wr_unlock_vg_mem_and_shm(session, vg_item); + LOG_DEBUG_INF( + "Succeed to truncate file:%s, size:%llu, written_size:%llu", node->name, node->size, node->written_size); + return CM_SUCCESS; +} + +status_t wr_truncate(wr_session_t *session, uint64 fid, ftid_t ftid, int64 length, char *vg_name) +{ + wr_vg_info_item_t *vg_item = wr_find_vg_item(vg_name); + if (vg_item == NULL) { + WR_RETURN_IFERR3(CM_ERROR, LOG_DEBUG_ERR("Failed to find vg with name %s.", vg_name), + WR_THROW_ERROR(ERR_WR_VG_NOT_EXIST, vg_name)); + } + + return wr_truncate_inner(session, fid, ftid, length, vg_item); +} + +// return is true means need to retry again +bool32 wr_try_revalidate_file(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node) +{ + LOG_DEBUG_INF("Refresh file:%llu found node:%s is invalid, need refresh from primary.", node->fid, + wr_display_metaid(node->id)); + + if (wr_need_exec_local()) { + wr_validate_fs_meta(session, vg_item, node); + } else { + + } + return CM_FALSE; +} + +status_t wr_refresh_file(wr_session_t *session, uint64 fid, ftid_t ftid, char *vg_name, int64 offset) +{ + return CM_SUCCESS; +} + +void wr_init_root_fs_block(wr_ctrl_t *wr_ctrl) +{ + CM_ASSERT(wr_ctrl != NULL); + wr_fs_block_root_t *block_root = WR_GET_FS_BLOCK_ROOT(wr_ctrl); + block_root->version = 0; + block_root->free.count = 0; + wr_set_auid(&block_root->free.first, CM_INVALID_ID64); + wr_set_auid(&block_root->free.last, CM_INVALID_ID64); +} + +status_t wr_refresh_volume(wr_session_t *session, const char *name_str, uint32 vgid, uint32 volumeid) +{ + return CM_SUCCESS; +} + +status_t wr_refresh_vginfo(wr_vg_info_item_t *vg_item) +{ + return CM_SUCCESS; +} + +status_t wr_load_fs_block_by_blockid( + wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_id_t blockid, int32 size) +{ + char *block = wr_find_block_in_shm(session, vg_item, blockid, WR_BLOCK_TYPE_FS, CM_FALSE, NULL, CM_FALSE); + CM_ASSERT(block != NULL); + int64 offset = wr_get_fs_block_offset(vg_item, blockid); + status_t status = wr_get_block_from_disk(vg_item, blockid, block, offset, size, CM_TRUE); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to get block %s.", vg_item->entry_path)); + + return CM_SUCCESS; +} +status_t wr_check_rename_path(wr_session_t *session, const char *src_path, const char *dst_path, text_t *dst_name) +{ + text_t src_dir; + text_t src_name; + cm_str2text((char *)src_path, &src_name); + if (!cm_fetch_rtext(&src_name, '/', '\0', &src_dir)) { + WR_RETURN_IFERR3(CM_ERROR, LOG_DEBUG_ERR("not a complete absolute path name(%s %s)", T2S(&src_dir), src_path), + WR_THROW_ERROR(ERR_WR_FILE_RENAME, "can not change path.")); + } + + text_t dst_dir; + cm_str2text((char *)dst_path, dst_name); + if (!cm_fetch_rtext(dst_name, '/', '\0', &dst_dir)) { + WR_RETURN_IFERR2(CM_ERROR, LOG_DEBUG_ERR("not a complete absolute path name(%s %s)", T2S(&dst_dir), dst_path)); + } + + if (cm_text_equal(&src_dir, &dst_dir) == CM_FALSE) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_FILE_RENAME, "can not change path.")); + } + return CM_SUCCESS; +} + +status_t wr_check_open_file_remote(wr_session_t *session, const char *vg_name, uint64 ftid, bool32 *is_open) +{ + *is_open = CM_FALSE; + + WR_LOG_DEBUG_OP("[WR-MES-CB]Begin to check file-open %llu.", ftid); + wr_vg_info_item_t *vg_item = wr_find_vg_item(vg_name); + if (vg_item == NULL) { + WR_RETURN_IFERR3( + CM_ERROR, WR_THROW_ERROR(ERR_WR_VG_NOT_EXIST, vg_name), LOG_DEBUG_ERR("Failed to find vg, %s.", vg_name)); + } + + status_t status = wr_check_open_file(session, vg_item, ftid, is_open); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to check open file, vg:%s, ftid:%llu.", vg_name, ftid)); + return CM_SUCCESS; +} + +status_t wr_refresh_ft_block(wr_session_t *session, char *vg_name, uint32 vgid, wr_block_id_t blockid) +{ + return CM_SUCCESS; +} + +status_t wr_update_file_written_size( + wr_session_t *session, uint32 vg_id, int64 offset, int64 size, wr_block_id_t ftid, uint64 fid) +{ + status_t status = CM_SUCCESS; + wr_vg_info_item_t *vg_item = wr_find_vg_item_by_id(vg_id); + if (!vg_item) { + WR_RETURN_IFERR3(CM_ERROR, LOG_DEBUG_ERR("Failed to find vg,vg id %u.", vg_id), + WR_THROW_ERROR(ERR_WR_INVALID_ID, "vg id", (uint64)vg_id)); + } + + // when be primary, reload all the block meta by wr_refresh_buffer_cache + uint64 written_size = (uint64)(offset + size); + + gft_node_t *node = NULL; + wr_lock_vg_mem_and_shm_s(session, vg_item); + + LOG_DEBUG_INF("Begin to update file:%s fid:%llu, node size:%llu, written_size:%llu, min_inited_size:%llu with." + "offset :%lld, size:%lld", + node->name, node->fid, node->size, node->written_size, node->min_inited_size, offset, size); + + if (node->written_size >= written_size && node->min_inited_size >= written_size) { + LOG_DEBUG_INF("Skip to update file:%s fid:%llu, node size:%llu, written_size:%llu, min_inited_size:%llu with." + "offset :%lld, size:%lld", + node->name, node->fid, node->size, node->written_size, node->min_inited_size, offset, size); + wr_unlock_vg_mem_and_shm(session, vg_item); + return CM_SUCCESS; + } + + wr_ft_block_t *cur_block = wr_get_ft_by_node(node); + + bool32 has_updt_min_written_size = CM_FALSE; + bool32 has_updt_written_size = CM_FALSE; + + // prevent changeed by other task + wr_latch_x_node(session, node, NULL); + if (WR_IS_FILE_INNER_INITED(node->flags) && (uint64)offset <= node->min_inited_size && + (written_size > node->min_inited_size)) { + node->min_inited_size = written_size; + has_updt_min_written_size = CM_TRUE; + } + + if (node->written_size < written_size) { + // when both truncate to 0 and update to written)size reach primary form diff node, may truncat process at first + uint64 written_size_real = written_size > (uint64)node->size ? (uint64)node->size : written_size; + node->written_size = node->written_size > written_size_real ? node->written_size : written_size_real; + + has_updt_written_size = CM_TRUE; + } + + if (has_updt_min_written_size || has_updt_written_size) { + status = wr_update_ft_block_disk(vg_item, cur_block, node->id); + if (status != CM_SUCCESS) { + wr_unlatch_node(node); + wr_unlock_vg_mem_and_shm(session, vg_item); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Fail to update written_size:%llu of file:%s, node size:%llu.", + node->written_size, node->name, node->size)); + } + } + + LOG_DEBUG_INF("End to update file:%s fid:%llu, node size:%llu, written_size:%llu, min_inited_size:%llu with." + "offset :%lld, size:%lld", + node->name, node->fid, node->size, node->written_size, node->min_inited_size, offset, size); + + wr_unlatch_node(node); + wr_unlock_vg_mem_and_shm(session, vg_item); + + return CM_SUCCESS; +} + +void wr_clean_all_sessions_latch() +{ + uint64 cli_pid = 0; + int64 start_time = 0; + bool32 cli_pid_alived = 0; + uint32 sid = 0; + wr_session_t *session = NULL; + + // check all used && connected session may occopy latch by dead client + wr_session_ctrl_t *session_ctrl = wr_get_session_ctrl(); + CM_ASSERT(session_ctrl != NULL); + while (sid < session_ctrl->alloc_sessions && sid < session_ctrl->total) { + session = wr_get_session(sid); + CM_ASSERT(session != NULL); + // ready next session + sid++; + // connected make sure the cli_pid and start_time are valid + if (!session->is_used || !session->connected) { + continue; + } + + if (session->cli_info.cli_pid == 0 || + (session->cli_info.cli_pid == cli_pid && start_time == session->cli_info.start_time && cli_pid_alived)) { + continue; + } + + cli_pid = session->cli_info.cli_pid; + start_time = session->cli_info.start_time; + cli_pid_alived = cm_sys_process_alived(cli_pid, start_time); + if (cli_pid_alived) { + continue; + } + LOG_RUN_INF("[CLEAN_LATCH]session id %u, pid %llu, start_time %lld, process name:%s, objectid %u.", session->id, + cli_pid, start_time, session->cli_info.process_name, session->objectid); + // clean the session lock and latch + if (!cm_spin_try_lock(&session->lock)) { + continue; + } + while (!cm_spin_timed_lock(&session->shm_lock, WR_SERVER_SESS_TIMEOUT)) { + // unlock if the client goes offline + cm_spin_unlock(&session->shm_lock); + LOG_RUN_INF("Succeed to unlock session %u shm lock", session->id); + cm_sleep(CM_SLEEP_500_FIXED); + } + LOG_DEBUG_INF("Succeed to lock session %u shm lock", session->id); + wr_clean_session_latch(session, CM_TRUE); + wr_server_session_unlock(session); + } +} + +gft_node_t *wr_get_next_node(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node) +{ + if (wr_cmp_blockid(node->next, CM_INVALID_ID64)) { + return NULL; + } + return wr_get_ft_node_by_ftid(session, vg_item, node->next, CM_TRUE, CM_FALSE); +} + +bool32 wr_is_last_tree_node(gft_node_t *node) +{ + return (node->type != GFT_PATH || node->items.count == 0); +} + +status_t wr_block_data_oper(char *op_desc, bool32 is_write, wr_vg_info_item_t *vg_item, wr_block_id_t block_id, + uint64 offset, char *data_buf, int32 size) +{ + status_t status; + wr_volume_t volume = vg_item->volume_handle[block_id.volume]; + if (volume.handle == WR_INVALID_HANDLE) { + status = wr_open_volume( + vg_item->wr_ctrl->volume.defs[block_id.volume].name, NULL, WR_INSTANCE_OPEN_FLAG, &volume); + WR_RETURN_IFERR2( + status, LOG_DEBUG_ERR("open volume %s failed.", vg_item->wr_ctrl->volume.defs[block_id.volume].name)); + vg_item->volume_handle[block_id.volume] = volume; + } + + int64 vol_offset = wr_get_au_offset(vg_item, block_id) + (uint32)offset; + if (is_write) { + status = wr_write_volume(&volume, vol_offset, data_buf, size); + } else { + status = wr_read_volume(&volume, vol_offset, data_buf, size); + } + if (status != CM_SUCCESS) { + LOG_RUN_ERR( + "%s volume failed, volume:%s, vol_offset:%lld, buf_size:%d", op_desc, volume.name, vol_offset, size); + return CM_ERROR; + } + WR_LOG_DEBUG_OP("%s data, volume:%s, vol_offset:%lld, auid:%llu, buf_size:%d", op_desc, volume.name, vol_offset, + WR_ID_TO_U64(block_id), size); + return CM_SUCCESS; +} + +status_t wr_data_oper(char *op_desc, bool32 is_write, wr_vg_info_item_t *vg_item, auid_t auid, uint32 au_offset, + char *data_buf, int32 size) +{ + uint32 au_size = (uint32)wr_get_vg_au_size(vg_item->wr_ctrl); + if (au_offset >= au_size || (au_offset + (uint32)size) > au_size || ((uint64)data_buf % WR_DISK_UNIT_SIZE) != 0) { + LOG_RUN_ERR("%s data para error", op_desc); + return CM_ERROR; + } + + return wr_block_data_oper(op_desc, is_write, vg_item, auid, au_offset, data_buf, size); +} + +status_t wr_write_zero2au(char *op_desc, wr_vg_info_item_t *vg_item, uint64 fid, auid_t auid, uint32 au_offset) +{ + char *zero_buf = wr_get_zero_buf(); + uint32 zero_buf_len = wr_get_zero_buf_len(); + LOG_DEBUG_INF("Try to write zero for fid:%llu to auid:%s au_offset:%u.", fid, wr_display_metaid(auid), au_offset); + uint64 au_size = wr_get_vg_au_size(vg_item->wr_ctrl); + do { + int32 write_size = (int32)((au_size - au_offset) < zero_buf_len ? (au_size - au_offset) : zero_buf_len); + status_t ret = wr_data_oper(op_desc, CM_TRUE, vg_item, auid, au_offset, zero_buf, write_size); + if (ret != CM_SUCCESS) { + return ret; + } + au_offset += (uint32)write_size; + } while (au_offset < au_size); + return CM_SUCCESS; +} + +status_t wr_try_write_zero_one_au( + char *desc, wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, int64 offset) +{ + return CM_SUCCESS; +} + +status_t wr_calculate_vg_usage(wr_session_t *session, wr_vg_info_item_t *vg_item, uint32 *usage) +{ + return CM_SUCCESS; +} + +void wr_alarm_check_vg_usage(wr_session_t *session) +{ + return; +} \ No newline at end of file diff --git a/src/common/wr_file.h b/src/common/wr_file.h new file mode 100644 index 0000000000000000000000000000000000000000..a84e8ddb174f9df3e5f4aa41e1aa04e62193cece --- /dev/null +++ b/src/common/wr_file.h @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_file.h + * + * + * IDENTIFICATION + * src/common/wr_file.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_FILE_H_ +#define __WR_FILE_H_ + +#include "wr_file_def.h" +#include "wr_diskgroup.h" +#include "wr_alloc_unit.h" +#include "wr_param.h" +#include "wr_meta_buf.h" +#include "wr_session.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_wr_node_data { + uint64 fid; + ftid_t ftid; + int64 offset; + int64 size; + int32 mode; + uint32 vgid; + char *vg_name; +} wr_node_data_t; + +status_t wr_make_dir(wr_session_t *session, const char *dir_name); +status_t wr_open_dir(wr_session_t *session, const char *dir_path, bool32 is_refresh, wr_find_node_t *find_info); +void wr_close_dir(wr_session_t *session, char *vg_name, uint64 ftid); +status_t wr_find_vg_by_dir(const char *dir_path, char *name, wr_vg_info_item_t **vg_item); + +void wr_lock_vg_mem_s_and_shm_x(wr_session_t *session, wr_vg_info_item_t *vg_item); +void wr_lock_vg_mem_and_shm_x(wr_session_t *session, wr_vg_info_item_t *vg_item); +void wr_lock_vg_mem_and_shm_x2ix(wr_session_t *session, wr_vg_info_item_t *vg_item); +void wr_lock_vg_mem_and_shm_ix2x(wr_session_t *session, wr_vg_info_item_t *vg_item); +void wr_lock_vg_mem_and_shm_s(wr_session_t *session, wr_vg_info_item_t *vg_item); +void wr_lock_vg_mem_and_shm_s_force(wr_session_t *session, wr_vg_info_item_t *vg_item); +void wr_unlock_vg_mem_and_shm(wr_session_t *session, wr_vg_info_item_t *vg_item); +void wr_lock_vg_mem_and_shm_ex_s(wr_session_t *session, char *vg_name); +void wr_unlock_vg_mem_and_shm_ex(wr_session_t *session, char *vg_name); + +status_t wr_create_file(wr_session_t *session, const char *parent, const char *name, int32_t flag); +status_t wr_exist_item(wr_session_t *session, const char *item, bool32 *result, gft_item_type_t *output_type); +status_t wr_open_file(wr_session_t *session, const char *file, int32_t flag, wr_find_node_t *find_info); +status_t wr_close_file(wr_session_t *session, wr_vg_info_item_t *vg_item, uint64 ftid); +status_t wr_extend_inner(wr_session_t *session, wr_node_data_t *node_data); +status_t wr_extend(wr_session_t *session, wr_node_data_t *node_data); +status_t wr_do_fallocate(wr_session_t *session, wr_node_data_t *node_data); +status_t wr_truncate(wr_session_t *session, uint64 fid, ftid_t ftid, int64 length, char *vg_name); +status_t wr_refresh_file(wr_session_t *session, uint64 fid, ftid_t ftid, char *vg_name, int64 offset); +status_t wr_refresh_volume(wr_session_t *session, const char *name_str, uint32 vgid, uint32 volumeid); +status_t wr_refresh_ft_block(wr_session_t *session, char *vg_name, uint32 vgid, wr_block_id_t blockid); +status_t wr_update_file_written_size( + wr_session_t *session, uint32 vg_id, int64 offset, int64 size, wr_block_id_t ftid, uint64 fid); +status_t wr_get_ftid_by_path(wr_session_t *session, const char *path, ftid_t *ftid, wr_vg_info_item_t **dir_vg_item); +gft_node_t *wr_get_gft_node_by_path( + wr_session_t *session, wr_vg_info_item_t *vg_item, const char *path, wr_vg_info_item_t **dir_vg_item); +// for wr internal call +status_t wr_alloc_ft_au_when_no_free( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_root_t *gft, bool32 *check_version); +void wr_check_ft_node_free(gft_node_t *node); +status_t wr_alloc_ft_node_when_create_vg( + wr_vg_info_item_t *vg_item, gft_node_t *parent_node, const char *name, gft_item_type_t type, uint32 flags); + +status_t wr_format_ft_node(wr_session_t *session, wr_vg_info_item_t *vg_item, auid_t auid); +void wr_free_ft_node_inner( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *parent_node, gft_node_t *node, bool32 real_del); +void wr_free_ft_node( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *parent_node, gft_node_t *node, bool32 real_del); +gft_node_t *wr_get_next_node(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node); +bool32 wr_is_last_tree_node(gft_node_t *node); +void wr_delay_clean_all_vg(wr_session_t *session); +gft_node_t *wr_find_ft_node( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *parent_node, const char *name, bool8 skip_del); +gft_node_t *wr_get_ft_node_by_ftid( + wr_session_t *session, wr_vg_info_item_t *vg_item, ftid_t id, bool32 check_version, bool32 active_refresh); +gft_node_t *wr_get_ft_node_by_ftid_from_disk_and_refresh_shm( + wr_session_t *session, wr_vg_info_item_t *vg_item, ftid_t id); +gft_node_t *wr_get_ft_node_by_ftid_no_refresh(wr_session_t *session, wr_vg_info_item_t *vg_item, ftid_t id); +status_t wr_update_ft_block_disk(wr_vg_info_item_t *vg_item, wr_ft_block_t *block, ftid_t id); +int64 wr_get_ft_block_offset(wr_vg_info_item_t *vg_item, ftid_t id); +char *wr_get_ft_block_by_ftid(wr_session_t *session, wr_vg_info_item_t *vg_item, ftid_t id); +status_t wr_refresh_root_ft(wr_vg_info_item_t *vg_item, bool32 check_version, bool32 active_refresh); + +status_t wr_update_au_disk( + wr_vg_info_item_t *vg_item, auid_t auid, ga_pool_id_e pool_id, uint32 first, uint32 count, uint32 size); +// for tool or instance +void wr_init_ft_root(wr_ctrl_t *wr_ctrl, gft_node_t **out_node); +status_t wr_update_ft_root(wr_vg_info_item_t *vg_item); +status_t wr_refresh_ft(wr_session_t *session, wr_vg_info_item_t *vg_item); +status_t wr_check_refresh_ft(wr_vg_info_item_t *vg_item); +status_t wr_alloc_ft_au(wr_session_t *session, wr_vg_info_item_t *vg_item, ftid_t *id); + +typedef struct st_wr_alloc_fs_block_info { + bool8 is_extend; + bool8 is_new_au; + uint16_t index; + gft_node_t *node; +} wr_alloc_fs_block_info_t; +status_t wr_alloc_fs_block( + wr_session_t *session, wr_vg_info_item_t *vg_item, char **block, wr_alloc_fs_block_info_t *info); +void wr_free_fs_block_addr(wr_session_t *session, wr_vg_info_item_t *vg_item, char *block, ga_obj_id_t obj_id); +int64 wr_get_fs_block_offset(wr_vg_info_item_t *vg_item, wr_block_id_t blockid); +status_t wr_update_fs_bitmap_block_disk( + wr_vg_info_item_t *item, wr_fs_block_t *block, uint32 size, bool32 had_checksum); +status_t wr_format_bitmap_node(wr_session_t *session, wr_vg_info_item_t *vg_item, auid_t auid); +status_t wr_check_refresh_fs_block( + wr_vg_info_item_t *vg_item, wr_block_id_t blockid, char *block, bool32 *is_changed); +void wr_init_root_fs_block(wr_ctrl_t *wr_ctrl); +status_t wr_load_fs_block_by_blockid( + wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_id_t blockid, int32 size); + +void wr_init_fs_block_head(wr_fs_block_t *fs_block); + +status_t wr_check_rename_path(wr_session_t *session, const char *src_path, const char *dst_path, text_t *dst_name); +status_t wr_get_name_from_path(const char *path, uint32_t *beg_pos, char *name); +status_t wr_check_dir(wr_session_t *session, const char *dir_path, gft_item_type_t type, + wr_check_dir_output_t *output_info, bool32 is_throw_err); + +wr_env_t *wr_get_env(void); +wr_config_t *wr_get_inst_cfg(void); +status_t wr_get_root_version(wr_vg_info_item_t *vg_item, uint64 *version); +status_t wr_check_name(const char *name); +status_t wr_check_path(const char *path); +status_t wr_check_volume_path(const char *path); +status_t wr_check_device_path(const char *path); +status_t wr_check_path_both(const char *path); + +status_t wr_refresh_vginfo(wr_vg_info_item_t *vg_item); + +/* AU is usually NOT serial/continuous within a single file, judged from R/W file behaviors */ +status_t wr_get_fs_block_info_by_offset( + int64 offset, uint64 au_size, uint32 *block_count, uint32 *block_au_count, uint32 *au_offset); +status_t wr_check_open_file_remote(wr_session_t *session, const char *vg_name, uint64 ftid, bool32 *is_open); +status_t wr_check_file(wr_vg_info_item_t *vg_item); + +status_t wr_check_rm_file( + wr_session_t *session, wr_vg_info_item_t *vg_item, ftid_t ftid, bool32 *should_rm_file, gft_node_t **file_node); + +void wr_set_node_flag( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, bool32 is_set, uint32 flags); +void wr_validate_fs_meta(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node); +status_t wr_invalidate_fs_meta(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node); + +static inline bool32 wr_is_node_deleted(gft_node_t *node) +{ + return (node->flags & WR_FT_NODE_FLAG_DEL); +} + +static inline bool32 wr_is_fs_meta_valid(gft_node_t *node) +{ + return !(node->flags & WR_FT_NODE_FLAG_INVALID_FS_META); +} + +static inline bool32 wr_is_fs_block_valid(gft_node_t *node, wr_fs_block_t *fs_block) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(fs_block); + return ((node->fid == block_ctrl->fid) && (node->file_ver == block_ctrl->file_ver) && + (block_ctrl->ftid == WR_ID_TO_U64(node->id))); +} + +static inline void wr_set_fs_block_file_ver(gft_node_t *node, wr_fs_block_t *fs_block) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(fs_block); + block_ctrl->fid = node->fid; + block_ctrl->ftid = WR_ID_TO_U64(node->id); + block_ctrl->file_ver = node->file_ver; + block_ctrl->node = (char *)node; +} + +static inline uint64 wr_get_fs_block_fid(wr_fs_block_t *fs_block) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(fs_block); + return block_ctrl->fid; +} + +static inline uint64 wr_get_fs_block_file_ver(wr_fs_block_t *fs_block) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(fs_block); + return block_ctrl->file_ver; +} + +static inline int64 wr_get_fsb_offset(uint32 au_size, const wr_block_id_t *id) +{ + return ((int64)id->au * au_size + (int64)WR_FILE_SPACE_BLOCK_SIZE * id->block); +} + +static inline int64 wr_get_ftb_offset(uint32 au_size, const wr_block_id_t *id) +{ + if ((id->au) == 0) { + return (int64)WR_CTRL_ROOT_OFFSET; + } + return (int64)((uint64)id->au * au_size + (uint64)WR_BLOCK_SIZE * id->block); +} + +static inline int64 wr_get_fab_offset(uint32 au_size, wr_block_id_t block_id) +{ + return (int64)(WR_FS_AUX_SIZE * block_id.block + au_size * block_id.au); +} + +static inline wr_ft_block_t *wr_get_ft_by_node(gft_node_t *node) +{ + CM_ASSERT(node != NULL); + + if ((node->id.au) == 0 && node->id.block == 0) { + return (wr_ft_block_t *)(((char *)node - sizeof(wr_root_ft_block_t)) - (node->id.item * sizeof(gft_node_t))); + } + + return (wr_ft_block_t *)(((char *)node - sizeof(wr_ft_block_t)) - (node->id.item * sizeof(gft_node_t))); +} + +static inline gft_node_t *wr_get_node_by_ft(wr_ft_block_t *block, uint32 item) +{ + return (gft_node_t *)(((char *)block + sizeof(wr_ft_block_t)) + item * sizeof(gft_node_t)); +} + +static inline gft_node_t *wr_get_node_by_block_ctrl(wr_block_ctrl_t *block, uint32 item) +{ + wr_ft_block_t *ft_block = WR_GET_META_FROM_BLOCK_CTRL(wr_ft_block_t, block); + return (gft_node_t *)((((char *)ft_block) + sizeof(wr_ft_block_t)) + item * sizeof(gft_node_t)); +} + +static inline bool32 wr_is_ft_block_valid(gft_node_t *node, wr_ft_block_t *ft_block) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(ft_block); + return ((block_ctrl->node != NULL) && (node->fid == block_ctrl->fid) && (node->file_ver == block_ctrl->file_ver) && + (block_ctrl->ftid == WR_ID_TO_U64(node->id))); +} + +static inline void wr_set_ft_block_file_ver(gft_node_t *node, wr_ft_block_t *ft_block) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(ft_block); + block_ctrl->fid = node->fid; + block_ctrl->ftid = WR_ID_TO_U64(node->id); + block_ctrl->file_ver = node->file_ver; + block_ctrl->node = (char *)node; +} + +static inline uint64 wr_get_ft_block_fid(wr_ft_block_t *ft_block) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(ft_block); + return block_ctrl->fid; +} + +static inline uint64 wr_get_ft_block_file_ver(wr_ft_block_t *ft_block) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(ft_block); + return block_ctrl->file_ver; +} + +static inline bool32 wr_is_block_ctrl_valid(wr_block_ctrl_t *block_ctrl) +{ + gft_node_t *node = NULL; + if (block_ctrl->type == WR_BLOCK_TYPE_FT) { + node = wr_get_node_by_block_ctrl(block_ctrl, 0); + return (((node->flags & WR_FT_NODE_FLAG_DEL) == 0) && (node->fid == block_ctrl->fid)); + } else { + node = (gft_node_t *)block_ctrl->node; + return ((node != NULL) && ((node->flags & WR_FT_NODE_FLAG_DEL) == 0) && (node->fid == block_ctrl->fid) && + (node->file_ver == block_ctrl->file_ver) && (block_ctrl->ftid == WR_ID_TO_U64(node->id))); + } +} + +static inline bool32 wr_get_is_refresh_ftid(gft_node_t *node) +{ + wr_ft_block_t *ft_block = wr_get_ft_by_node(node); + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(ft_block); + return block_ctrl->is_refresh_ftid; +} + +static inline void wr_set_is_refresh_ftid(gft_node_t *node, bool32 is_refresh_ftid) +{ + wr_ft_block_t *ft_block = wr_get_ft_by_node(node); + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(ft_block); + block_ctrl->is_refresh_ftid = is_refresh_ftid; +} + +static inline bool32 is_ft_root_block(ftid_t ftid) +{ + return ftid.au == 0 && ftid.block == 0; +} + +static inline wr_block_ctrl_t *wr_get_block_ctrl_by_node(gft_node_t *node) +{ + if (is_ft_root_block(node->id)) { + return NULL; + } + wr_ft_block_t *ft_block = + (wr_ft_block_t *)(((char *)node - node->id.item * sizeof(gft_node_t)) - sizeof(wr_ft_block_t)); + return WR_GET_BLOCK_CTRL_FROM_META(ft_block); +} + +static inline void wr_latch_node_init(gft_node_t *node) +{ + wr_block_ctrl_t *block_ctrl = wr_get_block_ctrl_by_node(node); + WR_ASSERT_LOG(block_ctrl != NULL, "block_ctrl is NULL when init latch because node is root block"); + cm_latch_init(&block_ctrl->latch); +} + +static inline void wr_latch_s_node(wr_session_t *session, gft_node_t *node, latch_statis_t *stat) +{ + wr_block_ctrl_t *block_ctrl = wr_get_block_ctrl_by_node(node); + WR_ASSERT_LOG(block_ctrl != NULL, "block_ctrl is NULL when latch s node because node is root block"); + wr_latch_s2(&block_ctrl->latch, WR_SESSIONID_IN_LOCK(session->id), CM_FALSE, stat); +} + +static inline void wr_latch_x_node(wr_session_t *session, gft_node_t *node, latch_statis_t *stat) +{ + wr_block_ctrl_t *block_ctrl = wr_get_block_ctrl_by_node(node); + WR_ASSERT_LOG(block_ctrl != NULL, "block_ctrl is NULL when latch x node because node is root block"); + cm_latch_x(&block_ctrl->latch, WR_SESSIONID_IN_LOCK(session->id), stat); +} + +static inline void wr_unlatch_node(gft_node_t *node) +{ + wr_block_ctrl_t *block_ctrl = wr_get_block_ctrl_by_node(node); + WR_ASSERT_LOG(block_ctrl != NULL, "block_ctrl is NULL when unlatch node because node is root block"); + wr_unlatch(&block_ctrl->latch); +} +static inline wr_file_context_t *wr_get_file_context_by_handle(wr_file_run_ctx_t *file_run_ctx, int32 handle) +{ + return &file_run_ctx->files.files_group[handle / WR_FILE_CONTEXT_PER_GROUP][handle % WR_FILE_CONTEXT_PER_GROUP]; +} +// this is need to re-consturct the code-file-place +typedef status_t (*wr_invalidate_other_nodes_proc_t)( + wr_vg_info_item_t *vg_item, char *meta_info, uint32 meta_info_size, bool32 *cmd_ack); +status_t wr_invalidate_other_nodes_proc( + wr_vg_info_item_t *vg_item, char *meta_info, uint32 meta_info_size, bool32 *cmd_ack); +void regist_invalidate_other_nodes_proc(wr_invalidate_other_nodes_proc_t proc); +typedef status_t (*wr_broadcast_check_file_open_proc_t)(wr_vg_info_item_t *vg_item, uint64 ftid, bool32 *cmd_ack); +void regist_broadcast_check_file_open_proc(wr_broadcast_check_file_open_proc_t proc); + +void wr_clean_all_sessions_latch(); + +status_t wr_block_data_oper(char *op_desc, bool32 is_write, wr_vg_info_item_t *vg_item, wr_block_id_t block_id, + uint64 offset, char *data_buf, int32 size); +status_t wr_data_oper(char *op_desc, bool32 is_write, wr_vg_info_item_t *vg_item, auid_t auid, uint32 au_offset, + char *data_buf, int32 size); +status_t wr_write_zero2au(char *op_desc, wr_vg_info_item_t *vg_item, uint64 fid, auid_t auid, uint32 au_offset); +status_t wr_try_write_zero_one_au( + char *desc, wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, int64 offset); +void wr_alarm_check_vg_usage(wr_session_t *session); +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/common/wr_filesystem.c b/src/common/wr_filesystem.c new file mode 100644 index 0000000000000000000000000000000000000000..7077bb1bf1aa0954b0b503eb7e4c1e2edcdb47d4 --- /dev/null +++ b/src/common/wr_filesystem.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_volume.c + * + * + * IDENTIFICATION + * src/common/wr_filesystem.c + * + * ------------------------------------------------------------------------- + */ +#include "wr_filesystem.h" +#ifndef WIN32 +#include +#include +#include +#endif // !WIN32 +#include "wr_file.h" +#include "wr_thv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +status_t wr_filesystem_mkdir(const char *name, mode_t mode) +{ + if (mkdir(name, mode) != 0) { + LOG_RUN_ERR("[FS]Failed to mkdir %s.", name); + return CM_ERROR; + } + return CM_SUCCESS; +} + +status_t wr_filesystem_rmdir(const char *name) +{ + if (rmdir(name) != 0) { + LOG_RUN_ERR("[FS]Failed to rmdir %s.", name); + return CM_ERROR; + } + return CM_SUCCESS; +} + +status_t wr_filesystem_touch(const char *name) +{ + FILE *file = fopen(name, "w"); + if (file) { + fclose(file); + } else { + LOG_RUN_ERR("[FS]Failed to touch %s.", name); + return CM_ERROR; + } + return CM_SUCCESS; +} + +status_t wr_filesystem_rm(const char *name) +{ + if (unlink(name) != 0) { + LOG_RUN_ERR("[FS]Failed to rm %s.", name); + return CM_ERROR; + } + return CM_SUCCESS; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/common/wr_filesystem.h b/src/common/wr_filesystem.h new file mode 100644 index 0000000000000000000000000000000000000000..dc600a7d20e39be4d66b3232cbe5eb71870ff811 --- /dev/null +++ b/src/common/wr_filesystem.h @@ -0,0 +1,21 @@ +#ifndef __WR_FILESYSTEM_H__ +#define __WR_FILESYSTEM_H__ + +#include "wr_defs.h" +#include "cm_date.h" +#include "wr_file_def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +status_t wr_filesystem_mkdir(const char *name, mode_t mode); +status_t wr_filesystem_rmdir(const char *name); +status_t wr_filesystem_touch(const char *name); +status_t wr_filesystem_rm(const char *name); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/wr_ga.c b/src/common/wr_ga.c new file mode 100644 index 0000000000000000000000000000000000000000..3ea1b6d30f550233012487ed3912052f08ff38ce --- /dev/null +++ b/src/common/wr_ga.c @@ -0,0 +1,572 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * cm_ga.c + * + * + * IDENTIFICATION + * src/common/cm_ga.c + * + * ------------------------------------------------------------------------- + */ + +#include "cm_defs.h" +#include "cm_debug.h" +#include "cm_log.h" +#include "wr_defs.h" +#include "wr_errno.h" +#include "wr_ga.h" + +char *g_app_area_addr; + +int32 g_sys_shm_id = -1; +int32 g_app_shm_id = -1; + +spinlock_t g_ga_attach_mutex = 0; + +// clang-format off +ga_pool_t g_app_pools[GA_APP_POOL_COUNT] = { + {"ctrl", NULL, NULL, NULL, NULL, {NULL}, {1, GA_INSTANCE_POOL_SIZE, 0}, 0, 0}, /* ctrl pool */ + {"sesseion", NULL, NULL, NULL, NULL, {NULL}, {0, 0, 0}, 0, 0}, /* inst pool */ + {"meta 8k", NULL, NULL, NULL, NULL, {NULL}, {0, 0, 0}, 0, 0}, /* 8k pool */ + {"meta 16k", NULL, NULL, NULL, NULL, {NULL}, {0, 0, 0}, 0, 0}, /* 16k pool */ + {"fs aux", NULL, NULL, NULL, NULL, {NULL}, {0, 0, 0}, 0, 0}, /* fs aux */ + {"hash segment", NULL, NULL, NULL, NULL, {NULL}, {0, 0, 0}, 0, 0}, /* hash segment */ +}; + +ga_pool_t g_app_pools_initial[GA_APP_POOL_COUNT] = { + {"ctrl", NULL, NULL, NULL, NULL, {NULL}, {1, GA_INSTANCE_POOL_SIZE, 0}, 0, 0}, /* ctrl pool */ + {"sesseion", NULL, NULL, NULL, NULL, {NULL}, {0, 0, 0}, 0, 0}, /* inst pool */ + {"meta 8k", NULL, NULL, NULL, NULL, {NULL}, {0, 0, 0}, 0, 0}, /* 8k pool */ + {"meta 16k", NULL, NULL, NULL, NULL, {NULL}, {0, 0, 0}, 0, 0}, /* 16k pool */ + {"fs aux", NULL, NULL, NULL, NULL, {NULL}, {0, 0, 0}, 0, 0}, /* fs aux */ + {"hash segment", NULL, NULL, NULL, NULL, {NULL}, {0, 0, 0}, 0, 0}, /* hash segment */ +}; + +void ga_reset_app_pools() +{ + (void)memcpy_s(g_app_pools, sizeof(g_app_pools), g_app_pools_initial, sizeof(g_app_pools_initial)); +} + +// clang-format on +static inline ga_pool_t *ga_get_pool(uint32 id) +{ + return &g_app_pools[GA_POOL_IDX(id)]; +} + +void ga_set_pool_def(ga_pool_id_e pool_id, const ga_pool_def_t *def) +{ + ga_pool_t *pool; + CM_ASSERT(def != NULL); + pool = ga_get_pool((uint32)pool_id); + pool->def = *def; + pool->capacity = CM_ALIGN_512((uint32)sizeof(ga_pool_ctrl_t)); + pool->capacity += CM_ALIGN_512(((ulong)def->object_size + (uint32)sizeof(ga_object_map_t)) * def->object_count); + LOG_RUN_INF("Succeed to init pool %s, object count is %u, object size is %u, ex_max is %u.", pool->pool_name, + pool->def.object_count, pool->def.object_size, pool->def.ex_max); +} + +static inline ga_object_map_t *ga_object_map(ga_pool_t *pool, uint32 object_id) +{ + uint32 ex_pool_id; + ga_object_map_t *ex_object_map; + + CM_ASSERT(pool != NULL); + + if (pool->ctrl->ex_count == 0 || object_id < pool->def.object_count) { + return &pool->object_map[object_id]; + } else { + ex_pool_id = (object_id / pool->def.object_count) - 1; + ex_object_map = (ga_object_map_t *)pool->ex_pool_addr[ex_pool_id]; + return &ex_object_map[object_id % pool->def.object_count]; + } +} + +static void ga_append_into_queue(ga_pool_t *pool, ga_queue_t *queue, uint32 object_id) +{ + ga_object_map_t *obj_map = ga_object_map(pool, object_id); + + CM_ASSERT(pool != NULL && queue != NULL); + + if (queue->count == 0) { + queue->count = 1; + queue->first = object_id; + queue->last = object_id; + obj_map->next = CM_INVALID_ID32; + obj_map->prior = CM_INVALID_ID32; + return; + } + + ga_object_map(pool, queue->last)->next = object_id; + obj_map->prior = queue->last; + obj_map->next = CM_INVALID_ID32; + queue->last = object_id; + queue->count++; +} + +void ga_append_into_queue_by_pool_id(ga_pool_id_e pool_id, ga_queue_t *queue, uint32 object_id) +{ + ga_pool_t *pool = ga_get_pool(pool_id); + ga_append_into_queue(pool, queue, object_id); +} + +static uint32 ga_remove_from_queue(ga_pool_t *pool, ga_queue_t *queue) +{ + uint32 object_id; + + CM_ASSERT(pool != NULL); + CM_ASSERT(queue != NULL); + + if (queue->count == 0) { + return CM_INVALID_ID32; + } + + object_id = queue->first; + queue->first = ga_object_map(pool, object_id)->next; + queue->count--; + if (queue->count > 0) { + ga_object_map(pool, queue->first)->prior = CM_INVALID_ID32; + } + + return object_id; +} + +static void ga_concat_queue(ga_pool_t *pool, ga_queue_t *queue1, ga_queue_t *queue2) +{ + CM_ASSERT(pool != NULL); + CM_ASSERT(queue1 != NULL); + CM_ASSERT(queue2 != NULL); + + if (queue1->count == 0) { + *queue1 = *queue2; + } else { + ga_object_map(pool, queue1->last)->next = queue2->first; + ga_object_map(pool, queue2->first)->prior = queue1->last; + queue1->count += queue2->count; + queue1->last = queue2->last; + } +} + +static void ga_init_pool(ga_offset_t offset, ga_pool_t *pool) +{ + uint32 i, object_offset; + CM_ASSERT(pool != NULL); + + pool->addr = g_app_area_addr + offset; + + object_offset = (uint32)sizeof(ga_pool_ctrl_t) + pool->def.object_count * (uint32)sizeof(ga_object_map_t); + pool->object_addr = pool->addr + object_offset; + + pool->ctrl = (ga_pool_ctrl_t *)pool->addr; + pool->object_map = (ga_object_map_t *)(pool->addr + (uint32)sizeof(ga_pool_ctrl_t)); + + pool->object_map[0].prior = CM_INVALID_ID32; + + for (i = 0; i < pool->def.object_count - 1; i++) { + pool->object_map[i].next = i + 1; + pool->object_map[(uint32)(i + 1)].prior = i; + } + + pool->object_map[pool->def.object_count - 1].next = CM_INVALID_ID32; + + GS_INIT_SPIN_LOCK(pool->ctrl->mutex); + pool->ctrl->def = pool->def; + pool->ctrl->offset = offset; + pool->ctrl->ex_count = 0; + + pool->ctrl->free_objects.count = pool->def.object_count; + pool->ctrl->free_objects.first = 0; + pool->ctrl->free_objects.last = pool->def.object_count - 1; +} + +status_t ga_create_global_area(void) +{ + uint64 app_area_size, offset; + uint32 i; + uint64 *pool_offsets; + + app_area_size = CM_ALIGN_512(GA_APP_POOL_COUNT * (uint32)sizeof(ulong)); + for (i = 0; i < GA_APP_POOL_COUNT; i++) { + if (g_app_pools[i].capacity == 0) { + LOG_RUN_ERR("The application pool %u is not defined.", i); + return ERR_WR_GA_INIT; + } + + app_area_size += g_app_pools[i].capacity; + } + + g_app_area_addr = (char *)cm_get_shm(SHM_TYPE_FIXED, (uint32)SHM_ID_APP_GA, app_area_size, CM_SHM_ATTACH_RW); + if (g_app_area_addr == NULL) { + LOG_RUN_ERR("Can't create the application area because of failed to get shm, area size = %llu.", app_area_size); + return ERR_WR_GA_INIT; + } + + offset = CM_ALIGN_512(GA_APP_POOL_COUNT * (uint32)sizeof(ulong)); + pool_offsets = (uint64 *)g_app_area_addr; + + for (i = 0; i < GA_APP_POOL_COUNT; i++) { + pool_offsets[i] = offset; + ga_init_pool(offset, &g_app_pools[i]); + offset += g_app_pools[i].capacity; + } + LOG_RUN_INF("Create global area successfully."); + return CM_SUCCESS; +} + +void ga_destroy_global_area(void) +{ + uint32 i; + + for (i = 0; i < CM_GA_SHM_MAX_ID; i++) { + (void)cm_del_shm(SHM_TYPE_GA, i); + } + + (void)cm_del_shm(SHM_TYPE_FIXED, (uint32)SHM_ID_APP_GA); +} + +static status_t ga_attach_pool(ga_pool_id_e id, uint32 attach_perm) +{ + uint32 i, object_offset; + char *area_addr; + ga_pool_t *pool = &g_app_pools[id]; + ulong *pool_offsets; + + area_addr = g_app_area_addr; + pool_offsets = (ulong *)area_addr; + + pool->addr = area_addr + pool_offsets[id]; + pool->ctrl = (ga_pool_ctrl_t *)(pool->addr); + pool->object_map = (ga_object_map_t *)(pool->addr + (uint32)sizeof(ga_pool_ctrl_t)); + pool->def = pool->ctrl->def; + + object_offset = (uint32)sizeof(ga_pool_ctrl_t) + pool->def.object_count * (uint32)sizeof(ga_object_map_t); + pool->object_addr = pool->addr + object_offset; + + if (pool->ctrl->ex_count > GA_MAX_EXTENDED_POOLS) { + LOG_RUN_ERR("Invalid pool info[id=%u] from shared memory: ex_count is %u, larger than maximum %u", id, + pool->ctrl->ex_count, GA_MAX_EXTENDED_POOLS); + return CM_ERROR; + } + + for (i = 0; i < GA_MAX_EXTENDED_POOLS; i++) { + pool->ex_pool_addr[i] = NULL; + } + + for (i = 0; i < pool->ctrl->ex_count; i++) { + pool->ex_pool_addr[i] = (char *)cm_attach_shm(SHM_TYPE_GA, (uint32)pool->ctrl->ex_shm_id[i], 0, attach_perm); + } + return CM_SUCCESS; +} + +status_t ga_attach_area(uint32 attach_perm) +{ + uint32 i = 0; + + if (cm_get_shm_ctrl_flag() != CM_SHM_CTRL_FLAG_TRUE) { + WR_RETURN_IFERR2(CM_ERROR, LOG_RUN_ERR("Can not attach the global area because the server is not ready yet.")); + } + + g_app_area_addr = (char *)cm_attach_shm(SHM_TYPE_FIXED, (uint32)SHM_ID_APP_GA, 0, attach_perm); + if (g_app_area_addr == NULL) { + WR_RETURN_IFERR2(CM_ERROR, LOG_RUN_ERR("can't attach the application area.")); + } + + for (i = 0; i < GA_APP_POOL_COUNT; i++) { + if (ga_attach_pool((ga_pool_id_e)i, attach_perm) != CM_SUCCESS) { + return CM_ERROR; + } + } + + return CM_SUCCESS; +} + +static void ga_detach_pool(ga_pool_id_e id) +{ + ga_pool_t *pool = &g_app_pools[id]; + uint32 i; + + if (!pool->ctrl) { + return; + } + + if (pool->ctrl->ex_count > GA_MAX_EXTENDED_POOLS) { + LOG_RUN_ERR("Invalid pool info[id=%u]: ex_count is %u, larger than maximum %u", id, pool->ctrl->ex_count, + GA_MAX_EXTENDED_POOLS); + return; + } + + for (i = 0; i < pool->ctrl->ex_count; i++) { + if (pool->ex_pool_addr[i] != NULL) { + (void)cm_detach_shm(SHM_TYPE_GA, (uint32)pool->ctrl->ex_shm_id[i]); + } + } +} + +void ga_detach_area(void) +{ + uint32 i = 0; + + for (i = 0; i < GA_APP_POOL_COUNT; i++) { + ga_detach_pool((ga_pool_id_e)i); + } + + (void)cm_detach_shm(SHM_TYPE_FIXED, (uint32)SHM_ID_APP_GA); +} + +uint32 ga_get_pool_usage(ga_pool_id_e pool_id) +{ + ga_pool_t *pool = &g_app_pools[GA_POOL_IDX(pool_id)]; + + if (pool == NULL || pool->ctrl == NULL) { + return 0; + } + uint64 max_usable_obj_cnt = (uint64)(pool->ctrl->def.ex_max + 1) * pool->ctrl->def.object_count; + uint64 max_init_obj_cnt = (uint64)(pool->ctrl->ex_count + 1) * pool->ctrl->def.object_count; + uint32 usage = (uint32)((max_init_obj_cnt - pool->ctrl->free_objects.count) * GA_USAGE_UNIT) / max_usable_obj_cnt; + return usage; +} + +static status_t ga_extend_pool(ga_pool_id_e pool_id) +{ + ulong ex_pool_size; + uint32 ex_start_id, object_id, object_cost, i; + char *ex_addr; + ga_queue_t ex_objects; + ga_pool_t *pool = ga_get_pool((uint32)pool_id); + ga_object_map_t *object_map; + uint32 pool_shm_id = GA_EXT_SHM_POOLID(pool_id) * GA_MAX_EXTENDED_POOLS + pool->ctrl->ex_count; + + if (pool->def.ex_max <= pool->ctrl->ex_count) { + WR_RETURN_IFERR2(CM_ERROR, + LOG_RUN_ERR("the extended number of %s pool reach to limitation %u.", pool->pool_name, pool->def.ex_max)); + } + + object_cost = pool->def.object_size + (uint32)sizeof(ga_object_map_t); + ex_pool_size = (ulong)object_cost * pool->def.object_count; + + ex_addr = (char *)cm_get_shm(SHM_TYPE_GA, pool_shm_id, ex_pool_size, CM_SHM_ATTACH_RW); + if (ex_addr == NULL) { + WR_RETURN_IFERR2( + CM_ERROR, LOG_RUN_ERR("get shared memory in failure when extending the %s pool.", pool->pool_name)); + } + + pool->ctrl->ex_shm_id[pool->ctrl->ex_count] = (int32)pool_shm_id; + pool->ex_pool_addr[pool->ctrl->ex_count] = ex_addr; + ex_start_id = (pool->ctrl->ex_count + 1) * pool->def.object_count; + + pool->ctrl->ex_count++; + + object_map = (ga_object_map_t *)ex_addr; + + object_map[0].prior = CM_INVALID_ID32; + + for (i = 0; i < pool->def.object_count - 1; i++) { + object_id = ex_start_id + i; + object_map[i].next = object_id + 1; + object_map[(uint32)(i + 1)].prior = object_id; + } + + object_map[(uint32)(pool->def.object_count - 1)].next = CM_INVALID_ID32; + + ex_objects.first = ex_start_id; + ex_objects.last = ex_start_id + pool->def.object_count - 1; + ex_objects.count = pool->def.object_count; + + ga_concat_queue(pool, &pool->ctrl->free_objects, &ex_objects); + + return CM_SUCCESS; +} + +uint32 ga_alloc_object(ga_pool_id_e pool_id, uint32 specific_id) +{ + uint32 object_id, next_id, prior_id; + ga_pool_t *pool = ga_get_pool((uint32)pool_id); + + cm_spin_lock(&pool->ctrl->mutex, NULL); + + if (pool->ctrl->free_objects.count == 0) { + if (pool->def.ex_max == 0) { + cm_spin_unlock(&pool->ctrl->mutex); + return CM_INVALID_ID32; + } + + if (ga_extend_pool(pool_id) != CM_SUCCESS) { + cm_spin_unlock(&pool->ctrl->mutex); + return CM_INVALID_ID32; + } + } + + if (specific_id != CM_INVALID_ID32) { + next_id = pool->object_map[specific_id].next; + prior_id = pool->object_map[specific_id].prior; + + if (next_id != CM_INVALID_ID32) { + pool->object_map[next_id].prior = prior_id; + } + + if (prior_id != CM_INVALID_ID32) { + pool->object_map[prior_id].next = next_id; + } + + if (pool->ctrl->free_objects.first == specific_id) { + pool->ctrl->free_objects.first = next_id; + } + + if (pool->ctrl->free_objects.last == specific_id) { + pool->ctrl->free_objects.last = prior_id; + } + + pool->ctrl->free_objects.count--; + object_id = specific_id; + } else { + object_id = ga_remove_from_queue(pool, &pool->ctrl->free_objects); + } + + cm_spin_unlock(&pool->ctrl->mutex); + + return object_id; +} + +int32 ga_alloc_object_list(ga_pool_id_e pool_id, uint32 count, ga_queue_t *list) +{ + uint32 last_id, i; + status_t status; + ga_pool_t *pool = ga_get_pool((uint32)pool_id); + + CM_ASSERT(list != NULL); + GA_INIT_QUEUE(list); + + if (count == 0) { + return CM_SUCCESS; + } + + cm_spin_lock(&pool->ctrl->mutex, NULL); + + while (pool->ctrl->free_objects.count < count) { + status = ga_extend_pool(pool_id); + WR_RETURN_IFERR3( + status, cm_spin_unlock(&pool->ctrl->mutex), LOG_DEBUG_ERR("Failed to extend pool:%u.", pool_id)); + LOG_DEBUG_INF("Extend pool:%u, free_obj_count:%u, count:%u.", pool_id, pool->ctrl->free_objects.count, count); + } + + if (pool->ctrl->free_objects.count == count) { + *list = pool->ctrl->free_objects; + GA_INIT_QUEUE(&pool->ctrl->free_objects); + } else { + list->first = pool->ctrl->free_objects.first; + list->count = count; + + last_id = list->first; + for (i = 1; i < count; i++) { + last_id = ga_object_map(pool, last_id)->next; + } + list->last = last_id; + + pool->ctrl->free_objects.first = ga_object_map(pool, last_id)->next; + + ga_object_map(pool, list->last)->next = CM_INVALID_ID32; + ga_object_map(pool, pool->ctrl->free_objects.first)->prior = CM_INVALID_ID32; + + pool->ctrl->free_objects.count -= count; + } + + cm_spin_unlock(&pool->ctrl->mutex); + + return CM_SUCCESS; +} +uint32 ga_next_object(ga_pool_id_e pool_id, uint32 object_id) +{ + ga_pool_t *pool = ga_get_pool((uint32)pool_id); + return ga_object_map(pool, object_id)->next; +} + +void ga_free_object(ga_pool_id_e pool_id, uint32 object_id) +{ + ga_pool_t *pool = ga_get_pool((uint32)pool_id); + + // For test cursor free mutiply times + CM_ASSERT(object_id != CM_INVALID_ID32); + + cm_spin_lock(&pool->ctrl->mutex, NULL); + ga_append_into_queue(pool, &pool->ctrl->free_objects, object_id); + cm_spin_unlock(&pool->ctrl->mutex); +} + +void ga_free_object_list(ga_pool_id_e pool_id, ga_queue_t *list) +{ + ga_pool_t *pool = ga_get_pool((uint32)pool_id); + CM_ASSERT(list != NULL); + + if (list->count == 0) { + return; + } + cm_spin_lock(&pool->ctrl->mutex, NULL); + ga_concat_queue(pool, &pool->ctrl->free_objects, list); + cm_spin_unlock(&pool->ctrl->mutex); +} + +// clang-format off +#define GA_MAIN_POOL_OBJECT_OFFSET(pool, object_id) \ + ((ga_offset_t)(CM_ALIGN_512(sizeof(ga_pool_ctrl_t) + \ + (ga_offset_t)(pool)->def.object_count * (ga_offset_t)sizeof(ga_object_map_t)) + \ + (ga_offset_t)(object_id) * (ga_offset_t)(pool)->def.object_size)) + +// clang-format on +char *ga_object_addr(ga_pool_id_e pool_id, uint32 object_id) +{ + ulong offset; + uint32 ex_pool_id; + ga_pool_t *pool = ga_get_pool((uint32)pool_id); + + if (object_id < pool->def.object_count) { + return pool->addr + GA_MAIN_POOL_OBJECT_OFFSET(pool, object_id); + } + + if (pool->ctrl->ex_count == 0) { + return NULL; + } else { + offset = CM_ALIGN_512((ga_offset_t)pool->def.object_count * (ga_offset_t)sizeof(ga_object_map_t)); + offset += (ga_offset_t)(object_id % pool->def.object_count) * (ga_offset_t)pool->def.object_size; + ex_pool_id = object_id / pool->def.object_count - 1; + if (ex_pool_id >= pool->ctrl->ex_count) { + return NULL; + } + if (pool->ex_pool_addr[ex_pool_id] == NULL) { + cm_spin_lock(&g_ga_attach_mutex, NULL); + if (pool->ex_pool_addr[ex_pool_id] == NULL) { + pool->ex_pool_addr[ex_pool_id] = + (char *)cm_attach_shm(SHM_TYPE_GA, (uint32)pool->ctrl->ex_shm_id[ex_pool_id], 0, CM_SHM_ATTACH_RW); + } + + cm_spin_unlock(&g_ga_attach_mutex); + } + + if (pool->ex_pool_addr[ex_pool_id] == NULL) { + return NULL; + } + + return pool->ex_pool_addr[ex_pool_id] + offset; + } +} + +cm_shm_key_t ga_object_key(ga_pool_id_e pool_id, uint32 object_id) +{ + ga_pool_t *pool = ga_get_pool((uint32)pool_id); + if (object_id < pool->def.object_count) { + return cm_shm_key_of(SHM_TYPE_FIXED, SHM_ID_APP_GA); + } + uint32 ex_pool_id = object_id / pool->def.object_count - 1; + return cm_shm_key_of(SHM_TYPE_GA, (uint32)pool->ctrl->ex_shm_id[ex_pool_id]); +} \ No newline at end of file diff --git a/src/common/wr_ga.h b/src/common/wr_ga.h new file mode 100644 index 0000000000000000000000000000000000000000..f3140cbfec84ad689ed97f287b2d9d2a4b827040 --- /dev/null +++ b/src/common/wr_ga.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_ga.h + * + * + * IDENTIFICATION + * src/common/wr_ga.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_GA_H_ +#define __WR_GA_H_ + +#include "cm_types.h" +#include "cm_defs.h" +#include "cm_spinlock.h" +#include "cm_error.h" +#include "wr_shm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GA_NULL (ulong)0 +#define GA_MAX_EXTENDED_POOLS 1024 +#define GA_MAX_8K_EXTENDED_POOLS 16 +#define GA_MAX_SESSION_EXTENDED_POOLS (uint32)(WR_MAX_SESSIONS / WR_SESSION_NUM_PER_GROUP) + +#define GA_SYS_AREA ((uint32)0x01000000) /* no extended pools */ +#define GA_APP_AREA ((uint32)0x02000000) /* including extended pools */ + +#define GA_EXT_SHM_POOLID(id) ((id) - (GA_APP_AREA)) + +#define GA_APP_POOL_COUNT 6 + +#define GA_INSTANCE_POOL_SIZE (uint32)(1048576) /* 1M */ + +#if defined(_DEBUG) || defined(DEBUG) || defined(DB_DEBUG_VERSION) +#define GA_USAGE_UNIT (CM_100X_FIXED * CM_100X_FIXED) +#else +#define GA_USAGE_UNIT (CM_100X_FIXED) +#endif + +typedef uint64 ga_offset_t; + +typedef enum tagga_pool_name { + GA_INSTANCE_POOL = GA_APP_AREA, + GA_SESSION_POOL = (GA_APP_AREA + 1), + GA_8K_POOL = (GA_APP_AREA + 2), + GA_16K_POOL = (GA_APP_AREA + 3), + GA_FS_AUX_POOL = (GA_APP_AREA + 4), + GA_SEGMENT_POOL = (GA_APP_AREA + 5), +} ga_pool_id_e; + +typedef struct tagga_object_map { + uint32 next; + uint32 prior; +} ga_object_map_t; + +typedef struct tagga_queue { + uint32 count; + uint32 first; + uint32 last; +} ga_queue_t; + +#define GA_INIT_QUEUE(queue) \ + do { \ + (queue)->count = 0; \ + (queue)->first = CM_INVALID_ID32; \ + (queue)->last = CM_INVALID_ID32; \ + } while (0) + +typedef struct tagga_pool_def { + uint32 object_count; + uint32 object_size; + uint32 ex_max; /* the max number of extended pools */ +} ga_pool_def_t; + +typedef struct tagga_pool_ctrl { + spinlock_t mutex; + ga_pool_def_t def; + uint64 offset; + ga_queue_t free_objects; + uint32 ex_count; + int32 ex_shm_id[GA_MAX_EXTENDED_POOLS]; +} ga_pool_ctrl_t; + +typedef struct tagga_pool { + char *pool_name; + char *addr; + char *object_addr; + ga_pool_ctrl_t *ctrl; + ga_object_map_t *object_map; + char *ex_pool_addr[GA_MAX_EXTENDED_POOLS]; + ga_pool_def_t def; + uint64 capacity; + uint32 ex_attach_count; +} ga_pool_t; + +/* text in global area */ +typedef struct tagga_text { + uint32 len; + ga_offset_t str; +} ga_text_t; + +/* word in global area */ +typedef struct tagga_word { + ga_text_t word_name; + uint32 word_type; + uint32 id; +} ga_word_t; + +#define GA_POOL_IDX(id) ((uint32)(id) & (uint32)0x00FFFFFF) + +typedef struct st_ga_obj_id_t { + ga_pool_id_e pool_id; + uint32 obj_id; +} ga_obj_id_t; + +extern ga_pool_t g_app_pools[GA_APP_POOL_COUNT]; +void ga_reset_app_pools(); +void ga_set_pool_def(ga_pool_id_e pool_id, const ga_pool_def_t *def); +status_t ga_create_global_area(void); +void ga_destroy_global_area(void); +int32 ga_attach_area(uint32 attach_perm); +void ga_detach_area(void); +uint32 ga_get_pool_usage(ga_pool_id_e pool_id); + +void ga_append_into_queue_by_pool_id(ga_pool_id_e pool_id, ga_queue_t *queue, uint32 object_id); +uint32 ga_alloc_object(ga_pool_id_e pool_id, uint32 specific_id); +int32 ga_alloc_object_list(ga_pool_id_e pool_id, uint32 count, ga_queue_t *list); +void ga_free_object(ga_pool_id_e pool_id, uint32 object_id); +void ga_free_object_list(ga_pool_id_e pool_id, ga_queue_t *list); +char *ga_object_addr(ga_pool_id_e pool_id, uint32 object_id); +cm_shm_key_t ga_object_key(ga_pool_id_e pool_id, uint32 object_id); +uint32 ga_next_object(ga_pool_id_e pool_id, uint32 object_id); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/wr_hashmap.c b/src/common/wr_hashmap.c new file mode 100644 index 0000000000000000000000000000000000000000..594b370e14a70de48c37f896f653952ee9f2e37f --- /dev/null +++ b/src/common/wr_hashmap.c @@ -0,0 +1,543 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * cm_hashmap.c + * + * + * IDENTIFICATION + * src/common/cm_hashmap.c + * + * ------------------------------------------------------------------------- + */ + +#include "cm_error.h" +#include "cm_hash.h" +#include "cm_log.h" +#include "wr_errno.h" +#include "wr_malloc.h" +#include "wr_hashmap.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define HASH_MASK 0x3fffffff + +// clang-format off +static uint32 const cm_primes[] = { + 7, + 13, + 31, + 61, + 127, + 251, + 509, + 1021, + 1297, + 2039, + 4093, + 8191, + 16381, + 32749, + 65521, + 131071, + 262139, + 524287, + 1048573, + 2097143, + 4194301, + 8388593, + 16777213, + 33554393, + 67108859, + 134217689, + 268435399, + 536870909, + 1073741789, + 2147483647, + 0xfffffffb +}; + +// clang-format on +uint32 cm_hash_int64(int64 i64) +{ + uint32 u32l = (uint32)i64; + uint32 u32h = (uint32)((uint64)i64 >> 32); + + u32l ^= (i64 >= 0) ? u32h : ~u32h; + + return cm_hash_uint32_shard(u32l); +} + +uint32 cm_hash_text(const text_t *text, uint32 range) +{ + return cm_hash_bytes((uint8 *)text->str, text->len, range); +} + +uint32 cm_hash_string(const char *str, uint32 range) +{ + return cm_hash_bytes((uint8 *)str, (uint32)strlen(str), range); +} + +bool32 cm_oamap_ptr_compare(void *key1, void *key2) +{ + CM_ASSERT(key1 != NULL && key2 != NULL); + return (key1 == key2); +} + +bool32 cm_oamap_uint64_compare(void *key1, void *key2) +{ + CM_ASSERT(key1 != NULL && key2 != NULL); + return (*(uint64 *)key1 == *(uint64 *)key2); +} + +bool32 cm_oamap_uint32_compare(void *key1, void *key2) +{ + CM_ASSERT(key1 != NULL); + CM_ASSERT(key2 != NULL); + return (*(uint32 *)key1 == *(uint32 *)key2); +} + +bool32 cm_oamap_string_compare(void *key1, void *key2) +{ + CM_ASSERT(key1 != NULL); + CM_ASSERT(key2 != NULL); + return (strcmp((char *)key1, (char *)key2) == 0); +} + +static uint32 oamap_get_near_prime(unsigned long n) +{ + uint32 low = 0; + uint32 cnt = (uint32)(sizeof(cm_primes) / sizeof(uint32)); + uint32 high = cnt; + + while (low != high) { + unsigned int mid = low + (high - low) / 2; + if (n > cm_primes[mid]) { + low = mid + 1; + } else { + high = mid; + } + } + if (low < cnt) { + return cm_primes[low]; + } else { + return (uint32)n; + } +} + +static void oamap_rehash_core(cm_oamap_t *map, uint32 new_capacity, cm_oamap_bucket_t *new_buckets, uint32 *used) +{ + bool32 found; + uint32 i, j, start; + cm_oamap_bucket_t *src_bucket, *dst_bucket; + + if (new_capacity == 0) { + cm_panic(0); + } + void **new_key = (void **)(new_buckets + new_capacity); + void **new_value = (void **)(new_key + new_capacity); + for (i = 0; i < map->num; i++) { + src_bucket = &(map->buckets[i]); + if (src_bucket->state != (uint32)USED) { + continue; + } + start = src_bucket->hash % new_capacity; + found = CM_FALSE; + for (j = start; j < new_capacity; j++) { + dst_bucket = &new_buckets[j]; + if (dst_bucket->state != (uint32)USED) { + *dst_bucket = *src_bucket; + new_key[j] = map->key[i]; + new_value[j] = map->value[i]; + found = CM_TRUE; + (*used)++; + break; + } + } + if (found) { + continue; + } + while (start > 0) { + start--; + dst_bucket = &new_buckets[start]; + if (dst_bucket->state != (uint32)USED) { + *dst_bucket = *src_bucket; + new_key[start] = map->key[i]; + new_value[start] = map->value[i]; + found = CM_TRUE; + (*used)++; + break; + } + } + } +} + +static int32 oamap_rehash(cm_oamap_t *map, uint32 new_capacity) +{ + CM_ASSERT(map != NULL); + uint32 used = 0; + if (new_capacity == 0) { + return ERR_WR_INVALID_PARAM; + } + + uint64 size = new_capacity * (uint64)(sizeof(cm_oamap_bucket_t) + sizeof(void *) + sizeof(void *)); + if (size >= CM_INVALID_ID32) { + LOG_DEBUG_ERR("Invalid capacity value specified for rehashing map."); + return ERR_WR_INVALID_PARAM; + } + + cm_oamap_bucket_t *new_buckets = (cm_oamap_bucket_t *)cm_malloc((uint32)size); + if (new_buckets == NULL) { + LOG_DEBUG_ERR("Malloc failed"); + return CM_ERROR; + } + void **new_key = (void **)(new_buckets + new_capacity); + void **new_value = (void **)(new_key + new_capacity); + + for (uint32 i = 0; i < new_capacity; i++) { + new_buckets[i].state = (uint32)FREE; + new_key[i] = NULL; + new_value[i] = NULL; + } + oamap_rehash_core(map, new_capacity, new_buckets, &used); + + cm_free(map->buckets); + map->buckets = new_buckets; + map->key = new_key; + map->value = new_value; + map->num = new_capacity; + map->deleted = 0; + map->used = used; + return CM_SUCCESS; +} + +void cm_oamap_init_mem(cm_oamap_t *map) +{ + if (map == NULL) { + LOG_DEBUG_ERR("Null pointer specified"); + return; + } + + map->buckets = NULL; + map->key = NULL; + map->value = NULL; + map->num = 0; + map->used = 0; + map->deleted = 0; + map->compare_func = NULL; +} + +int32 cm_oamap_init( + cm_oamap_t *map, uint32 init_capacity, cm_oamap_compare_t compare_func /* , memory_context_t *mem_ctx */) +{ + uint64 size; + uint32 i; + if (map == NULL || compare_func == NULL) { + LOG_DEBUG_ERR("Null pointer specified"); + return ERR_WR_INVALID_PARAM; + } + // The max oamap + map->num = oamap_get_near_prime(init_capacity); + if (map->num >= MAX_OAMAP_BUCKET_NUM) { + LOG_DEBUG_ERR("Invalid bucket num specified"); + return ERR_WR_INVALID_PARAM; + } + map->used = 0; + size = map->num * (uint32)(sizeof(cm_oamap_bucket_t) + sizeof(void *) + sizeof(void *)); + if (size >= CM_INVALID_ID32) { + LOG_DEBUG_ERR("Invalid map size"); + return ERR_WR_INVALID_PARAM; + } + map->compare_func = compare_func; + map->buckets = (cm_oamap_bucket_t *)cm_malloc((uint32)size); + if (map->buckets == NULL) { + LOG_DEBUG_ERR("Malloc failed"); + return CM_ERROR; + } + map->key = (void **)(map->buckets + map->num); + map->value = (void **)(map->key + map->num); + + for (i = 0; i < map->num; i++) { + map->buckets[i].state = (uint32)FREE; + map->key[i] = NULL; + map->value[i] = NULL; + } + map->deleted = 0; + return CM_SUCCESS; +} + +void cm_oamap_destroy(cm_oamap_t *map) +{ + CM_ASSERT(map != NULL); + map->num = 0; + map->deleted = 0; + map->used = 0; + + if (map->buckets != NULL) { + cm_free(map->buckets); + map->buckets = NULL; + } + + map->compare_func = NULL; +} + +static int32 cm_oamap_find_pos_forward(cm_oamap_t *map, uint32 hash, void *key, bool32 *found_pos, uint32 *insert_pos) +{ + cm_oamap_bucket_t *cm_oamap_bucket; + uint32 start = hash % map->num; + while (start > 0) { + start--; + cm_oamap_bucket = &(map->buckets[start]); + if (cm_oamap_bucket->state == (uint32)FREE) { + if (!(*found_pos)) { + // find a new free pos to insert. so need to update the used counter + map->used++; + *found_pos = CM_TRUE; + *insert_pos = start; + } + break; + } else if (cm_oamap_bucket->state == (uint32)DELETED) { + if (!(*found_pos)) { + // find a deleted pos to reuse for insert. so need to update the deleted counter + map->deleted--; + *found_pos = CM_TRUE; + *insert_pos = start; + } + } else { + if (cm_oamap_bucket->hash == hash && map->compare_func(map->key[start], key) == CM_TRUE) { + LOG_DEBUG_ERR("Duplicate key being inserted"); + return ERR_WR_OAMAP_INSERT_DUP_KEY; + } + } + } + return CM_SUCCESS; +} + +static int32 cm_oamap_insert_core(cm_oamap_t *map, uint32 hash, void *key, void *value) +{ + uint32 i; + cm_oamap_bucket_t *cm_oamap_bucket; + bool32 found_free = CM_FALSE; + bool32 found_pos = CM_FALSE; + uint32 insert_pos = 0; + uint32 start = hash % map->num; + for (i = start; i < map->num; i++) { + cm_oamap_bucket = &(map->buckets[i]); + if (cm_oamap_bucket->state == (uint32)FREE) { + found_free = CM_TRUE; + if (!found_pos) { + // find a new free pos to insert. so need to update the used counter + map->used++; + found_pos = CM_TRUE; + insert_pos = i; + } + break; + } else if (cm_oamap_bucket->state == (uint32)DELETED) { + if (!found_pos) { + // find a deleted pos to reuse for insert. so need to udpate the deleted counter + map->deleted--; + found_pos = CM_TRUE; + insert_pos = i; + } + } else { + if (cm_oamap_bucket->hash == hash && map->compare_func(map->key[i], key)) { + LOG_DEBUG_ERR("Duplicate key being inserted, i:%u, hash:%u", i, hash); + return ERR_WR_OAMAP_INSERT_DUP_KEY; + } + } + } + if (!found_free) { + CM_RETURN_IFERR(cm_oamap_find_pos_forward(map, hash, key, &found_pos, &insert_pos)); + } + + if (found_pos) { + cm_oamap_bucket = &(map->buckets[insert_pos]); + cm_oamap_bucket->hash = hash; + cm_oamap_bucket->state = (uint32)USED; + map->key[insert_pos] = key; + map->value[insert_pos] = value; + return CM_SUCCESS; + } + LOG_DEBUG_ERR("Insertion failed"); + return ERR_WR_OAMAP_INSERT; +} + +int32 cm_oamap_insert(cm_oamap_t *map, uint32 hash, void *key, void *value) +{ + int32 ret; + uint32 new_size; + if (map == NULL) { + LOG_DEBUG_ERR("Pointer to map is NULL"); + return ERR_WR_INVALID_PARAM; + } + if ((map->used - map->deleted) * 3 > map->num * 2) { + new_size = oamap_get_near_prime(map->num + 1); + if (new_size > MAX_OAMAP_BUCKET_NUM) { + LOG_DEBUG_ERR("Invalid bucket num specified"); + return ERR_WR_INVALID_PARAM; + } + ret = oamap_rehash(map, new_size); + if (ret != CM_SUCCESS) { + LOG_DEBUG_ERR("OAMAP rehash failed,%d.", ret); + return ret; + } + } + hash = hash & HASH_MASK; + return cm_oamap_insert_core(map, hash, key, value); +} + +void *cm_oamap_lookup(cm_oamap_t *map, uint32 hash, void *key) +{ + uint32 i, start; + cm_oamap_bucket_t *bucket; + + if (map == NULL) { + LOG_DEBUG_ERR("Pointer to map is NULL"); + return NULL; + } + + if (map->num == 0) { + LOG_DEBUG_ERR("The map is not initialized."); + return NULL; + } + + hash = hash & HASH_MASK; + start = hash % map->num; + + for (i = start; i < map->num; i++) { + bucket = &(map->buckets[i]); + if (bucket->state == (uint32)FREE) { + return NULL; + } else if (bucket->state == (uint32)USED) { + if (bucket->hash == hash && map->compare_func(map->key[i], key) == CM_TRUE) { + return map->value[i]; + } + } else { + // for lint + } + } + + while (start > 0) { + start--; + bucket = &(map->buckets[start]); + if (bucket->state == (uint32)FREE) { + return NULL; + } else if (bucket->state == (uint32)USED) { + if (bucket->hash == hash && map->compare_func(map->key[start], key) == CM_TRUE) { + return map->value[start]; + } + } else { + // for lint + } + } + return NULL; +} + +void *cm_oamap_remove(cm_oamap_t *map, uint32 hash, void *key) +{ + uint32 i, start; + cm_oamap_bucket_t *bucket; + void *value = NULL; + if (map == NULL) { + LOG_DEBUG_ERR("Pointer to map is NULL"); + return NULL; + } + + hash = hash & HASH_MASK; + start = hash % map->num; + for (i = start; i < map->num; i++) { + bucket = &(map->buckets[i]); + if (bucket->state == (uint32)FREE) { + return NULL; + } else if (bucket->state == (uint32)USED) { + if (bucket->hash == hash && map->compare_func(map->key[i], key) == CM_TRUE) { + bucket->hash = 0; + bucket->state = (uint32)DELETED; + map->deleted++; + value = map->value[i]; + map->key[i] = NULL; + map->value[i] = NULL; + return value; + } + } else { + // for lint + } + } + + while (start > 0) { + start--; + bucket = &(map->buckets[start]); + if (bucket->state == (uint32)FREE) { + return NULL; + } else if (bucket->state == (uint32)USED) { + if (bucket->hash == hash && map->compare_func(map->key[start], key) == CM_TRUE) { + bucket->hash = 0; + bucket->state = (uint32)DELETED; + map->deleted++; + value = map->value[start]; + map->key[start] = NULL; + map->value[start] = NULL; + return value; + } + } else { + // for lint + } + } + LOG_DEBUG_ERR("Key to remove not found"); + return value; +} + +void cm_oamap_reset_iterator(cm_oamap_iterator_t *iter) +{ + CM_ASSERT(iter != NULL); + *iter = 0; +} + +int32 cm_oamap_fetch(cm_oamap_t *map, cm_oamap_iterator_t *iter, void **key, void **value) +{ + uint32 i; + cm_oamap_bucket_t *bucket; + + CM_ASSERT(map != NULL); + CM_ASSERT(iter != NULL); + CM_ASSERT(key != NULL); + CM_ASSERT(value != NULL); + + for (i = *iter; i < map->num; i++) { + bucket = &(map->buckets[i]); + if (bucket->state == (uint32)USED) { + *key = map->key[i]; + *value = map->value[i]; + *iter = i + 1; + return CM_SUCCESS; + } + } + + *key = NULL; + *value = NULL; + *iter = map->num; + return ERR_WR_OAMAP_FETCH; +} + +uint32 cm_oamap_size(cm_oamap_t *map) +{ + CM_ASSERT(map != NULL); + return map->num; +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ diff --git a/src/common/wr_hashmap.h b/src/common/wr_hashmap.h new file mode 100644 index 0000000000000000000000000000000000000000..0e643b5020c8418662e60e809e6f9f89f9efc77d --- /dev/null +++ b/src/common/wr_hashmap.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_hashmap.h + * + * + * IDENTIFICATION + * src/common/wr_hashmap.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_HASHMAP_H__ +#define __WR_HASHMAP_H__ + +#include "cm_types.h" +#include "cm_text.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// should not too big.it will allow to insert max node in oa map is MAX_OAMAP_NUM +#define MAX_OAMAP_BUCKET_NUM (1024 * 1024 * 2) +typedef uint32 (*cm_oamap_hash_t)(void *key); +typedef bool32 (*cm_oamap_compare_t)(void *key1, void *key2); +typedef uint32 cm_oamap_iterator_t; + +typedef enum tag_cm_oamap_bucket_state { + FREE, + USED, + DELETED, +} cm_oamap_bucket_state_e; + +// open address map is use for small numbers of key map +typedef struct tag_cm_oamap_bucket { + uint32 hash : 30; + uint32 state : 2; +} cm_oamap_bucket_t; + +typedef struct tag_cm_oamap { + cm_oamap_bucket_t *buckets; + void **key; + void **value; + uint32 num; + uint32 used; + uint32 deleted; + cm_oamap_compare_t compare_func; +} cm_oamap_t; + +// mem_ctx == NULL will use the standard malloc and free +void cm_oamap_init_mem(cm_oamap_t *map); + +int32 cm_oamap_init( + cm_oamap_t *map, uint32 init_capacity, cm_oamap_compare_t compare_func /* , memory_context_t *mem_ctx */); + +void cm_oamap_destroy(cm_oamap_t *map); + +int32 cm_oamap_insert(cm_oamap_t *map, uint32 hash, void *key, void *value); + +void *cm_oamap_lookup(cm_oamap_t *map, uint32 hash, void *key); + +void *cm_oamap_remove(cm_oamap_t *map, uint32 hash, void *key); + +void cm_oamap_reset_iterator(cm_oamap_iterator_t *iter); + +int32 cm_oamap_fetch(cm_oamap_t *map, cm_oamap_iterator_t *iter, void **key, void **value); + +bool32 cm_oamap_ptr_compare(void *key1, void *key2); + +bool32 cm_oamap_uint64_compare(void *key1, void *key2); + +bool32 cm_oamap_uint32_compare(void *key1, void *key2); + +bool32 cm_oamap_string_compare(void *key1, void *key2); + +uint32 cm_oamap_size(cm_oamap_t *map); + +uint32 cm_hash_uint32_shard(uint32 val); +uint32 cm_hash_int64(int64 i64); +uint32 cm_hash_text(const text_t *text, uint32 range); +uint32 cm_hash_string(const char *str, uint32 range); + +#ifdef __cplusplus +} +#endif + +#endif /* __WR_HASHMAP_H__ */ diff --git a/src/common/wr_io_fence.c b/src/common/wr_io_fence.c new file mode 100644 index 0000000000000000000000000000000000000000..46f3f80d5d5331c32fe270dd610b03989059bf99 --- /dev/null +++ b/src/common/wr_io_fence.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_io_fence.c + * + * + * IDENTIFICATION + * src/common/wr_io_fence.c + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#include "wr_log.h" +#include "wr_io_fence.h" + +#ifdef IOFENCE + +static void print_dev_info(ptlist_t *devs) +{ + return; +} + +static void print_reg_info(ptlist_t *regs) +{ + return; +} + +static status_t wr_modify_cluster_node_info( + wr_vg_info_item_t *vg_item, wr_config_t *inst_cfg, wr_inq_status_e inq_status, int64 host_id) +{ + return CM_SUCCESS; +} + +status_t wr_get_vg_non_entry_info( + wr_config_t *inst_cfg, wr_vg_info_item_t *vg_item, bool32 is_lock, bool32 check_redo) +{ + return CM_SUCCESS; +} + +status_t wr_inq_lun(const char *home) +{ + return CM_SUCCESS; +} + +status_t wr_inq_reg(const char *home) +{ + return CM_SUCCESS; +} + +bool32 is_register(iof_reg_in_t *reg, int64 host_id, int64 *iofence_key) +{ + return WR_FALSE; +} + +status_t wr_check_volume_register(char *entry_path, int64 host_id, bool32 *is_reg, int64 *iofence_key) +{ + return CM_SUCCESS; +} + +static status_t wr_reghl_inner(wr_vg_info_item_t *item, int64 host_id) +{ + return CM_SUCCESS; +} + +static void wr_printf_iofence_key(int64 *iofence_key) +{ + return; +} + +status_t wr_reghl_core(const char *home) +{ + return CM_SUCCESS; +} + +static status_t wr_unreghl_inner(wr_vg_info_item_t *item, int64 host_id) +{ + return CM_SUCCESS; +} + +status_t wr_unreghl_core(const char *home, bool32 is_lock) +{ + return CM_SUCCESS; +} + +static status_t wr_inq_reg_inner(wr_vg_info_t *vg_info, wr_config_t *inst_cfg, int64 host_id, int64 *iofence_key) +{ + return CM_PIPECLOSED; +} + +status_t wr_inq_reg_core(const char *home, int64 host_id) +{ + return CM_PIPECLOSED; +} + +static status_t wr_clean_inner(wr_vg_info_t *vg_info, wr_config_t *inst_cfg, int64 inst_id) +{ + return CM_SUCCESS; +} + +status_t wr_check_disk_latch_remain_inner( + int64 inst_id, wr_vg_info_t *vg_info, bool32 *is_remain, uint64 *latch_status) +{ + return CM_SUCCESS; +} + +status_t wr_check_lock_remain(wr_vg_info_t *vg_info, int32 wr_mode, int64 inst_id) +{ + return CM_SUCCESS; +} + +status_t wr_check_disk_latch_remain(int64 inst_id, wr_vg_info_t *vg_info) +{ + return CM_SUCCESS; +} + +static status_t wr_get_latch_flag(int64 type, uint64 *flags) +{ + return CM_SUCCESS; +} + +status_t wr_query_latch_remain(const char *home, int64 inst_id, int64 type) +{ + return CM_SUCCESS; +} + +status_t wr_clean_vg_lock(const char *home, int64 inst_id) +{ + return CM_SUCCESS; +} + +static status_t wr_kickh_inner(wr_vg_info_t *vg_info, wr_config_t *inst_cfg, int64 host_id, bool32 is_lock) +{ + return CM_SUCCESS; +} + +status_t wr_kickh_core(const char *home, int64 host_id) +{ + return CM_SUCCESS; +} + + +#endif \ No newline at end of file diff --git a/src/common/wr_io_fence.h b/src/common/wr_io_fence.h new file mode 100644 index 0000000000000000000000000000000000000000..117259c7bc550877fcae4d1fd84ec36f1fa71b29 --- /dev/null +++ b/src/common/wr_io_fence.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_io_fence.h + * + * + * IDENTIFICATION + * src/common/wr_io_fence.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_IO_FENCE_H__ +#define __WR_IO_FENCE_H__ + +#include "wr_defs.h" +#include "wr_session.h" +#include "wr_file.h" +#include "cm_scsi.h" +#include "cm_iofence.h" +#include "cm_list.h" + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef IOFENCE +typedef struct st_dev_info { + char *dev; + inquiry_data_t data; +} dev_info_t; + +// because cm_destory_ptlist will NOT FRE ptlist->item[idx] memory +void wr_destroy_ptlist(ptlist_t *ptlist); + +// kick/reg host with all devs +status_t wr_iof_kick_all_volumes(wr_vg_info_t *wr_vg_info, int64 rk, int64 rk_kick, ptlist_t *reg_list); +status_t wr_iof_sync_all_vginfo(wr_session_t *session, wr_vg_info_t *wr_vg_info); +status_t wr_iof_kick_all(wr_vg_info_t *vg_info, wr_config_t *inst_cfg, int64 rk, int64 rk_kick); +status_t wr_iof_register_core(int64 rk, wr_vg_info_t *wr_vg_info); +status_t wr_iof_unregister_core(int64 rk, wr_vg_info_t *wr_vg_info); + +// inquire lun info +status_t wr_inquiry_luns_from_ctrl(wr_vg_info_item_t *item, ptlist_t *lunlist); +status_t wr_inquiry_luns(wr_vg_info_t *vg_info, ptlist_t *lunlist); +status_t wr_inquiry_lun(dev_info_t *dev_info); + +// read keys and reservations +status_t wr_iof_inql_regs_core(ptlist_t *reglist, wr_vg_info_item_t *item); +status_t wr_iof_inql_regs(wr_vg_info_t *vg_info, ptlist_t *reglist); + +status_t wr_iof_unregister_single(int64 rk, char *dev); +status_t wr_iof_register_single(int64 rk, char *dev); + +#endif +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/common/wr_latch.c b/src/common/wr_latch.c new file mode 100644 index 0000000000000000000000000000000000000000..da98c966e979fe20e09fc9e0a01d79fa514d237e --- /dev/null +++ b/src/common/wr_latch.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_latch.c + * + * + * IDENTIFICATION + * src/common/wr_latch.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_latch.h" +#include "wr_shm.h" +#include "cm_utils.h" + +latch_statis_t g_latch_stat[LATCH_STAT_TYPE_COUNT] = {0}; + +void wr_latch_s(latch_t *latch) +{ + cm_latch_s(latch, WR_DEFAULT_SESSIONID, CM_FALSE, NULL); +} + +void wr_latch_x(latch_t *latch) +{ + cm_latch_x(latch, WR_DEFAULT_SESSIONID, NULL); +} + +bool32 wr_latch_timed_x(latch_t *latch, uint32 wait_ticks) +{ + return cm_latch_timed_x(latch, WR_DEFAULT_SESSIONID, wait_ticks, NULL); +} + +void wr_unlatch(latch_t *latch) +{ + cm_unlatch(latch, NULL); +} + +void wr_latch_x2(latch_t *latch, uint32 sid) +{ + cm_latch_x(latch, sid, NULL); +} + +void wr_latch_s2(latch_t *latch, uint32 sid, bool32 is_force, latch_statis_t *stat) +{ + cm_latch_s(latch, sid, is_force, stat); +} + +void wr_latch_x2ix(latch_t *latch, uint32 sid, latch_statis_t *stat) +{ + (void)cm_latch_x2ix(latch, sid, stat); +} + +void wr_latch_ix2x(latch_t *latch, uint32 sid, latch_statis_t *stat) +{ + cm_latch_ix2x(latch, sid, stat); +} + +void wr_latch_degrade(latch_t *latch, uint32 sid, latch_statis_t *stat) +{ + cm_latch_degrade(latch, sid, stat); +} + +void wr_set_latch_extent(wr_latch_extent_t *latch_extent, uint16 stat, uint16 shared_count) +{ + latch_extent->stat_bak = stat; + latch_extent->shared_count_bak = shared_count; + latch_extent->shared_sid_count_bak = latch_extent->shared_sid_count; +} \ No newline at end of file diff --git a/src/common/wr_latch.h b/src/common/wr_latch.h new file mode 100644 index 0000000000000000000000000000000000000000..3bc445a4c8fcd8ee7c10965cb10735ebf22c9f46 --- /dev/null +++ b/src/common/wr_latch.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_latch.h + * + * + * IDENTIFICATION + * src/common/wr_latch.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_LATCH_H__ +#define __WR_LATCH_H__ + +#include "cm_latch.h" + +#ifdef __cplusplus +extern "C" { +#endif +typedef enum en_wr_latch_mode { + LATCH_MODE_SHARE = 0, /* SHARE */ + LATCH_MODE_EXCLUSIVE = 1 /* EXCLUSIVE*/ +} wr_latch_mode_e; + +typedef enum en_wr_latch_shared_op { + LATCH_SHARED_OP_NONE = 0, + LATCH_SHARED_OP_LATCH_S = 1, + LATCH_SHARED_OP_LATCH_S_BEG = 2, + LATCH_SHARED_OP_LATCH_S_END = 3, + LATCH_SHARED_OP_UNLATCH = 4, + LATCH_SHARED_OP_UNLATCH_BEG = 5, + LATCH_SHARED_OP_UNLATCH_END = 6, +} wr_latch_shared_op_e; + +typedef enum en_wr_latch_stat_type { + LATCH_SWITCH = 0, + LATCH_STAT_TYPE_COUNT +} wr_latch_stat_type_t; + +extern latch_statis_t g_latch_stat[LATCH_STAT_TYPE_COUNT]; +#define LATCH_STAT(stat_id) (&g_latch_stat[(stat_id)]) + +typedef struct st_wr_latch_extent { + volatile uint16 shared_count_bak; + volatile uint16 stat_bak; + volatile uint64 shared_sid_count; + volatile uint64 shared_sid_count_bak; +} wr_latch_extent_t; + +typedef struct st_wr_shared_latch { + latch_t latch; + wr_latch_extent_t latch_extent; +} wr_shared_latch_t; + +#define SPIN_SLEEP_TIME 500 +#define SPIN_WAIT_FOREVER (-1) +#define WR_CLIENT_TIMEOUT_COUNT 30 +#define WR_CLIENT_TIMEOUT 1000 // ms + +#define WR_DEFAULT_SESSIONID (uint16)0xFFFF +#define WR_SESSIONID_IN_LOCK(sid) ((sid) + 1) + +typedef bool32 (*latch_should_exit)(void); + +void wr_latch_s(latch_t *latch); +void wr_latch_x(latch_t *latch); +void wr_unlatch(latch_t *latch); +void wr_latch_x2(latch_t *latch, uint32 sid); +bool32 wr_latch_timed_x(latch_t *latch, uint32 wait_ticks); +static inline void wr_latch(latch_t *latch, wr_latch_mode_e latch_mode, uint32 sid) +{ + latch_mode == LATCH_MODE_SHARE ? cm_latch_s(latch, sid, CM_FALSE, NULL) : cm_latch_x(latch, sid, NULL); +} + +void wr_latch_s2(latch_t *latch, uint32 sid, bool32 is_force, latch_statis_t *stat); +void wr_latch_x2ix(latch_t *latch, uint32 sid, latch_statis_t *stat); +void wr_latch_ix2x(latch_t *latch, uint32 sid, latch_statis_t *stat); +void wr_latch_degrade(latch_t *latch, uint32 sid, latch_statis_t *stat); + +void wr_set_latch_extent(wr_latch_extent_t *latch_extent, uint16 stat, uint16 shared_count); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/common/wr_malloc.h b/src/common/wr_malloc.h new file mode 100644 index 0000000000000000000000000000000000000000..34a0b9c3723372b1a949d57b3ea4585384d3b9f2 --- /dev/null +++ b/src/common/wr_malloc.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_malloc.h + * + * + * IDENTIFICATION + * src/common/wr_malloc.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_MALLOC_H__ +#define __WR_MALLOC_H__ + +#include +#include +#include "cm_types.h" +#include "cm_debug.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define cm_malloc(size) (cm_malloc_ex(size, __LINE__, __FILE_NAME__)) + +static inline void *cm_malloc_ex(uint32 size, uint32 line, char *file) +{ + CM_ASSERT(size != 0); + // To do some je_malloc + uint8 *p = (uint8 *)malloc(size); + return (void *)p; +} + +#define cm_free free + +static inline void *cm_malloc_align(uint32 alignment, uint32 size) +{ +#ifndef WIN32 + int ret; + void *memptr; + ret = posix_memalign(&memptr, alignment, size); + if (ret == 0) { + return memptr; + } else { + return NULL; + } +#else + return cm_malloc(size); +#endif +} + +#ifdef __cplusplus +} +#endif +#endif // __WR_MALLOC_H__ diff --git a/src/common/wr_meta_buf.c b/src/common/wr_meta_buf.c new file mode 100644 index 0000000000000000000000000000000000000000..8e4b153388b371ecbbd25607ea7107405ca2ae02 --- /dev/null +++ b/src/common/wr_meta_buf.c @@ -0,0 +1,1230 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_meta_buf.c + * + * + * IDENTIFICATION + * src/common/wr_meta_buf.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_meta_buf.h" +#include "wr_alloc_unit.h" +#include "wr_file.h" +#include "cm_bilist.h" +#include "wr_fs_aux.h" +#include "wr_syn_meta.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void wr_enter_shm_x(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + wr_lock_shm_meta_x(session, vg_item->vg_latch); +} + +bool32 wr_enter_shm_time_x(wr_session_t *session, wr_vg_info_item_t *vg_item, uint32 wait_ticks) +{ + if (!wr_lock_shm_meta_timed_x(session, vg_item->vg_latch, WR_LOCK_SHM_META_TIMEOUT)) { + return CM_FALSE; + } + return CM_TRUE; +} + +void wr_enter_shm_s(wr_session_t *session, wr_vg_info_item_t *vg_item, bool32 is_force, int32 timeout) +{ + CM_ASSERT(session != NULL); + if (wr_is_server()) { + (void)wr_lock_shm_meta_s_without_stack(session, vg_item->vg_latch, is_force, timeout); + return; + } + + wr_latch_offset_t latch_offset; + latch_offset.type = WR_LATCH_OFFSET_SHMOFFSET; + latch_offset.offset.shm_offset = wr_get_vg_latch_shm_offset(vg_item); + (void)wr_lock_shm_meta_s_with_stack(session, &latch_offset, vg_item->vg_latch, timeout); +} + +void wr_leave_shm(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + CM_ASSERT(session != NULL); + if (wr_is_server()) { + wr_unlock_shm_meta_without_stack(session, vg_item->vg_latch); + } else { + (void)wr_unlock_shm_meta_s_with_stack(session, vg_item->vg_latch, CM_FALSE); + } +} + +wr_block_ctrl_t *wr_buffer_get_block_ctrl_addr(ga_pool_id_e pool_id, uint32 object_id) +{ + return (wr_block_ctrl_t *)ga_object_addr(pool_id, object_id); +} + +char *wr_buffer_get_meta_addr(ga_pool_id_e pool_id, uint32 object_id) +{ + wr_block_ctrl_t *block_ctrl = wr_buffer_get_block_ctrl_addr(pool_id, object_id); + if (block_ctrl != NULL) { + return WR_GET_META_FROM_BLOCK_CTRL(char, block_ctrl); + } + return NULL; +} + +static void wr_remove_recycle_meta(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_ctrl_t *block_ctrl); + +bool32 wr_buffer_cache_key_compare(void *key, void *key2) +{ + uint64 id = WR_BLOCK_ID_IGNORE_UNINITED(*(uint64 *)key); + uint64 id2 = WR_BLOCK_ID_IGNORE_UNINITED(*(uint64 *)key2); + return cm_oamap_uint64_compare(&id, &id2); +} + +static inline ga_pool_id_e wr_buffer_cache_get_pool_id(uint32_t block_type) +{ + CM_ASSERT(block_type < WR_BLOCK_TYPE_MAX); + if (block_type == WR_BLOCK_TYPE_FT) { + return GA_8K_POOL; + } else if (block_type == WR_BLOCK_TYPE_FS) { + return GA_16K_POOL; + } else { + return GA_FS_AUX_POOL; + } +} + +uint32 wr_buffer_cache_get_block_size(uint32_t block_type) +{ + CM_ASSERT(block_type < WR_BLOCK_TYPE_MAX); + if (block_type == WR_BLOCK_TYPE_FT) { + return WR_BLOCK_SIZE; + } else if (block_type == WR_BLOCK_TYPE_FS) { + return WR_FILE_SPACE_BLOCK_SIZE; + } else { + return WR_FS_AUX_SIZE; + } +} + +static void wr_register_buffer_cache_inner(wr_session_t *session, shm_hash_ctrl_t *hash_ctrl, + shm_hashmap_bucket_t *bucket, ga_obj_id_t obj_id, char *meta_addr, uint32 hash) +{ + CM_ASSERT(bucket != NULL); + CM_ASSERT(meta_addr != NULL); + + wr_block_ctrl_t *first_block_ctrl = NULL; + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(meta_addr); + if (bucket->has_next) { + ga_obj_id_t first_obj_id = *(ga_obj_id_t *)&bucket->first; + first_block_ctrl = wr_buffer_get_block_ctrl_addr(first_obj_id.pool_id, first_obj_id.obj_id); + WR_ASSERT_LOG(first_block_ctrl != NULL, "obj meta_addr is NULL when register buffer cache"); + } else { + block_ctrl->has_next = CM_FALSE; + } + block_ctrl->hash = hash; + block_ctrl->my_obj_id = obj_id; + SHM_HASH_BUCKET_INSERT(bucket, *(sh_mem_p *)&obj_id, block_ctrl, first_block_ctrl); +} + +static void wr_unregister_buffer_cache_inner( + shm_hash_ctrl_t *hash_ctrl, shm_hashmap_bucket_t *bucket, ga_obj_id_t next_id, char *meta_addr) +{ + wr_block_ctrl_t *prev_block_ctrl = NULL; + wr_block_ctrl_t *next_block_ctrl = NULL; + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(meta_addr); + if (block_ctrl->has_prev) { + ga_obj_id_t obj_id = *(ga_obj_id_t *)&block_ctrl->hash_prev; + prev_block_ctrl = wr_buffer_get_block_ctrl_addr(obj_id.pool_id, obj_id.obj_id); + } + if (block_ctrl->has_next) { + ga_obj_id_t obj_id = *(ga_obj_id_t *)&block_ctrl->hash_next; + next_block_ctrl = wr_buffer_get_block_ctrl_addr(obj_id.pool_id, obj_id.obj_id); + } + SHM_HASH_BUCKET_REMOVE(bucket, *(sh_mem_p *)&next_id, block_ctrl, prev_block_ctrl, next_block_ctrl); +} + +status_t shm_hashmap_move_bucket_node( + wr_session_t *session, shm_hash_ctrl_t *hash_ctrl, uint32 old_bucket_idx, uint32 new_bucket_idx) +{ + LOG_DEBUG_INF("[HASHMAP]Begin to move some entry from bucket %u to bucket %u.", old_bucket_idx, new_bucket_idx); + shm_hashmap_bucket_t *old_bucket = shm_hashmap_get_bucket(hash_ctrl, old_bucket_idx, NULL); + shm_hashmap_bucket_t *new_bucket = shm_hashmap_get_bucket(hash_ctrl, new_bucket_idx, NULL); + WR_ASSERT_LOG(old_bucket != NULL, "[HASHMAP]Expect bucket %u is not null.", old_bucket_idx); + WR_ASSERT_LOG(new_bucket != NULL, "[HASHMAP]Expect bucket %u is not null.", new_bucket_idx); + ga_obj_id_t tmp_id = *(ga_obj_id_t *)&old_bucket->first; + ga_obj_id_t next_id = *(ga_obj_id_t *)&old_bucket->first; + bool32 has_next = old_bucket->has_next; + char *meta_addr = NULL; + wr_block_ctrl_t *block_ctrl = NULL; + wr_common_block_t *block = NULL; + auid_t block_id_tmp = {0}; + uint32 hash; + uint32 bucket_idx; + while (has_next) { + meta_addr = wr_buffer_get_meta_addr(next_id.pool_id, next_id.obj_id); + WR_ASSERT_LOG(meta_addr != NULL, "[HASHMAP]Expect meta_addr is not null, pool id is %u, object id is %u.", + next_id.pool_id, next_id.obj_id); + block = WR_GET_COMMON_BLOCK_HEAD(meta_addr); + block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(meta_addr); + block_id_tmp = ((wr_common_block_t *)meta_addr)->id; + hash = WR_BUFFER_CACHE_HASH(block_id_tmp); + has_next = block_ctrl->has_next; + tmp_id = next_id; + next_id = *(ga_obj_id_t *)&block_ctrl->hash_next; + bucket_idx = shm_hashmap_calc_bucket_idx(hash_ctrl, hash); + if (bucket_idx != old_bucket_idx) { + wr_lock_shm_meta_bucket_x(session, &old_bucket->enque_lock); + wr_lock_shm_meta_bucket_x(session, &new_bucket->enque_lock); + wr_unregister_buffer_cache_inner(hash_ctrl, old_bucket, tmp_id, meta_addr); + LOG_DEBUG_INF("[HASHMAP]Move block id %s from bucket %u, hash:%u, type:%u, num:%u.", + wr_display_metaid(block_id_tmp), old_bucket_idx, hash, block->type, old_bucket->entry_num); + WR_ASSERT_LOG(bucket_idx == new_bucket_idx, "Expect bucket idx is %u, but bucket idx is %u.", + new_bucket_idx, bucket_idx); + wr_register_buffer_cache_inner(session, hash_ctrl, new_bucket, tmp_id, meta_addr, hash); + LOG_DEBUG_INF( + "[HASHMAP]Succeed to register buffer cache, bucket %u, num %u.", new_bucket_idx, new_bucket->entry_num); + wr_unlock_shm_meta_bucket(session, &old_bucket->enque_lock); + wr_unlock_shm_meta_bucket(session, &new_bucket->enque_lock); + LOG_DEBUG_INF("[HASHMAP]Move block id %s from bucket %u to bucket %u, object id:{%u,%u}, hash:%u, type:%u.", + wr_display_metaid(block_id_tmp), old_bucket_idx, new_bucket_idx, tmp_id.pool_id, tmp_id.obj_id, hash, + block->type); + ga_obj_id_t new_id = *(ga_obj_id_t *)&new_bucket->first; + WR_ASSERT_LOG(new_id.pool_id == tmp_id.pool_id && new_id.obj_id == tmp_id.obj_id, + "[HASHMAP]new id is {%u,%u}, tmp id is {%u,%u}.", new_id.pool_id, new_id.obj_id, tmp_id.pool_id, + tmp_id.obj_id); + } + } + return CM_SUCCESS; +} + +status_t wr_hashmap_extend_and_redistribute_batch( + wr_session_t *session, shm_hash_ctrl_t *hash_ctrl, uint32 extend_num) +{ + uint32 i = 0; + while (i < extend_num) { + if (hash_ctrl->bucket_num == hash_ctrl->bucket_limits && hash_ctrl->max_bucket == hash_ctrl->high_mask) { + LOG_DEBUG_WAR("[HASHMAP]No need to extend hashmap for it has reached the upper limit."); + return CM_SUCCESS; + } + status_t status = wr_hashmap_extend_and_redistribute(session, hash_ctrl); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("[HASHMAP]Failed to extend hashmap, extend_num is %u, i is %u.", extend_num, i); + return status; + } + i++; + } + return CM_SUCCESS; +} + +void wr_hashmap_dynamic_extend_and_redistribute_per_vg(wr_vg_info_item_t *vg_item, wr_session_t *session) +{ + shm_hash_ctrl_t *hash_ctrl = &vg_item->buffer_cache->hash_ctrl; + if (shm_hashmap_need_extend_and_redistribute(hash_ctrl)) { + wr_enter_shm_x(session, vg_item); + LOG_DEBUG_INF("[HASHMAP]Begin to extend hashmap of vg %s.", vg_item->vg_name); + status_t status = wr_hashmap_extend_and_redistribute_batch(session, hash_ctrl, WR_EXTEND_BATCH); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR( + "[HASHMAP]Failed to extend hashmap of vg %s, nsegments is %u, max_bucket is %u, bucket_num is %u.", + vg_item->vg_name, hash_ctrl->nsegments, hash_ctrl->max_bucket, hash_ctrl->bucket_num); + wr_leave_shm(session, vg_item); + return; + } + LOG_DEBUG_INF( + "[HASHMAP]Succeed to extend hashmap of vg %s, nsegments is %u, max_bucket is %u, bucket_num is %u.", + vg_item->vg_name, hash_ctrl->nsegments, hash_ctrl->max_bucket, hash_ctrl->bucket_num); + wr_leave_shm(session, vg_item); + } +} + +status_t wr_hashmap_redistribute(wr_session_t *session, shm_hash_ctrl_t *hash_ctrl, uint32 old_bucket) +{ + hash_ctrl->max_bucket++; + uint32 new_bucket = shm_hashmap_calc_bucket_idx(hash_ctrl, hash_ctrl->max_bucket); + return shm_hashmap_move_bucket_node(session, hash_ctrl, old_bucket, new_bucket); +} + +void wr_hashmap_extend_bucket_num(shm_hash_ctrl_t *hash_ctrl) +{ + if (hash_ctrl->max_bucket >= hash_ctrl->high_mask) { + LOG_RUN_INF("[HASHMAP]Before update hash ctrl, max_bucket %u, bucket_num:%u, low mask:%u, high mask:%u.", + hash_ctrl->max_bucket, hash_ctrl->bucket_num, hash_ctrl->low_mask, hash_ctrl->high_mask); + hash_ctrl->bucket_num <<= 1; + hash_ctrl->low_mask = hash_ctrl->high_mask; + hash_ctrl->high_mask = (hash_ctrl->max_bucket + 1) | hash_ctrl->low_mask; + LOG_RUN_INF("[HASHMAP]Update hash ctrl, max_bucket %u, bucket_num:%u, low mask:%u, high mask:%u.", + hash_ctrl->max_bucket, hash_ctrl->bucket_num, hash_ctrl->low_mask, hash_ctrl->high_mask); + } +} + +status_t wr_hashmap_extend_segment(shm_hash_ctrl_t *hash_ctrl) +{ + uint32 segment = (hash_ctrl->max_bucket + 1) / WR_BUCKETS_PER_SEGMENT; + if (segment >= hash_ctrl->nsegments) { + WR_RETURN_IF_ERROR(shm_hashmap_extend_segment(hash_ctrl)); + } + return CM_SUCCESS; +} + +status_t wr_hashmap_extend_and_redistribute(wr_session_t *session, shm_hash_ctrl_t *hash_ctrl) +{ + uint32 old_bucket = shm_hashmap_calc_bucket_idx(hash_ctrl, hash_ctrl->max_bucket + 1); + WR_RETURN_IF_ERROR(wr_hashmap_extend_segment(hash_ctrl)); + wr_hashmap_extend_bucket_num(hash_ctrl); + return wr_hashmap_redistribute(session, hash_ctrl, old_bucket); +} + +status_t wr_register_buffer_cache(wr_session_t *session, wr_vg_info_item_t *vg_item, const wr_block_id_t block_id, + ga_obj_id_t obj_id, char *meta_addr, wr_block_type_t type) +{ + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(meta_addr); + shm_hash_ctrl_t *hash_ctrl = &vg_item->buffer_cache->hash_ctrl; + uint32 hash = WR_BUFFER_CACHE_HASH(block_id); + uint32 bucket_idx = shm_hashmap_calc_bucket_idx(hash_ctrl, hash); + shm_hashmap_bucket_t *bucket = shm_hashmap_get_bucket(hash_ctrl, bucket_idx, NULL); + if (bucket == NULL) { + return CM_ERROR; + } + errno_t errcode = memset_s(block_ctrl, sizeof(wr_block_ctrl_t), 0, sizeof(wr_block_ctrl_t)); + if (errcode) { + LOG_DEBUG_ERR("Failed to memset block ctrl, block id %s.", wr_display_metaid(block_id)); + return CM_ERROR; + } + wr_lock_shm_meta_bucket_x(session, &bucket->enque_lock); + WR_LOG_DEBUG_OP("Register block id %s, hash:%u, type:%u, bucket_idx is %u.", wr_display_metaid(block_id), hash, + type, bucket_idx); + cm_latch_init(&block_ctrl->latch); + block_ctrl->type = type; + block_ctrl->block_id = block_id; + wr_register_buffer_cache_inner(session, hash_ctrl, bucket, obj_id, meta_addr, hash); + LOG_DEBUG_INF("Succeed to register buffer cache, bucket %u, num %u.", bucket_idx, bucket->entry_num); + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + return CM_SUCCESS; +} + +void wr_unregister_buffer_cache(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_id_t block_id) +{ + char *meta_addr = NULL; + wr_block_ctrl_t *block_ctrl = NULL; + wr_common_block_t *block = NULL; + auid_t block_id_tmp = {0}; + uint32 hash = WR_BUFFER_CACHE_HASH(block_id); + shm_hash_ctrl_t *hash_ctrl = &vg_item->buffer_cache->hash_ctrl; + uint32 bucket_idx = shm_hashmap_calc_bucket_idx(hash_ctrl, hash); + shm_hashmap_bucket_t *bucket = shm_hashmap_get_bucket(hash_ctrl, bucket_idx, NULL); + cm_panic(bucket != NULL); + wr_lock_shm_meta_bucket_x(session, &bucket->enque_lock); + ga_obj_id_t next_id = *(ga_obj_id_t *)&bucket->first; + bool32 has_next = bucket->has_next; + while (has_next) { + meta_addr = wr_buffer_get_meta_addr(next_id.pool_id, next_id.obj_id); + cm_panic(meta_addr != NULL); + block = WR_GET_COMMON_BLOCK_HEAD(meta_addr); + block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(meta_addr); + block_id_tmp = ((wr_common_block_t *)meta_addr)->id; + if ((block_ctrl->hash == hash) && (wr_buffer_cache_key_compare(&block_id_tmp, &block_id) == CM_TRUE)) { + // may has been linked to recycle meta list + wr_remove_recycle_meta(session, vg_item, block_ctrl); + wr_unregister_buffer_cache_inner(hash_ctrl, bucket, next_id, meta_addr); + LOG_DEBUG_INF("Move block id %s from bucket %u, hash:%u, type:%u, num:%u.", + wr_display_metaid(block_id_tmp), bucket_idx, hash, block->type, bucket->entry_num); + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + return; + } + has_next = block_ctrl->has_next; + next_id = *(ga_obj_id_t *)&block_ctrl->hash_next; + } + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + LOG_DEBUG_ERR("Key to remove not found"); +} + +status_t wr_get_block_from_disk( + wr_vg_info_item_t *vg_item, wr_block_id_t block_id, char *buf, int64_t offset, int32 size, bool32 calc_checksum) +{ + bool32 remote = calc_checksum; + CM_ASSERT(block_id.volume < WR_MAX_VOLUMES); + status_t status = wr_check_read_volume(vg_item, (uint32)block_id.volume, offset, buf, size, &remote); + if (status != CM_SUCCESS) { + return status; + } + + // check the checksum when read the file table block and file space block. + if ((calc_checksum) && (remote == CM_FALSE)) { + cm_panic((uint32)size == WR_BLOCK_SIZE || (uint32)size == WR_FILE_SPACE_BLOCK_SIZE || + (uint32)size == WR_FS_AUX_SIZE); + uint32 checksum = wr_get_checksum(buf, (uint32)size); + wr_common_block_t *block = (wr_common_block_t *)buf; + wr_check_checksum(checksum, block->checksum); + } + + return CM_SUCCESS; +} + +status_t wr_check_block_version(wr_vg_info_item_t *vg_item, wr_block_id_t block_id, wr_block_type_t type, + char *meta_addr, bool32 *is_changed, bool32 force_refresh) +{ +#ifndef WIN32 + char buf[WR_DISK_UNIT_SIZE] __attribute__((__aligned__(WR_DISK_UNIT_SIZE))); +#else + char buf[WR_DISK_UNIT_SIZE]; +#endif + + if (is_changed) { + *is_changed = CM_FALSE; + } + + uint64 version = ((wr_common_block_t *)meta_addr)->version; + uint32 size = wr_buffer_cache_get_block_size(type); + int64 offset = wr_get_block_offset(vg_item, (uint64)size, block_id.block, block_id.au); + // just read block header + status_t status = wr_get_block_from_disk(vg_item, block_id, buf, offset, WR_DISK_UNIT_SIZE, CM_FALSE); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to get block: %s from disk, meta_addr:%p, offset:%lld, size:%d.", + wr_display_metaid(block_id), buf, offset, WR_DISK_UNIT_SIZE); + return status; + } + uint64 disk_version = ((wr_common_block_t *)buf)->version; + if (wr_compare_version(disk_version, version) || force_refresh) { + WR_LOG_DEBUG_OP( + "wr_check_block_version, version:%llu, disk_version:%llu, block_id: %s, type:%u, force_refresh:%u.", + version, disk_version, wr_display_metaid(block_id), type, (uint32)force_refresh); + // if size == WR_DISK_UNIT_SIZE, the buf has been changed all, not need load again + if (size == WR_DISK_UNIT_SIZE) { + securec_check_ret(memcpy_s(meta_addr, WR_DISK_UNIT_SIZE, buf, WR_DISK_UNIT_SIZE)); + } else { + if (force_refresh && version == 0) { + status = wr_get_block_from_disk(vg_item, block_id, meta_addr, offset, (int32)size, CM_FALSE); + } else { + status = wr_get_block_from_disk(vg_item, block_id, meta_addr, offset, (int32)size, CM_TRUE); + } + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to get block: %s from disk, meta_addr:%p, offset:%lld, size:%u.", + wr_display_metaid(block_id), meta_addr, offset, size); + return status; + } + } + if (is_changed) { + *is_changed = CM_TRUE; + } + } + + return CM_SUCCESS; +} + +static status_t wr_load_buffer_cache(wr_session_t *session, wr_vg_info_item_t *vg_item, auid_t block_id, + wr_block_type_t type, char **block_addr, ga_obj_id_t *out_obj_id) +{ + char *meta_addr = NULL; + wr_block_ctrl_t *block_ctrl = NULL; + wr_common_block_t *block = NULL; + auid_t block_id_tmp = {0}; + shm_hash_ctrl_t *hash_ctrl = &vg_item->buffer_cache->hash_ctrl; + uint32 hash = WR_BUFFER_CACHE_HASH(block_id); + uint32 bucket_idx = shm_hashmap_calc_bucket_idx(hash_ctrl, hash); + shm_hashmap_bucket_t *bucket = shm_hashmap_get_bucket(hash_ctrl, bucket_idx, NULL); + if (bucket == NULL) { + LOG_RUN_ERR("Failed to find bucket %u.", bucket_idx); + return CM_ERROR; + } + wr_lock_shm_meta_bucket_x(session, &bucket->enque_lock); + ga_obj_id_t next_id = *(ga_obj_id_t *)&bucket->first; + bool32 has_next = bucket->has_next; + while (has_next) { + meta_addr = wr_buffer_get_meta_addr(next_id.pool_id, next_id.obj_id); + cm_panic(meta_addr != NULL); + block = WR_GET_COMMON_BLOCK_HEAD(meta_addr); + block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(meta_addr); + block_id_tmp = ((wr_common_block_t *)meta_addr)->id; + if ((block_ctrl->hash == hash) && (wr_buffer_cache_key_compare(&block_id_tmp, &block_id) == CM_TRUE)) { + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + status_t status = wr_check_block_version(vg_item, block_id, type, meta_addr, NULL, CM_FALSE); + if (status != CM_SUCCESS) { + return status; + } + *block_addr = meta_addr; + if (out_obj_id) { + *out_obj_id = next_id; + } + block_ctrl->type = type; + wr_inc_meta_ref_hot(block_ctrl); + return CM_SUCCESS; + } + has_next = block_ctrl->has_next; + next_id = *(ga_obj_id_t *)&block_ctrl->hash_next; + } + + ga_pool_id_e pool_id = wr_buffer_cache_get_pool_id(type); + uint32 size = wr_buffer_cache_get_block_size(type); + int64_t offset = wr_get_block_offset(vg_item, (uint64)size, block_id.block, block_id.au); + uint32 obj_id = ga_alloc_object(pool_id, CM_INVALID_ID32); + if (obj_id == CM_INVALID_ID32) { + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + return CM_ERROR; + } + meta_addr = wr_buffer_get_meta_addr(pool_id, obj_id); + + status_t status = wr_get_block_from_disk(vg_item, block_id, meta_addr, offset, (int32)size, CM_TRUE); + if (status != CM_SUCCESS) { + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + ga_free_object(pool_id, obj_id); + LOG_DEBUG_ERR("Failed to get block from disk, v:%u,au:%llu,block:%u,item:%u,type:%d.", block_id.volume, + (uint64)block_id.au, block_id.block, block_id.item, type); + return status; + } + block = WR_GET_COMMON_BLOCK_HEAD(meta_addr); + WR_LOG_DEBUG_OP("WR load buffer cache, v:%u,au:%llu,block:%u,item:%u,type:%d.", block->id.volume, + (uint64)block->id.au, block->id.block, block->id.item, block->type); + block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(meta_addr); + errno_t errcode = memset_s(block_ctrl, sizeof(wr_block_ctrl_t), 0, sizeof(wr_block_ctrl_t)); + if (errcode != EOK) { + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + ga_free_object(pool_id, obj_id); + LOG_DEBUG_ERR("Failed to memset block ctrl, v:%u,au:%llu,block:%u,item:%u,type:%d.", block_id.volume, + (uint64)block_id.au, block_id.block, block_id.item, type); + return CM_ERROR; + } + cm_latch_init(&block_ctrl->latch); + block_ctrl->type = type; + block_ctrl->block_id = block_id; + + ga_obj_id_t ga_obj_id; + ga_obj_id.pool_id = pool_id; + ga_obj_id.obj_id = obj_id; + wr_register_buffer_cache_inner(session, hash_ctrl, bucket, ga_obj_id, meta_addr, hash); + LOG_DEBUG_INF("Succeed to register buffer cache, bucket %u, num %u.", bucket_idx, bucket->entry_num); + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + if (out_obj_id) { + *out_obj_id = ga_obj_id; + } + *block_addr = meta_addr; + wr_inc_meta_ref_hot(block_ctrl); + WR_LOG_DEBUG_OP("Succeed to load meta block, v:%u,au:%llu,block:%u,item:%u,type:%d.", block_id.volume, + (uint64)block_id.au, block_id.block, block_id.item, type); + return CM_SUCCESS; +} + +void *wr_find_block_in_bucket(wr_session_t *session, wr_vg_info_item_t *vg_item, uint32 hash, uint64 *key, + bool32 is_print_error_log, ga_obj_id_t *out_obj_id) +{ + CM_ASSERT(key != NULL); + shm_hashmap_t *hashmap = vg_item->buffer_cache; + if (hashmap == NULL) { + if (is_print_error_log) { + LOG_DEBUG_ERR("Pointer to map or compare_func is NULL"); + } + return NULL; + } + shm_hash_ctrl_t *hash_ctrl = &vg_item->buffer_cache->hash_ctrl; + char *meta_addr = NULL; + wr_block_ctrl_t *block_ctrl = NULL; + auid_t block_id_tmp = {0}; + uint32 bucket_idx = shm_hashmap_calc_bucket_idx(hash_ctrl, hash); + uint32 segment_objid = WR_INVALID_ID32; + shm_hashmap_bucket_t *bucket = shm_hashmap_get_bucket(hash_ctrl, bucket_idx, &segment_objid); + if (bucket == NULL) { + if (is_print_error_log) { + LOG_DEBUG_ERR("Pointer to bucket %u is NULL.", bucket_idx); + } + return NULL; + } + if (vg_item->from_type == FROM_SHM) { + wr_lock_shm_meta_bucket_s(session, segment_objid, &bucket->enque_lock); + } + ga_obj_id_t next_id = *(ga_obj_id_t *)&bucket->first; + bool32 has_next = bucket->has_next; + while (has_next) { + meta_addr = wr_buffer_get_meta_addr(next_id.pool_id, next_id.obj_id); + cm_panic(meta_addr != NULL); + block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(meta_addr); + block_id_tmp = ((wr_common_block_t *)meta_addr)->id; + if ((block_ctrl->hash == hash) && (wr_buffer_cache_key_compare(&block_id_tmp, key) == CM_TRUE)) { + if (vg_item->from_type == FROM_SHM) { + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + } + if (out_obj_id != NULL) { + *out_obj_id = next_id; + } + + wr_inc_meta_ref_hot(block_ctrl); + return meta_addr; + } + has_next = block_ctrl->has_next; + next_id = *(ga_obj_id_t *)&block_ctrl->hash_next; + } + if (vg_item->from_type == FROM_SHM) { + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + } + return NULL; +} + +// do not care content change +static void *wr_find_block_in_bucket_ex(wr_session_t *session, wr_vg_info_item_t *vg_item, uint32 hash, uint64 *key, + bool32 is_print_error_log, ga_obj_id_t *out_obj_id) +{ + shm_hashmap_t *map = vg_item->buffer_cache; + CM_ASSERT(key != NULL); + if (map == NULL) { + if (is_print_error_log) { + LOG_DEBUG_ERR("Pointer to map or compare_func is NULL"); + } + return NULL; + } + char *meta_addr = NULL; + wr_block_ctrl_t *block_ctrl = NULL; + wr_block_ctrl_t *next_block_ctrl = NULL; + auid_t block_id_tmp = {0}; + shm_hash_ctrl_t *hash_ctrl = &vg_item->buffer_cache->hash_ctrl; + uint32 bucket_idx = shm_hashmap_calc_bucket_idx(hash_ctrl, hash); + uint32 segment_objid = WR_INVALID_ID32; + shm_hashmap_bucket_t *bucket = shm_hashmap_get_bucket(hash_ctrl, bucket_idx, &segment_objid); + if (bucket == NULL) { + if (is_print_error_log) { + LOG_DEBUG_ERR("Pointer to bucket %u is NULL.", bucket_idx); + } + return NULL; + } + (void)wr_lock_shm_meta_bucket_s(session, segment_objid, &bucket->enque_lock); + ga_obj_id_t next_id = *(ga_obj_id_t *)&bucket->first; + bool32 has_next = bucket->has_next; + if (has_next) { + meta_addr = wr_buffer_get_meta_addr(next_id.pool_id, next_id.obj_id); + cm_panic(meta_addr != NULL); + block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(meta_addr); + block_id_tmp = ((wr_common_block_t *)meta_addr)->id; + wr_latch_s(&block_ctrl->latch); + } + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + + while (has_next) { + if ((block_ctrl->hash == hash) && (wr_buffer_cache_key_compare(&block_id_tmp, key) == CM_TRUE)) { + if (out_obj_id != NULL) { + *out_obj_id = next_id; + } + wr_inc_meta_ref_hot(block_ctrl); + wr_unlatch(&block_ctrl->latch); + return meta_addr; + } + has_next = block_ctrl->has_next; + next_id = *(ga_obj_id_t *)&block_ctrl->hash_next; + if (has_next) { + meta_addr = wr_buffer_get_meta_addr(next_id.pool_id, next_id.obj_id); + cm_panic(meta_addr != NULL); + next_block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(meta_addr); + block_id_tmp = ((wr_common_block_t *)meta_addr)->id; + wr_latch_s(&next_block_ctrl->latch); + } + wr_unlatch(&block_ctrl->latch); + block_ctrl = next_block_ctrl; + next_block_ctrl = NULL; + } + + return NULL; +} + +status_t wr_find_block_objid_in_shm(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_id_t block_id, + wr_block_type_t type, ga_obj_id_t *objid) +{ + char *meta_addr = NULL; + uint32 hash = WR_BUFFER_CACHE_HASH(block_id); + meta_addr = wr_find_block_in_bucket(session, vg_item, hash, (uint64 *)&block_id, CM_FALSE, objid); + if (meta_addr != NULL) { + return CM_SUCCESS; + } + return CM_ERROR; +} + +static status_t wr_add_buffer_cache_inner(wr_session_t *session, shm_hash_ctrl_t *hash_ctrl, + shm_hashmap_bucket_t *bucket, auid_t add_block_id, wr_block_type_t type, char *refresh_buf, char **shm_buf) +{ + ga_pool_id_e pool_id = wr_buffer_cache_get_pool_id(type); + uint32 size = wr_buffer_cache_get_block_size(type); + wr_block_ctrl_t *block_ctrl = NULL; + uint32 hash = WR_BUFFER_CACHE_HASH(add_block_id); + uint32 obj_id = ga_alloc_object(pool_id, CM_INVALID_ID32); + if (obj_id == CM_INVALID_ID32) { + WR_THROW_ERROR(ERR_WR_GA_ALLOC_OBJECT, pool_id); + return CM_ERROR; + } + char *meta_addr = wr_buffer_get_meta_addr(pool_id, obj_id); + if (meta_addr == NULL) { + ga_free_object(pool_id, obj_id); + WR_THROW_ERROR(ERR_WR_GA_GET_ADDR, pool_id, obj_id); + return CM_ERROR; + } + errno_t errcode = memcpy_s(meta_addr, size, refresh_buf, size); + if (errcode != EOK) { + ga_free_object(pool_id, obj_id); + LOG_DEBUG_ERR("Failed to memcpy block, v:%u,au:%llu,block:%u,item:%u,type:%d.", add_block_id.volume, + (uint64)add_block_id.au, add_block_id.block, add_block_id.item, type); + CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode); + return CM_ERROR; + } + wr_common_block_t *block = WR_GET_COMMON_BLOCK_HEAD(meta_addr); + WR_LOG_DEBUG_OP("wr add buffer cache, v:%u,au:%llu,block:%u,item:%u,type:%d.", block->id.volume, + (uint64)block->id.au, block->id.block, block->id.item, block->type); + block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(meta_addr); + errcode = memset_s(block_ctrl, sizeof(wr_block_ctrl_t), 0, sizeof(wr_block_ctrl_t)); + if (errcode != EOK) { + ga_free_object(pool_id, obj_id); + LOG_DEBUG_ERR("Failed to memset block ctrl, v:%u,au:%llu,block:%u,item:%u,type:%d.", add_block_id.volume, + (uint64)add_block_id.au, add_block_id.block, add_block_id.item, type); + CM_THROW_ERROR(ERR_SYSTEM_CALL, errcode); + return CM_ERROR; + } + cm_latch_init(&block_ctrl->latch); + block_ctrl->type = type; + block_ctrl->block_id = add_block_id; + + ga_obj_id_t ga_obj_id; + ga_obj_id.pool_id = pool_id; + ga_obj_id.obj_id = obj_id; + wr_register_buffer_cache_inner(session, hash_ctrl, bucket, ga_obj_id, meta_addr, hash); + wr_inc_meta_ref_hot(block_ctrl); + WR_LOG_DEBUG_OP("Succeed to load meta_addr block, v:%u,au:%llu,block:%u,item:%u,type:%d.", add_block_id.volume, + (uint64)add_block_id.au, add_block_id.block, add_block_id.item, type); + *shm_buf = meta_addr; + return CM_SUCCESS; +} + +static status_t wr_add_buffer_cache(wr_session_t *session, wr_vg_info_item_t *vg_item, auid_t add_block_id, + wr_block_type_t type, char *refresh_buf, char **shm_buf) +{ + char *meta_addr = NULL; + wr_block_ctrl_t *block_ctrl = NULL; + auid_t block_id_tmp = {0}; + uint32 hash = WR_BUFFER_CACHE_HASH(add_block_id); + shm_hash_ctrl_t *hash_ctrl = &vg_item->buffer_cache->hash_ctrl; + uint32 bucket_idx = shm_hashmap_calc_bucket_idx(hash_ctrl, hash); + shm_hashmap_bucket_t *bucket = shm_hashmap_get_bucket(hash_ctrl, bucket_idx, NULL); + if (bucket == NULL) { + return CM_ERROR; + } + wr_lock_shm_meta_bucket_x(session, &bucket->enque_lock); + ga_obj_id_t next_id = *(ga_obj_id_t *)&bucket->first; + bool32 has_next = bucket->has_next; + while (has_next) { + meta_addr = wr_buffer_get_meta_addr(next_id.pool_id, next_id.obj_id); + if (meta_addr == NULL) { + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + WR_THROW_ERROR(ERR_WR_GA_GET_ADDR, next_id.pool_id, next_id.obj_id); + return CM_ERROR; + } + + block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(meta_addr); + block_id_tmp = ((wr_common_block_t *)meta_addr)->id; + block_ctrl->type = type; + if ((block_ctrl->hash == hash) && (wr_buffer_cache_key_compare(&block_id_tmp, &add_block_id) == CM_TRUE)) { + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + if (((wr_common_block_t *)meta_addr)->type != type) { + WR_THROW_ERROR(ERR_WR_INVALID_BLOCK_TYPE, type, ((wr_common_block_t *)meta_addr)->type); + return ERR_WR_INVALID_BLOCK_TYPE; + } + uint32 size = wr_buffer_cache_get_block_size(type); + securec_check_ret(memcpy_s(meta_addr, size, refresh_buf, size)); + wr_common_block_t *ref_block = WR_GET_COMMON_BLOCK_HEAD(meta_addr); + wr_inc_meta_ref_hot(block_ctrl); + WR_LOG_DEBUG_OP("wr refresh block in shm, v:%u,au:%llu,block:%u,item:%u,type:%d.", ref_block->id.volume, + (uint64)ref_block->id.au, ref_block->id.block, ref_block->id.item, ref_block->type); + *shm_buf = meta_addr; + return CM_SUCCESS; + } + has_next = block_ctrl->has_next; + next_id = *(ga_obj_id_t *)&block_ctrl->hash_next; + } + status_t ret = wr_add_buffer_cache_inner(session, hash_ctrl, bucket, add_block_id, type, refresh_buf, shm_buf); + if (ret == CM_SUCCESS) { + LOG_DEBUG_INF("Succeed to register buffer cache, bucket %u, num %u.", bucket_idx, bucket->entry_num); + } + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + return ret; +} + +status_t wr_refresh_block_in_shm(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_id_t block_id, + wr_block_type_t type, char *buf, char **shm_buf) +{ + char *meta_addr = NULL; + uint32 hash = WR_BUFFER_CACHE_HASH(block_id); + meta_addr = wr_find_block_in_bucket(session, vg_item, hash, (uint64 *)&block_id, CM_FALSE, NULL); + if (meta_addr != NULL) { + if (((wr_common_block_t *)meta_addr)->type != type) { + WR_THROW_ERROR(ERR_WR_INVALID_BLOCK_TYPE, type, ((wr_common_block_t *)meta_addr)->type); + return ERR_WR_INVALID_BLOCK_TYPE; + } + uint32 size = wr_buffer_cache_get_block_size(type); + securec_check_ret(memcpy_s(meta_addr, size, buf, size)); + wr_common_block_t *block = WR_GET_COMMON_BLOCK_HEAD(meta_addr); + WR_LOG_DEBUG_OP("wr refresh block in shm, v:%u,au:%llu,block:%u,item:%u,type:%d.", block->id.volume, + (uint64)block->id.au, block->id.block, block->id.item, block->type); + *shm_buf = meta_addr; + return CM_SUCCESS; + } + return wr_add_buffer_cache(session, vg_item, block_id, type, buf, shm_buf); +} + +char *wr_find_block_in_shm(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_id_t block_id, + wr_block_type_t type, bool32 check_version, ga_obj_id_t *out_obj_id, bool32 active_refresh) +{ + status_t status; + char *meta_addr = NULL; + uint32 hash = WR_BUFFER_CACHE_HASH(block_id); + meta_addr = wr_find_block_in_bucket(session, vg_item, hash, (uint64 *)&block_id, CM_FALSE, out_obj_id); + if (!wr_is_server()) { + return meta_addr; + } + if (meta_addr != NULL) { + if (check_version && (WR_STANDBY_CLUSTER || !wr_is_readwrite() || active_refresh)) { + status = wr_check_block_version(vg_item, block_id, type, meta_addr, NULL, CM_FALSE); + if (status != CM_SUCCESS) { + return NULL; + } + } + if (wr_is_readwrite()) { + WR_ASSERT_LOG(wr_need_exec_local(), "only masterid %u can be readwrite.", wr_get_master_id()); + } + return meta_addr; + } + + status = wr_load_buffer_cache(session, vg_item, block_id, type, &meta_addr, out_obj_id); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to load meta_addr block, block_id: %s.", wr_display_metaid(block_id)); + return NULL; + } + return meta_addr; +} + +char *wr_find_block_from_disk_and_refresh_shm(wr_session_t *session, wr_vg_info_item_t *vg_item, + wr_block_id_t block_id, wr_block_type_t type, ga_obj_id_t *out_obj_id) +{ + status_t status; + char *meta_addr = NULL; + uint32 hash = WR_BUFFER_CACHE_HASH(block_id); + meta_addr = wr_find_block_in_bucket(session, vg_item, hash, (uint64 *)&block_id, CM_FALSE, out_obj_id); + if (meta_addr != NULL) { + if (((wr_common_block_t *)meta_addr)->version != 0) { + status = wr_check_block_version(vg_item, block_id, type, meta_addr, NULL, CM_TRUE); + if (status != CM_SUCCESS) { + return NULL; + } + } + return meta_addr; + } + + if (!wr_is_server()) { + return NULL; + } + if (wr_load_buffer_cache(session, vg_item, block_id, type, &meta_addr, out_obj_id) != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to load meta_addr block, block_id: %s.", wr_display_metaid(block_id)); + return NULL; + } + return meta_addr; +} + +char *wr_find_block_in_shm_no_refresh( + wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_id_t block_id, ga_obj_id_t *out_obj_id) +{ + uint32 hash = WR_BUFFER_CACHE_HASH(block_id); + return wr_find_block_in_bucket(session, vg_item, hash, (uint64 *)&block_id, CM_FALSE, out_obj_id); +} + +// do not care content change +char *wr_find_block_in_shm_no_refresh_ex( + wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_id_t block_id, ga_obj_id_t *out_obj_id) +{ + uint32 hash = WR_BUFFER_CACHE_HASH(block_id); + return wr_find_block_in_bucket_ex(session, vg_item, hash, (uint64 *)&block_id, CM_FALSE, out_obj_id); +} + +static status_t wr_refresh_buffer_cache_inner(wr_session_t *session, wr_vg_info_item_t *vg_item, uint32 bucket_idx, + ga_queue_t *obj_que, ga_pool_id_e *obj_pool_id) +{ + shm_hash_ctrl_t *hash_ctrl = &vg_item->buffer_cache->hash_ctrl; + shm_hashmap_bucket_t *bucket = shm_hashmap_get_bucket(hash_ctrl, bucket_idx, NULL); + CM_ASSERT(bucket != NULL); + + wr_block_ctrl_t *block_ctrl = NULL; + wr_block_ctrl_t *block_ctrl_prev = NULL; + wr_block_ctrl_t *block_ctrl_next = NULL; + + ga_obj_id_t obj_id = {0}; + ga_obj_id_t obj_id_next = {0}; + + bool32 has_next = CM_FALSE; + bool32 need_remove = CM_FALSE; + + wr_lock_shm_meta_bucket_x(session, &bucket->enque_lock); + if (!bucket->has_next) { + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + return CM_SUCCESS; + } + + status_t status = CM_SUCCESS; + obj_id = *(ga_obj_id_t *)&bucket->first; + block_ctrl = wr_buffer_get_block_ctrl_addr(obj_id.pool_id, obj_id.obj_id); + do { + // no recycle mem for ft block because api cache the meta_addr + if (block_ctrl->type == WR_BLOCK_TYPE_FT) { + wr_init_wr_fs_block_cache_info(&block_ctrl->fs_block_cache_info); + char *meta_addr = WR_GET_META_FROM_BLOCK_CTRL(char, block_ctrl); + status = wr_check_block_version( + vg_item, ((wr_common_block_t *)meta_addr)->id, block_ctrl->type, meta_addr, NULL, CM_FALSE); + WR_BREAK_IF_ERROR(status); + + // no need remove ft block, so make it to the lastest prev block ctrl for remove every time + block_ctrl_prev = block_ctrl; + } else { + // cache the pool info and obj info + ga_append_into_queue_by_pool_id(obj_id.pool_id, &obj_que[block_ctrl->type], obj_id.obj_id); + obj_pool_id[block_ctrl->type] = obj_id.pool_id; + + need_remove = CM_TRUE; + } + + has_next = block_ctrl->has_next; + obj_id_next = *(ga_obj_id_t *)&block_ctrl->hash_next; + if (has_next) { + block_ctrl_next = wr_buffer_get_block_ctrl_addr(obj_id_next.pool_id, obj_id_next.obj_id); + } else { + block_ctrl_next = NULL; + } + + if (need_remove) { + // may has been linked to recycle meta list + wr_remove_recycle_meta(session, vg_item, block_ctrl); + SHM_HASH_BUCKET_REMOVE(bucket, *(sh_mem_p *)&obj_id, block_ctrl, block_ctrl_prev, block_ctrl_next); + need_remove = CM_FALSE; + } + + obj_id = obj_id_next; + block_ctrl = block_ctrl_next; + } while (has_next); + + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + return status; +} + +status_t wr_refresh_buffer_cache(wr_session_t *session, wr_vg_info_item_t *vg_item, shm_hashmap_t *map) +{ + ga_queue_t obj_que[WR_BLOCK_TYPE_MAX] = {0}; + ga_pool_id_e obj_pool_id[WR_BLOCK_TYPE_MAX] = {0}; + shm_hash_ctrl_t *hash_ctrl = &vg_item->buffer_cache->hash_ctrl; + for (uint32_t i = 0; i <= hash_ctrl->max_bucket; i++) { + status_t status = wr_refresh_buffer_cache_inner(session, vg_item, i, obj_que, obj_pool_id); + if (status != CM_SUCCESS) { + return status; + } + } + // free all the obj as batch + for (uint32 i = 0; i < WR_BLOCK_TYPE_MAX; i++) { + if (obj_que[i].count > 0) { + ga_free_object_list(obj_pool_id[i], &obj_que[i]); + } + } + return CM_SUCCESS; +} + +void wr_init_wr_fs_block_cache_info(wr_fs_block_cache_info_t *fs_block_cache_info) +{ + (void)memset_s(fs_block_cache_info, sizeof(wr_fs_block_cache_info_t), 0x00, sizeof(wr_fs_block_cache_info_t)); +} + +void wr_init_vg_cache_node_info(wr_vg_info_item_t *vg_item) +{ + (void)memset_s(vg_item->vg_cache_node, sizeof(vg_item->vg_cache_node), 0x00, sizeof(vg_item->vg_cache_node)); +} + +// do not need control concurrence +void wr_inc_meta_ref_hot(wr_block_ctrl_t *block_ctrl) +{ + (void)cm_atomic_add((atomic_t *)&block_ctrl->ref_hot, WR_RECYCLE_META_HOT_INC_STEP); +} + +// do not need control concurrence +void wr_desc_meta_ref_hot(wr_block_ctrl_t *block_ctrl) +{ + if (block_ctrl->ref_hot > 0) { + int64 ref_hot = block_ctrl->ref_hot; + int64 new_ref_hot = (int64)((uint64)ref_hot >> 1); + (void)cm_atomic_cas((atomic_t *)&block_ctrl->ref_hot, ref_hot, new_ref_hot); + } +} + +static void wr_append_recycle_meta(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_ctrl_t *block_ctrl) +{ + CM_ASSERT(block_ctrl->recycle_meta_node.next == NULL); + CM_ASSERT(block_ctrl->recycle_meta_node.prev == NULL); + uint32 sid = (session == NULL) ? WR_DEFAULT_SESSIONID : WR_SESSIONID_IN_LOCK(session->id); + wr_latch_x2(&vg_item->recycle_meta_desc.latch, sid); + cm_bilist_add_tail(&block_ctrl->recycle_meta_node, &vg_item->recycle_meta_desc.bilist); + wr_unlatch(&vg_item->recycle_meta_desc.latch); +} + +static bilist_node_t *wr_pop_recycle_meta(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + uint32 sid = (session == NULL) ? WR_DEFAULT_SESSIONID : WR_SESSIONID_IN_LOCK(session->id); + wr_latch_x2(&vg_item->recycle_meta_desc.latch, sid); + bilist_node_t *recycle_meta_node = cm_bilist_pop_first(&vg_item->recycle_meta_desc.bilist); + wr_unlatch(&vg_item->recycle_meta_desc.latch); + if (recycle_meta_node != NULL) { + CM_ASSERT(recycle_meta_node->next == NULL); + CM_ASSERT(recycle_meta_node->prev == NULL); + } + return recycle_meta_node; +} + +static void wr_remove_recycle_meta(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_ctrl_t *block_ctrl) +{ + uint32 sid = (session == NULL) ? WR_DEFAULT_SESSIONID : WR_SESSIONID_IN_LOCK(session->id); + wr_latch_x2(&vg_item->recycle_meta_desc.latch, sid); + cm_bilist_del(&block_ctrl->recycle_meta_node, &vg_item->recycle_meta_desc.bilist); + wr_unlatch(&vg_item->recycle_meta_desc.latch); + CM_ASSERT(block_ctrl->recycle_meta_node.next == NULL); + CM_ASSERT(block_ctrl->recycle_meta_node.prev == NULL); +} + +static uint32 wr_try_find_recycle_meta_by_bucket(wr_session_t *session, wr_vg_info_item_t *vg_item, + shm_hashmap_bucket_t *bucket, wr_recycle_meta_args_t *recycle_meta_args) +{ + bool32 has_next = CM_FALSE; + ga_obj_id_t next_id = {0}; + wr_block_ctrl_t *block_ctrl = NULL; + + status_t status = wr_lock_shm_meta_bucket_s(session, vg_item->id, &bucket->enque_lock); + if (status != CM_SUCCESS) { + return 0; + } + + uint32 found_num = 0; + uint32 fs_usage = ga_get_pool_usage(GA_16K_POOL); + uint32 fs_aux_usage = ga_get_pool_usage(GA_FS_AUX_POOL); + + next_id = *(ga_obj_id_t *)&bucket->first; + has_next = bucket->has_next; + while (has_next) { + block_ctrl = wr_buffer_get_block_ctrl_addr(next_id.pool_id, next_id.obj_id); + if (!block_ctrl->recycle_disable && + ((fs_usage >= recycle_meta_args->recyle_meta_pos->hwm && block_ctrl->type == WR_BLOCK_TYPE_FS) || + (fs_aux_usage >= recycle_meta_args->recyle_meta_pos->hwm && + block_ctrl->type == WR_BLOCK_TYPE_FS_AUX))) { + wr_desc_meta_ref_hot(block_ctrl); + if (block_ctrl->ref_hot == 0) { + wr_append_recycle_meta(session, vg_item, block_ctrl); + found_num++; + } + } + + has_next = block_ctrl->has_next; + next_id = *(ga_obj_id_t *)&block_ctrl->hash_next; + } + wr_unlock_shm_meta_bucket(session, &bucket->enque_lock); + return found_num; +} + +static void wr_meta_init_owner_fs_block_cache(wr_block_ctrl_t *owner_block_ctrl) +{ + owner_block_ctrl->fs_block_cache_info.entry_block_addr = NULL; + owner_block_ctrl->fs_block_cache_info.entry_block_id = 0; + owner_block_ctrl->fs_block_cache_info.fs_block_addr = NULL; + owner_block_ctrl->fs_block_cache_info.fs_block_id = 0; + owner_block_ctrl->fs_block_cache_info.fs_aux_addr = NULL; + owner_block_ctrl->fs_block_cache_info.fs_aux_block_id = 0; +} + +static bool32 wr_try_clean_cache_meta(wr_session_t *session, wr_block_ctrl_t *block_ctrl) +{ + if (block_ctrl->type != WR_BLOCK_TYPE_FS && block_ctrl->type != WR_BLOCK_TYPE_FS_AUX) { + return CM_FALSE; + } + + gft_node_t *owner_node = (gft_node_t *)block_ctrl->fs_block_cache_info.owner_node_addr; + if (owner_node == NULL) { + return CM_TRUE; + } + + bool32 need_clean = CM_FALSE; + wr_latch_x_node(session, owner_node, NULL); + // not cached, clean the owner info + if (WR_ID_TO_U64(owner_node->id) != block_ctrl->fs_block_cache_info.owner_node_id) { + need_clean = CM_TRUE; + } else { + // cached + wr_block_ctrl_t *owner_block_ctrl = wr_get_block_ctrl_by_node(owner_node); + // the owner has been deleted, clean the owner's cache info, and then clean the owner info + if (wr_is_node_deleted(owner_node)) { + wr_meta_init_owner_fs_block_cache(owner_block_ctrl); + need_clean = CM_TRUE; + // the onwer is ok, but not cache this block, clean the onwer info + } else if (owner_block_ctrl->fs_block_cache_info.entry_block_id != WR_ID_TO_U64(block_ctrl->block_id) && + owner_block_ctrl->fs_block_cache_info.fs_block_id != WR_ID_TO_U64(block_ctrl->block_id) && + owner_block_ctrl->fs_block_cache_info.fs_aux_block_id != WR_ID_TO_U64(block_ctrl->block_id)) { + need_clean = CM_TRUE; + } + } + wr_unlatch_node(owner_node); + + if (need_clean) { + block_ctrl->fs_block_cache_info.owner_node_addr = NULL; + block_ctrl->fs_block_cache_info.owner_node_id = 0; + } + return need_clean; +} + +static void wr_try_recycle_meta_batch(wr_session_t *session, wr_vg_info_item_t *vg_item, bool32 trigger_enable) +{ + wr_block_ctrl_t *block_ctrl = NULL; + uint32 fs_recyle_cnt = 0; + uint32 fs_aux_recyle_cnt = 0; + + if (vg_item->recycle_meta_desc.bilist.count == 0) { + return; + } + + wr_enter_shm_x(session, vg_item); + bilist_node_t *recycle_meta_node = wr_pop_recycle_meta(session, vg_item); + while (recycle_meta_node) { + block_ctrl = BILIST_NODE_OF(wr_block_ctrl_t, recycle_meta_node, recycle_meta_node); + // only the ref_hot is 0, and not in syn meta, and clean the invalid cache info + if (!block_ctrl->recycle_disable && block_ctrl->ref_hot == 0 && wr_try_clean_cache_meta(session, block_ctrl)) { + if (block_ctrl->type == WR_BLOCK_TYPE_FS) { + fs_recyle_cnt++; + LOG_DEBUG_INF("recycle fs meta pool item id:%s", wr_display_metaid(block_ctrl->block_id)); + } else { + fs_aux_recyle_cnt++; + LOG_DEBUG_INF("recycle fs aux meta pool item id:%s", wr_display_metaid(block_ctrl->block_id)); + } + + wr_unregister_buffer_cache(session, vg_item, block_ctrl->block_id); + ga_free_object(block_ctrl->my_obj_id.pool_id, block_ctrl->my_obj_id.obj_id); + } + recycle_meta_node = wr_pop_recycle_meta(session, vg_item); + } + wr_leave_shm(session, vg_item); + + LOG_DEBUG_INF("recycle fs meta pool item count:%u", fs_recyle_cnt); + LOG_DEBUG_INF("recycle fs aux meta pool item count:%u", fs_aux_recyle_cnt); +} + +static inline uint32 wr_recycle_meta_batch_num(bool32 trigger_enable) +{ + return trigger_enable ? WR_RECYCLE_META_TRIGGER_CLEAN_BATCH_NUM : WR_RECYCLE_META_TIME_CLEAN_BATCH_NUM; +} + +static void wr_recycle_meta_by_vg(wr_session_t *session, wr_vg_info_item_t *vg_item, + wr_recycle_meta_args_t *recycle_meta_args, bool32 trigger_enable) +{ + shm_hashmap_t *map = vg_item->buffer_cache; + if (map == NULL) { + return; + } + + shm_hash_ctrl_t *hash_ctrl = &map->hash_ctrl; + // hash_ctrl->max_bucket may change + uint32 cur_map_num = hash_ctrl->max_bucket; + if (cur_map_num == 0) { + return; + } + + shm_hashmap_bucket_t *bucket = NULL; + uint32 found_num = 0; + uint32 bucket_id = recycle_meta_args->last_bucket_id[vg_item->id]; + if (bucket_id >= cur_map_num || bucket_id >= hash_ctrl->max_bucket) { + bucket_id = 0; + } + + for (; (bucket_id < cur_map_num && bucket_id < hash_ctrl->max_bucket); bucket_id++) { + bucket = shm_hashmap_get_bucket(hash_ctrl, bucket_id, NULL); + if (bucket == NULL || !bucket->has_next) { + continue; + } + + found_num += wr_try_find_recycle_meta_by_bucket(session, vg_item, bucket, recycle_meta_args); + uint32 batch_num = wr_recycle_meta_batch_num(trigger_enable); + if ((found_num >= batch_num) || ((bucket_id + 1) == cur_map_num)) { + wr_try_recycle_meta_batch(session, vg_item, trigger_enable); + found_num = 0; + } + + // check the recycle end + uint32 fs_usage = ga_get_pool_usage(GA_16K_POOL); + uint32 fs_aux_usage = ga_get_pool_usage(GA_FS_AUX_POOL); + if (fs_usage <= recycle_meta_args->recyle_meta_pos->lwm && + fs_aux_usage <= recycle_meta_args->recyle_meta_pos->lwm) { + break; + } + } + recycle_meta_args->last_bucket_id[vg_item->id] = bucket_id; + + if (found_num > 0) { + wr_try_recycle_meta_batch(session, vg_item, trigger_enable); + } +} + +void wr_recycle_meta(wr_session_t *session, wr_bg_task_info_t *bg_task_info, date_t *clean_time) +{ + wr_recycle_meta_args_t *recycle_meta_args = (wr_recycle_meta_args_t *)bg_task_info->task_args; + + (void)cm_wait_cond(&recycle_meta_args->trigger_cond, recycle_meta_args->trigger_clean_wait_time); + bool32 trigger_enable = recycle_meta_args->trigger_enable; + if (!trigger_enable) { + uint64 time_now = (uint64)cm_now(); + if ((time_now - (*clean_time)) < (recycle_meta_args->time_clean_wait_time * MICROSECS_PER_SECOND)) { + return; + } + } else { + recycle_meta_args->trigger_enable = CM_FALSE; + } + + // check wheather need to recycle meta first + uint32 fs_usage = ga_get_pool_usage(GA_16K_POOL); + uint32 fs_aux_usage = ga_get_pool_usage(GA_FS_AUX_POOL); + if ((fs_usage <= recycle_meta_args->recyle_meta_pos->hwm) && + (fs_aux_usage <= recycle_meta_args->recyle_meta_pos->hwm)) { + return; + } + + LOG_DEBUG_INF("try recycle meta, trigger_enable:%u", (uint32)trigger_enable); + // do recycle meta for vg one by one + for (uint32_t i = bg_task_info->vg_id_beg; i < bg_task_info->vg_id_end; i++) { + wr_recycle_meta_by_vg(session, &g_vgs_info->volume_group[i], recycle_meta_args, trigger_enable); + } + + if (!trigger_enable) { + *clean_time = cm_now(); + } + + (void)cm_wait_cond(&recycle_meta_args->trigger_cond, recycle_meta_args->trigger_clean_wait_time); +} + +void wr_buffer_recycle_disable(wr_block_ctrl_t *block_ctrl, bool8 recycle_disable) +{ + block_ctrl->recycle_disable = recycle_disable; +} + +void wr_set_recycle_meta_args_to_vg(wr_bg_task_info_t *bg_task_info) +{ + // do recycle meta for vg one by one + for (uint32_t i = bg_task_info->vg_id_beg; i < bg_task_info->vg_id_end; i++) { + g_vgs_info->volume_group[i].recycle_meta_desc.task_args = bg_task_info->task_args; + } +} + +void wr_trigger_recycle_meta(wr_vg_info_item_t *vg_item) +{ + wr_recycle_meta_args_t *recycle_meta_args = (wr_recycle_meta_args_t *)vg_item->recycle_meta_desc.task_args; + recycle_meta_args->trigger_enable = CM_TRUE; + cm_release_cond(&recycle_meta_args->trigger_cond); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/common/wr_meta_buf.h b/src/common/wr_meta_buf.h new file mode 100644 index 0000000000000000000000000000000000000000..adb460dfced158282b0c49f25478e1c177153084 --- /dev/null +++ b/src/common/wr_meta_buf.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_meta_buf.h + * + * + * IDENTIFICATION + * src/common/wr_meta_buf.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_META_BUF_H__ +#define __WR_META_BUF_H__ + +#include "wr_ga.h" +#include "wr_au.h" +#include "wr_diskgroup.h" +#include "wr_session.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// this meta_addr should be formated as: block_ctrl(512) | meta(ft/fs/fs-aux) +#define WR_GET_META_FROM_BLOCK_CTRL(meta_type, block_ctrl) ((meta_type *)((char *)(block_ctrl) + WR_BLOCK_CTRL_SIZE)) +#define WR_GET_BLOCK_CTRL_FROM_META(meta_addr) ((wr_block_ctrl_t *)((char *)(meta_addr)-WR_BLOCK_CTRL_SIZE)) + +#if defined(_DEBUG) || defined(DEBUG) || defined(DB_DEBUG_VERSION) +#define WR_RECYCLE_META_RECYCLE_RATE_HWM 8000 // unit is 0.01% +#define WR_RECYCLE_META_RECYCLE_RATE_LWM 6000 // unit is 0.01% +#else +#define WR_RECYCLE_META_RECYCLE_RATE_HWM 80 // unit is 1% +#define WR_RECYCLE_META_RECYCLE_RATE_LWM 60 // unit is 1% +#endif + +#define WR_RECYCLE_META_HOT_INC_STEP 3 +#define WR_RECYCLE_META_TIME_CLEAN_BATCH_NUM 8 +#define WR_RECYCLE_META_TRIGGER_CLEAN_BATCH_NUM 1 +#define WR_RECYCLE_META_TRIGGER_WAIT_TIME 200 // ms + +typedef struct st_wr_recycle_meta_args { + wr_recycle_meta_pos_t *recyle_meta_pos; + uint32 time_clean_wait_time; // ms + uint32 trigger_clean_wait_time; // ms + cm_thread_cond_t trigger_cond; // for tigger recycle meta by other task + bool32 trigger_enable; + uint32 last_bucket_id[WR_MAX_VOLUME_GROUP_NUM]; // for re-start from last recycle stop point +} wr_recycle_meta_args_t; + +typedef struct st_wr_recycle_meta { + wr_recycle_meta_args_t recycle_meta_args; + wr_bg_task_info_t recycle_meta_task[WR_RECYLE_META_TASK_NUM_MAX]; +} wr_recycle_meta_t; + +#define WR_LOCK_SHM_META_TIMEOUT 200 +#define WR_BUFFER_CACHE_HASH(block_id) cm_hash_int64((int64)WR_BLOCK_ID_IGNORE_UNINITED((block_id))) +void wr_enter_shm_x(wr_session_t *session, wr_vg_info_item_t *vg_item); +bool32 wr_enter_shm_time_x(wr_session_t *session, wr_vg_info_item_t *vg_item, uint32 wait_ticks); +void wr_enter_shm_s(wr_session_t *session, wr_vg_info_item_t *vg_item, bool32 is_force, int32 timeout); +void wr_leave_shm(wr_session_t *session, wr_vg_info_item_t *vg_item); + +wr_block_ctrl_t *wr_buffer_get_block_ctrl_addr(ga_pool_id_e pool_id, uint32 object_id); +char *wr_buffer_get_meta_addr(ga_pool_id_e pool_id, uint32 object_id); + +uint32 wr_buffer_cache_get_block_size(uint32_t block_type); +bool32 wr_buffer_cache_key_compare(void *key, void *key2); + +status_t wr_register_buffer_cache(wr_session_t *session, wr_vg_info_item_t *vg_item, const wr_block_id_t block_id, + ga_obj_id_t obj_id, char *meta_addr, wr_block_type_t type); +void wr_unregister_buffer_cache(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_id_t block_id); +status_t wr_find_block_objid_in_shm(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_id_t block_id, + wr_block_type_t type, ga_obj_id_t *objid); +char *wr_find_block_in_shm(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_id_t block_id, + wr_block_type_t type, bool32 check_version, ga_obj_id_t *out_obj_id, bool32 active_refresh); +char *wr_find_block_from_disk_and_refresh_shm(wr_session_t *session, wr_vg_info_item_t *vg_item, + wr_block_id_t block_id, wr_block_type_t type, ga_obj_id_t *out_obj_id); +char *wr_find_block_in_shm_no_refresh( + wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_id_t block_id, ga_obj_id_t *out_obj_id); +// do not care content change, just care about exist +char *wr_find_block_in_shm_no_refresh_ex( + wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_id_t block_id, ga_obj_id_t *out_obj_id); + +status_t wr_refresh_buffer_cache(wr_session_t *session, wr_vg_info_item_t *vg_item, shm_hashmap_t *map); +status_t wr_get_block_from_disk( + wr_vg_info_item_t *vg_item, wr_block_id_t block_id, char *buf, int64_t offset, int32 size, bool32 calc_checksum); +status_t wr_check_block_version(wr_vg_info_item_t *vg_item, wr_block_id_t block_id, wr_block_type_t type, + char *meta_addr, bool32 *is_changed, bool32 force_refresh); +status_t wr_refresh_block_in_shm(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_id_t block_id, + wr_block_type_t type, char *buf, char **shm_buf); +static inline int64 wr_get_block_offset(wr_vg_info_item_t *vg_item, uint64 block_size, uint64 blockid, uint64 auid) +{ + return (int64)(block_size * blockid + wr_get_vg_au_size(vg_item->wr_ctrl) * auid); +} + +void wr_init_wr_fs_block_cache_info(wr_fs_block_cache_info_t *fs_block_cache_info); +void wr_init_vg_cache_node_info(wr_vg_info_item_t *vg_item); +status_t wr_hashmap_extend_and_redistribute(wr_session_t *session, shm_hash_ctrl_t *hash_ctrl); +status_t wr_hashmap_extend_and_redistribute_batch( + wr_session_t *session, shm_hash_ctrl_t *hash_ctrl, uint32 extend_num); +void wr_hashmap_dynamic_extend_and_redistribute_per_vg(wr_vg_info_item_t *vg_item, wr_session_t *session); + +// do not need control concurrence +void wr_inc_meta_ref_hot(wr_block_ctrl_t *block_ctrl); +// do not need control concurrence +void wr_desc_meta_ref_hot(wr_block_ctrl_t *block_ctrl); + +void wr_buffer_recycle_disable(wr_block_ctrl_t *block_ctrl, bool8 recycle_disable); +void wr_set_recycle_meta_args_to_vg(wr_bg_task_info_t *bg_task_info); +void wr_recycle_meta(wr_session_t *session, wr_bg_task_info_t *bg_task_info, date_t *clean_time); +void wr_trigger_recycle_meta(wr_vg_info_item_t *vg_item); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/common/wr_open_file.c b/src/common/wr_open_file.c new file mode 100644 index 0000000000000000000000000000000000000000..5e9f7f636036aac30726117a4a2520b3ba2c674a --- /dev/null +++ b/src/common/wr_open_file.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_open_file.c + * + * + * IDENTIFICATION + * src/common/wr_open_file.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_open_file.h" +#include "cm_system.h" + +bilist_node_t *wr_find_open_file_node(bilist_t *open_file_list, uint64 ftid, uint64 pid, int64 start_time) +{ + wr_open_file_info_t *open_file = NULL; + + bilist_node_t *node = cm_bilist_head(open_file_list); + for (; node != NULL; node = BINODE_NEXT(node)) { + open_file = BILIST_NODE_OF(wr_open_file_info_t, node, link); + if (open_file->ftid == ftid && open_file->pid == pid && open_file->start_time == start_time) { + return node; + } + } + return NULL; +} + +status_t wr_insert_open_file_index( + wr_session_t *session, wr_vg_info_item_t *vg_item, uint64 ftid, uint64 pid, int64 start_time) +{ + wr_open_file_info_t *open_file = NULL; + + wr_latch_x2(&vg_item->open_file_latch, session->id); + bilist_node_t *node = wr_find_open_file_node(&vg_item->open_file_list, ftid, pid, start_time); + if (node != NULL) { + open_file = BILIST_NODE_OF(wr_open_file_info_t, node, link); + open_file->ref++; + LOG_DEBUG_INF("Succeed to insert open file index, ftid:%llu, pid:%llu, ref:%llu.", ftid, pid, open_file->ref); + wr_unlatch(&vg_item->open_file_latch); + return CM_SUCCESS; + } + + open_file = (wr_open_file_info_t *)cm_malloc(sizeof(wr_open_file_info_t)); + if (open_file == NULL) { + wr_unlatch(&vg_item->open_file_latch); + WR_THROW_ERROR(ERR_WR_OUT_OF_MEM); + return CM_ERROR; + } + errno_t ret = memset_s(open_file, sizeof(wr_open_file_info_t), 0, sizeof(wr_open_file_info_t)); + if (ret != EOK) { + wr_unlatch(&vg_item->open_file_latch); + CM_FREE_PTR(open_file); + WR_THROW_ERROR(ERR_SYSTEM_CALL, ret); + return CM_ERROR; + } + open_file->ftid = ftid; + open_file->pid = pid; + open_file->start_time = start_time; + open_file->ref = 1; + cm_bilist_add_tail(&open_file->link, &vg_item->open_file_list); + LOG_DEBUG_INF("Succeed to insert open file index, ftid:%llu, pid:%llu, ref:%llu.", ftid, pid, open_file->ref); + wr_unlatch(&vg_item->open_file_latch); + return CM_SUCCESS; +} + +status_t wr_delete_open_file_index( + wr_session_t *session, wr_vg_info_item_t *vg_item, uint64 ftid, uint64 pid, int64 start_time) +{ + wr_latch_x(&vg_item->open_file_latch); + bilist_node_t *node = wr_find_open_file_node(&vg_item->open_file_list, ftid, pid, start_time); + if (node == NULL) { + wr_unlatch(&vg_item->open_file_latch); + WR_THROW_ERROR_EX(ERR_WR_FILE_CLOSE, "Failed to delete open file index, ftid:%llu, pid:%llu.", ftid, pid); + return CM_ERROR; + } + wr_open_file_info_t *open_file = BILIST_NODE_OF(wr_open_file_info_t, node, link); + LOG_DEBUG_INF( + "Succeed to delete open file index, ftid:%llu, pid:%llu, old ref is %llu.", ftid, pid, open_file->ref); + if (open_file->ref > 1) { + open_file->ref--; + } else { + wr_free_open_file_node(node, &vg_item->open_file_list); + } + wr_unlatch(&vg_item->open_file_latch); + return CM_SUCCESS; +} + +status_t wr_check_open_file(wr_session_t *session, wr_vg_info_item_t *vg_item, uint64 ftid, bool32 *is_open) +{ + *is_open = CM_FALSE; + wr_open_file_info_t *open_file = NULL; + + wr_latch_x2(&vg_item->open_file_latch, session->id); + bilist_node_t *curr_node = cm_bilist_head(&vg_item->open_file_list); + bilist_node_t *next_node = NULL; + while (curr_node != NULL) { + open_file = BILIST_NODE_OF(wr_open_file_info_t, curr_node, link); + next_node = curr_node->next; + if (!cm_sys_process_alived(open_file->pid, open_file->start_time)) { + wr_free_open_file_node(curr_node, &vg_item->open_file_list); + curr_node = next_node; + continue; + } + if (open_file->ftid == ftid) { + *is_open = CM_TRUE; + break; + } + curr_node = next_node; + } + + wr_unlatch(&vg_item->open_file_latch); + return CM_SUCCESS; +} diff --git a/src/common/wr_open_file.h b/src/common/wr_open_file.h new file mode 100644 index 0000000000000000000000000000000000000000..088d8b9ced764007cbc5efd97cfa63d4bee258f7 --- /dev/null +++ b/src/common/wr_open_file.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_open_file.h + * + * + * IDENTIFICATION + * src/common/wr_open_file.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_OPEN_FILE_H__ +#define __WR_OPEN_FILE_H__ + +#include "wr_diskgroup.h" +#include "wr_file_def.h" +#include "wr_malloc.h" +#include "wr_session.h" + +typedef struct st_wr_open_file_info_t { + uint64 ftid; + uint64 pid; + uint64 ref; + int64 start_time; + bilist_node_t link; +} wr_open_file_info_t; + +status_t wr_init_open_file_index(wr_vg_info_item_t *vg_item); +void wr_destroy_open_file_index(wr_vg_info_item_t *vg_item); + +status_t wr_insert_open_file_index( + wr_session_t *session, wr_vg_info_item_t *vg_item, uint64 ftid, uint64 pid, int64 start_time); +status_t wr_delete_open_file_index( + wr_session_t *session, wr_vg_info_item_t *vg_item, uint64 ftid, uint64 pid, int64 start_time); +status_t wr_check_open_file(wr_session_t *session, wr_vg_info_item_t *vg_item, uint64 ftid, bool32 *is_open); +static inline void wr_free_open_file_node(bilist_node_t *node, bilist_t *bilist) +{ + cm_bilist_del(node, bilist); + wr_open_file_info_t *open_file = BILIST_NODE_OF(wr_open_file_info_t, node, link); + cm_free(open_file); +} +#endif diff --git a/src/common/wr_protocol.c b/src/common/wr_protocol.c new file mode 100644 index 0000000000000000000000000000000000000000..8135ca1368f11f003f915d5067ec126c0b6e898b --- /dev/null +++ b/src/common/wr_protocol.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_protocol.c + * + * + * IDENTIFICATION + * src/common/wr_protocol.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_errno.h" +#include "wr_log.h" +#include "wr_thv.h" +#include "wr_protocol.h" + + +static char *g_wr_cmd_desc[WR_CMD_TYPE_OFFSET(WR_CMD_END)] = { + [WR_CMD_TYPE_OFFSET(WR_CMD_MKDIR)] = "mkdir", + [WR_CMD_TYPE_OFFSET(WR_CMD_RMDIR)] = "rmdir", + [WR_CMD_TYPE_OFFSET(WR_CMD_OPEN_DIR)] = "open dir", + [WR_CMD_TYPE_OFFSET(WR_CMD_CLOSE_DIR)] = "close dir", + [WR_CMD_TYPE_OFFSET(WR_CMD_OPEN_FILE)] = "open file", + [WR_CMD_TYPE_OFFSET(WR_CMD_CLOSE_FILE)] = "close file", + [WR_CMD_TYPE_OFFSET(WR_CMD_CREATE_FILE)] = "create file", + [WR_CMD_TYPE_OFFSET(WR_CMD_DELETE_FILE)] = "delete file", + [WR_CMD_TYPE_OFFSET(WR_CMD_EXTEND_FILE)] = "extend file", + [WR_CMD_TYPE_OFFSET(WR_CMD_RENAME_FILE)] = "rename file", + [WR_CMD_TYPE_OFFSET(WR_CMD_REFRESH_FILE)] = "refresh file", + [WR_CMD_TYPE_OFFSET(WR_CMD_TRUNCATE_FILE)] = "truncate file", + [WR_CMD_TYPE_OFFSET(WR_CMD_FALLOCATE_FILE)] = "fallocate file", + [WR_CMD_TYPE_OFFSET(WR_CMD_KICKH)] = "kick off host", + [WR_CMD_TYPE_OFFSET(WR_CMD_LOAD_CTRL)] = "load ctrl", + [WR_CMD_TYPE_OFFSET(WR_CMD_UPDATE_WRITTEN_SIZE)] = "update written size", + [WR_CMD_TYPE_OFFSET(WR_CMD_STOP_SERVER)] = "stopserver", + [WR_CMD_TYPE_OFFSET(WR_CMD_SETCFG)] = "setcfg", + [WR_CMD_TYPE_OFFSET(WR_CMD_SET_MAIN_INST)] = "set main inst", + [WR_CMD_TYPE_OFFSET(WR_CMD_SWITCH_LOCK)] = "switch cm lock", + [WR_CMD_TYPE_OFFSET(WR_CMD_HANDSHAKE)] = "handshake with server", + [WR_CMD_TYPE_OFFSET(WR_CMD_EXIST)] = "exist item", + [WR_CMD_TYPE_OFFSET(WR_CMD_GET_FTID_BY_PATH)] = "get ftid by path", + [WR_CMD_TYPE_OFFSET(WR_CMD_GETCFG)] = "getcfg", + [WR_CMD_TYPE_OFFSET(WR_CMD_GET_INST_STATUS)] = "get inst status", + [WR_CMD_TYPE_OFFSET(WR_CMD_GET_TIME_STAT)] = "get time stat", + [WR_CMD_TYPE_OFFSET(WR_CMD_EXEC_REMOTE)] = "exec remote", + [WR_CMD_TYPE_OFFSET(WR_CMD_QUERY_HOTPATCH)] = "query status of hotpatch", +}; + +char *wr_get_cmd_desc(wr_cmd_type_e cmd_type) +{ + if (cmd_type < WR_CMD_BEGIN || cmd_type >= WR_CMD_END) { + return "unknown"; + } + return g_wr_cmd_desc[WR_CMD_TYPE_OFFSET(cmd_type)]; +} + +typedef status_t (*recv_func_t)(void *link, char *buf, uint32 size, int32 *recv_size); +typedef status_t (*recv_timed_func_t)(void *link, char *buf, uint32 size, uint32 timeout); +typedef status_t (*send_timed_func_t)(void *link, const char *buf, uint32 size, uint32 timeout); +typedef status_t (*wait_func_t)(void *link, uint32 wait_for, int32 timeout, bool32 *ready); + +typedef struct st_vio { + recv_func_t vio_recv; + wait_func_t vio_wait; + recv_timed_func_t vio_recv_timed; + send_timed_func_t vio_send_timed; +} vio_t; + +static const vio_t g_vio_list[] = { + {NULL, NULL, NULL, NULL}, + + // TCP io functions + {(recv_func_t)cs_tcp_recv, (wait_func_t)cs_tcp_wait, (recv_timed_func_t)cs_tcp_recv_timed, + (send_timed_func_t)cs_tcp_send_timed}, + + // IPC not implemented + {NULL, NULL, NULL, NULL}, + + // UDS io functions + {(recv_func_t)cs_uds_recv, (wait_func_t)cs_uds_wait, (recv_timed_func_t)cs_uds_recv_timed, + (send_timed_func_t)cs_uds_send_timed}, + + // SSL io functions + {(recv_func_t)cs_ssl_recv, (wait_func_t)cs_ssl_wait, (recv_timed_func_t)cs_ssl_recv_timed, + (send_timed_func_t)cs_ssl_send_timed}, + + // CS_TYPE_EMBEDDED not implemented + {NULL, NULL, NULL, NULL}, + + // CS_TYPE_DIRECT not implemented + {NULL, NULL, NULL, NULL}, +}; + +/* + Macro definitions for pipe I/O operations + @note + Performance sensitive, the pipe->type should be guaranteed by the caller. + e.g. CS_TYPE_TCP, CS_TYPE_SSL, CS_TYPE_DOMAIN_SOCKET +*/ +#define GET_VIO(pipe) (&g_vio_list[(pipe)->type]) + +#define VIO_SEND_TIMED(pipe, buf, size, timeout) GET_VIO(pipe)->vio_send_timed(&(pipe)->link, buf, size, timeout) + +#define VIO_RECV(pipe, buf, size, len) GET_VIO(pipe)->vio_recv(&(pipe)->link, buf, size, len) + +#define VIO_RECV_TIMED(pipe, buf, size, timeout) GET_VIO(pipe)->vio_recv_timed(&(pipe)->link, buf, size, timeout) + +#define VIO_WAIT(pipe, ev, timeout, ready) GET_VIO(pipe)->vio_wait(&(pipe)->link, ev, timeout, ready) + +status_t wr_put_text(wr_packet_t *pack, text_t *text) +{ + errno_t errcode; + CM_ASSERT(pack != NULL); + CM_ASSERT(text != NULL); + + /* put the length of text */ + (void)wr_put_int32(pack, text->len); + if (text->len == 0) { + return CM_SUCCESS; + } + /* put the string of text, and append the terminated sign */ + errcode = memcpy_s(WR_WRITE_ADDR(pack), WR_REMAIN_SIZE(pack), text->str, text->len); + WR_SECUREC_RETURN_IF_ERROR(errcode, CM_ERROR); + + pack->head->size += CM_ALIGN4(text->len); + return CM_SUCCESS; +} + +status_t wr_put_str_with_cutoff(wr_packet_t *pack, const char *str) +{ + uint32 size; + char *addr = NULL; + errno_t errcode = 0; + + CM_ASSERT(pack != NULL); + CM_ASSERT(str != NULL); + size = (uint32)strlen(str); + addr = WR_WRITE_ADDR(pack); + if (size != 0) { + // for such as err msg , len max is 2K, too long for wr packet, which is fixed len at present, so cut it off + // for '\0' + if (WR_REMAIN_SIZE(pack) <= 1) { + size = 0; + } else if (size >= WR_REMAIN_SIZE(pack)) { + // for '\0' + size = WR_REMAIN_SIZE(pack) - 1; + } + errcode = memcpy_s(addr, WR_REMAIN_SIZE(pack), str, size); + WR_SECUREC_RETURN_IF_ERROR(errcode, CM_ERROR); + } + WR_WRITE_ADDR(pack)[size] = '\0'; + pack->head->size += CM_ALIGN4(size + 1); + + return CM_SUCCESS; +} + +status_t wr_write_packet(cs_pipe_t *pipe, wr_packet_t *pack) +{ + if (pack->head->size > WR_MAX_PACKET_SIZE) { + WR_RETURN_IFERR2(CM_ERROR, CM_THROW_ERROR(ERR_BUFFER_OVERFLOW, pack->head->size, WR_MAX_PACKET_SIZE)); + } + status_t status = VIO_SEND_TIMED(pipe, pack->buf, pack->head->size, WR_DEFAULT_NULL_VALUE); + WR_RETURN_IFERR2(status, CM_THROW_ERROR(ERR_PACKET_SEND, pack->buf_size, pack->head->size, pack->head->size)); + return CM_SUCCESS; +} + +status_t wr_write(cs_pipe_t *pipe, wr_packet_t *pack) +{ + CM_ASSERT(pipe != NULL); + CM_ASSERT(pack != NULL); + pack->options = pipe->options; + + return wr_write_packet(pipe, pack); +} + +/* before call cs_read_tcp_packet(), cs_tcp_wait() is called */ +static status_t wr_read_packet(cs_pipe_t *pipe, wr_packet_t *pack, bool32 cs_client) +{ + int32 remain_size, offset, recv_size; + bool32 ready = CM_FALSE; + + offset = 0; + status_t status; + char *cs_mes = cs_client ? "read wait for server response" : "read wait for client request"; + for (;;) { + status = VIO_RECV(pipe, pack->buf + offset, (uint32)(pack->buf_size - offset), &recv_size); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_TCP_RECV, "uds", cm_get_sock_error())); + offset += recv_size; + if (offset >= (int32)sizeof(wr_packet_head_t)) { + break; + } + status = VIO_WAIT(pipe, CS_WAIT_FOR_READ, CM_NETWORK_IO_TIMEOUT, &ready); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_TCP_TIMEOUT, cs_mes)); + if (!ready) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_TCP_TIMEOUT_REMAIN, (uint32)(sizeof(uint32) - offset))); + } + } + + if (pack->head->size > pack->buf_size) { + WR_THROW_ERROR_EX(ERR_TCP_RECV, "Receive protocol failed, head size is %u, buffer size is %u, errno %d.", + pack->head->size, pack->buf_size, cm_get_sock_error()); + cm_fync_logfile(); + CM_ASSERT(0); + } + + remain_size = (int32)pack->head->size - offset; + if (remain_size <= 0) { + return CM_SUCCESS; + } + + status = VIO_WAIT(pipe, CS_WAIT_FOR_READ, CM_NETWORK_IO_TIMEOUT, &ready); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_TCP_TIMEOUT, cs_mes)); + + if (!ready) { + WR_THROW_ERROR(ERR_TCP_TIMEOUT, cs_mes); + return CM_ERROR; + } + + status = VIO_RECV_TIMED(pipe, pack->buf + offset, (uint32)remain_size, CM_NETWORK_IO_TIMEOUT); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_TCP_RECV, "Receive protocol failed.")); + + return CM_SUCCESS; +} + +status_t wr_read(cs_pipe_t *pipe, wr_packet_t *pack, bool32 cs_client) +{ + CM_ASSERT(pipe != NULL); + CM_ASSERT(pack != NULL); + pack->options = pipe->options; + + return wr_read_packet(pipe, pack, cs_client); +} + +static status_t wr_call_base(cs_pipe_t *pipe, wr_packet_t *req, wr_packet_t *ack) +{ + bool32 ready = CM_FALSE; + + if (wr_write(pipe, req) != CM_SUCCESS) { + LOG_RUN_ERR("wr write failed."); + return CM_ERROR; + } + + if (cs_wait(pipe, CS_WAIT_FOR_READ, pipe->socket_timeout, &ready) != CM_SUCCESS) { + LOG_RUN_ERR("cs wait failed."); + return CM_ERROR; + } + + if (!ready) { + WR_RETURN_IFERR2( + CM_ERROR, WR_THROW_ERROR(ERR_SOCKET_TIMEOUT, pipe->socket_timeout / (int32)CM_TIME_THOUSAND_UN)); + } + + return wr_read(pipe, ack, CM_TRUE); +} + +status_t wr_call_ex(cs_pipe_t *pipe, wr_packet_t *req, wr_packet_t *ack) +{ + status_t ret = wr_call_base(pipe, req, ack); + if (ret != CM_SUCCESS) { + LOG_RUN_ERR("[WR] ABORT INFO: wr call server failed, ack command type:%d, application exit.", ack->head->cmd); + cs_disconnect(pipe); + cm_fync_logfile(); + wr_exit(1); + } + return ret; +} diff --git a/src/common/wr_protocol.h b/src/common/wr_protocol.h new file mode 100644 index 0000000000000000000000000000000000000000..11d2be872094df3b8808451fda1919031a356935 --- /dev/null +++ b/src/common/wr_protocol.h @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_protocol.h + * + * + * IDENTIFICATION + * src/common/wr_protocol.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_PROTOCOL_H__ +#define __WR_PROTOCOL_H__ +#include "cm_base.h" +#ifndef WIN32 +#include +#endif + +#include "cm_defs.h" +#include "cs_packet.h" +#include "cs_pipe.h" +#include "wr_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// The value of each command type cannot be changed for compatibility reasons. +// If you want to add a command type, add it at the end. Before WR_CMD_END +typedef enum { + WR_CMD_BASE, + WR_CMD_BEGIN, + WR_CMD_MODIFY_BEGIN = WR_CMD_BEGIN, + WR_CMD_MKDIR = WR_CMD_MODIFY_BEGIN, + WR_CMD_RMDIR, + WR_CMD_OPEN_DIR, + WR_CMD_CLOSE_DIR, + WR_CMD_OPEN_FILE, + WR_CMD_CLOSE_FILE, + WR_CMD_CREATE_FILE, + WR_CMD_DELETE_FILE, + WR_CMD_EXTEND_FILE, + WR_CMD_RENAME_FILE, + WR_CMD_REFRESH_FILE, + WR_CMD_TRUNCATE_FILE, + WR_CMD_FALLOCATE_FILE, + WR_CMD_KICKH, // 20 + WR_CMD_LOAD_CTRL, + WR_CMD_UPDATE_WRITTEN_SIZE, + WR_CMD_STOP_SERVER, + WR_CMD_SETCFG, + WR_CMD_SET_MAIN_INST, + WR_CMD_SWITCH_LOCK, + WR_CMD_MODIFY_END = 127, + WR_CMD_QUERY_BEGIN = WR_CMD_MODIFY_END, + WR_CMD_HANDSHAKE = WR_CMD_QUERY_BEGIN, + WR_CMD_EXIST, // 128 + WR_CMD_GET_FTID_BY_PATH, + WR_CMD_GETCFG, + WR_CMD_GET_INST_STATUS, + WR_CMD_GET_TIME_STAT, + WR_CMD_EXEC_REMOTE, + WR_CMD_QUERY_HOTPATCH, + WR_CMD_QUERY_END, + WR_CMD_END // must be the last item +} wr_cmd_type_e; + +#define WR_CMD_TYPE_OFFSET(cmd_id) ((uint32)(cmd_id) - (uint32)WR_CMD_BEGIN) + +char *wr_get_cmd_desc(wr_cmd_type_e cmd_type); + +static inline bool32 wr_can_cmd_type_no_open(wr_cmd_type_e type) +{ + return ((type == WR_CMD_GET_INST_STATUS) || (type == WR_CMD_HANDSHAKE) || (type == WR_CMD_STOP_SERVER) || + (type == WR_CMD_SETCFG) || (type == WR_CMD_GETCFG)); +} + +typedef struct st_wr_packet_head { + uint32 version; + uint32 client_version; + uint32 size; + uint8 cmd; /* command in request packet */ + uint8 result; /* code in response packet, success(0) or error(1) */ + uint16 flags; + uint32 serial_number; + uint8 reserve[60]; +} wr_packet_head_t; + +typedef enum en_wr_packet_version { + WR_VERSION_0 = 0, /* version 0 */ + WR_VERSION_1 = 1, /* version 1 */ + WR_VERSION_2 = 2, /* version 2 */ +} wr_packet_version_e; + +#define WR_PROTO_VERSION WR_VERSION_2 +#define WR_INVALID_VERSION (int32)0x7FFFFFFF + +#define WR_PACKET_SIZE(pack) ((pack)->head->size) +#define WR_WRITE_ADDR(pack) ((pack)->buf + (pack)->head->size) +#define WR_REMAIN_SIZE(pack) ((pack)->buf_size - ((pack)->head->size)) +#define WR_READ_ADDR(pack) ((pack)->buf + (pack)->offset) + +typedef struct st_wr_packet { + uint32 offset; // for reading + uint32 options; // options + wr_packet_head_t *head; + uint32 max_buf_size; // MAX_ALLOWED_PACKET + uint32 buf_size; + char *buf; + char init_buf[WR_MAX_PACKET_SIZE]; +} wr_packet_t; + +static inline void wr_init_packet(wr_packet_t *pack, uint32 options) +{ + CM_ASSERT(pack != NULL); + pack->offset = 0; + pack->max_buf_size = WR_MAX_PACKET_SIZE; + pack->buf_size = WR_MAX_PACKET_SIZE; + pack->buf = pack->init_buf; + pack->head = (wr_packet_head_t *)pack->buf; + pack->options = options; +} + +static inline void wr_set_client_version(wr_packet_t *pack, uint32 version) +{ + CM_ASSERT(pack != NULL); + pack->head->client_version = version; +} + +static inline void wr_set_version(wr_packet_t *pack, uint32 version) +{ + CM_ASSERT(pack != NULL); + pack->head->version = version; +} + +static inline uint32 wr_get_client_version(wr_packet_t *pack) +{ + CM_ASSERT(pack != NULL); + return pack->head->client_version; +} + +static inline uint32 wr_get_version(wr_packet_t *pack) +{ + CM_ASSERT(pack != NULL); + return pack->head->version; +} + +static inline void wr_init_get(wr_packet_t *pack) +{ + if (pack == NULL) { + return; + } + pack->offset = (uint32)sizeof(wr_packet_head_t); +} + +static inline void wr_init_set(wr_packet_t *pack, uint32 proto_version) +{ + if (pack == NULL) { + return; + } + (void)memset_s(pack->head, sizeof(wr_packet_head_t), 0, sizeof(wr_packet_head_t)); + pack->head->size = (uint32)sizeof(wr_packet_head_t); + wr_set_version(pack, proto_version); + wr_set_client_version(pack, WR_PROTO_VERSION); +} + +static inline status_t wr_put_str(wr_packet_t *pack, const char *str) +{ + uint32 size; + char *addr = NULL; + errno_t errcode = 0; + + CM_ASSERT(pack != NULL); + CM_ASSERT(str != NULL); + size = (uint32)strlen(str); + addr = WR_WRITE_ADDR(pack); + uint32 estimated_size = pack->head->size + CM_ALIGN4(size + 1); + if (estimated_size > pack->buf_size) { + CM_THROW_ERROR(ERR_BUFFER_OVERFLOW, estimated_size, pack->buf_size); + return CM_ERROR; + } + if (size != 0) { + errcode = memcpy_s(addr, WR_REMAIN_SIZE(pack), str, size); + WR_SECUREC_RETURN_IF_ERROR(errcode, CM_ERROR); + } + WR_WRITE_ADDR(pack)[size] = '\0'; + pack->head->size = estimated_size; + + return CM_SUCCESS; +} + +static inline status_t wr_put_data(wr_packet_t *pack, const void *data, uint32 size) +{ + errno_t errcode = 0; + + CM_ASSERT(pack != NULL); + CM_ASSERT(data != NULL); + + if (size != 0) { + errcode = memcpy_s(WR_WRITE_ADDR(pack), WR_REMAIN_SIZE(pack), data, size); + WR_SECUREC_RETURN_IF_ERROR(errcode, CM_ERROR); + } + pack->head->size += CM_ALIGN4(size); + return CM_SUCCESS; +} + +static inline status_t wr_put_int64(wr_packet_t *pack, uint64 value) +{ + CM_ASSERT(pack != NULL); + + *(uint64 *)WR_WRITE_ADDR(pack) = (CS_DIFFERENT_ENDIAN(pack->options) != 0) ? cs_reverse_int64(value) : value; + pack->head->size += (uint32)sizeof(uint64); + return CM_SUCCESS; +} + +static inline status_t wr_put_int32(wr_packet_t *pack, uint32 value) +{ + CM_ASSERT(pack != NULL); + + *(uint32 *)WR_WRITE_ADDR(pack) = (CS_DIFFERENT_ENDIAN(pack->options) != 0) ? cs_reverse_int32(value) : value; + pack->head->size += (uint32)sizeof(uint32); + return CM_SUCCESS; +} + +static inline status_t wr_reserv_text_buf(wr_packet_t *pack, uint32 size, char **data_buf) +{ + CM_ASSERT(pack != NULL); + CM_ASSERT(data_buf != NULL); + if (CM_ALIGN4(size) >= WR_REMAIN_SIZE(pack) - sizeof(uint32)) { + CM_THROW_ERROR(ERR_BUFFER_OVERFLOW, size, WR_REMAIN_SIZE(pack) - 1); + return CM_ERROR; + } + + // record the size first + *(uint32 *)WR_WRITE_ADDR(pack) = (CS_DIFFERENT_ENDIAN(pack->options) != 0) ? cs_reverse_int32(size) : size; + pack->head->size += (uint32)sizeof(uint32); + + *data_buf = WR_WRITE_ADDR(pack); + pack->head->size += CM_ALIGN4(size); + return CM_SUCCESS; +} + +static inline status_t wr_pack_check_len(wr_packet_t *pack, uint32 inc) +{ + if ((pack->offset + inc) > pack->head->size) { + CM_THROW_ERROR(ERR_BUFFER_OVERFLOW, (pack->offset + inc), pack->head->size); + return CM_ERROR; + } + + return CM_SUCCESS; +} + +static inline status_t wr_get_data(wr_packet_t *pack, uint32 size, void **buf) +{ + int64 len; + char *temp_buf = NULL; + CM_ASSERT(pack != NULL); + + len = (int64)CM_ALIGN4(size); + TO_UINT32_OVERFLOW_CHECK(len, int64); + CM_RETURN_IFERR(wr_pack_check_len(pack, len)); + temp_buf = WR_READ_ADDR(pack); + pack->offset += CM_ALIGN4(size); + if (buf != NULL) { + *buf = (void *)temp_buf; + } + return CM_SUCCESS; +} + +static inline status_t wr_get_packet_strlen(wr_packet_t *pack, char *str, size_t *str_len) +{ + uint32 rem_len = (pack->head->size - pack->offset) - 1; + while (str[*str_len] != '\0') { + if ((*str_len)++ > rem_len) { + CM_THROW_ERROR(ERR_TYPE_OVERFLOW, "UNSIGNED STRING"); + return CM_ERROR; + } + } + (*str_len)++; + return CM_SUCCESS; +} + +static inline status_t wr_get_str(wr_packet_t *pack, char **buf) +{ + char *str = NULL; + int64 len; + size_t str_len = 0; + CM_ASSERT(pack != NULL); + + CM_RETURN_IFERR(wr_pack_check_len(pack, 1)); + str = WR_READ_ADDR(pack); + CM_RETURN_IFERR(wr_get_packet_strlen(pack, str, &str_len)); + len = (int64)CM_ALIGN4(str_len); + TO_UINT32_OVERFLOW_CHECK(len, int64); + pack->offset += (uint32)len; + if (buf != NULL) { + *buf = str; + } + return CM_SUCCESS; +} + +static inline status_t wr_get_int64(wr_packet_t *pack, int64 *value) +{ + int64 temp_value; + CM_ASSERT(pack != NULL); + + CM_RETURN_IFERR(wr_pack_check_len(pack, sizeof(int64))); + + temp_value = *(int64 *)WR_READ_ADDR(pack); + temp_value = (CS_DIFFERENT_ENDIAN(pack->options) != 0) ? (int64)cs_reverse_int64((uint64)temp_value) : temp_value; + pack->offset += (uint32)sizeof(int64); + if (value != NULL) { + *value = temp_value; + } + return CM_SUCCESS; +} + +static inline status_t wr_get_int32(wr_packet_t *pack, int32 *value) +{ + int32 temp_value; + CM_ASSERT(pack != NULL); + + CM_RETURN_IFERR(wr_pack_check_len(pack, sizeof(int32))); + + temp_value = *(int32 *)WR_READ_ADDR(pack); + pack->offset += (uint32)sizeof(int32); + temp_value = (CS_DIFFERENT_ENDIAN(pack->options) != 0) ? (int32)cs_reverse_int32((uint32)temp_value) : temp_value; + if (value != NULL) { + *value = temp_value; + } + return CM_SUCCESS; +} + +static inline status_t wr_get_text(wr_packet_t *pack, text_t *text) +{ + CM_ASSERT(pack != NULL); + CM_ASSERT(text != NULL); + + CM_RETURN_IFERR(wr_get_int32(pack, (int32 *)&text->len)); + if ((text->len > WR_MAX_PACKET_SIZE) || (text->len == 0)) { + CM_THROW_ERROR(ERR_BUFFER_OVERFLOW, "PACKET OVERFLOW"); + return CM_ERROR; + } + + return wr_get_data(pack, text->len, (void **)&(text->str)); +} + +static inline void wr_free_packet_buffer(wr_packet_t *pack) +{ + if (pack->buf != pack->init_buf) { + if (pack->buf != NULL) { + free(pack->buf); + pack->buf = NULL; + } + + wr_init_packet(pack, 0); + } +} + +status_t wr_put_text(wr_packet_t *pack, text_t *text); +status_t wr_put_str_with_cutoff(wr_packet_t *pack, const char *str); +status_t wr_write_packet(cs_pipe_t *pipe, wr_packet_t *pack); +status_t wr_write(cs_pipe_t *pipe, wr_packet_t *pack); +status_t wr_read(cs_pipe_t *pipe, wr_packet_t *pack, bool32 cs_client); +status_t wr_call_ex(cs_pipe_t *pipe, wr_packet_t *req, wr_packet_t *ack); + +#ifdef __cplusplus +} +#endif + +#endif // __WR_PROTOCOL_H__ diff --git a/src/common/wr_session.c b/src/common/wr_session.c new file mode 100644 index 0000000000000000000000000000000000000000..eb1bfb6f4082ca219f63633b02aabc523adf598d --- /dev/null +++ b/src/common/wr_session.c @@ -0,0 +1,941 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_session.c + * + * + * IDENTIFICATION + * src/common/wr_session.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_session.h" +#include "cm_utils.h" +#include "wr_diskgroup.h" +#include "wr_malloc.h" +#include "wr_file.h" +#include "wr_redo.h" +#include "cm_system.h" +#include "wr_thv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +wr_session_ctrl_t g_wr_session_ctrl = {0}; + +status_t wr_extend_session(uint32 extend_num) +{ + uint32 objectid; + uint32_t old_alloc_sessions = g_wr_session_ctrl.alloc_sessions; + uint32_t new_alloc_sessions = g_wr_session_ctrl.alloc_sessions + extend_num; + if (new_alloc_sessions > g_wr_session_ctrl.total) { + LOG_RUN_ERR("Failed to extend session, expect new alloc sessions %u, but max is %u.", new_alloc_sessions, + g_wr_session_ctrl.total); + WR_THROW_ERROR(ERR_WR_SESSION_EXTEND, "expect new alloc sessions %u, but max is %u.", new_alloc_sessions, + g_wr_session_ctrl.total); + return CM_ERROR; + } + for (uint32_t i = old_alloc_sessions; i < new_alloc_sessions; i++) { + objectid = ga_alloc_object(GA_SESSION_POOL, WR_INVALID_ID32); + if (objectid == WR_INVALID_ID32) { + LOG_RUN_ERR("Failed to alloc object for session %u.", i); + WR_THROW_ERROR(ERR_WR_SESSION_EXTEND, "Failed to alloc object for session %u.", i); + return CM_ERROR; + } + LOG_DEBUG_INF("Alloc object %u for session %u.", objectid, i); + g_wr_session_ctrl.sessions[i] = (wr_session_t *)ga_object_addr(GA_SESSION_POOL, objectid); + g_wr_session_ctrl.sessions[i]->id = i; + g_wr_session_ctrl.sessions[i]->is_used = CM_FALSE; + g_wr_session_ctrl.sessions[i]->is_closed = CM_TRUE; + g_wr_session_ctrl.sessions[i]->put_log = CM_FALSE; + g_wr_session_ctrl.sessions[i]->objectid = objectid; + g_wr_session_ctrl.sessions[i]->is_holding_hotpatch_latch = CM_FALSE; + g_wr_session_ctrl.alloc_sessions++; + } + LOG_RUN_INF("Succeed to extend sessions to %u.", g_wr_session_ctrl.alloc_sessions); + return CM_SUCCESS; +} + +status_t wr_init_session_pool(uint32 max_session_num) +{ + uint32 wr_session_size = (uint32)(max_session_num * sizeof(wr_session_t *)); + g_wr_session_ctrl.sessions = cm_malloc(wr_session_size); + if (g_wr_session_ctrl.sessions == NULL) { + return ERR_WR_GA_INIT; + } + errno_t errcode = memset_s(g_wr_session_ctrl.sessions, wr_session_size, 0, wr_session_size); + securec_check_ret(errcode); + g_wr_session_ctrl.alloc_sessions = 0; + uint32 extend_num = max_session_num >= WR_SESSION_NUM_PER_GROUP ? WR_SESSION_NUM_PER_GROUP : max_session_num; + g_wr_session_ctrl.total = max_session_num; + status_t status = wr_extend_session(extend_num); + if (status != CM_SUCCESS) { + return status; + } + g_wr_session_ctrl.is_inited = CM_TRUE; + return CM_SUCCESS; +} + +wr_session_ctrl_t *wr_get_session_ctrl(void) +{ + return &g_wr_session_ctrl; +} + +uint32 wr_get_uwression_startid(void) +{ + wr_config_t *inst_cfg = wr_get_inst_cfg(); + uint32 start_sid = (uint32)WR_BACKGROUND_TASK_NUM; + if (inst_cfg->params.nodes_list.inst_cnt > 1) { + start_sid = start_sid + inst_cfg->params.channel_num + inst_cfg->params.work_thread_cnt; + } + return start_sid; +} + +uint32 wr_get_max_total_session_cnt(void) +{ + wr_config_t *inst_cfg = wr_get_inst_cfg(); + return wr_get_uwression_startid() + inst_cfg->params.cfg_session_num; +} + +uint32 wr_get_recover_task_idx(void) +{ + return (wr_get_uwression_startid() - (uint32)WR_BACKGROUND_TASK_NUM); +} + +uint32 wr_get_delay_clean_task_idx(void) +{ + return (wr_get_uwression_startid() - (uint32)WR_BACKGROUND_TASK_NUM) + WR_DELAY_CLEAN_BACKGROUND_TASK; +} + +uint32 wr_get_hashmap_dynamic_extend_task_idx(void) +{ + return (wr_get_uwression_startid() - (uint32)WR_BACKGROUND_TASK_NUM) + WR_HASHMAP_DYNAMIC_EXTEND_TASK; +} + +uint32 wr_get_bg_task_set_idx(uint32 task_id_base, uint32 idx) +{ + return (wr_get_uwression_startid() - (uint32)WR_BACKGROUND_TASK_NUM) + task_id_base + idx; +} + +uint32 wr_get_meta_syn_task_idx(uint32 idx) +{ + return wr_get_bg_task_set_idx(WR_META_SYN_BG_TASK_BASE, idx); +} + +uint32 wr_get_recycle_meta_task_idx(uint32 idx) +{ + return wr_get_bg_task_set_idx(WR_RECYCLE_META_TASK_BASE, idx); +} + +uint32 wr_get_alarm_check_task_idx(void) +{ + return (wr_get_uwression_startid() - (uint32)WR_BACKGROUND_TASK_NUM) + WR_ALARM_CHECK_TASK; +} + +static status_t wr_init_session(wr_session_t *session, const cs_pipe_t *pipe) +{ + wr_latch_stack_t *latch_stack = &session->latch_stack; + errno_t errcode = memset_s(latch_stack, sizeof(wr_latch_stack_t), 0, sizeof(wr_latch_stack_t)); + securec_check_ret(errcode); + session->is_direct = CM_TRUE; + session->connected = CM_FALSE; + if (pipe != NULL) { + session->pipe = *pipe; + session->connected = CM_TRUE; + } + session->is_closed = CM_FALSE; + session->proto_type = PROTO_TYPE_UNKNOWN; + session->status = WR_SESSION_STATUS_IDLE; + session->client_version = WR_PROTO_VERSION; + session->proto_version = WR_PROTO_VERSION; + errcode = memset_s( + session->wr_session_stat, WR_EVT_COUNT * sizeof(wr_stat_item_t), 0, WR_EVT_COUNT * sizeof(wr_stat_item_t)); + securec_check_ret(errcode); + session->is_holding_hotpatch_latch = CM_FALSE; + return CM_SUCCESS; +} + +wr_session_t *wr_get_reserv_session(uint32 idx) +{ + wr_session_ctrl_t *session_ctrl = wr_get_session_ctrl(); + wr_session_t *session = session_ctrl->sessions[idx]; + return session; +} + +status_t wr_create_session(const cs_pipe_t *pipe, wr_session_t **session) +{ + uint32 i, id; + + *session = NULL; + id = WR_INVALID_ID32; + cm_spin_lock(&g_wr_session_ctrl.lock, NULL); + + uint32 start_sid = wr_get_uwression_startid(); + uint32 end_sid = wr_get_max_total_session_cnt(); + status_t status; + for (i = start_sid; i < end_sid; i++) { + if (i >= g_wr_session_ctrl.alloc_sessions) { + uint32 extend_num = + g_wr_session_ctrl.total - g_wr_session_ctrl.alloc_sessions >= WR_SESSION_NUM_PER_GROUP ? + WR_SESSION_NUM_PER_GROUP : + g_wr_session_ctrl.total - g_wr_session_ctrl.alloc_sessions; + status = wr_extend_session(extend_num); + if (status != CM_SUCCESS) { + cm_spin_unlock(&g_wr_session_ctrl.lock); + return status; + } + } + if (g_wr_session_ctrl.sessions[i]->is_used == CM_FALSE) { + id = i; + break; + } + } + if (id == WR_INVALID_ID32) { + LOG_DEBUG_INF("No sessions are available."); + cm_spin_unlock(&g_wr_session_ctrl.lock); + return ERR_WR_SESSION_CREATE; + } + *session = g_wr_session_ctrl.sessions[i]; + LOG_DEBUG_INF("Session[%u] is available.", id); + cm_spin_lock(&(*session)->lock, NULL); + g_wr_session_ctrl.used_count++; + (*session)->is_used = CM_TRUE; + cm_spin_unlock(&(*session)->lock); + cm_spin_unlock(&g_wr_session_ctrl.lock); + WR_RETURN_IF_ERROR(wr_init_session(*session, pipe)); + return CM_SUCCESS; +} +void wr_destroy_session_inner(wr_session_t *session) +{ + if (session->connected == CM_TRUE) { + cs_disconnect(&session->pipe); + session->connected = CM_FALSE; + } + g_wr_session_ctrl.used_count--; + session->is_closed = CM_TRUE; + session->is_used = CM_FALSE; + errno_t ret = memset_sp(&session->cli_info, sizeof(session->cli_info), 0, sizeof(session->cli_info)); + securec_check_panic(ret); + session->client_version = WR_PROTO_VERSION; + session->proto_version = WR_PROTO_VERSION; + session->put_log = CM_FALSE; + session->is_holding_hotpatch_latch = CM_FALSE; +} +void wr_destroy_session(wr_session_t *session) +{ + cm_spin_lock(&g_wr_session_ctrl.lock, NULL); + cm_spin_lock(&session->shm_lock, NULL); + LOG_DEBUG_INF("Succeed to lock session %u shm lock", session->id); + wr_destroy_session_inner(session); + cm_spin_unlock(&session->shm_lock); + LOG_DEBUG_INF("Succeed to unlock session %u shm lock", session->id); + cm_spin_unlock(&g_wr_session_ctrl.lock); +} + +wr_session_t *wr_get_session(uint32 sid) +{ + if (sid >= g_wr_session_ctrl.alloc_sessions || sid >= g_wr_session_ctrl.total) { + return NULL; + } + return g_wr_session_ctrl.sessions[sid]; +} + +static bool32 wr_is_timeout(int32 timeout, int32 sleep_times, int32 sleeps) +{ + if ((timeout == SPIN_WAIT_FOREVER) || (sleeps == 0)) { + return CM_FALSE; + } + + /* ms --> us, and translate to times */ + return (bool32)(((timeout * 1000) / (sleeps)) < sleep_times); +} + +status_t wr_lock_shm_meta_s_without_stack( + wr_session_t *session, wr_shared_latch_t *shared_latch, bool32 is_force, int32 timeout) +{ + cm_panic_log(wr_is_server(), "can not op shared latch without session latch stack in client"); + int32 sleep_times = 0; + latch_statis_t *stat = NULL; + uint32 count = 0; + uint32 sid = WR_SESSIONID_IN_LOCK(session->id); + do { + cm_spin_lock_by_sid(sid, &shared_latch->latch.lock, (stat != NULL) ? &stat->s_spin : NULL); + if (shared_latch->latch.stat == LATCH_STATUS_IDLE) { + shared_latch->latch.stat = LATCH_STATUS_S; + shared_latch->latch.shared_count = 1; + shared_latch->latch.sid = (uint16)sid; + shared_latch->latch_extent.shared_sid_count += sid; + cm_spin_unlock(&shared_latch->latch.lock); + cm_latch_stat_inc(stat, count); + return CM_SUCCESS; + } + if ((shared_latch->latch.stat == LATCH_STATUS_S) || (shared_latch->latch.stat == LATCH_STATUS_IX && is_force)) { + shared_latch->latch.shared_count++; + shared_latch->latch_extent.shared_sid_count += sid; + cm_spin_unlock(&shared_latch->latch.lock); + cm_latch_stat_inc(stat, count); + return CM_SUCCESS; + } + + cm_spin_unlock(&shared_latch->latch.lock); + if (stat != NULL) { + stat->misses++; + } + while (shared_latch->latch.stat != LATCH_STATUS_IDLE && shared_latch->latch.stat != LATCH_STATUS_S) { + count++; + if (count < GS_SPIN_COUNT) { + continue; + } + + SPIN_STAT_INC(stat, s_sleeps); + cm_usleep(SPIN_SLEEP_TIME); + sleep_times++; + + if (wr_is_timeout(timeout, sleep_times, SPIN_SLEEP_TIME)) { + return CM_ERROR; + } + count = 0; + } + } while (1); + return CM_SUCCESS; +} + +// only used by api-client +status_t wr_lock_shm_meta_s_with_stack( + wr_session_t *session, wr_latch_offset_t *offset, wr_shared_latch_t *shared_latch, int32 timeout) +{ + cm_panic_log(!(wr_is_server()), "can not op shared latch with session latch stack in server"); + WR_ASSERT_LOG(session != NULL, "session ptr is NULL"); + WR_ASSERT_LOG(session->latch_stack.stack_top < WR_MAX_LATCH_STACK_DEPTH, "latch_stack overflow"); + + session->latch_stack.stack_top_bak = session->latch_stack.stack_top; + session->latch_stack.op = LATCH_SHARED_OP_LATCH_S; + session->latch_stack.latch_offset_stack[session->latch_stack.stack_top] = *offset; + + int32 sleep_times = 0; + latch_statis_t *stat = NULL; + uint32 count = 0; + uint32 sid = WR_SESSIONID_IN_LOCK(session->id); + bool32 is_force = CM_FALSE; + do { + cm_spin_lock_by_sid(sid, &shared_latch->latch.lock, (stat != NULL) ? &stat->s_spin : NULL); + + // for shared latch in shm, need to backup first + wr_set_latch_extent(&shared_latch->latch_extent, shared_latch->latch.stat, shared_latch->latch.shared_count); + + if (shared_latch->latch.stat == LATCH_STATUS_IDLE) { + session->latch_stack.op = LATCH_SHARED_OP_LATCH_S_BEG; + + shared_latch->latch.stat = LATCH_STATUS_S; + shared_latch->latch.shared_count = 1; + shared_latch->latch.sid = (uint16)sid; + shared_latch->latch_extent.shared_sid_count += sid; + + // put this before the unlock to make sure: whn error happen, no one else can change the status of this + // latch + session->latch_stack.stack_top++; + session->latch_stack.op = LATCH_SHARED_OP_LATCH_S_END; + + cm_spin_unlock(&shared_latch->latch.lock); + cm_latch_stat_inc(stat, count); + return CM_SUCCESS; + } + if ((shared_latch->latch.stat == LATCH_STATUS_S) || (shared_latch->latch.stat == LATCH_STATUS_IX && is_force)) { + session->latch_stack.op = LATCH_SHARED_OP_LATCH_S_BEG; + + shared_latch->latch.shared_count++; + shared_latch->latch_extent.shared_sid_count += sid; + + // put this before the unlock to make sure: whn error happen, no one else can change the status of this + // latch + session->latch_stack.stack_top++; + session->latch_stack.op = LATCH_SHARED_OP_LATCH_S_END; + + cm_spin_unlock(&shared_latch->latch.lock); + cm_latch_stat_inc(stat, count); + return CM_SUCCESS; + } + + cm_spin_unlock(&shared_latch->latch.lock); + if (stat != NULL) { + stat->misses++; + } + while (shared_latch->latch.stat != LATCH_STATUS_IDLE && shared_latch->latch.stat != LATCH_STATUS_S) { + count++; + if (count < GS_SPIN_COUNT) { + continue; + } + + SPIN_STAT_INC(stat, s_sleeps); + cm_usleep(SPIN_SLEEP_TIME); + sleep_times++; + + if (wr_is_timeout(timeout, sleep_times, SPIN_SLEEP_TIME)) { + if (session != NULL) { + session->latch_stack.latch_offset_stack[session->latch_stack.stack_top].type = + WR_LATCH_OFFSET_INVALID; + session->latch_stack.op = LATCH_SHARED_OP_NONE; + } + + return CM_ERROR; + } + count = 0; + } + } while (1); + return CM_SUCCESS; +} + +status_t wr_lock_shm_meta_bucket_s(wr_session_t *session, uint32 id, wr_shared_latch_t *shared_latch) +{ + CM_ASSERT(session != NULL); + if (wr_is_server()) { + return wr_lock_shm_meta_s_without_stack(session, shared_latch, CM_FALSE, SPIN_WAIT_FOREVER); + } + wr_latch_offset_t latch_offset; + latch_offset.type = WR_LATCH_OFFSET_SHMOFFSET; + cm_shm_key_t key = ga_object_key(GA_SEGMENT_POOL, id); + latch_offset.offset.shm_offset = cm_trans_shm_offset(key, &shared_latch->latch); + return wr_lock_shm_meta_s_with_stack(session, &latch_offset, shared_latch, SPIN_WAIT_FOREVER); +} + +status_t wr_cli_lock_shm_meta_s( + wr_session_t *session, wr_latch_offset_t *offset, wr_shared_latch_t *shared_latch, latch_should_exit should_exit) +{ + for (int i = 0; i < WR_CLIENT_TIMEOUT_COUNT; i++) { + if (session->is_closed) { + WR_THROW_ERROR(ERR_WR_SHM_LOCK, "uds connection is closed."); + LOG_RUN_ERR("[WR] ABORT INFO: Failed to lock vg share memery because uds connection is closed."); + cm_fync_logfile(); + wr_exit(1); + } + if (wr_lock_shm_meta_s_with_stack(session, offset, shared_latch, SPIN_WAIT_FOREVER) == CM_SUCCESS) { + return CM_SUCCESS; + } + + if (should_exit && should_exit()) { + LOG_RUN_ERR("Caller want to exit when waiting for shared_latch!!"); + return ERR_WR_LOCK_TIMEOUT; + } + } + LOG_RUN_ERR("The client want to lock meta timeout."); + return ERR_WR_LOCK_TIMEOUT; +} + +void wr_lock_shm_meta_x(const wr_session_t *session, wr_shared_latch_t *shared_latch) +{ + CM_ASSERT(session != NULL); + cm_panic_log(wr_is_server(), "can not op x latch in client"); + latch_statis_t *stat = NULL; + uint32 count = 0; + uint32 sid = WR_SESSIONID_IN_LOCK(session->id); + + do { + cm_spin_lock_by_sid(sid, &shared_latch->latch.lock, (stat != NULL) ? &stat->x_spin : NULL); + if (shared_latch->latch.stat == LATCH_STATUS_IDLE) { + shared_latch->latch.sid = (uint16)sid; + shared_latch->latch.stat = LATCH_STATUS_X; + cm_spin_unlock(&shared_latch->latch.lock); + cm_latch_stat_inc(stat, count); + return; + } + if (shared_latch->latch.stat == LATCH_STATUS_S) { + shared_latch->latch.stat = LATCH_STATUS_IX; + cm_spin_unlock(&shared_latch->latch.lock); + cm_latch_ix2x(&shared_latch->latch, sid, stat); + return; + } + cm_spin_unlock(&shared_latch->latch.lock); + if (stat != NULL) { + stat->misses++; + } + while (shared_latch->latch.stat != LATCH_STATUS_IDLE && shared_latch->latch.stat != LATCH_STATUS_S) { + count++; + if (count >= GS_SPIN_COUNT) { + SPIN_STAT_INC(stat, x_sleeps); + cm_spin_sleep(); + count = 0; + } + } + } while (CM_TRUE); +} + +bool32 wr_lock_shm_meta_timed_x(const wr_session_t *session, wr_shared_latch_t *shared_latch, uint32 wait_ticks) +{ + CM_ASSERT(session != NULL); + cm_panic_log(wr_is_server(), "can not op x latch in client"); + latch_statis_t *stat = NULL; + uint32 count = 0; + uint32 sid = WR_SESSIONID_IN_LOCK(session->id); + uint32 actual_ticks = 0; + do { + cm_spin_lock_by_sid(sid, &shared_latch->latch.lock, (stat != NULL) ? &stat->x_spin : NULL); + if (shared_latch->latch.stat == LATCH_STATUS_IDLE) { + shared_latch->latch.sid = (uint16)sid; + shared_latch->latch.stat = LATCH_STATUS_X; + cm_spin_unlock(&shared_latch->latch.lock); + cm_latch_stat_inc(stat, count); + return CM_TRUE; + } + if (shared_latch->latch.stat == LATCH_STATUS_S) { + shared_latch->latch.stat = LATCH_STATUS_IX; + cm_spin_unlock(&shared_latch->latch.lock); + if (!cm_latch_timed_ix2x(&shared_latch->latch, sid, wait_ticks, stat)) { + cm_spin_lock_by_sid(sid, &shared_latch->latch.lock, (stat != NULL) ? &stat->x_spin : NULL); + shared_latch->latch.stat = shared_latch->latch.shared_count > 0 ? LATCH_STATUS_S : LATCH_STATUS_IDLE; + cm_spin_unlock(&shared_latch->latch.lock); + return CM_FALSE; + } + return CM_TRUE; + } + cm_spin_unlock(&shared_latch->latch.lock); + if (stat != NULL) { + stat->misses++; + } + while (shared_latch->latch.stat != LATCH_STATUS_IDLE && shared_latch->latch.stat != LATCH_STATUS_S) { + if (actual_ticks >= wait_ticks) { + return CM_FALSE; + } + count++; + if (count >= GS_SPIN_COUNT) { + SPIN_STAT_INC(stat, x_sleeps); + cm_spin_sleep(); + count = 0; + actual_ticks++; + } + } + } while (CM_TRUE); + return CM_FALSE; +} + +void wr_lock_shm_meta_x2ix(wr_session_t *session, wr_shared_latch_t *shared_latch) +{ + CM_ASSERT(session != NULL); + cm_panic_log(wr_is_server(), "can not op x latch in client"); + CM_ASSERT(shared_latch->latch.stat == LATCH_STATUS_X); + latch_statis_t *stat = NULL; + uint32 sid = WR_SESSIONID_IN_LOCK(session->id); + wr_latch_x2ix(&shared_latch->latch, sid, stat); +} + +void wr_lock_shm_meta_ix2x(wr_session_t *session, wr_shared_latch_t *shared_latch) +{ + CM_ASSERT(session != NULL); + cm_panic_log(wr_is_server(), "can not op x latch in client"); + CM_ASSERT(shared_latch->latch.stat == LATCH_STATUS_IX); + latch_statis_t *stat = NULL; + uint32 sid = WR_SESSIONID_IN_LOCK(session->id); + wr_latch_ix2x(&shared_latch->latch, sid, stat); +} + +void wr_lock_shm_meta_degrade(wr_session_t *session, wr_shared_latch_t *shared_latch) +{ + CM_ASSERT(session != NULL); + cm_panic_log(wr_is_server(), "can not op x latch degradation in client."); + uint32 sid = (session == NULL) ? WR_DEFAULT_SESSIONID : WR_SESSIONID_IN_LOCK(session->id); + cm_panic_log(sid == shared_latch->latch.sid && shared_latch->latch.stat == LATCH_STATUS_X, + "Invalid degradation: sid:%u, sid on latch:%u, latch status:%u.", sid, shared_latch->latch.sid, + shared_latch->latch.stat); + cm_spin_lock_by_sid(sid, &shared_latch->latch.lock, NULL); + shared_latch->latch.stat = LATCH_STATUS_S; + shared_latch->latch.shared_count = 1; + shared_latch->latch_extent.shared_sid_count += sid; + cm_spin_unlock(&shared_latch->latch.lock); +} + +void wr_lock_shm_meta_bucket_x(wr_session_t *session, wr_shared_latch_t *shared_latch) +{ + CM_ASSERT(session != NULL); + wr_lock_shm_meta_x(session, shared_latch); +} + +// only used by wrserver +void wr_unlock_shm_meta_without_stack(wr_session_t *session, wr_shared_latch_t *shared_latch) +{ + CM_ASSERT(session != NULL); + cm_panic_log(wr_is_server(), "can not op shared latch without session latch stack in client"); + CM_ASSERT(shared_latch->latch.stat != LATCH_STATUS_IDLE); + + spin_statis_t *stat_spin = NULL; + uint32 sid = WR_SESSIONID_IN_LOCK(session->id); + cm_spin_lock_by_sid(sid, &shared_latch->latch.lock, stat_spin); + + if (shared_latch->latch.stat == LATCH_STATUS_S || shared_latch->latch.stat == LATCH_STATUS_IX) { + CM_ASSERT(shared_latch->latch.shared_count > 0); + shared_latch->latch.shared_count--; + if (shared_latch->latch.shared_count == 0) { + if (shared_latch->latch.stat == LATCH_STATUS_S) { + shared_latch->latch.stat = LATCH_STATUS_IDLE; + } + shared_latch->latch.sid = 0; + } + shared_latch->latch_extent.shared_sid_count -= sid; + } else if (shared_latch->latch.stat == LATCH_STATUS_X) { + CM_ASSERT(shared_latch->latch.shared_count == 0); + shared_latch->latch.stat = LATCH_STATUS_IDLE; + shared_latch->latch.sid = 0; + } + cm_spin_unlock(&shared_latch->latch.lock); +} + +// only used by api-client or by clean +bool32 wr_unlock_shm_meta_s_with_stack(wr_session_t *session, wr_shared_latch_t *shared_latch, bool32 is_try_lock) +{ + CM_ASSERT(session != NULL); + // can not call checkcm_paninc_log with wr_is_server + CM_ASSERT(shared_latch->latch.stat != LATCH_STATUS_IDLE); + session->latch_stack.stack_top_bak = session->latch_stack.stack_top; + session->latch_stack.op = LATCH_SHARED_OP_UNLATCH; + + spin_statis_t *stat_spin = NULL; + uint32 sid = WR_SESSIONID_IN_LOCK(session->id); + if (!is_try_lock) { + cm_spin_lock_by_sid(sid, &shared_latch->latch.lock, stat_spin); + } else { + bool32 is_locked = cm_spin_try_lock(&shared_latch->latch.lock); + if (!is_locked) { + return CM_FALSE; + } + } + // for shared latch in shm, need to backup first + wr_set_latch_extent(&shared_latch->latch_extent, shared_latch->latch.stat, shared_latch->latch.shared_count); + + // begin to change latch + session->latch_stack.op = LATCH_SHARED_OP_UNLATCH_BEG; + + CM_ASSERT(shared_latch->latch.shared_count > 0); + shared_latch->latch.shared_count--; + if (shared_latch->latch.shared_count == 0) { + if (shared_latch->latch.stat == LATCH_STATUS_S) { + shared_latch->latch.stat = LATCH_STATUS_IDLE; + } + shared_latch->latch.sid = 0; + } + shared_latch->latch_extent.shared_sid_count -= sid; + + cm_spin_unlock(&shared_latch->latch.lock); + + // put this after the unlock to make sure:when error happen after unlock, do NOT op the unlatch-ed latch + // begin to change stack + CM_ASSERT(session->latch_stack.stack_top); + // in the normal, should be stack_top-- first, then set [stack_top].typ = WR_LATCH_OFFSET_INVALID + // but may NOT do [stack_top].typ = WR_LATCH_OFFSET_INVALID when some error happen, + // so leave the stack_top-- on the second step + session->latch_stack.latch_offset_stack[session->latch_stack.stack_top - 1].type = WR_LATCH_OFFSET_INVALID; + session->latch_stack.stack_top--; + session->latch_stack.op = LATCH_SHARED_OP_UNLATCH_END; + return CM_TRUE; +} + +void wr_unlock_shm_meta_bucket(wr_session_t *session, wr_shared_latch_t *shared_latch) +{ + CM_ASSERT(session != NULL); + if (wr_is_server()) { + wr_unlock_shm_meta_without_stack(session, shared_latch); + return; + } else { + (void)wr_unlock_shm_meta_s_with_stack(session, shared_latch, CM_FALSE); + } +} + +static void wr_clean_latch_s_without_bak(wr_session_t *session, wr_shared_latch_t *shared_latch) +{ + LOG_DEBUG_INF("Clean sid:%u latch_stack old stack_top:%u.", WR_SESSIONID_IN_LOCK(session->id), + session->latch_stack.stack_top); + session->latch_stack.latch_offset_stack[session->latch_stack.stack_top].type = WR_LATCH_OFFSET_INVALID; + LOG_DEBUG_INF("Clean sid:%u latch_stack new stack_top:%u.", WR_SESSIONID_IN_LOCK(session->id), + session->latch_stack.stack_top); +} + +static void wr_clean_latch_s_with_bak(wr_session_t *session, wr_shared_latch_t *shared_latch) +{ + LOG_DEBUG_INF("Clean sid:%u shared_latch old count:%hu, old stat:%u.", WR_SESSIONID_IN_LOCK(session->id), + shared_latch->latch.shared_count, shared_latch->latch.stat); + + // do not care about the new value, just using the shared_count_bak + shared_latch->latch.shared_count = shared_latch->latch_extent.shared_count_bak; + shared_latch->latch.stat = shared_latch->latch_extent.stat_bak; + shared_latch->latch_extent.shared_sid_count = shared_latch->latch_extent.shared_sid_count_bak; + + if (shared_latch->latch.shared_count == 0) { + if (shared_latch->latch.stat == LATCH_STATUS_S) { + shared_latch->latch.stat = LATCH_STATUS_IDLE; + } + shared_latch->latch.sid = 0; + } + + LOG_DEBUG_INF("Clean sid:%u latch_stack old stack_top:%u.", WR_SESSIONID_IN_LOCK(session->id), + session->latch_stack.stack_top); + + LOG_DEBUG_INF("Clean sid:%u shared_latch new count:%hu, new stat:%u.", WR_SESSIONID_IN_LOCK(session->id), + shared_latch->latch.shared_count, shared_latch->latch.stat); + + // not sure last latch finish, so using the stack_top_bak + session->latch_stack.stack_top = session->latch_stack.stack_top_bak; + // when latch first, and not finish, the stack_top may be zero + if (session->latch_stack.stack_top > 0) { + session->latch_stack.latch_offset_stack[session->latch_stack.stack_top - 1].type = WR_LATCH_OFFSET_INVALID; + session->latch_stack.stack_top--; + } else { + session->latch_stack.latch_offset_stack[session->latch_stack.stack_top].type = WR_LATCH_OFFSET_INVALID; + } + LOG_DEBUG_INF("Clean sid:%u latch_stack new stack_top:%u.", WR_SESSIONID_IN_LOCK(session->id), + session->latch_stack.stack_top); +} + +static void wr_clean_unlatch_without_bak(wr_session_t *session, wr_shared_latch_t *shared_latch) +{ + LOG_DEBUG_INF("Clean sid:%u unlatch shared_latch without bak, old count:%hu, old stat:%u.", + WR_SESSIONID_IN_LOCK(session->id), shared_latch->latch.shared_count, shared_latch->latch.stat); + + CM_ASSERT(shared_latch->latch.shared_count > 0); + shared_latch->latch.shared_count--; + shared_latch->latch_extent.shared_sid_count -= WR_SESSIONID_IN_LOCK(session->id); + + if (shared_latch->latch.shared_count == 0) { + if (shared_latch->latch.stat == LATCH_STATUS_S) { + shared_latch->latch.stat = LATCH_STATUS_IDLE; + } + shared_latch->latch.sid = 0; + } + + LOG_DEBUG_INF("Clean sid:%u shared_latch new count:%hu, new stat:%u.", WR_SESSIONID_IN_LOCK(session->id), + shared_latch->latch.shared_count, shared_latch->latch.stat); + + LOG_DEBUG_INF("Clean sid:%u latch_stack old stack_top:%u.", WR_SESSIONID_IN_LOCK(session->id), + session->latch_stack.stack_top); + CM_ASSERT(session->latch_stack.stack_top > 0); + session->latch_stack.latch_offset_stack[session->latch_stack.stack_top - 1].type = WR_LATCH_OFFSET_INVALID; + session->latch_stack.stack_top--; + LOG_DEBUG_INF("Clean sid:%u latch_stack new stack_top:%u.", WR_SESSIONID_IN_LOCK(session->id), + session->latch_stack.stack_top); +} + +static void wr_clean_unlatch_with_bak(wr_session_t *session, wr_shared_latch_t *shared_latch) +{ + LOG_DEBUG_INF("Clean sid:%u unlatch shared_latch with bak, old count:%hu, old stat:%u.", + WR_SESSIONID_IN_LOCK(session->id), shared_latch->latch.shared_count, shared_latch->latch.stat); + // not sure last unlatch finsh, using the shared_count_bak first + shared_latch->latch.shared_count = shared_latch->latch_extent.shared_count_bak; + shared_latch->latch.stat = shared_latch->latch_extent.stat_bak; + shared_latch->latch_extent.shared_sid_count = shared_latch->latch_extent.shared_sid_count_bak; + + CM_ASSERT(shared_latch->latch.shared_count > 0); + shared_latch->latch.shared_count--; + shared_latch->latch_extent.shared_sid_count -= WR_SESSIONID_IN_LOCK(session->id); + + if (shared_latch->latch.shared_count == 0) { + if (shared_latch->latch.stat == LATCH_STATUS_S) { + shared_latch->latch.stat = LATCH_STATUS_IDLE; + } + shared_latch->latch.sid = 0; + } + LOG_DEBUG_INF("Clean sid:%u shared_latch new count:%hu, new stat:%u.", WR_SESSIONID_IN_LOCK(session->id), + shared_latch->latch.shared_count, shared_latch->latch.stat); + + LOG_DEBUG_INF("Clean sid:%u latch_stack old stack_top:%u.", WR_SESSIONID_IN_LOCK(session->id), + session->latch_stack.stack_top); + // not sure last unlatch finish, so using the stack_top_bak + session->latch_stack.stack_top = session->latch_stack.stack_top_bak; + CM_ASSERT(session->latch_stack.stack_top > 0); + session->latch_stack.latch_offset_stack[session->latch_stack.stack_top - 1].type = WR_LATCH_OFFSET_INVALID; + session->latch_stack.stack_top--; + LOG_DEBUG_INF("Clean sid:%u latch_stack new stack_top:%u.", WR_SESSIONID_IN_LOCK(session->id), + session->latch_stack.stack_top); +} + +static void wr_clean_last_op_with_lock(wr_session_t *session, wr_shared_latch_t *shared_latch) +{ + CM_ASSERT(WR_SESSIONID_IN_LOCK(session->id) == shared_latch->latch.lock); + + LOG_DEBUG_INF("Clean sid:%u last op with lock latch_stack op:%u, stack_top_bak:%hu.", + WR_SESSIONID_IN_LOCK(session->id), session->latch_stack.op, session->latch_stack.stack_top_bak); + + LOG_DEBUG_INF("Clean sid:%u latch_extent stat_bak:%hu, shared_count_bak:%hu.", WR_SESSIONID_IN_LOCK(session->id), + shared_latch->latch_extent.stat_bak, shared_latch->latch_extent.shared_count_bak); + + // step 1, try to clean + // no backup, no change + if (session->latch_stack.op == LATCH_SHARED_OP_LATCH_S) { + wr_clean_latch_s_without_bak(session, shared_latch); + // when latch with backup, undo the latch witch backup + } else if (session->latch_stack.op == LATCH_SHARED_OP_LATCH_S_BEG || + session->latch_stack.op == LATCH_SHARED_OP_LATCH_S_END) { + wr_clean_latch_s_with_bak(session, shared_latch); + // when unlatch, no backup, no change, redo the unlatch without backup + } else if (session->latch_stack.op == LATCH_SHARED_OP_UNLATCH) { + wr_clean_unlatch_without_bak(session, shared_latch); + // when unlatch not finish with backup, redo unlatch with backup + } else if (session->latch_stack.op == LATCH_SHARED_OP_UNLATCH_BEG) { + wr_clean_unlatch_with_bak(session, shared_latch); + } + + session->latch_stack.op = LATCH_SHARED_OP_UNLATCH_END; + // step2 + cm_spin_unlock(&shared_latch->latch.lock); +} + +static void wr_clean_last_op_without_lock(wr_session_t *session, wr_shared_latch_t *shared_latch) +{ + if (session->latch_stack.op == LATCH_SHARED_OP_NONE || session->latch_stack.op == LATCH_SHARED_OP_LATCH_S) { + session->latch_stack.latch_offset_stack[session->latch_stack.stack_top].type = WR_LATCH_OFFSET_INVALID; + session->latch_stack.op = LATCH_SHARED_OP_UNLATCH_END; + LOG_DEBUG_INF("Clean sid:%u reset to latch_stack op:%u, stack_top:%hu.", WR_SESSIONID_IN_LOCK(session->id), + session->latch_stack.op, session->latch_stack.stack_top); + // LATCH_SHARED_OP_UNLATCH_BEG and not in lock, means has finished to unlatch the latch, + // but not finished to set lack_stack[stack_top].type + } else if (session->latch_stack.op == LATCH_SHARED_OP_UNLATCH_BEG) { + CM_ASSERT(session->latch_stack.stack_top > 0); + session->latch_stack.latch_offset_stack[session->latch_stack.stack_top - 1].type = WR_LATCH_OFFSET_INVALID; + session->latch_stack.stack_top--; + session->latch_stack.op = LATCH_SHARED_OP_UNLATCH_END; + LOG_DEBUG_INF("Clean sid:%u reset to latch_stack op:%u, stack_top:%hu.", WR_SESSIONID_IN_LOCK(session->id), + session->latch_stack.op, session->latch_stack.stack_top); + } +} + +static bool32 wr_clean_lock_for_shm_meta(wr_session_t *session, wr_shared_latch_t *shared_latch, bool32 is_daemon) +{ + LOG_DEBUG_INF("Clean sid:%u latch_stack op:%u, stack_top:%hu.", WR_SESSIONID_IN_LOCK(session->id), + session->latch_stack.op, session->latch_stack.stack_top); + // last op between lock & unlock for this latch not finish + if (WR_SESSIONID_IN_LOCK(session->id) == shared_latch->latch.lock) { + wr_clean_last_op_with_lock(session, shared_latch); + // if last op not happen, or latch not begin + } else if (session->latch_stack.op == LATCH_SHARED_OP_NONE || session->latch_stack.op == LATCH_SHARED_OP_LATCH_S || + session->latch_stack.op == LATCH_SHARED_OP_UNLATCH_BEG) { + wr_clean_last_op_without_lock(session, shared_latch); + // otherwise unlatch the latch + } else { + // may exist other session lock but dead after last check the lsat->spin_lock, so if it's daemon, do lock with + // try this + if (is_daemon) { + LOG_DEBUG_INF("Clean sid:%u latch_stack op:%u, stack_top:%hu wait next try.", + WR_SESSIONID_IN_LOCK(session->id), session->latch_stack.op, session->latch_stack.stack_top); + return wr_unlock_shm_meta_s_with_stack(session, shared_latch, CM_TRUE); + } + (void)wr_unlock_shm_meta_s_with_stack(session, shared_latch, CM_FALSE); + } + return CM_TRUE; +} + +static bool32 wr_need_clean_session_latch(wr_session_t *session, uint64 cli_pid, int64 start_time) +{ + if (cli_pid == 0 || !session->is_used || !session->connected || cm_sys_process_alived(cli_pid, start_time)) { + return CM_FALSE; + } + return CM_TRUE; +} + +void wr_clean_session_latch(wr_session_t *session, bool32 is_daemon) +{ + int32 i = 0; + sh_mem_p offset; + int32 latch_place; + wr_latch_offset_type_e offset_type; + wr_shared_latch_t *shared_latch = NULL; + if (!session->is_direct) { + LOG_DEBUG_INF("Clean sid:%u is not direct.", WR_SESSIONID_IN_LOCK(session->id)); + return; + } + uint64 cli_pid = session->cli_info.cli_pid; + int64 start_time = session->cli_info.start_time; + if (is_daemon && !wr_need_clean_session_latch(session, cli_pid, start_time)) { + LOG_RUN_INF("[CLEAN_LATCH]session id %u, pid %llu, start_time %lld, process name:%s need check next time.", + session->id, cli_pid, start_time, session->cli_info.process_name); + return; + } + LOG_RUN_INF("[CLEAN_LATCH]session id %u, pid %llu, start_time %lld, process name:%s in lock.", session->id, cli_pid, + start_time, session->cli_info.process_name); + LOG_DEBUG_INF("Clean sid:%u latch_stack op:%u, stack_top:%hu.", WR_SESSIONID_IN_LOCK(session->id), + session->latch_stack.op, session->latch_stack.stack_top); + for (i = (int32)session->latch_stack.stack_top; i >= WR_MAX_LATCH_STACK_BOTTON; i--) { + // the stack_top may NOT be moveed to the right place + if (i == WR_MAX_LATCH_STACK_DEPTH) { + latch_place = i - 1; + } else { + latch_place = i; + } + offset_type = session->latch_stack.latch_offset_stack[latch_place].type; + // the stack_top may be the right invalid or latch not finish to set offset_type + // or unlatch not over, just finish unlatch the latch, but not set offset_type + if (offset_type != WR_LATCH_OFFSET_SHMOFFSET) { + LOG_DEBUG_ERR("Clean sid:%u shared_latch offset type is invalid %u,latch_place:%d.", + WR_SESSIONID_IN_LOCK(session->id), session->latch_stack.latch_offset_stack[latch_place].type, + latch_place); + if (session->latch_stack.op == LATCH_SHARED_OP_UNLATCH_BEG && i != (int32)session->latch_stack.stack_top) { + session->latch_stack.stack_top = latch_place; + session->latch_stack.op = LATCH_SHARED_OP_UNLATCH_END; + } + LOG_DEBUG_INF("Clean sid:%u reset to latch_stack op:%u, stack_top:%hu.", WR_SESSIONID_IN_LOCK(session->id), + session->latch_stack.op, session->latch_stack.stack_top); + continue; + } else { + offset = session->latch_stack.latch_offset_stack[latch_place].offset.shm_offset; + CM_ASSERT(offset != SHM_INVALID_ADDR); + shared_latch = (wr_shared_latch_t *)OFFSET_TO_ADDR(offset); + LOG_DEBUG_INF("Clean sid:%u shared_latch,latch_place:%d, offset:%llu.", WR_SESSIONID_IN_LOCK(session->id), + latch_place, (uint64)offset); + } + // the lock is locked by this session in the dead-client, + if (is_daemon && shared_latch->latch.lock != 0 && + WR_SESSIONID_IN_LOCK(session->id) != shared_latch->latch.lock) { + LOG_DEBUG_INF("Clean sid:%u daemon wait next time to clean.", WR_SESSIONID_IN_LOCK(session->id)); + return; + } else { + bool32 is_clean = wr_clean_lock_for_shm_meta(session, shared_latch, is_daemon); + if (!is_clean) { + LOG_DEBUG_INF("Clean sid:%u daemon wait next time to clean.", WR_SESSIONID_IN_LOCK(session->id)); + return; + } + } + } + session->latch_stack.op = LATCH_SHARED_OP_NONE; + session->latch_stack.stack_top = WR_MAX_LATCH_STACK_BOTTON; +} + +void wr_server_session_lock(wr_session_t *session) +{ + // session->lock to contrl the concurrency of cleaning session latch thread + cm_spin_lock(&session->lock, NULL); + while (!cm_spin_timed_lock(&session->shm_lock, WR_SERVER_SESS_TIMEOUT)) { + bool32 alived = cm_sys_process_alived(session->cli_info.cli_pid, session->cli_info.start_time); + if (!alived) { + // unlock if the client goes offline + LOG_DEBUG_INF("Process:%s is not alive, pid:%llu, start_time:%lld.", session->cli_info.process_name, + session->cli_info.cli_pid, session->cli_info.start_time); + cm_spin_unlock(&session->shm_lock); + LOG_DEBUG_INF("Succeed to unlock session %u shm lock", session->id); + continue; + } + LOG_DEBUG_INF("Process:%s is alive, pid:%llu, start_time:%lld.", session->cli_info.process_name, + session->cli_info.cli_pid, session->cli_info.start_time); + cm_sleep(CM_SLEEP_500_FIXED); + } + LOG_DEBUG_INF("Succeed to lock session %u shm lock", session->id); +} + +void wr_server_session_unlock(wr_session_t *session) +{ + cm_spin_unlock(&session->shm_lock); + LOG_DEBUG_INF("Succeed to unlock session %u shm lock", session->id); + cm_spin_unlock(&session->lock); + LOG_DEBUG_INF("Succeed to unlock session %u lock", session->id); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/common/wr_session.h b/src/common/wr_session.h new file mode 100644 index 0000000000000000000000000000000000000000..15229fd8691e1933e68f92520de5af78c271f5b2 --- /dev/null +++ b/src/common/wr_session.h @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_session.h + * + * + * IDENTIFICATION + * src/common/wr_session.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_SESSION_H__ +#define __WR_SESSION_H__ + +#include "cm_defs.h" +#include "cm_thread_pool.h" +#include "cm_date.h" +#include "cs_packet.h" +#include "cs_pipe.h" +#include "wr_defs.h" +#include "wr_au.h" +#include "wr_log.h" +#include "wr_protocol.h" +#include "wr_latch.h" +#include "wr_stats.h" +#include "wr_shm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WR_INVALID_SESSIONID CM_INVALID_ID32 +#define WR_MAX_LATCH_STACK_BOTTON 0 +#define WR_MAX_LATCH_STACK_DEPTH 8 +#define WR_LOCK_CLEAN_SLEEP_TIME 500 +#define WR_SESSION_PAUSED_WAIT 50 + +#define WR_META_SYN_BG_TASK_NUM_MAX 4 +#define WR_RECYLE_META_TASK_NUM_MAX 4 + +#define WR_SERVER_SESS_TIMEOUT 100 +typedef enum st_wr_background_task_type { + WR_RECOVERY_BACKGROUND_TASK = 0, + WR_DELAY_CLEAN_BACKGROUND_TASK = 1, + WR_HASHMAP_DYNAMIC_EXTEND_TASK = 2, + WR_ALARM_CHECK_TASK = 3, + WR_META_SYN_BG_TASK_BASE = 4, + WR_META_SYN_BG_TASK_END = WR_META_SYN_BG_TASK_BASE + WR_META_SYN_BG_TASK_NUM_MAX, + WR_RECYCLE_META_TASK_BASE = WR_META_SYN_BG_TASK_END, + WR_RECYCLE_META_TASK_END = WR_RECYCLE_META_TASK_BASE + WR_RECYLE_META_TASK_NUM_MAX, + WR_BACKGROUND_TASK_NUM = WR_RECYCLE_META_TASK_END, +} wr_background_task_type_e; + +typedef struct st_wr_bg_task_info { + uint32 task_num_max; + uint32 my_task_id; + uint32 vg_id_beg; + uint32 vg_id_end; + void *task_args; +} wr_bg_task_info_t; + +typedef struct wr_cli_info { + uint64 cli_pid; + int64 start_time; + char process_name[WR_FILE_NAME_BUFFER_SIZE + 1]; + uint32 thread_id; + uint64 connect_time; +} wr_cli_info_t; + +typedef enum st_wr_latch_offset_type { + WR_LATCH_OFFSET_INVALID = 0, + WR_LATCH_OFFSET_UNIQ_ID, + WR_LATCH_OFFSET_SHMOFFSET, +} wr_latch_offset_type_e; + +typedef struct st_wr_latch_offset { + wr_latch_offset_type_e type; + union { + uint32 unique_id; + uint64 shm_offset; + } offset; +} wr_latch_offset_t; + +typedef struct st_wr_latch_stack { + wr_latch_offset_t latch_offset_stack[WR_MAX_LATCH_STACK_DEPTH]; + uint32 stack_top; + uint32 stack_top_bak; + wr_latch_shared_op_e op; +} wr_latch_stack_t; + +typedef enum en_protocol_type { + PROTO_TYPE_UNKNOWN = 0, + PROTO_TYPE_GS = 1, +} protocol_type_t; + +typedef enum en_wr_session_status { + WR_SESSION_STATUS_IDLE = 0, + WR_SESSION_STATUS_RUNNING, + WR_SESSION_STATUS_PAUSING, + WR_SESSION_STATUS_PAUSED, +} wr_session_status_t; + +typedef struct st_wr_session { + spinlock_t lock; // for control current rw of the same session in server + uint32 id; + bool32 is_closed; + bool32 is_used; + bool32 connected; + bool32 reactor_added; + cs_pipe_t pipe; + wr_packet_t recv_pack; + wr_packet_t send_pack; + text_t send_info; // send extra info, please use recv_pack.init_buf, len = 0 if no info ack + ftid_t curr_dir; + protocol_type_t proto_type; // gauss or mysql (not realized) + wr_cli_info_t cli_info; + wr_latch_stack_t latch_stack; + volatile uint64 curr_lsn; // latest lsn generated by current session + wr_audit_info_t audit_info; + wr_session_status_t status; + void *reactor; + void *workthread_ctx; + wr_stat_item_t wr_session_stat[WR_EVT_COUNT]; + uint32 client_version; /* client version */ + uint32 proto_version; /* client and server negotiated version */ + uint32 objectid; + wr_stat_ctx_t stat_ctx; + bool8 is_direct; + bool8 put_log; + bool8 is_holding_hotpatch_latch; + spinlock_t shm_lock; // for control current rw of the same session in shm +} wr_session_t; + +static inline char *wr_init_sendinfo_buf(char *input) +{ + return (input + sizeof(wr_packet_head_t) + sizeof(int32)); +} + +static inline void wr_session_end_stat(wr_session_t *session, timeval_t *begin_tv, wr_wait_event_e event) +{ + if (session != NULL) { + wr_end_stat_base(&session->wr_session_stat[event], begin_tv); + } +} + +typedef struct st_wr_session_ctrl { + spinlock_t lock; + bool32 is_inited; + uint32 used_count; + uint32 total; + uint32 alloc_sessions; + wr_session_t **sessions; +} wr_session_ctrl_t; + +extern wr_session_ctrl_t g_wr_session_ctrl; +status_t wr_init_session_pool(uint32 max_session_num); +wr_session_ctrl_t *wr_get_session_ctrl(void); +status_t wr_create_session(const cs_pipe_t *pipe, wr_session_t **session); +void wr_destroy_session(wr_session_t *session); +void wr_destroy_session_inner(wr_session_t *session); +wr_session_t *wr_get_session(uint32 sid); + +status_t wr_lock_shm_meta_s_with_stack( + wr_session_t *session, wr_latch_offset_t *offset, wr_shared_latch_t *shared_latch, int32 timeout); +status_t wr_lock_shm_meta_s_without_stack( + wr_session_t *session, wr_shared_latch_t *shared_latch, bool32 is_force, int32 timeout); +status_t wr_cli_lock_shm_meta_s(wr_session_t *session, wr_latch_offset_t *offset, wr_shared_latch_t *shared_latch, + latch_should_exit should_exit); +void wr_lock_shm_meta_x(const wr_session_t *session, wr_shared_latch_t *shared_latch); +void wr_lock_shm_meta_x2ix(wr_session_t *session, wr_shared_latch_t *shared_latch); +void wr_lock_shm_meta_ix2x(wr_session_t *session, wr_shared_latch_t *shared_latch); +void wr_lock_shm_meta_degrade(wr_session_t *session, wr_shared_latch_t *shared_latch); +// only used by wrserver +void wr_unlock_shm_meta_without_stack(wr_session_t *session, wr_shared_latch_t *shared_latch); +// only used by api-client or by clean +bool32 wr_unlock_shm_meta_s_with_stack(wr_session_t *session, wr_shared_latch_t *shared_latch, bool32 is_try_lock); +status_t wr_lock_shm_meta_bucket_s(wr_session_t *session, uint32 id, wr_shared_latch_t *shared_latch); +void wr_lock_shm_meta_bucket_x(wr_session_t *session, wr_shared_latch_t *shared_latch); +void wr_unlock_shm_meta_bucket(wr_session_t *session, wr_shared_latch_t *shared_latch); +void wr_clean_session_latch(wr_session_t *session, bool32 is_daemon); +uint32 wr_get_uwression_startid(void); +uint32 wr_get_recover_task_idx(void); +uint32 wr_get_max_total_session_cnt(void); +uint32 wr_get_delay_clean_task_idx(void); +uint32 wr_get_hashmap_dynamic_extend_task_idx(void); +bool32 wr_lock_shm_meta_timed_x(const wr_session_t *session, wr_shared_latch_t *shared_latch, uint32 wait_ticks); +uint32 wr_get_delay_clean_task_idx(void); +typedef uint32 (*wr_get_bg_task_idx_func_t)(uint32 idx); +uint32 wr_get_meta_syn_task_idx(uint32 idx); +uint32 wr_get_recycle_meta_task_idx(uint32 idx); +uint32 wr_get_alarm_check_task_idx(void); +void wr_server_session_lock(wr_session_t *session); +void wr_server_session_unlock(wr_session_t *session); +wr_session_t *wr_get_reserv_session(uint32 idx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/wr_shm.c b/src/common/wr_shm.c new file mode 100644 index 0000000000000000000000000000000000000000..6d10cc3f9b35d17d49ad6f1d5423217539221a77 --- /dev/null +++ b/src/common/wr_shm.c @@ -0,0 +1,599 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * cm_shm.c + * + * + * IDENTIFICATION + * src/common/cm_shm.c + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#include +#ifndef WIN32 +#include +#include +#include +#include +#endif +#include "cm_date.h" +#include "cm_memory.h" +#include "cm_thread.h" +#include "cm_debug.h" +#include "wr_defs.h" +#include "wr_log.h" +#include "wr_errno.h" +#include "wr_malloc.h" +#include "wr_shm.h" + +uint32 g_shm_key = 0; + +/* shared memory mapping */ +cm_shm_map_t g_shm_map; +static thread_lock_t g_shm_map_lock; +bool32 g_shm_inited = CM_FALSE; + +#define CM_INVALID_SHM_KEY (0) + +static cm_shm_ctrl_t *cm_shm_ctrl(void) +{ + return (cm_shm_ctrl_t *)g_shm_map.entries[SHM_ID_MNG_CTRL].addr; +} + +static uint32 cm_shm_idx_of(cm_shm_type_e type, uint32 id) +{ + uint32 result; + + if (type == SHM_TYPE_FIXED) { + if (id >= CM_FIXED_SHM_ID_TAIL) { + LOG_DEBUG_ERR("Fixed shared memory ID is out of range : %u", id); + return CM_INVALID_SHM_IDX; + } + result = id; + } else if (type == SHM_TYPE_HASH) { + if (id >= CM_HASH_SHM_MAX_ID) { + LOG_DEBUG_ERR("GA shared memory ID is out of range : %u", id); + return CM_INVALID_SHM_IDX; + } + result = CM_FIXED_SHM_ID_TAIL + id; + } else if (type == SHM_TYPE_GA) { + if (id >= CM_GA_SHM_MAX_ID) { + LOG_DEBUG_ERR("GA shared memory ID is out of range : %u", id); + return CM_INVALID_SHM_IDX; + } + result = CM_FIXED_SHM_ID_TAIL + CM_HASH_SHM_MAX_ID + id; + } else { + LOG_DEBUG_ERR("invalid type, type: %u", type); + return CM_INVALID_SHM_IDX; + } + return result; +} + +cm_shm_key_t cm_shm_key_of(cm_shm_type_e type, uint32 id) +{ + uint32 idx = cm_shm_idx_of(type, id); + + return idx != CM_INVALID_SHM_IDX ? CM_SHM_IDX_TO_KEY(idx) : CM_INVALID_SHM_KEY; +} + +#define CM_SHM_MAP_ENTRY_OF(key) (&g_shm_map.entries[CM_SHM_KEY2IDX(key)]) +#define SHM_ADDR_OF(key) (CM_SHM_MAP_ENTRY_OF(key)->addr) +#define SHM_ADDR_BAK_OF(key) (CM_SHM_MAP_ENTRY_OF(key)->addr_bak) + +static void cm_lock_shm_map(void) +{ + cm_thread_lock(&g_shm_map_lock); +} + +static void cm_unlock_shm_map(void) +{ + cm_thread_unlock(&g_shm_map_lock); +} + +#ifdef WIN32 +static void cm_fill_shm_name(char *name, cm_shm_key_t key) +{ + if (snprintf_s(name, CM_FILE_NAME_BUFFER_SIZE, CM_FILE_NAME_BUFFER_SIZE, "gmdb_0x%08x", key) == -1) { + cm_panic(0); + } +} +#endif + +cm_shm_handle_t cm_native_create_shm(cm_shm_key_t key, uint64 size, uint32 permission) +{ +#ifdef WIN32 + char name[CM_FILE_NAME_BUFFER_SIZE]; + uint32 high = (uint32)(size >> 32); + uint32 low = (uint32)(size & 0xFFFFFFFF); + (void)permission; + + cm_fill_shm_name(name, key); + + return CreateFileMapping(CM_INVALID_SHM_HANDLE, NULL, PAGE_READWRITE, high, low, name); +#else + /* PL/MDE:qinchaoli 712:Loss of precision (Context) (Type to Type) */ + return shmget((key_t)key, size, (int32)(IPC_CREAT | IPC_EXCL | permission)); +#endif +} + +void cm_native_close_shm(cm_shm_handle_t handle) +{ +#ifdef WIN32 + (void)CloseHandle(handle); +#else + (void)handle; +#endif +} + +void *cm_native_attach_shm(cm_shm_handle_t handle, uint32 flag) +{ +#ifdef WIN32 + return MapViewOfFile(handle, flag, 0, 0, 0); +#else + uint32 retry_num = SHM_MAX_RETRY_ATTACH_NUM; + uint64 offset; + void *result = NULL; + for (uint32 i = 0; i < retry_num; i++) { + result = shmat(handle, result, (int)flag); + /* shmat will return -1 when error */ + if ((int64)result == -1) { + return NULL; + } else { + offset = ((uint64)result) % WR_ALIGN_SIZE; + if (offset == 0) { + return result; + } else { + shmdt(result); + result = (char *)result + (WR_ALIGN_SIZE - offset) + WR_ALIGN_SIZE * retry_num; + } + } + } + return NULL; +#endif +} + +static void *cm_create_shm(cm_shm_key_t key, uint64 size, uint32 flag, uint32 permission) +{ + cm_shm_map_entry_t *entry = &g_shm_map.entries[CM_SHM_KEY2IDX(key)]; + + entry->handle = cm_native_create_shm(key, size, permission); + if (entry->handle == CM_INVALID_SHM_HANDLE) { + WR_LOG_WITH_OS_MSG( + "Failed to create shared memory, key=0x%08x, size=%llu. The system memory may be insufficient, please " + "check it firstly. Or there may be existent shared memory which is created by other process or last " + "existed gmdb instance, please delete it manually and retry again", + key, size); + return NULL; + } + + entry->addr = cm_native_attach_shm(entry->handle, flag); + if (entry->addr == NULL) { + WR_LOG_WITH_OS_MSG( + "Failed to attach shared memory, handle=%d, key=0x%08x, size=%llu. The existent shared memory may be " + "created by other process or last existed gmdb instance, please delete it manually and retry again", + entry->handle, key, size); + (void)cm_native_del_shm(entry->handle); + entry->handle = CM_INVALID_SHM_HANDLE; + } else { +#ifdef WIN32 + /* for Windows 32bit OS, the memory address can't bigger than 4G, + * so convert uint64 to uint32. + * IMPORTANT: NOT portable for Windows 64bit OS + */ + errno_t errcode = memset_s(entry->addr, size, 0, (uint32)size); + if (errcode != EOK) { + cm_panic(0); + } +#else + errno_t errcode = memset_s(entry->addr, size, 0, size); + if (errcode != EOK) { + cm_panic(0); + } +#endif + } + + return entry->addr; +} + +cm_shm_handle_t cm_native_open_shm(uint32 key) +{ +#ifdef WIN32 + char name[CM_FILE_NAME_BUFFER_SIZE]; + cm_shm_handle_t result; + + cm_fill_shm_name(name, key); + result = OpenFileMapping(FILE_MAP_ALL_ACCESS, CM_FALSE, name); + + return (NULL == result) ? CM_INVALID_SHM_HANDLE : result; +#else + return shmget((int32)key, 0, 0); +#endif +} + +uint64 cm_native_shm_size(cm_shm_key_t key) +{ +#ifdef WIN32 + (void)key; + return 0; +#else + cm_shm_handle_t handle = cm_native_open_shm(key); + if (handle == CM_INVALID_SHM_HANDLE) { + return 0; + } else { + struct shmid_ds shm_stat; + int32 ret; + ret = shmctl(handle, IPC_STAT, &shm_stat); + if (ret != -1) { + return shm_stat.shm_segsz; + } else { + return 0; + } + } +#endif +} + +bool32 cm_native_detach_shm(void *addr) +{ +#ifdef WIN32 + return UnmapViewOfFile(addr); +#else + int32 result = shmdt(addr); + return result != -1; +#endif +} + +#define SHM_CTRL_LOCK (cm_shm_ctrl()->lock_for_self) + +static void *cm_attach_to_existing_shm(cm_shm_key_t key, cm_shm_handle_t handle, uint64 size, uint32 flag) +{ + void *result = cm_native_attach_shm(handle, flag); + + if (result == NULL) { + WR_LOG_WITH_OS_MSG( + "Failed to attach shared memory, handle=%d, key=0x%08x, size=%llu. The existent shared memory may be " + "created by other process or last existed gmdb instance, please delete it manually and retry again.", + handle, key, size); + } + +#ifndef WIN32 + if ((result != NULL) && (size != 0)) { + if (cm_native_shm_size(key) != size) { + LOG_DEBUG_ERR("Failed to attach shared memory, key=0x%08x, reason=expected size %llu can not match actual " + "size %llu. The existent shared memory may be created by other process or last existed gmdb " + "instance, please delete it manually and retry again.", + key, size, cm_native_shm_size(key)); + (void)cm_native_detach_shm(result); + result = NULL; + } + } +#endif + + return result; +} + +void *cm_do_attach_shm_without_register(cm_shm_key_t key, uint64 size, uint32 flag, bool32 logging_open_err) +{ + cm_shm_map_entry_t *entry = CM_SHM_MAP_ENTRY_OF(key); + + if (entry->addr != NULL) { + return entry->addr; + } + +#ifndef WIN32 + entry->handle = cm_native_open_shm(key); +#else + if (entry->handle == CM_INVALID_SHM_HANDLE) { + entry->handle = cm_native_open_shm(key); + } +#endif + + if (entry->handle == CM_INVALID_SHM_HANDLE) { + if (logging_open_err) { + WR_LOG_WITH_OS_MSG("Failed to open shared memory, key=0x%08x, size=%llu", key, size); + } + return NULL; + } else { + entry->addr = cm_attach_to_existing_shm(key, entry->handle, size, flag); + return entry->addr; + } +} + +static void *cm_do_attach_shm(cm_shm_key_t key, uint64 size, uint32 flag, bool32 logging_open_err) +{ + return cm_do_attach_shm_without_register(key, size, flag, logging_open_err); +} + +static status_t cm_create_shm_ctrl(void) +{ + if (cm_create_shm(CM_SHM_CTRL_KEY, CM_SHM_SIZE_OF_CTRL, CM_SHM_ATTACH_RW, CM_SHM_PERMISSION) == NULL) { + return ERR_WR_SHM_CREATE; + } + + GS_INIT_SPIN_LOCK(SHM_CTRL_LOCK); + errno_t errcode = + memcpy_s(cm_shm_ctrl()->magic, sizeof(cm_shm_ctrl()->magic), CM_SHM_MAGIC, sizeof(cm_shm_ctrl()->magic)); + securec_check_ret(errcode); + cm_shm_ctrl()->self_version = CM_SHM_CTRL_CURRENT_VERSION; + cm_shm_ctrl()->instance_id = CM_SHM_KEY2INSTANCE(CM_SHM_CTRL_KEY); + + return CM_SUCCESS; +} + +static void *cm_create_shm_block(cm_shm_key_t key, uint64 size, uint32 flag) +{ + return cm_create_shm(key, size, flag, CM_SHM_PERMISSION); +} + +static void init_entry(cm_shm_map_entry_t *entry) +{ + CM_ASSERT(entry != NULL); + + entry->handle = CM_INVALID_SHM_HANDLE; + entry->addr = NULL; +} + +static void cm_init_shm_map(void) +{ + for (uint32 i = 0; i < ELEMENT_COUNT(g_shm_map.entries); i++) { + init_entry(&g_shm_map.entries[i]); + } + + return; +} + +static status_t cm_check_shm_ctrl(void) +{ +#ifndef WIN32 + if (cm_native_shm_size(CM_SHM_CTRL_KEY) != CM_SHM_SIZE_OF_CTRL) { + WR_THROW_ERROR(ERR_WR_SHM_CHECK, CM_SHM_CTRL_KEY, "mismatched size"); + return CM_ERROR; + } +#endif + + if (memcmp(cm_shm_ctrl()->magic, CM_SHM_MAGIC, sizeof(cm_shm_ctrl()->magic)) != 0) { + LOG_DEBUG_ERR("mismatched magic number"); + return ERR_WR_SHM_CHECK; + } + + if (cm_shm_ctrl()->self_version != CM_SHM_CTRL_CURRENT_VERSION) { + LOG_DEBUG_ERR("Failed to check shared memory ctrl ,key=0x%08x, reason=expected version %u can not match actual " + "version %u.", + CM_SHM_CTRL_KEY, CM_SHM_CTRL_CURRENT_VERSION, cm_shm_ctrl()->self_version); + return ERR_WR_SHM_CHECK; + } + + return CM_SUCCESS; +} + +static bool32 cm_do_detach_shm(cm_shm_key_t key, bool32 logging_err) +{ + void *addr = SHM_ADDR_OF(key); + + if (addr == NULL) { + return CM_TRUE; + } + + if (cm_native_detach_shm(addr)) { + SHM_ADDR_BAK_OF(key) = addr; + SHM_ADDR_OF(key) = NULL; + return CM_TRUE; + } else { + if (logging_err) { + WR_LOG_WITH_OS_MSG("Failed to detach shared memory,key=0x%08x", key); + } + return CM_FALSE; + } +} + +static status_t cm_init_shm_ctrl() +{ + cm_shm_key_t key = CM_SHM_CTRL_KEY; + if (cm_do_attach_shm_without_register(key, 0, CM_SHM_ATTACH_RW, CM_TRUE) == NULL) { + return cm_create_shm_ctrl(); + } else { + status_t result = cm_check_shm_ctrl(); + if (result != CM_SUCCESS) { + (void)cm_do_detach_shm(CM_SHM_CTRL_KEY, CM_FALSE); + } + + return result; + } +} + +status_t cm_do_init_shm(uint32 shm_key) +{ + int32 result; + + g_shm_key = shm_key; + + cm_init_shm_map(); + cm_init_thread_lock(&g_shm_map_lock); + + result = cm_init_shm_ctrl(); + if (result != CM_SUCCESS) { + cm_destroy_thread_lock(&g_shm_map_lock); + } + + return result; +} + +status_t cm_init_shm(uint32 shm_key) +{ + if (g_shm_inited) { + return CM_SUCCESS; + } else { + status_t result = cm_do_init_shm(shm_key); + if (result == CM_SUCCESS) { + g_shm_inited = CM_TRUE; + } + + return result; + } +} + +// todo 客户端不能加载共享内存 +static void *cm_do_get_shm(cm_shm_key_t key, uint64 size, uint32 flag) +{ + void *result = cm_do_attach_shm(key, size, flag, CM_FALSE); + + return result != NULL ? result : cm_create_shm_block(key, size, flag); +} + +void *cm_get_shm(cm_shm_type_e type, uint32 id, uint64 size, uint32 flag) +{ + cm_shm_key_t key = cm_shm_key_of(type, id); + if (key == CM_INVALID_SHM_KEY) { + return NULL; + } + cm_lock_shm_map(); + void *result = cm_do_get_shm(key, size, flag); + cm_unlock_shm_map(); + return result; +} + +void *cm_attach_shm(cm_shm_type_e type, uint32 id, uint64 size, uint32 flag) +{ + cm_shm_key_t key = cm_shm_key_of(type, id); + if (key == CM_INVALID_SHM_KEY) { + return NULL; + } + cm_lock_shm_map(); + void *result = cm_do_attach_shm(key, size, flag, CM_TRUE); + cm_unlock_shm_map(); + return result; +} + +#define CM_SHM_HANDLE_OF(key) (g_shm_map.entries[CM_SHM_KEY2IDX(key)].handle) + +bool32 cm_native_del_shm(cm_shm_handle_t handle) +{ +#ifdef WIN32 + return CloseHandle(handle); +#else + int32 ret = shmctl(handle, IPC_RMID, NULL); + return ret != -1; +#endif +} + +static bool32 do_del_shm_directly(cm_shm_key_t key) +{ + cm_shm_handle_t handle; +#ifdef WIN32 + handle = CM_SHM_HANDLE_OF(key); +#else + handle = cm_native_open_shm(key); +#endif + if (handle == CM_INVALID_SHM_HANDLE) { + return CM_TRUE; + } + return cm_native_del_shm(handle); +} + +static bool32 cm_del_shm_block(cm_shm_key_t key) +{ + if (!do_del_shm_directly(key)) { + WR_LOG_WITH_OS_MSG("Failed to delete shared memory,key=0x%08x", key); + return CM_FALSE; + } + CM_SHM_HANDLE_OF(key) = CM_INVALID_SHM_HANDLE; + return CM_TRUE; +} + +static bool32 cm_do_del_shm(cm_shm_key_t key) +{ + return cm_do_detach_shm(key, CM_TRUE) ? cm_del_shm_block(key) : CM_FALSE; +} + +bool32 del_shm_by_key(cm_shm_key_t key) +{ + cm_lock_shm_map(); + bool32 result = cm_do_del_shm(key); + cm_unlock_shm_map(); + return result; +} + +bool32 cm_del_shm(cm_shm_type_e type, uint32 id) +{ + cm_shm_key_t key = cm_shm_key_of(type, id); + if (key == CM_INVALID_SHM_KEY) { + return CM_FALSE; + } + return del_shm_by_key(key); +} + +bool32 cm_detach_shm(cm_shm_type_e type, uint32 id) +{ + cm_shm_key_t key = cm_shm_key_of(type, id); + if (key == CM_INVALID_SHM_KEY) { + return CM_FALSE; + } + cm_lock_shm_map(); + bool32 result = cm_do_detach_shm(key, CM_TRUE); + cm_unlock_shm_map(); + return result; +} + +static void cm_do_destroy_shm(void) +{ + cm_destroy_thread_lock(&g_shm_map_lock); + + memset_s(&g_shm_map_lock, sizeof(g_shm_map_lock), 0, sizeof(g_shm_map_lock)); +} + +void cm_destroy_shm(void) +{ + if (g_shm_inited) { + cm_do_destroy_shm(); + g_shm_inited = CM_FALSE; + } +} + +void cm_set_shm_ctrl_flag(uint64 value) +{ + cm_shm_ctrl()->flag = value; + CM_MFENCE +} + +uint64 cm_get_shm_ctrl_flag(void) +{ + return cm_shm_ctrl()->flag; +} + +sh_mem_p cm_trans_shm_offset(uint32_t key, void *ptr) +{ + sh_mem_p ptr_uint64 = 0; + sh_mem_t *shm_ptr = (sh_mem_t *)(void *)&ptr_uint64; + cm_shm_map_entry_t *entry = CM_SHM_MAP_ENTRY_OF(key); + + shm_ptr->offset = (uint32)((char *)ptr - (char *)entry->addr); + shm_ptr->seg = CM_SHM_KEY2IDX(key); + + return ptr_uint64; +} + +sh_mem_p cm_trans_shm_offset_from_malloc(uint32_t key, void *ptr) +{ + sh_mem_p ptr_uint64 = 0; + sh_mem_t *shm_ptr = (sh_mem_t *)(void *)&ptr_uint64; + cm_shm_map_entry_t *entry = CM_SHM_MAP_ENTRY_OF(key); + entry->handle = CM_INVALID_SHM_HANDLE; + entry->addr = ptr; + shm_ptr->offset = (uint32)((char *)ptr - (char *)entry->addr); + shm_ptr->seg = CM_SHM_KEY2IDX(key); + return ptr_uint64; +} \ No newline at end of file diff --git a/src/common/wr_shm.h b/src/common/wr_shm.h new file mode 100644 index 0000000000000000000000000000000000000000..b35e0ac34c937a1f944da5ca0a3f4cf05f05ab82 --- /dev/null +++ b/src/common/wr_shm.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_shm.h + * + * + * IDENTIFICATION + * src/common/wr_shm.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_SHM_H_ +#define __WR_SHM_H_ + +#ifndef WIN32 +#include +#include +#else +#include +#endif +#include +#include "cm_types.h" +#include "cm_defs.h" +#include "cm_spinlock.h" +#include "cm_error.h" +// #ifndef ARM/*def CONFIG_64BIT_PROGRAM*/ +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WIN32 +typedef HANDLE cm_shm_handle_t; +#define CM_INVALID_SHM_HANDLE INVALID_HANDLE_VALUE +#else +typedef int32 cm_shm_handle_t; +#define CM_INVALID_SHM_HANDLE (-1) +#endif + +extern uint32 g_shm_key; +extern bool32 g_shm_inited; + +#define CM_FIXED_SHM_MAX_ID CM_FIXED_SHM_ID_TAIL +#define CM_HASH_SHM_MAX_ID 65 +#define CM_GA_SHM_MAX_ID 20480U // max total extended pool +#define CM_SHM_MAX_BLOCK ((CM_FIXED_SHM_MAX_ID) + (CM_HASH_SHM_MAX_ID) + (CM_GA_SHM_MAX_ID)) +/* share memory manager control block magic string, must be 8Bytes aligned, now 48Bytes */ +#define CM_SHM_MAGIC "Huawei Tech. Co., Ltd. gauss100 DB WR Software" + +/* share memory control block reserved for future use */ +#define CM_SHM_CTRL_RESERVED 1020 + +/* share memory block reserved for future use */ +#define CM_SHM_BLOCK_RESERVED 16 + +/* pids stored in share memory block */ +#define CM_SHM_BLOCK_PID_CNT 128 + +typedef uint32 cm_shm_key_t; + +#ifdef WIN32 +#define CM_SHM_ATTACH_RDONLY FILE_MAP_READ +#define CM_SHM_ATTACH_RW FILE_MAP_ALL_ACCESS +#define CM_SHM_PERMISSION 0 +#else +#define CM_SHM_ATTACH_RDONLY SHM_RDONLY +#define CM_SHM_ATTACH_RW 0 /* the default attach mode is read write */ +#define CM_SHM_PERMISSION 0600 +#endif + +#define CM_SHM_CTRL_CURRENT_VERSION 6u +#define CM_INVALID_SHM_IDX 0xFFFFFFFF +#define CM_SHM_MAKE_KEY(shm_key, idx) ((uint32)(((uint32)(shm_key) & (0xFFFF)) << 16) | (uint32)((idx) & (0xFFFF))) +#define CM_SHM_KEY2IDX(key) ((uint32)((key) & (0xFFFF))) +#define CM_SHM_KEY2INSTANCE(key) (((uint32)((key) & (0xFFFF0000))) >> 16) +#define CM_SHM_IDX_TO_KEY(idx) CM_SHM_MAKE_KEY(g_shm_key, idx) +#define CM_SHM_SIZE_OF_CTRL (sizeof(cm_shm_ctrl_t)) + +typedef struct tagcm_shm_ctrl { + char magic[sizeof(CM_SHM_MAGIC)]; /* share memory control block magic string */ + uint32 self_version; /* share memory control block version */ + uint32 instance_id; /* mdb instance ID, to identify the share memory control block */ + spinlock_t lock_for_self; + uint64 flag; /* flag for database instance initialization integrality */ + char reserved[CM_SHM_CTRL_RESERVED]; /* reserved */ +} cm_shm_ctrl_t; + +typedef enum tagcm_fixed_shm_id { + SHM_ID_MNG_CTRL = 1, /* The first id must be for shared memory management control block */ + SHM_ID_APP_GA, + SHM_ID_MNG_VG, + SHM_ID_MNG_SESS, + CM_FIXED_SHM_ID_TAIL +} cm_fixed_shm_id_e; + +#define CM_SHM_CTRL_KEY CM_SHM_IDX_TO_KEY((uint32)SHM_ID_MNG_CTRL) + +typedef struct sh_mem_struct { + uint64_t offset : 32; + uint64_t seg : 32; +} sh_mem_t; + +typedef enum tagcm_shm_type { + SHM_TYPE_FIXED = 0, + SHM_TYPE_GA, + SHM_TYPE_HASH, +} cm_shm_type_e; + +typedef uint64_t sh_mem_p; + +#define SHM_EXTEND_MAX_NUM (1024 * 5) + +#define MAX_INSTANCE_NUM 1 + +#define DB_MAX_HASH_INDEX_TABLE_NUM 2 + +#define SHM_INVALID_ADDR 0 + +#define DB_BLK_SHM_MAX_NUM SHM_EXTEND_MAX_NUM + +#define DB_MAX_MAP_NUM (SHM_EXTEND_MAX_NUM * 3 + DB_MAX_HASH_INDEX_TABLE_NUM) + +#define MAX_SEG_NUM (DB_MAX_MAP_NUM * MAX_INSTANCE_NUM) + +#define INVALID_SHM_ATTACH_NUM (-1) + +#define SHM_GET_STRUCT_OFFSET(base_offset, type, element) ((base_offset) + (sh_mem_p) & (((type)0)->(element))) + +#define SHM_ENABLE_HUGEPAGE_FLAGS 1 + +#define CM_SHM_CTRL_FLAG_TRUE ((uint64)0x0123456789ABCDEF) + +#define SHM_MAX_RETRY_ATTACH_NUM 10 + +#define CM_SHM_CTRL_KEY CM_SHM_IDX_TO_KEY((uint32)SHM_ID_MNG_CTRL) + +status_t cm_init_shm(uint32 shm_key); +void cm_destroy_shm(void); + +void *cm_get_shm(cm_shm_type_e type, uint32 id, uint64 size, uint32 flag); +bool32 cm_del_shm(cm_shm_type_e type, uint32 id); +void *cm_attach_shm(cm_shm_type_e type, uint32 id, uint64 size, uint32 flag); +uint64 cm_get_shm_ctrl_flag(void); +bool32 cm_detach_shm(cm_shm_type_e type, uint32 id); +bool32 cm_native_del_shm(cm_shm_handle_t handle); +cm_shm_key_t cm_shm_key_of(cm_shm_type_e type, uint32 id); +sh_mem_p cm_trans_shm_offset(uint32_t key, void *ptr); +void *cm_do_attach_shm_without_register(cm_shm_key_t key, uint64 size, uint32 flag, bool32 logging_open_err); +void cm_set_shm_ctrl_flag(uint64 value); +bool32 del_shm_by_key(cm_shm_key_t key); +sh_mem_p cm_trans_shm_offset_from_malloc(uint32_t key, void *ptr); +typedef struct tagcm_shm_map_entry { + cm_shm_handle_t handle; + void *addr; /* Attached address of the block */ + void *addr_bak; /* Attached address backup of the block */ +} cm_shm_map_entry_t; + +typedef struct tagcm_shm_map { + cm_shm_map_entry_t entries[CM_SHM_MAX_BLOCK]; +} cm_shm_map_t; +extern cm_shm_map_t g_shm_map; +#define OFFSET_TO_ADDR(offset_ptr) \ + ((g_shm_map.entries[((sh_mem_t *)(void *)&(offset_ptr))->seg].addr == NULL ? \ + (uint8_t *)cm_do_attach_shm_without_register( \ + (cm_shm_key_t)((sh_mem_t *)(void *)&(offset_ptr))->seg, 0, CM_SHM_ATTACH_RW, CM_FALSE) + \ + ((sh_mem_t *)(void *)&(offset_ptr))->offset : \ + (uint8_t *)g_shm_map.entries[((sh_mem_t *)(void *)&(offset_ptr))->seg].addr + \ + ((sh_mem_t *)(void *)&(offset_ptr))->offset)) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/common/wr_shm_hashmap.c b/src/common/wr_shm_hashmap.c new file mode 100644 index 0000000000000000000000000000000000000000..5e7128bd80c896725e086f1550dbd4f2e7979cbb --- /dev/null +++ b/src/common/wr_shm_hashmap.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_shm_hashmap.c + * + * + * IDENTIFICATION + * src/common/wr_shm_hashmap.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_shm_hashmap.h" +#include "wr_ga.h" +#include "wr_log.h" +#include "wr_errno.h" +#include "wr_defs.h" + +uint32 shm_hashmap_calc_bucket_idx(shm_hash_ctrl_t *hash_ctrl, uint32 hash) +{ + uint32 bucket_idx = hash & hash_ctrl->high_mask; + if (bucket_idx > hash_ctrl->max_bucket) { + bucket_idx &= hash_ctrl->low_mask; + } + return bucket_idx; +} + +bool32 shm_hashmap_need_extend_and_redistribute(shm_hash_ctrl_t *hash_ctrl) +{ + if (hash_ctrl->bucket_num == hash_ctrl->bucket_limits && hash_ctrl->max_bucket == hash_ctrl->high_mask) { + return CM_FALSE; + } + uint32 max_bucket = hash_ctrl->max_bucket; + uint64 enums = 0; + for (uint32 i = 0; i <= max_bucket; i++) { + shm_hashmap_bucket_t *bucket = shm_hashmap_get_bucket(hash_ctrl, i, NULL); + if (bucket != NULL) { + enums += bucket->entry_num; + } + } + return ((enums >= (uint64)(WR_HASH_FILL_FACTOR * (hash_ctrl->max_bucket + 1))) && + ((hash_ctrl->bucket_num != hash_ctrl->bucket_limits) || (hash_ctrl->max_bucket != hash_ctrl->high_mask))); +} + +status_t shm_hashmap_extend_segment(shm_hash_ctrl_t *hash_ctrl) +{ + uint32 segment_num = hash_ctrl->nsegments; + uint32 objectid = ga_alloc_object(GA_SEGMENT_POOL, CM_INVALID_ID32); + if (objectid == CM_INVALID_ID32) { + WR_THROW_ERROR(ERR_WR_GA_ALLOC_OBJECT, GA_SEGMENT_POOL); + return CM_ERROR; + } + shm_hashmap_bucket_t *addr = (shm_hashmap_bucket_t *)ga_object_addr(GA_SEGMENT_POOL, objectid); + if (addr == NULL) { + WR_THROW_ERROR(ERR_WR_GA_GET_ADDR, GA_SEGMENT_POOL, objectid); + return CM_ERROR; + } + errno_t rc = memset_s(addr, WR_BUCKETS_SIZE_PER_SEGMENT, 0, WR_BUCKETS_SIZE_PER_SEGMENT); + if (rc != EOK) { + CM_THROW_ERROR(ERR_SYSTEM_CALL, rc); + return CM_ERROR; + } + uint32 *dirs = (uint32 *)OFFSET_TO_ADDR(hash_ctrl->dirs); + dirs[segment_num] = objectid; + hash_ctrl->nsegments++; + LOG_DEBUG_INF( + "[HASHMAP]Succeed to extend segment, segment num is %u, object id is %u.", hash_ctrl->nsegments, objectid); + return CM_SUCCESS; +} + +shm_hashmap_bucket_t *shm_hashmap_get_bucket(shm_hash_ctrl_t *hash_ctrl, uint32 bucket_idx, uint32 *segment_objid) +{ + uint32 *dirs = (uint32 *)OFFSET_TO_ADDR(hash_ctrl->dirs); + uint32 segment_idx = bucket_idx / WR_BUCKETS_PER_SEGMENT; + WR_ASSERT_LOG(segment_idx < hash_ctrl->nsegments, "segment idx %u exceeds nsegments %u, bucket_idx is %u.", + segment_idx, hash_ctrl->nsegments, bucket_idx); + uint32 objectid = dirs[segment_idx]; + shm_hashmap_bucket_t *segment = (shm_hashmap_bucket_t *)ga_object_addr(GA_SEGMENT_POOL, objectid); + if (segment == NULL) { + WR_THROW_ERROR(ERR_WR_GA_GET_ADDR, GA_SEGMENT_POOL, objectid); + return NULL; + } + if (segment_objid != NULL) { + *segment_objid = objectid; + } + uint32 sub_bucket_idx = bucket_idx % WR_BUCKETS_PER_SEGMENT; + return &segment[sub_bucket_idx]; +} + +static status_t shm_hashmap_init_segments(shm_hash_ctrl_t *hash_ctrl) +{ + uint32 expect_segments = CM_ALIGN_CEIL(hash_ctrl->bucket_num, WR_BUCKETS_PER_SEGMENT); + for (uint32 i = 0; i < expect_segments; i++) { + status_t status = shm_hashmap_extend_segment(hash_ctrl); + if (status != CM_SUCCESS) { + return status; + } + } + return CM_SUCCESS; +} +int32 shm_hashmap_init(shm_hashmap_t *map, uint32 id, cm_oamap_compare_t compare_func) +{ + void *addr = NULL; + uint32 shm_key; + if (map == NULL) { + LOG_DEBUG_ERR("Null pointer specified"); + return ERR_WR_INVALID_PARAM; + } + map->hash_ctrl.bucket_limits = WR_MAX_BUCKET_NUM; + map->hash_ctrl.bucket_num = WR_INIT_BUCKET_NUM; + map->hash_ctrl.max_bucket = map->hash_ctrl.bucket_num - 1; + map->hash_ctrl.high_mask = map->hash_ctrl.bucket_num - 1; + map->hash_ctrl.low_mask = map->hash_ctrl.bucket_num - 1; + map->hash_ctrl.func = compare_func; + map->shm_id = id; + map->not_extend = 1; + uint64 size = WR_MAX_SEGMENT_NUM * (uint32)sizeof(uint32_t); + addr = cm_get_shm(SHM_TYPE_HASH, id, size, CM_SHM_ATTACH_RW); + if (addr == NULL) { + LOG_RUN_ERR("get hash map shm failed, id is %u.", id); + return CM_ERROR; + } + shm_key = cm_shm_key_of(SHM_TYPE_HASH, id); + map->hash_ctrl.dirs = cm_trans_shm_offset(shm_key, addr); + errno_t err = memset_s(addr, size, 0, size); + if (err != EOK) { + CM_THROW_ERROR(ERR_SYSTEM_CALL, err); + (void)cm_del_shm(SHM_TYPE_HASH, id); + return CM_ERROR; + } + status_t status = shm_hashmap_init_segments(&map->hash_ctrl); + if (status != CM_SUCCESS) { + (void)cm_del_shm(SHM_TYPE_HASH, id); + return CM_ERROR; + } + return CM_SUCCESS; +} + +void shm_hashmap_destroy(shm_hashmap_t *map, uint32 id) +{ + CM_ASSERT(map != NULL); + if (map->hash_ctrl.dirs != SHM_INVALID_ADDR) { + (void)cm_del_shm(SHM_TYPE_HASH, id); + map->hash_ctrl.dirs = SHM_INVALID_ADDR; + } +} diff --git a/src/common/wr_shm_hashmap.h b/src/common/wr_shm_hashmap.h new file mode 100644 index 0000000000000000000000000000000000000000..7d3fd6c8e9ddfd298d5cd08fa452b41cc91abad3 --- /dev/null +++ b/src/common/wr_shm_hashmap.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_shm_hashmap.h + * + * + * IDENTIFICATION + * src/common/wr_shm_hashmap.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_SHM_HASHMAP_H_ +#define __WR_SHM_HASHMAP_H_ + +#include "cm_defs.h" +#include "cm_types.h" +#include "wr_hashmap.h" +#include "wr_shm.h" +#include "cm_latch.h" +#include "wr_latch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WR_MAX_SEGMENT_NUM (1024) +#define WR_MAX_BUCKET_NUM (2097152) +#ifdef ENABLE_WRTEST +#define WR_INIT_BUCKET_NUM (2048) +#else +#define WR_INIT_BUCKET_NUM (32768) +#endif + +#define WR_BUCKETS_PER_SEGMENT (WR_MAX_BUCKET_NUM / WR_MAX_SEGMENT_NUM) +#define WR_BUCKETS_SIZE_PER_SEGMENT (WR_BUCKETS_PER_SEGMENT * sizeof(shm_hashmap_bucket_t)) +#define WR_EXTEND_BATCH (128) +#define WR_HASH_FILL_FACTOR ((float)0.75) +typedef struct st_shm_oamap_bucket { + uint32 hash : 30; + uint32 state : 2; +} shm_oamap_bucket_t; + +typedef struct st_shm_oamap { + sh_mem_p buckets_offset; /* ptr offset */ + sh_mem_p key_offset; /* ptr offset */ + sh_mem_p value_offset; /* ptr offset */ + uint32 num; + uint32 used; + uint32 deleted; + uint32 not_extend : 1; + uint32 shm_id : 31; + uint64 reserve; +} shm_oamap_t; + +typedef struct st_shm_hashmap_bucket { + wr_shared_latch_t enque_lock; + sh_mem_p first; + bool32 has_next; + uint32 entry_num; +} shm_hashmap_bucket_t; + +typedef shm_hashmap_bucket_t *shm_hashmap_segment; +typedef struct st_shm_hash_ctrl { + sh_mem_p dirs; + uint32 bucket_limits; + uint32 bucket_num; + uint32 max_bucket; + uint32 low_mask; + uint32 high_mask; + uint32 nsegments; + cm_oamap_compare_t func; +} shm_hash_ctrl_t; +typedef struct st_shm_hashmap { + shm_hash_ctrl_t hash_ctrl; + uint32 not_extend : 1; + uint32 shm_id : 31; +} shm_hashmap_t; + +typedef struct st_shm_oamap_param { + uint32 hash; + shm_oamap_t *map; + void *key_acl; + cm_oamap_compare_t compare_func; +} shm_oamap_param_t; + +int32 shm_hashmap_init(shm_hashmap_t *map, uint32 id, cm_oamap_compare_t compare_func); +void shm_hashmap_destroy(shm_hashmap_t *map, uint32 id); +shm_hashmap_bucket_t *shm_hashmap_get_bucket(shm_hash_ctrl_t *hash_ctrl, uint32 bucket_idx, uint32 *segment_objid); +status_t shm_hashmap_extend_segment(shm_hash_ctrl_t *hash_ctrl); +bool32 shm_hashmap_need_extend_and_redistribute(shm_hash_ctrl_t *hash_ctrl); +uint32 shm_hashmap_calc_bucket_idx(shm_hash_ctrl_t *hash_ctrl, uint32 hash); + +#define SHM_HASH_BUCKET_INSERT(bucket, item, item_ctrl, first_ctrl) \ + do { \ + if ((bucket)->has_next) { \ + (item_ctrl)->hash_next = (bucket)->first; \ + (item_ctrl)->has_next = CM_TRUE; \ + (first_ctrl)->hash_prev = (item); \ + (first_ctrl)->has_prev = CM_TRUE; \ + } else { \ + (bucket)->has_next = CM_TRUE; \ + } \ + (bucket)->first = (item); \ + (bucket)->entry_num++; \ + } while (0) + +#define SHM_HASH_BUCKET_REMOVE(bucket, item, item_ctrl, prev_ctrl, next_ctrl) \ + do { \ + if ((prev_ctrl) != NULL) { \ + (prev_ctrl)->hash_next = (item_ctrl)->hash_next; \ + (prev_ctrl)->has_next = (item_ctrl)->has_next; \ + } \ + if ((next_ctrl) != NULL) { \ + (next_ctrl)->hash_prev = (item_ctrl)->hash_prev; \ + (next_ctrl)->has_prev = (item_ctrl)->has_prev; \ + } \ + if ((item) == (bucket)->first) { \ + (bucket)->first = (item_ctrl)->hash_next; \ + (bucket)->has_next = (item_ctrl)->has_next; \ + } \ + (item_ctrl)->has_next = CM_FALSE; \ + (item_ctrl)->has_prev = CM_FALSE; \ + (bucket)->entry_num--; \ + } while (0) + +#ifdef __cplusplus +} +#endif + +#endif /* _CM_SHM_HASHMAP_H_ */ diff --git a/src/common/wr_simulation_cm.c b/src/common/wr_simulation_cm.c new file mode 100644 index 0000000000000000000000000000000000000000..a88a2cad7d407c7c7334cee433155aa064326025 --- /dev/null +++ b/src/common/wr_simulation_cm.c @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2023Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_simulation_cm.c + * + * + * IDENTIFICATION + * src/common/wr_simulation_cm.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_errno.h" +#include "cm_num.h" +#include "cm_utils.h" +#include "cm_res_mgr.h" +#include "wr_malloc.h" +#include "wr_file.h" +#include "wr_simulation_cm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ENABLE_WRTEST +simulation_cm_t g_simulation_cm; +static config_item_t g_cm_params[] = { + { CM_LOCK_OWNER_ID, CM_TRUE, CM_FALSE, "0", NULL, NULL, "-", "[0, 63]", "INTEGER", NULL, CM_PARAM_LOCK_OWNER_ID, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL }, + { CM_BITMAP_ONLINE, CM_TRUE, CM_FALSE, "1", NULL, NULL, "-", "-", "BIG INTEGER", NULL, CM_PARAM_BITMAP_ONLINE, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL }, +}; +char g_cm_config_realpath[CM_MAX_PATH_LEN]; +static void wr_simulation_init() +{ + g_simulation_cm.params.lock_owner_id = CM_INVALID_ID32; + g_simulation_cm.params.bitmap_online = 0; + GS_INIT_SPIN_LOCK(g_simulation_cm.lock); +} + +void wr_simulation_cm_refresh(void) +{ + char *value = cm_get_config_value(&g_simulation_cm.config, CM_LOCK_OWNER_ID); + if (cm_str2uint32(value, &g_simulation_cm.params.lock_owner_id) != CM_SUCCESS) { + LOG_RUN_ERR("[WR][simulation_cm]fail to get LOCK_OWNER_ID"); + return; + } + if (g_simulation_cm.params.lock_owner_id < WR_MIN_INST_ID || g_simulation_cm.params.lock_owner_id >= WR_MAX_INST_ID) { + LOG_RUN_ERR("[WR][simulation_cm]the value of 'LOCK_OWNER_ID' is invalid"); + return; + } + value = cm_get_config_value(&g_simulation_cm.config, CM_BITMAP_ONLINE); + if (cm_str2uint64(value, &g_simulation_cm.params.bitmap_online) != CM_SUCCESS) { + LOG_RUN_ERR("[WR][simulation_cm]fail to get BITMAP_ONLINE"); + return; + } +} + +// load config and refresh global variables +static void wr_simulation_cm_thread(thread_t *thread) +{ + cm_set_thread_name("simulation_cm"); + while (!thread->closed) { + char *cm_config_realpath = (char *)thread->argument; + cm_spin_lock(&g_simulation_cm.lock, NULL); + status_t status = + cm_load_config(g_cm_params, CM_PARAM_COUNT, cm_config_realpath, &g_simulation_cm.config, CM_FALSE); + if (status != CM_SUCCESS) { + cm_spin_unlock(&g_simulation_cm.lock); + LOG_RUN_ERR("[WR][simulation_cm]fail to load cm simulation"); + cm_sleep(WR_LONG_TIMEOUT); + continue; + } + wr_simulation_cm_refresh(); + cm_spin_unlock(&g_simulation_cm.lock); + cm_sleep(WR_LONG_TIMEOUT); + } +} + +status_t wr_simulation_cm_lsnr(void) +{ + char *cm_config_path = getenv(CM_CONFIG_PATH); + if (cm_config_path == NULL) { + LOG_RUN_ERR("[WR][simulation_cm]fail to get CM_CONFIG_PATH"); + return CM_ERROR; + } + + int status = realpath_file(cm_config_path, g_cm_config_realpath, CM_MAX_PATH_LEN); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("[WR][simulation_cm]invalid cfg dir"); + return CM_ERROR; + } + LOG_RUN_INF("[WR][simulation_cm]wr_simulation_cm thread started"); + wr_simulation_init(); + int ret = cm_create_thread(wr_simulation_cm_thread, 0, g_cm_config_realpath, &g_simulation_cm.thread); + if (ret != CM_SUCCESS) { + LOG_RUN_ERR("[WR][simulation_cm]fail to create wr_simulation_cm_thread"); + return CM_ERROR; + } + return ret; +} + +status_t wr_refresh_cm_config_lock_owner_id(unsigned int inst_id) +{ + status_t status = CM_SUCCESS; + char lock_owner_buf[CM_BUFLEN_32]; + int ret = sprintf_s(lock_owner_buf, CM_BUFLEN_32, "%d", (int)inst_id); + if (ret == -1) { + LOG_RUN_ERR("[WR][simulation_cm]fail to copy inst_id"); + return CM_ERROR; + } + cm_spin_lock(&g_simulation_cm.lock, NULL); + status = cm_alter_config(&g_simulation_cm.config, CM_LOCK_OWNER_ID, lock_owner_buf, CONFIG_SCOPE_BOTH, CM_TRUE); + if (status != CM_SUCCESS) { + cm_spin_unlock(&g_simulation_cm.lock); + LOG_RUN_ERR("[WR][simulation_cm]fail to modify LOCK_OWNER_ID"); + return CM_ERROR; + } + wr_simulation_cm_refresh(); + cm_spin_unlock(&g_simulation_cm.lock); + return CM_SUCCESS; +} + +status_t wr_simulation_cm_init(unsigned int instance_id, const char *res_name, cm_notify_func_t func) +{ + status_t status = wr_simulation_cm_lsnr(); + if(status == CM_SUCCESS) { + LOG_RUN_INF("[WR][simulation_cm]cm_res_init success"); + } else { + LOG_RUN_ERR("[WR][simulation_cm]cm_res_init fail"); + } + return status; +} + + char *wr_simulation_cm_get_res_stat(void) +{ + uint64 bitmap_online = g_simulation_cm.params.bitmap_online; + char *result = (char *)malloc(CM_MAX_INT64_STRLEN + 1); + if (result == NULL) { + LOG_RUN_ERR("[WR][simulation_cm]fail to malloc bitmap online."); + return NULL; + } + int ret = + snprintf_s(result, CM_MAX_INT64_STRLEN + 1, CM_MAX_INT64_STRLEN, PRINT_FMT_BIGINT, (long long)bitmap_online); + if (ret == -1) { + WR_THROW_ERROR(ERR_SYSTEM_CALL, ret); + return NULL; + } + return result; +} + +void wr_simulation_cm_free_res_stat(char *res_stat) +{ + if (res_stat != NULL) { + cm_free(res_stat); + res_stat = NULL; + } +} + +status_t wr_simulation_cm_res_lock(const char *lock_name) +{ + wr_config_t *inst_cfg = wr_get_inst_cfg(); + uint32 curr_id = (uint32)inst_cfg->params.inst_id; + LOG_RUN_INF("[WR][simulation_cm]Simulate to lock %s.", lock_name); + if (g_simulation_cm.params.lock_owner_id == CM_INVALID_ID32) { + return wr_refresh_cm_config_lock_owner_id(curr_id); + } + return CM_SUCCESS; +} + +status_t wr_simulation_cm_res_unlock(const char *lock_name) +{ + wr_config_t *inst_cfg = wr_get_inst_cfg(); + uint32 curr_id = (uint32)inst_cfg->params.inst_id; + LOG_RUN_INF("[WR][simulation_cm]Simulate to unlock %s.", lock_name); + if (g_simulation_cm.params.lock_owner_id == curr_id) { + return wr_refresh_cm_config_lock_owner_id(CM_INVALID_ID32); + } + return CM_SUCCESS; +} + +status_t wr_simulation_cm_res_get_lock_owner(const char *lock_name, unsigned int *inst_id) +{ + *inst_id = g_simulation_cm.params.lock_owner_id; + LOG_RUN_INF_INHIBIT( + LOG_INHIBIT_LEVEL4, "[WR][simulation_cm]master id is %u when get cm lock %s.", *inst_id, lock_name); + return CM_SUCCESS; +} + +status_t wr_simulation_cm_res_trans_lock(const char *lock_name, unsigned int inst_id) +{ + LOG_RUN_INF("[WR][simulation_cm]Simulate to trans lock %s.", lock_name); + return wr_refresh_cm_config_lock_owner_id(inst_id); +} + +void wr_simulation_cm_uninit(void) +{ + cm_close_thread(&g_simulation_cm.thread); +} + +#define CM_SIMULATION_PATH_LEN 10 +status_t wr_simulation_cm_res_mgr_init(const char *so_lib_path, cm_res_mgr_t *cm_res_mgr, cm_allocator_t *alloc) +{ + if (so_lib_path == NULL || strlen(so_lib_path) == 0) { + cm_res_mgr->so_hanle = NULL; + return CM_SUCCESS; + } + if (strcmp("simulation", so_lib_path) != 0) { + g_simulation_cm.simulation = CM_FALSE; + LOG_RUN_INF("[WR][simulation_cm]Start simulate cm with so."); + return cm_res_mgr_init(so_lib_path, cm_res_mgr, alloc); + } + LOG_RUN_INF("[WR][simulation_cm]Start simulate cm."); + char *cm_simulation_path = (char *)malloc(CM_SIMULATION_PATH_LEN + 1); + if (cm_simulation_path == NULL) { + CM_THROW_ERROR(ERR_ALLOC_MEMORY, CM_SIMULATION_PATH_LEN + 1, "simulation cm"); + return CM_ERROR; + } + errno_t rc = strcpy_s(cm_simulation_path, CM_SIMULATION_PATH_LEN + 1, so_lib_path); + if (rc != EOK) { + CM_THROW_ERROR(ERR_SYSTEM_CALL, rc); + return CM_ERROR; + } + g_simulation_cm.simulation = CM_TRUE; + cm_res_mgr->so_hanle = (char *)cm_simulation_path; + cm_res_mgr->cm_init = wr_simulation_cm_init; + cm_res_mgr->cm_get_res_stat = wr_simulation_cm_get_res_stat; + cm_res_mgr->cm_free_res_stat = wr_simulation_cm_free_res_stat; + cm_res_mgr->cm_res_lock = wr_simulation_cm_res_lock; + cm_res_mgr->cm_res_unlock = wr_simulation_cm_res_unlock; + cm_res_mgr->cm_res_get_lock_owner = wr_simulation_cm_res_get_lock_owner; + cm_res_mgr->cm_res_trans_lock = wr_simulation_cm_res_trans_lock; + return CM_SUCCESS; +} + +void wr_simulation_cm_res_mgr_uninit(cm_res_mgr_t *cm_res_mgr) +{ + if (cm_res_mgr->so_hanle != NULL) { + if (g_simulation_cm.simulation) { + cm_free(cm_res_mgr->so_hanle); + cm_res_mgr->so_hanle = NULL; + return; + } + cm_res_mgr_uninit(cm_res_mgr); + } +} +#endif + +#ifdef __cplusplus +} +#endif diff --git a/src/common/wr_simulation_cm.h b/src/common/wr_simulation_cm.h new file mode 100644 index 0000000000000000000000000000000000000000..78cdb94dd2412fe412543d32e204a9ee027651b7 --- /dev/null +++ b/src/common/wr_simulation_cm.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_simulation_cm.h + * + * + * IDENTIFICATION + * src/common/wr_simulation_cm.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_SIMULATION_CM_H__ +#define __WR_SIMULATION_CM_H__ + +#include "wr_defs.h" +#include "cm_config.h" +#include "cs_pipe.h" +#include "mes_metadata.h" +#include "wr_errno.h" +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ENABLE_WRTEST +#define CM_CONFIG_PATH "CM_CONFIG_PATH" +#define CM_LOCK_OWNER_ID "LOCK_OWNER_ID" +#define CM_BITMAP_ONLINE "BITMAP_ONLINE" +#define WR_LONG_TIMEOUT 300 + +typedef enum en_cm_params { + CM_PARAM_LOCK_OWNER_ID, + CM_PARAM_BITMAP_ONLINE, + /* add above here */ + CM_PARAM_COUNT +} cm_params_e; + +typedef struct st_cm_params { + uint64 bitmap_online; + uint32 lock_owner_id; +} cm_params_t; + +typedef struct st_simulation_cm { + thread_t thread; + spinlock_t lock; + config_t config; + cm_params_t params; + bool32 simulation; +} simulation_cm_t; +extern simulation_cm_t g_simulation_cm; +void wr_simulation_cm_res_mgr_uninit(cm_res_mgr_t *cm_res_mgr); +status_t wr_simulation_cm_res_mgr_init(const char *so_lib_path, cm_res_mgr_t *cm_res_mgr, cm_allocator_t *alloc); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/wr_stack.c b/src/common/wr_stack.c new file mode 100644 index 0000000000000000000000000000000000000000..439025d89a13a207f4cc5e2f12e5c829bfd9c616 --- /dev/null +++ b/src/common/wr_stack.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_stack.c + * + * + * IDENTIFICATION + * src/common/wr_stack.c + * + * ------------------------------------------------------------------------- + */ +#include "wr_stack.h" +#include "cm_log.h" +#include "cm_debug.h" +#include "wr_defs.h" +#include "wr_log.h" + +char *wr_get_stack_pos(wr_stack *stack, uint32 depth) +{ + CM_ASSERT(stack != NULL); + + if (stack->depth < depth) { + return NULL; + } + + return (stack->buff + stack->indicator[depth]); +} + +void wr_pop_ex(wr_stack *stack, uint32 depth) +{ + CM_ASSERT(stack != NULL); + + if (depth >= WR_MAX_STACK_DEPTH) { + LOG_DEBUG_ERR("pop vg_item stack depth is out of bound"); + return; + } + + stack->depth = depth; + stack->buff_pos = stack->indicator[depth]; +} diff --git a/src/common/wr_stack.h b/src/common/wr_stack.h new file mode 100644 index 0000000000000000000000000000000000000000..531a9cc7e4048ed441885c0ee82caba4ef3e2a5e --- /dev/null +++ b/src/common/wr_stack.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_stack.h + * + * + * IDENTIFICATION + * src/common/wr_stack.h + * + * ------------------------------------------------------------------------- + */ +#ifndef __WR_STACK_H_ +#define __WR_STACK_H_ + +#include "cm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WR_MAX_STACK_DEPTH 32 +typedef struct tagknl_stack { + uint32 depth; + uint32 buff_pos; + uint32 indicator[WR_MAX_STACK_DEPTH]; + uint32 size; + uint32 reserve; + char *buff; +} wr_stack; + +char *wr_get_stack_pos(wr_stack *stack, uint32 depth); +void wr_pop_ex(wr_stack *stack, uint32 depth); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/wr_stats.c b/src/common/wr_stats.c new file mode 100644 index 0000000000000000000000000000000000000000..09dfb1cf126f905689ccd994a2fbfb2b55b085fa --- /dev/null +++ b/src/common/wr_stats.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_stats.c + * + * + * IDENTIFICATION + * src/common/wr_stats.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_stats.h" + +#ifdef __cplusplus +extern "C" { +#endif + +const char *g_wr_stat_events[WR_EVT_COUNT] = { + [WR_PREAD] = "WR Pread", + [WR_PWRITE] = "WR Pwrite", + [WR_PREAD_SYN_META] = "WR Pread Sync Metadata", + [WR_PWRITE_SYN_META] = "WR Pwrite Sync Metadata", + [WR_PREAD_DISK] = "WR Pread Disk", + [WR_PWRITE_DISK] = "WR Pwrite Disk", + [WR_FOPEN] = "WR File Open", + [WR_STAT] = "WR Stat", + [WR_FIND_FT_ON_SERVER] = "Find File Node On Server", +}; + +const char *wr_get_stat_event(wr_wait_event_e event) +{ + return g_wr_stat_events[event]; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/common/wr_stats.h b/src/common/wr_stats.h new file mode 100644 index 0000000000000000000000000000000000000000..42bbff7d897dd4061bf93ea7245728a8f328bafb --- /dev/null +++ b/src/common/wr_stats.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_stats.h + * + * + * IDENTIFICATION + * src/common/wr_stats.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_STATS_H__ +#define __WR_STATS_H__ + +#include "cm_defs.h" +#include "cm_date.h" +#include "cm_timer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum en_wr_wait_event { + WR_PREAD = 0, + WR_PWRITE, + WR_PREAD_SYN_META, + WR_PWRITE_SYN_META, + WR_PREAD_DISK, + WR_PWRITE_DISK, + WR_FOPEN, + WR_STAT, + WR_FIND_FT_ON_SERVER, + WR_EVT_COUNT, +} wr_wait_event_e; + +typedef struct st_wr_stat_item { + atomic_t total_wait_time; + atomic_t max_single_time; + atomic_t wait_count; +} wr_stat_item_t; + +typedef struct st_wr_stat_ctx { + bool32 enable_stat; + wr_wait_event_e wait_event; +} wr_stat_ctx_t; + +static inline void wr_begin_stat(timeval_t *begin_tv) +{ + (void)cm_gettimeofday(begin_tv); +} + +static inline void wr_end_stat_base(wr_stat_item_t *stat_item, timeval_t *begin_tv) +{ + timeval_t end_tv; + uint64 usecs; + + (void)cm_gettimeofday(&end_tv); + usecs = (uint64)TIMEVAL_DIFF_US(begin_tv, &end_tv); + (void)cm_atomic_add(&stat_item->total_wait_time, (int64)usecs); + (void)cm_atomic_set(&stat_item->max_single_time, (int64)MAX((uint64)stat_item->max_single_time, usecs)); + (void)cm_atomic_inc(&stat_item->wait_count); +} + +static inline void wr_end_stat_ex(wr_stat_ctx_t *stat_ctx, wr_stat_item_t *stat_item, timeval_t *begin_tv) +{ + if (stat_ctx->enable_stat) { + wr_end_stat_base(stat_item, begin_tv); + } +} + +static inline void wr_set_stat(wr_stat_ctx_t *stat_ctx, wr_wait_event_e event) +{ + stat_ctx->enable_stat = CM_TRUE; + stat_ctx->wait_event = event; +} + +static inline void wr_unset_stat(wr_stat_ctx_t *stat_ctx) +{ + stat_ctx->enable_stat = CM_FALSE; +} + +const char *wr_get_stat_event(wr_wait_event_e event); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/wr_syn_meta.c b/src/common/wr_syn_meta.c new file mode 100644 index 0000000000000000000000000000000000000000..a5701e10c5afcd922a6d8c2e28967c7efb0d1133 --- /dev/null +++ b/src/common/wr_syn_meta.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_syn_meta.c + * + * + * IDENTIFICATION + * src/common/wr_syn_meta.c + * + * ------------------------------------------------------------------------- + */ +#include "wr_syn_meta.h" +#include "wr_file.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static bool32 enable_syn_meta = CM_TRUE; + +wr_meta_syn2other_nodes_proc_t meta_syn2other_nodes_proc = NULL; +void regist_meta_syn2other_nodes_proc(wr_meta_syn2other_nodes_proc_t proc) +{ + meta_syn2other_nodes_proc = proc; +} + +void wr_del_syn_meta(wr_vg_info_item_t *vg_item, wr_block_ctrl_t *block_ctrl, int64 syn_meta_ref_cnt) +{ + if (!enable_syn_meta || meta_syn2other_nodes_proc == NULL) { + return; + } + + // syn_meta_ref_cnt at most eq block_ctrl->syn_meta_ref_cnt, may less + if ((uint64)cm_atomic_get((atomic_t *)&block_ctrl->syn_meta_ref_cnt) > 0) { + (void)cm_atomic_add((atomic_t *)&block_ctrl->syn_meta_ref_cnt, (0 - syn_meta_ref_cnt)); + } + if ((uint64)cm_atomic_get((atomic_t *)&block_ctrl->syn_meta_ref_cnt) != 0) { + return; + } + wr_latch_x(&vg_item->syn_meta_desc.latch); + LOG_DEBUG_INF("del syn meta for fid:%llu, ftid:%llu, file_ver:%llu, type:%u, id:%llu, ref_cnt:%llu", + block_ctrl->fid, block_ctrl->ftid, block_ctrl->file_ver, (uint32)block_ctrl->type, + WR_ID_TO_U64(block_ctrl->block_id), block_ctrl->syn_meta_ref_cnt); + cm_bilist_del(&block_ctrl->syn_meta_node, &vg_item->syn_meta_desc.bilist); + wr_buffer_recycle_disable(block_ctrl, CM_FALSE); + wr_unlatch(&vg_item->syn_meta_desc.latch); +} + +void wr_syn_meta(wr_session_t *session, wr_vg_info_item_t *vg_item, wr_block_ctrl_t *block_ctrl) +{ + if (wr_need_exec_local() && wr_is_readwrite()) { + wr_meta_syn_t meta_syn; + // too many place to change the value of block_ctrl->data + wr_lock_vg_mem_and_shm_s(session, vg_item); + char *meta_addr = WR_GET_META_FROM_BLOCK_CTRL(char, block_ctrl); + wr_common_block_t *block = (wr_common_block_t *)meta_addr; + meta_syn.ftid = block_ctrl->ftid; + meta_syn.fid = block_ctrl->fid; + meta_syn.file_ver = block_ctrl->file_ver; + meta_syn.syn_meta_version = block->version; + meta_syn.meta_block_id = WR_ID_TO_U64(block->id); + meta_syn.vg_id = vg_item->id; + meta_syn.meta_type = block_ctrl->type; + meta_syn.meta_len = wr_buffer_cache_get_block_size(block_ctrl->type); + errno_t errcode = memcpy_s(meta_syn.meta, meta_syn.meta_len, (char *)block, meta_syn.meta_len); + if (SECUREC_UNLIKELY(errcode != EOK)) { + wr_unlock_vg_mem_and_shm(session, vg_item); + WR_THROW_ERROR(ERR_SYSTEM_CALL, errcode); + return; + } + wr_unlock_vg_mem_and_shm(session, vg_item); + + (void)meta_syn2other_nodes_proc( + vg_item, (char *)&meta_syn, (OFFSET_OF(wr_meta_syn_t, meta) + meta_syn.meta_len), NULL); + LOG_DEBUG_INF("syn meta file:%llu file_ver:%llu, vg:%u, block:%llu type:%u, with version:%llu.", meta_syn.fid, + meta_syn.file_ver, meta_syn.vg_id, meta_syn.meta_block_id, meta_syn.meta_type, meta_syn.syn_meta_version); + } +} + +// if primary, syn meta, if not, just clean the link +bool32 wr_syn_buffer_cache(wr_session_t *session, wr_vg_info_item_t *vg_item) +{ + if (!enable_syn_meta || meta_syn2other_nodes_proc == NULL) { + return CM_TRUE; + } + + if (cm_bilist_empty(&vg_item->syn_meta_desc.bilist)) { + return CM_TRUE; + } + + bool32 is_valid; + wr_block_ctrl_t *block_ctrl = NULL; + wr_block_ctrl_t *onwer_block_ctrl = NULL; + + bilist_node_t *bilist_node = NULL; + bilist_node_t *bilist_node_tail = NULL; + bilist_node_t *bilist_node_next = NULL; + + // without latch here, may miss this time, but can get next time + bilist_node = cm_bilist_head(&vg_item->syn_meta_desc.bilist); + bilist_node_tail = cm_bilist_tail(&vg_item->syn_meta_desc.bilist); + while (bilist_node != NULL) { + block_ctrl = BILIST_NODE_OF(wr_block_ctrl_t, bilist_node, syn_meta_node); + // forbid delay node recycle task recycle node + if (block_ctrl->type == WR_BLOCK_TYPE_FT) { + (void)cm_atomic_inc((atomic_t *)&block_ctrl->bg_task_ref_cnt); + } else { + onwer_block_ctrl = wr_get_block_ctrl_by_node((gft_node_t *)block_ctrl->node); + WR_ASSERT_LOG(onwer_block_ctrl != NULL, "owner block ctrl is NULL because it is root block"); + (void)cm_atomic_inc((atomic_t *)&onwer_block_ctrl->bg_task_ref_cnt); + } + + int64 syn_meta_ref_cnt = (int64)cm_atomic_get((atomic_t *)&block_ctrl->syn_meta_ref_cnt); + + LOG_DEBUG_INF("try syn meta for fid:%llu, ftid:%llu, file_ver:%llu, type:%u, id:%llu, ref_cnt:%llu", + block_ctrl->fid, block_ctrl->ftid, block_ctrl->file_ver, (uint32)block_ctrl->type, + WR_ID_TO_U64(block_ctrl->block_id), block_ctrl->syn_meta_ref_cnt); + + is_valid = wr_is_block_ctrl_valid(block_ctrl); + if (!is_valid) { + if (bilist_node_tail == bilist_node) { + bilist_node_next = NULL; + } else { + bilist_node_next = BINODE_NEXT(bilist_node); + } + wr_del_syn_meta(vg_item, block_ctrl, syn_meta_ref_cnt); + if (block_ctrl->type == WR_BLOCK_TYPE_FT) { + (void)cm_atomic_dec((atomic_t *)&block_ctrl->bg_task_ref_cnt); + } else { + (void)cm_atomic_dec((atomic_t *)&onwer_block_ctrl->bg_task_ref_cnt); + } + + bilist_node = bilist_node_next; + continue; + } + + wr_syn_meta(session, vg_item, block_ctrl); + + if (bilist_node_tail != bilist_node) { + bilist_node_next = BINODE_NEXT(bilist_node); + } else { + bilist_node_next = NULL; + } + wr_del_syn_meta(vg_item, block_ctrl, syn_meta_ref_cnt); + + if (block_ctrl->type == WR_BLOCK_TYPE_FT) { + (void)cm_atomic_dec((atomic_t *)&block_ctrl->bg_task_ref_cnt); + } else { + (void)cm_atomic_dec((atomic_t *)&onwer_block_ctrl->bg_task_ref_cnt); + } + bilist_node = bilist_node_next; + } + + return cm_bilist_empty(&vg_item->syn_meta_desc.bilist); +} + +status_t wr_meta_syn_remote(wr_session_t *session, wr_meta_syn_t *meta_syn, uint32 size, bool32 *ack) +{ + if (!enable_syn_meta || meta_syn2other_nodes_proc == NULL) { + return CM_SUCCESS; + } + + *ack = CM_FALSE; + + LOG_DEBUG_INF("notify syn meta file:%llu, file_ver:%llu, vg :%u, block:%llu type:%u, with version:%llu.", + meta_syn->fid, meta_syn->file_ver, meta_syn->vg_id, meta_syn->meta_block_id, meta_syn->meta_type, + meta_syn->syn_meta_version); + + wr_vg_info_item_t *vg_item = wr_find_vg_item_by_id(meta_syn->vg_id); + if (vg_item == NULL) { + WR_RETURN_IFERR2(CM_ERROR, LOG_DEBUG_ERR("Failed to find vg:%u.", meta_syn->vg_id)); + } + + uint32 meta_len = wr_buffer_cache_get_block_size(meta_syn->meta_type); + uint32 check_sum = wr_get_checksum(meta_syn->meta, meta_len); + wr_common_block_t *syn_meta_block = WR_GET_COMMON_BLOCK_HEAD(meta_syn->meta); + if (meta_len != meta_syn->meta_len || check_sum != syn_meta_block->checksum) { + WR_RETURN_IFERR2(CM_ERROR, + LOG_DEBUG_ERR( + "syn meta file:%llu, file_ver:%llu, vg :%u, block: %llu, type:%u, with version:%llu data error skip.", + meta_syn->fid, meta_syn->file_ver, meta_syn->vg_id, meta_syn->meta_block_id, meta_syn->meta_type, + meta_syn->syn_meta_version)); + } + + ga_obj_id_t out_obj_id; + wr_block_id_t meta_block_id; + wr_set_blockid(&meta_block_id, meta_syn->meta_block_id); + char *block = wr_find_block_in_shm_no_refresh_ex(session, vg_item, meta_block_id, &out_obj_id); + if (block == NULL) { + LOG_DEBUG_INF( + "syn meta file:%llu, file_ver:%llu, vg :%u, block:%llu type:%u, with version:%llu not found node fail.", + meta_syn->fid, meta_syn->file_ver, meta_syn->vg_id, meta_syn->meta_block_id, meta_syn->meta_type, + meta_syn->syn_meta_version); + *ack = CM_TRUE; + return CM_SUCCESS; + } + + wr_common_block_t *common_block = WR_GET_COMMON_BLOCK_HEAD(block); + wr_block_ctrl_t *block_ctrl = WR_GET_BLOCK_CTRL_FROM_META(block); + gft_node_t *node = NULL; + if (common_block->type == WR_BLOCK_TYPE_FT) { + node = wr_get_node_by_block_ctrl(block_ctrl, 0); + } + + if (!wr_enter_shm_time_x(session, vg_item, WR_LOCK_SHM_META_TIMEOUT)) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_SHM_LOCK_TIMEOUT)); + } + if ((block_ctrl->fid != meta_syn->fid) || + (common_block->type != WR_BLOCK_TYPE_FT && block_ctrl->file_ver != meta_syn->file_ver) || + (common_block->type == WR_BLOCK_TYPE_FT && block_ctrl->file_ver >= meta_syn->file_ver) || + (common_block->version >= meta_syn->syn_meta_version) || + (node != NULL && (node->flags & WR_FT_NODE_FLAG_INVALID_FS_META))) { + LOG_DEBUG_INF( + "syn meta file:%llu, file_ver:%llu, vg :%u, block: %llu type:%u, with version:%llu fid or version skip.", + meta_syn->fid, meta_syn->file_ver, meta_syn->vg_id, meta_syn->meta_block_id, meta_syn->meta_type, + meta_syn->syn_meta_version); + } else { + errno_t errcode = memcpy_s(block, meta_len, meta_syn->meta, meta_syn->meta_len); + if (SECUREC_UNLIKELY(errcode != EOK)) { + wr_leave_shm(session, vg_item); + WR_THROW_ERROR(ERR_SYSTEM_CALL, errcode); + return CM_ERROR; + } + } + + wr_leave_shm(session, vg_item); + *ack = CM_TRUE; + LOG_DEBUG_INF( + "syn ack:%u when notify syn meta file:%llu, file_ver:%llu, vg :%u, block: %llu type:%u, with version:%llu.", + (uint32)(*ack), meta_syn->fid, meta_syn->file_ver, meta_syn->vg_id, meta_syn->meta_block_id, + meta_syn->meta_type, meta_syn->syn_meta_version); + return CM_SUCCESS; +} + +status_t wr_invalidate_meta_remote( + wr_session_t *session, wr_invalidate_meta_msg_t *invalidate_meta_msg, uint32 size, bool32 *invalid_ack) +{ + return CM_SUCCESS; +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/common/wr_syn_meta.h b/src/common/wr_syn_meta.h new file mode 100644 index 0000000000000000000000000000000000000000..e5f5dd7f6eac8bf88682d9d307ffc8208f537320 --- /dev/null +++ b/src/common/wr_syn_meta.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_syn_meta.h + * + * + * IDENTIFICATION + * src/common/wr_syn_meta.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_SYN_META_H__ +#define __WR_SYN_META_H__ + +#include "wr_defs.h" +#include "wr_file_def.h" +#include "wr_session.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_wr_meta_syn_msg { + uint64 ftid; + uint64 fid; // it's the owner's gft_node_t.fid + uint64 file_ver; // it's the owner's gft_node_t.file_ver + uint64 syn_meta_version; + uint64 meta_block_id; + uint32 vg_id; + uint32 meta_type; + uint32 meta_len; + char meta[WR_MAX_META_BLOCK_SIZE]; +} wr_meta_syn_t; + +typedef struct st_wr_invalidate_meta_msg { + uint32 vg_id; + uint32 meta_type; + uint64 meta_block_id; +} wr_invalidate_meta_msg_t; + +void wr_del_syn_meta(wr_vg_info_item_t *vg_item, wr_block_ctrl_t *block_ctrl, int64 syn_meta_ref_cnt); +bool32 wr_syn_buffer_cache(wr_session_t *session, wr_vg_info_item_t *vg_item); +status_t wr_meta_syn_remote(wr_session_t *session, wr_meta_syn_t *meta_syn, uint32 size, bool32 *ack); +status_t wr_invalidate_meta_remote( + wr_session_t *session, wr_invalidate_meta_msg_t *invalidate_meta_msg, uint32 size, bool32 *invalid_ack); + +typedef status_t (*wr_meta_syn2other_nodes_proc_t)( + wr_vg_info_item_t *vg_item, char *meta_syn, uint32 meta_syn_size, bool32 *cmd_ack); +void regist_meta_syn2other_nodes_proc(wr_meta_syn2other_nodes_proc_t proc); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/common/wr_thv.c b/src/common/wr_thv.c new file mode 100644 index 0000000000000000000000000000000000000000..ef7db1fab2268d68a8f8df69aec6098813ecb9cb --- /dev/null +++ b/src/common/wr_thv.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * cm_thv.c + * + * + * IDENTIFICATION + * src/common/cm_thv.c + * + * ------------------------------------------------------------------------- + */ + +#include "cm_thread.h" +#include "cm_error.h" +#include "wr_log.h" +#include "cm_log.h" +#include "wr_thv.h" +#ifndef WIN32 +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WIN32 +static __thread wr_thv_run_ctx_t wr_thv_run_ctx = {0}; +#else +__declspec(thread) wr_thv_run_ctx_t wr_thv_run_ctx = {0}; +#endif + +#ifndef WIN32 +/* ****Thread variable defined begin.**** */ +// THV --> THREAD VARIANT +// Thread variable control function. +static thv_ctrl_t g_thv_ctrl_func[MAX_THV_TYPE]; + +// Thread variant address, it will be created in function create_var_func and released in function release_var_func. +static __thread pointer_t g_thv_addr[MAX_THV_TYPE] = {0}; +// Thread variant is call pthread_setspcific +static __thread bool32 g_thv_spec = CM_FALSE; +static pthread_key_t g_thv_key; + +void wr_exit(int32 exit_code) +{ + LOG_RUN_INF("Try to exit."); + _exit(1); +} +// destroy all thread variable content when thread exit +static void cm_destroy_thv(pointer_t thread_var) +{ + if (thread_var == NULL) { + return; + } + pointer_t *curr_thread_var = (pointer_t *)thread_var; + for (uint32 i = 0; i < MAX_THV_TYPE; i++) { + if (curr_thread_var[i] != NULL) { + if (g_thv_ctrl_func[i].release != NULL) { + g_thv_ctrl_func[i].release(curr_thread_var[i]); + } + curr_thread_var[i] = NULL; + } + } +} + +void wr_destroy_thv(thv_type_e type) +{ + cm_destroy_thv(&g_thv_addr[type]); +} + +status_t cm_create_thv_ctrl(void) +{ + int32 ret = pthread_key_create(&g_thv_key, cm_destroy_thv); + if (ret != EOK) { + LOG_RUN_ERR("call pthread_key_create failed"); + return CM_ERROR; + } + errno_t errcode = + memset_s(g_thv_ctrl_func, sizeof(thv_ctrl_t) * MAX_THV_TYPE, 0, sizeof(thv_ctrl_t) * MAX_THV_TYPE); + securec_check_ret(errcode); + return CM_SUCCESS; +} + +status_t cm_set_thv_args_by_id( + thv_type_e var_type, init_thv_func init, create_thv_func create, release_thv_func release) +{ + if (var_type >= MAX_THV_TYPE) { + LOG_RUN_ERR("invalid var type %u", (uint32)var_type); + return CM_ERROR; + } + + g_thv_ctrl_func[var_type].init = init; + + if (create == NULL) { + LOG_RUN_ERR("create_thv_func cannot be null"); + return CM_ERROR; + } + g_thv_ctrl_func[var_type].create = create; + g_thv_ctrl_func[var_type].release = release; + + return CM_SUCCESS; +} + +void cm_init_thv(void) +{ + for (uint32 var_type = 0; var_type < MAX_THV_TYPE; var_type++) { + if (g_thv_ctrl_func[var_type].init != NULL) { + g_thv_ctrl_func[var_type].init(); + } + } +} + +status_t cm_get_thv(thv_type_e var_type, bool32 is_create, pointer_t *result, const char* addr) +{ + if (g_thv_addr[var_type] == NULL && is_create) { + int32 ret = g_thv_ctrl_func[var_type].create(&g_thv_addr[var_type], addr); + if (ret != EOK) { + LOG_RUN_ERR("create thread variable failed, var_type %u", (uint32)var_type); + return CM_ERROR; + } + if (!g_thv_spec) { + ret = pthread_setspecific(g_thv_key, g_thv_addr); + if (ret != EOK) { + WR_THROW_ERROR(ERR_SYSTEM_CALL, ret); + LOG_RUN_ERR("call pthread_setspecific failed"); + return CM_ERROR; + } + g_thv_spec = CM_TRUE; + } + } + + *result = g_thv_addr[var_type]; + return CM_SUCCESS; +} + +status_t cm_launch_thv(thv_ctrl_t *thv_ctrls, uint32 thv_ctrl_cnt) +{ + // now begin init thread variant + if (cm_create_thv_ctrl() != CM_SUCCESS) { + return CM_ERROR; + } + + for (uint32 i = 0; i < thv_ctrl_cnt; i++) { + if (cm_set_thv_args_by_id(i, thv_ctrls[i].init, thv_ctrls[i].create, thv_ctrls[i].release) != CM_SUCCESS) { + return CM_ERROR; + } + } + + cm_init_thv(); + + return CM_SUCCESS; +} + +/* ****Thread variable defined end.**** */ +#else + +status_t cm_create_thv_ctrl(void) +{ + return CM_SUCCESS; +} + +status_t cm_set_thv_args_by_id( + thv_type_e var_type, init_thv_func init, create_thv_func create, release_thv_func release) +{ + return CM_SUCCESS; +} + +void cm_init_thv(void) +{} + +status_t cm_get_thv(thv_type_e var_type, bool32 is_create, pointer_t *result, const char* addr) +{ + return CM_ERROR; +} + +status_t cm_launch_thv(thv_ctrl_t *thv_ctrls, uint32 thv_ctrl_cnt) +{ + return CM_SUCCESS; +} + +#endif + +uint32 wr_get_current_thread_id() +{ + if (wr_thv_run_ctx.thread_id != 0) { + return wr_thv_run_ctx.thread_id; + } + wr_thv_run_ctx.thread_id = cm_get_current_thread_id(); + return wr_thv_run_ctx.thread_id; +} + +void wr_set_thv_run_ctx_item(wr_thv_run_ctx_item_e item, void *item_addr) +{ + if (item < WR_THV_RUN_CTX_ITEM_MAX) { + wr_thv_run_ctx.item_addr[item] = item_addr; + } +} + +void *wr_get_thv_run_ctx_item(wr_thv_run_ctx_item_e item) +{ + if (item < WR_THV_RUN_CTX_ITEM_MAX) { + return wr_thv_run_ctx.item_addr[item]; + } + return NULL; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/common/wr_thv.h b/src/common/wr_thv.h new file mode 100644 index 0000000000000000000000000000000000000000..66cb891a6bb5f1a3785dfc9ee00c58014d9d118b --- /dev/null +++ b/src/common/wr_thv.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_thv.h + * + * + * IDENTIFICATION + * src/common/wr_thv.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_THV_H__ +#define __WR_THV_H__ + +#include "cm_atomic.h" +#include "cm_defs.h" +#include "cm_error.h" + +#ifdef WIN32 +#else +#include +#include +#include +#include +#include +#include +#endif + +#ifndef WIN32 +#include +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum tag_wr_thv_run_ctx_item { + WR_THV_RUN_CTX_ITEM_SESSION = 0, // bind one session to cur thd + WR_THV_RUN_CTX_ITEM_MAX, +} wr_thv_run_ctx_item_e; + +typedef struct tag_wr_thv_run_ctx { + uint32 thread_id; + void *item_addr[WR_THV_RUN_CTX_ITEM_MAX]; +} wr_thv_run_ctx_t; + +/* ****Thread variable defined begin.**** */ +#define DB_MAX_THV_OBJ_NUM 3 + +typedef enum tag_thv_type { + GLOBAL_THV_OBJ0 = 0, // had been occupied by wr connection + GLOBAL_THV_OBJ1 = 1, // wr connection options + GLOBAL_THV_OBJ2 = 2, + // add more here, notice modify DB_MAX_THV_OBJ_NUM + MAX_THV_TYPE +} thv_type_e; + +typedef handle_t (*init_thv_func)(void); +typedef status_t (*create_thv_func)(pointer_t *result, const char *addr); +typedef void (*release_thv_func)(pointer_t thv_addr); + +typedef struct tag_thv_ctrl { + // It will be called one time for a process. + init_thv_func init; + // It will be called one time for per thread when use it. + create_thv_func create; + // It will be called when thread_var_addr isn't null and the thread whill exit. + release_thv_func release; +} thv_ctrl_t; + +// create thread variant storages +// NOTICE: all release operation will mount in release_thv_func +status_t cm_create_thv_ctrl(void); + +status_t cm_set_thv_args_by_id( + thv_type_e var_type, init_thv_func init, create_thv_func create, release_thv_func release); +// initialize all thread variant,call it after cm_set_thv_args_by_id +void cm_init_thv(void); + +status_t cm_get_thv(thv_type_e var_type, bool32 is_create, pointer_t *result, const char *addr); + +status_t cm_launch_thv(thv_ctrl_t *thv_ctrls, uint32 thv_ctrl_cnt); + +uint32 wr_get_current_thread_id(); +void wr_set_thv_run_ctx_item(wr_thv_run_ctx_item_e item, void *item_addr); +void *wr_get_thv_run_ctx_item(wr_thv_run_ctx_item_e item); + +void wr_exit(int32 exit_code); +void wr_destroy_thv(thv_type_e type); +#ifdef __cplusplus +} +#endif + +#endif // __WR_THV_H__ diff --git a/src/common/wr_volume.c b/src/common/wr_volume.c new file mode 100644 index 0000000000000000000000000000000000000000..915c2ee60279d68d872ecd1bd9aad31b9fc8d13a --- /dev/null +++ b/src/common/wr_volume.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_volume.c + * + * + * IDENTIFICATION + * src/common/wr_volume.c + * + * ------------------------------------------------------------------------- + */ +#include "wr_volume.h" +#ifndef WIN32 +#include +#include +#include +#endif // !WIN32 +#include "wr_file.h" +#include "wr_thv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +uint64 g_log_offset = WR_INVALID_ID64; +#ifdef WIN32 +int32 device_os_error_array[] = { + EOPNOTSUPP, ETIMEDOUT, ENOSPC, ENOLINK, ENODATA, EILSEQ, ENOMEM, EBUSY, EAGAIN, ENODEV, EOVERFLOW, EIO}; +}; +#else +int32 device_os_error_array[] = {EOPNOTSUPP, ETIMEDOUT, ENOSPC, ENOLINK, EBADE, ENODATA, EILSEQ, ENOMEM, EBUSY, EAGAIN, + ENODEV, EREMCHG, ETOOMANYREFS, EOVERFLOW, EIO}; +#endif + +bool32 wr_is_device_os_error(int32 os_err) +{ + uint8 size = (uint8)sizeof(device_os_error_array) / sizeof(device_os_error_array[0]); + for (uint8 i = 0; i < size; i++) { + if (os_err == device_os_error_array[i]) { + return CM_TRUE; + } + } + return CM_FALSE; +} + +static inline void wr_open_fail(const char *name) +{ + if (wr_is_device_os_error(cm_get_os_error())) { + WR_THROW_ERROR(ERR_WR_VOLUME_SYSTEM_IO, name); + LOG_RUN_ERR("[WR] ABORT OPEN VOLUME RAW, because Linux OS error: errno:%d, errmsg:%s.", cm_get_os_error(), + strerror(cm_get_os_error())); + cm_fync_logfile(); + wr_exit(1); + } else { + WR_THROW_ERROR(ERR_WR_VOLUME_OPEN, name, cm_get_os_error()); + } +} + +static status_t wr_open_filehandle_raw(const char *name, int flags, volume_handle_t *fd, volume_handle_t *unaligned_fd) +{ + // O_RDWR | O_SYNC | O_DIRECT + *fd = open(name, flags, 0); + if (*fd == -1) { + wr_open_fail(name); + return CM_ERROR; + } + + // O_RDWR | O_SYNC + *unaligned_fd = open(name, WR_NOD_OPEN_FLAG, 0); + if (*unaligned_fd == -1) { + wr_open_fail(name); + return CM_ERROR; + } + + return CM_SUCCESS; +} + +status_t wr_open_volume_raw(const char *name, const char *code, int flags, wr_volume_t *volume) +{ + if (wr_open_filehandle_raw(name, flags, &volume->handle, &volume->unaligned_handle) != CM_SUCCESS) { + return CM_ERROR; + } + errno_t ret = snprintf_s(volume->name, WR_MAX_VOLUME_PATH_LEN, WR_MAX_VOLUME_PATH_LEN - 1, "%s", name); + WR_SECUREC_SS_RETURN_IF_ERROR(ret, CM_ERROR); + volume->name_p = volume->name; + return CM_SUCCESS; +} + +status_t wr_open_simple_volume_raw(const char *name, int flags, wr_simple_volume_t *volume) +{ + if (wr_open_filehandle_raw(name, flags, &volume->handle, &volume->unaligned_handle) != CM_SUCCESS) { + return CM_ERROR; + } + return CM_SUCCESS; +} + +void wr_close_volume_raw(wr_volume_t *volume) +{ + int ret = close(volume->handle); + if (ret != 0) { + LOG_RUN_ERR("failed to close file with handle %d, error code %d", volume->handle, errno); + } + ret = close(volume->unaligned_handle); + if (ret != 0) { + LOG_RUN_ERR("failed to close file with unaligned_handle %d, error code %d", volume->unaligned_handle, errno); + } + + if (memset_s(volume, sizeof(wr_volume_t), 0, sizeof(wr_volume_t)) != EOK) { + cm_panic(0); + } + volume->handle = WR_INVALID_HANDLE; + volume->unaligned_handle = WR_INVALID_HANDLE; +} + +void wr_close_simple_volume_raw(wr_simple_volume_t *simple_volume) +{ + (void)close(simple_volume->handle); + simple_volume->handle = WR_INVALID_HANDLE; + (void)close(simple_volume->unaligned_handle); + simple_volume->unaligned_handle = WR_INVALID_HANDLE; +} + +uint64 wr_get_volume_size_raw(wr_volume_t *volume) +{ + int64 size = lseek64(volume->handle, 0, SEEK_END); + if (size == -1) { + WR_LOG_WITH_OS_MSG("failed to seek file with handle %d", volume->handle); + if (wr_is_device_os_error(cm_get_os_error())) { + WR_THROW_ERROR(ERR_WR_VOLUME_SYSTEM_IO, volume->name_p); + LOG_RUN_ERR("[WR] ABORT GET VOLUME SIZE, because Linux OS error: errno:%d, errmsg:%s.", cm_get_os_error(), + strerror(cm_get_os_error())); + cm_fync_logfile(); + wr_exit(1); + } else { + WR_THROW_ERROR(ERR_WR_VOLUME_SEEK, volume->name_p, volume->id, cm_get_os_error()); + } + return WR_INVALID_64; + } + return (uint64)size; +} + +static status_t wr_try_pread_volume_raw(wr_volume_t *volume, int64 offset, char *buffer, int32 size, int32 *read_size) +{ + *read_size = (int32)pread(volume->handle, buffer, size, (off_t)offset); + if (*read_size == -1) { + if (wr_is_device_os_error(cm_get_os_error())) { + WR_THROW_ERROR(ERR_WR_VOLUME_SYSTEM_IO, volume->name_p); + LOG_RUN_ERR("[WR] ABORT PREAD VOLUME, because Linux OS error: errno:%d, errmsg:%s.", cm_get_os_error(), + strerror(cm_get_os_error())); + cm_fync_logfile(); + wr_exit(1); + } else { + WR_THROW_ERROR(ERR_WR_VOLUME_READ, volume->name_p, volume->id, cm_get_os_error()); + } + return CM_ERROR; + } + + return CM_SUCCESS; +} + +static int32 wr_try_pwrite_volume_raw( + wr_volume_t *volume, int64 offset, char *buffer, int32 size, int32 *written_size) +{ + bool8 aligned_pwrite = + offset % WR_DISK_UNIT_SIZE == 0 && size % WR_DISK_UNIT_SIZE == 0 && (uint64)buffer % WR_DISK_UNIT_SIZE == 0; + if (aligned_pwrite) { + *written_size = (int32)pwrite(volume->handle, buffer, size, (off_t)offset); + if (*written_size == -1) { + if (wr_is_device_os_error(cm_get_os_error())) { + WR_THROW_ERROR(ERR_WR_VOLUME_SYSTEM_IO, volume->name_p); + LOG_RUN_ERR("[WR] ABORT ALIGNED PWRITE VOLUME, because Linux OS error: errno:%d, errmsg:%s.", cm_get_os_error(), + strerror(cm_get_os_error())); + cm_fync_logfile(); + wr_exit(1); + } else { + WR_THROW_ERROR(ERR_WR_VOLUME_WRITE, volume->name_p, volume->id, cm_get_os_error()); + } + return CM_ERROR; + } + } else { + *written_size = (int32)pwrite(volume->unaligned_handle, buffer, size, (off_t)offset); + if (*written_size == -1) { + if (wr_is_device_os_error(cm_get_os_error())) { + WR_THROW_ERROR(ERR_WR_VOLUME_SYSTEM_IO, volume->name_p); + LOG_RUN_ERR("[WR] ABORT UNALIGNED PWRITE VOLUME, because Linux OS error: errno:%d, errmsg:%s.", cm_get_os_error(), + strerror(cm_get_os_error())); + cm_fync_logfile(); + wr_exit(1); + } else { + WR_THROW_ERROR(ERR_WR_VOLUME_WRITE, volume->name_p, volume->id, cm_get_os_error()); + } + return CM_ERROR; + } + } + + return CM_SUCCESS; +} + +typedef struct wr_file_mgr { + status_t (*open_volume)(const char *name, const char *code, int flags, wr_volume_t *volume); + status_t (*open_simple_volume)(const char *name, int flags, wr_simple_volume_t *volume); + void (*close_volume)(wr_volume_t *volume); + void (*close_simple_volume)(wr_simple_volume_t *simple_volume); + uint64 (*get_volume_size)(wr_volume_t *volume); + status_t (*try_pread_volume)(wr_volume_t *volume, int64 offset, char *buffer, int32 size, int32 *read_size); + int32 (*try_pwrite_volume)(wr_volume_t *volume, int64 offset, char *buffer, int32 size, int32 *written_size); +} file_mgr; + +static const file_mgr file_mgr_funcs[] = { + {wr_open_volume_raw, wr_open_simple_volume_raw, wr_close_volume_raw, wr_close_simple_volume_raw, + wr_get_volume_size_raw, wr_try_pread_volume_raw, wr_try_pwrite_volume_raw} +}; + +wr_vg_device_Type_e parse_vg_open_type(const char *name) +{ + return WR_VOLUME_TYPE_RAW; +} + +status_t wr_open_volume(const char *name, const char *code, int flags, wr_volume_t *volume) +{ + volume->vg_type = parse_vg_open_type(name); + return (*(file_mgr_funcs[volume->vg_type].open_volume))(name, code, flags, volume); +} + +status_t wr_open_simple_volume(const char *name, int flags, wr_simple_volume_t *volume) +{ + volume->vg_type = parse_vg_open_type(name); + return (*(file_mgr_funcs[volume->vg_type].open_simple_volume))(name, flags, volume); +} + +void wr_close_volume(wr_volume_t *volume) +{ + (*(file_mgr_funcs[volume->vg_type].close_volume))(volume); +} + +void wr_close_simple_volume(wr_simple_volume_t *simple_volume) +{ + (*(file_mgr_funcs[simple_volume->vg_type].close_simple_volume))(simple_volume); +} + +uint64 wr_get_volume_size(wr_volume_t *volume) +{ + return (*(file_mgr_funcs[volume->vg_type].get_volume_size))(volume); +} + +static status_t wr_try_pread_volume(wr_volume_t *volume, int64 offset, char *buffer, int32 size, int32 *read_size) +{ + return (*(file_mgr_funcs[volume->vg_type].try_pread_volume))(volume, offset, buffer, size, read_size); +} + +static int32 wr_try_pwrite_volume(wr_volume_t *volume, int64 offset, char *buffer, int32 size, int32 *written_size) +{ + return (*(file_mgr_funcs[volume->vg_type].try_pwrite_volume))(volume, offset, buffer, size, written_size); +} + +status_t wr_read_volume(wr_volume_t *volume, int64 offset, void *buf, int32 size) +{ + status_t ret; + int32 curr_size, total_size; +#ifdef WIN32 + if (wr_seek_volume(volume, offset) != CM_SUCCESS) { + return CM_ERROR; + } +#endif + total_size = 0; + + do { + curr_size = 0; +#ifdef WIN32 + ret = wr_try_read_volume(volume, (char *)buf + total_size, size - total_size, &curr_size); +#else + ret = + wr_try_pread_volume(volume, offset + total_size, (char *)buf + total_size, size - total_size, &curr_size); +#endif + if (ret != CM_SUCCESS) { + LOG_RUN_ERR("Failed to read volume %s, begin:%d, volume id:%u, size:%d, offset:%lld, errmsg:%s.", + volume->name_p, total_size, volume->id, size - total_size, offset, strerror(errno)); + return CM_ERROR; + } + + if ((curr_size == 0) && (total_size < size)) { + LOG_RUN_ERR("Read volume %s size error, begin:%d, volume id:%u, size:%d, offset:%lld.", volume->name_p, + total_size, volume->id, size - total_size, offset); + return CM_ERROR; + } + + total_size += curr_size; + } while (total_size < size); + + return CM_SUCCESS; +} + +status_t wr_write_volume(wr_volume_t *volume, int64 offset, const void *buf, int32 size) +{ + status_t ret; + int32 curr_size, total_size; +#ifdef WIN32 + if (wr_seek_volume(volume, offset) != CM_SUCCESS) { + LOG_RUN_ERR("failed to seek volume %s , volume id:%u", volume->name_p, volume->id); + return CM_ERROR; + } +#endif + total_size = 0; + + do { +#ifdef WIN32 + ret = wr_try_write_volume(volume, (char *)buf + total_size, size - total_size, &curr_size); +#else + ret = + wr_try_pwrite_volume(volume, offset + total_size, (char *)buf + total_size, size - total_size, &curr_size); +#endif + if (ret != CM_SUCCESS) { + LOG_RUN_ERR("Failed to write volume %s, begin:%d, volume id:%u,size:%d, offset:%lld, errmsg:%s.", + volume->name_p, total_size, volume->id, size - total_size, offset, strerror(errno)); + return CM_ERROR; + } + + total_size += curr_size; + } while (total_size < size); + + return CM_SUCCESS; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/common/wr_volume.h b/src/common/wr_volume.h new file mode 100644 index 0000000000000000000000000000000000000000..ee6ae40e9c9cf37bcebea1b80fadf806de121a2d --- /dev/null +++ b/src/common/wr_volume.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_volume.h + * + * + * IDENTIFICATION + * src/common/wr_volume.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_VOLUME_H__ +#define __WR_VOLUME_H__ + +#include "wr_defs.h" +#include "cm_date.h" +#include "wr_file_def.h" + +#ifdef __cplusplus +extern "C" { +#endif +extern uint64 g_log_offset; +status_t wr_open_volume(const char *name, const char *code, int flags, wr_volume_t *volume); +void wr_close_volume(wr_volume_t *volume); +status_t wr_read_volume(wr_volume_t *volume, int64 offset, void *buf, int32 size); +status_t wr_write_volume(wr_volume_t *volume, int64 offset, const void *buf, int32 size); +uint64 wr_get_volume_size(wr_volume_t *volume); + +status_t wr_open_simple_volume(const char *name, int flags, wr_simple_volume_t *volume); +void wr_close_simple_volume(wr_simple_volume_t *simple_volume); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/wr_zero.c b/src/common/wr_zero.c new file mode 100644 index 0000000000000000000000000000000000000000..c363a8cb415e962cd366a81feb692fcf9cf65b5e --- /dev/null +++ b/src/common/wr_zero.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_zero.c + * + * + * IDENTIFICATION + * src/common/wr_zero.c + * + * ------------------------------------------------------------------------- + */ +#include "wr_zero.h" +#ifndef WIN32 +#include +#include +#include +#include +#endif +#include "cm_log.h" + +static int32 wr_zero_mmap_fd = 0; +static char *wr_zero_buf = NULL; +static uint32 wr_zero_buf_len = 0; + +status_t wr_init_zero_buf() +{ + uint32 len = WR_DEFAULT_AU_SIZE; + char *buf = NULL; +#ifndef WIN32 + int32 fd = open("/dev/zero", O_RDWR); + if (fd < 0) { + LOG_RUN_ERR("Failed to open /dev/zero"); + return CM_ERROR; + } + + buf = (char *)mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0); + if (buf == MAP_FAILED) { + LOG_RUN_ERR("Failed to map /dev/zero, error code :%d", errno); + (void)close(fd); + return CM_ERROR; + } + wr_zero_mmap_fd = fd; +#else + buf = (char *)_aligned_malloc(len, WR_DISK_UNIT_SIZE); + if (buf == NULL) { + LOG_RUN_ERR("Failed to alloc"); + return CM_ERROR; + } + (void)memset_s(buf, len, 0x00, len); +#endif + wr_zero_buf = buf; + wr_zero_buf_len = len; + return CM_SUCCESS; +} + +void wr_uninit_zero_buf() +{ +#ifndef WIN32 + if (wr_zero_mmap_fd > 0) { + (void)close(wr_zero_mmap_fd); + wr_zero_mmap_fd = 0; + } +#else + if (wr_zero_buf != NULL) { + free(wr_zero_buf); + } +#endif + wr_zero_buf_len = 0; + wr_zero_buf = NULL; +} + +char *wr_get_zero_buf() +{ + return wr_zero_buf; +} + +uint32 wr_get_zero_buf_len() +{ + return wr_zero_buf_len; +} \ No newline at end of file diff --git a/src/common/wr_zero.h b/src/common/wr_zero.h new file mode 100644 index 0000000000000000000000000000000000000000..d78bfaaa85c4387de885f33e13fd394f62e039b7 --- /dev/null +++ b/src/common/wr_zero.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_zero.h + * + * + * IDENTIFICATION + * src/common/wr_zero.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_ZERO_H +#define __WR_ZERO_H + +#include "wr_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +status_t wr_init_zero_buf(); +void wr_uninit_zero_buf(); +char *wr_get_zero_buf(); +uint32 wr_get_zero_buf_len(); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/common_api/wr_api_impl.c b/src/common_api/wr_api_impl.c new file mode 100644 index 0000000000000000000000000000000000000000..63ec7b495bf02200309699f1c48d605330a5530a --- /dev/null +++ b/src/common_api/wr_api_impl.c @@ -0,0 +1,1885 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_api_impl.c + * + * + * IDENTIFICATION + * src/common_api/wr_api_impl.c + * + * ------------------------------------------------------------------------- + */ + +#include "cm_system.h" +#include "cm_date.h" +#include "wr_defs.h" +#include "wr_diskgroup.h" +#include "wr_file.h" +#include "wr_file_def.h" +#include "wr_latch.h" +#include "wr_malloc.h" +#include "wr_api_impl.h" +#include "wr_defs.h" +#include "wr_fs_aux.h" +#include "wr_thv.h" +#include "wr_stats.h" +#include "wr_cli_conn.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WR_ACCMODE 00000003 +#define WR_OPEN_MODE(flag) ((flag + 1) & WR_ACCMODE) +int32 g_wr_uds_conn_timeout = WR_UDS_CONNECT_TIMEOUT; +uint32 g_wr_server_pid = 0; + +typedef struct str_files_rw_ctx { + wr_conn_t *conn; + wr_file_context_t *file_ctx; + wr_env_t *env; + int32 handle; + int32 size; + bool32 read; + int64 offset; +} files_rw_ctx_t; + +status_t wr_kick_host_sync(wr_conn_t *conn, int64 kick_hostid) +{ + return wr_msg_interact(conn, WR_CMD_KICKH, (void *)&kick_hostid, NULL); +} + +status_t wr_apply_refresh_volume(wr_conn_t *conn, wr_file_context_t *context, auid_t auid); +status_t wr_refresh_volume_handle(wr_conn_t *conn, wr_file_context_t *context, auid_t auid); +status_t wr_reopen_volume_handle(wr_conn_t *conn, wr_file_context_t *context, auid_t auid); + +status_t wr_apply_extending_file(wr_conn_t *conn, int32 handle, int64 size, int64 offset) +{ + wr_env_t *wr_env = wr_get_env(); + wr_file_run_ctx_t *file_run_ctx = &wr_env->file_run_ctx; + if (handle >= (int32)file_run_ctx->max_open_file || handle < 0) { + return CM_ERROR; + } + wr_file_context_t *context = wr_get_file_context_by_handle(file_run_ctx, handle); + if (context->flag == WR_FILE_CONTEXT_FLAG_FREE) { + return CM_ERROR; + } + + LOG_DEBUG_INF("Apply extending file:%s, handle:%d, curr size:%llu, curr written_size:%llu, offset:%lld, size:%lld.", + context->node->name, handle, context->node->size, context->node->written_size, offset, size); + wr_extend_info_t send_info; + send_info.fid = context->fid; + send_info.ftid = *(uint64 *)&(context->node->id); + send_info.offset = offset; + send_info.size = size; + send_info.vg_name = context->vg_name; + send_info.vg_id = context->vgid; + return wr_msg_interact_with_stat(conn, WR_CMD_EXTEND_FILE, (void *)&send_info, NULL); +} + +status_t wr_apply_fallocate_file(wr_conn_t *conn, int32 handle, int32 mode, int64 offset, int64 size) +{ + wr_env_t *wr_env = wr_get_env(); + wr_file_run_ctx_t *file_run_ctx = &wr_env->file_run_ctx; + if (handle >= (int32)file_run_ctx->max_open_file || handle < 0) { + return CM_ERROR; + } + wr_file_context_t *context = wr_get_file_context_by_handle(file_run_ctx, handle); + if (context->flag == WR_FILE_CONTEXT_FLAG_FREE) { + return CM_ERROR; + } + + LOG_DEBUG_INF( + "Apply fallocate file:%s, handle:%d, curr size:%llu, curr written_size:%llu, mode:%d, offset:%lld, size:%lld.", + context->node->name, handle, context->node->size, context->node->written_size, mode, offset, size); + + wr_fallocate_info_t send_info; + send_info.fid = context->fid; + send_info.ftid = *(uint64 *)&(context->node->id); + send_info.offset = offset; + send_info.size = size; + send_info.vg_id = context->vgid; + send_info.mode = mode; + return wr_msg_interact(conn, WR_CMD_FALLOCATE_FILE, (void *)&send_info, NULL); +} + +status_t wr_apply_refresh_file(wr_conn_t *conn, wr_file_context_t *context, int64 offset) +{ + ftid_t ftid = context->node->id; + LOG_DEBUG_INF( + "Apply refresh file:%s, curr size:%llu, refresh ft id:%llu, refresh entry id:%llu, refresh offset:%llu.", + context->node->name, context->node->size, WR_ID_TO_U64(ftid), WR_ID_TO_U64(context->node->entry), offset); + + wr_refresh_file_info_t send_info; + send_info.fid = context->fid; + send_info.ftid = *(uint64 *)(&ftid); + send_info.vg_name = context->vg_name; + send_info.vg_id = context->vgid; + send_info.offset = offset; + return wr_msg_interact_with_stat(conn, WR_CMD_REFRESH_FILE, (void *)&send_info, NULL); +} + +static status_t wr_check_apply_refresh_file(wr_conn_t *conn, wr_file_context_t *context, int64 offset) +{ + bool32 is_valid = CM_FALSE; + do { + WR_UNLOCK_VG_META_S(context->vg_item, conn->session); + status_t status = wr_apply_refresh_file(conn, context, offset); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to apply refresh file:%s, fid:%llu.", context->node->name, context->fid); + return CM_ERROR; + } + WR_LOCK_VG_META_S_RETURN_ERROR(context->vg_item, conn->session); + is_valid = wr_is_fs_meta_valid(context->node); + if (is_valid) { + break; + } + LOG_DEBUG_INF("The node:%s name:%s is invalid, need refresh from server again.", + wr_display_metaid(context->node->id), context->node->name); + cm_sleep(WR_READ_REMOTE_INTERVAL); + } while (!is_valid); + return CM_SUCCESS; +} + +static status_t wr_check_refresh_file_by_offset( + wr_conn_t *conn, wr_file_context_t *context, int64 offset, bool32 is_read) +{ + return CM_SUCCESS; +} + +status_t wr_refresh_volume_handle(wr_conn_t *conn, wr_file_context_t *context, auid_t auid) +{ + return CM_SUCCESS; +} + +status_t wr_reopen_volume_handle(wr_conn_t *conn, wr_file_context_t *context, auid_t auid) +{ + return CM_SUCCESS; +} + +status_t wr_lock_vg_s(wr_vg_info_item_t *vg_item, wr_session_t *session) +{ + wr_latch_offset_t latch_offset; + latch_offset.type = WR_LATCH_OFFSET_SHMOFFSET; + latch_offset.offset.shm_offset = wr_get_vg_latch_shm_offset(vg_item); + return wr_cli_lock_shm_meta_s(session, &latch_offset, vg_item->vg_latch, NULL); +} + +static inline void wr_init_conn(wr_conn_t *conn) +{ + conn->flag = CM_FALSE; + conn->cli_vg_handles = NULL; + conn->session = NULL; +} + +status_t wr_alloc_conn(wr_conn_t **conn) +{ + wr_conn_t *_conn = (wr_conn_t *)cm_malloc_align(WRAPI_BLOCK_SIZE, sizeof(wr_conn_t)); + if (_conn != NULL) { + wr_init_conn(_conn); + *conn = _conn; + return CM_SUCCESS; + } + + return CM_ERROR; +} + +void wr_free_conn(wr_conn_t *conn) +{ + WR_FREE_POINT(conn); + return; +} + +/* +status_t wr_connect(const char *server_locator, wr_conn_opt_t *options, wr_conn_t *conn) +{ + if (server_locator == NULL) { + WR_THROW_ERROR(ERR_WR_UDS_INVALID_URL, "NULL", 0); + return CM_ERROR; + } + + if ((conn->flag == CM_TRUE) && (conn->pipe.link.uds.closed == CM_FALSE)) { + return CM_SUCCESS; + } + + conn->flag = CM_FALSE; + text_t uds = {"UDS:", 4}; + if (wr_check_url_format(server_locator, &uds) != CM_SUCCESS) { + WR_THROW_ERROR(ERR_WR_UDS_INVALID_URL, server_locator, strlen(server_locator)); + return ERR_WR_UDS_INVALID_URL; + } + conn->cli_vg_handles = NULL; + conn->pipe.options = 0; + int32 timeout = options != NULL ? options->timeout : g_wr_uds_conn_timeout; + conn->pipe.connect_timeout = timeout < 0 ? WR_UDS_CONNECT_TIMEOUT : timeout; + conn->pipe.socket_timeout = WR_UDS_SOCKET_TIMEOUT; + conn->pipe.link.uds.sock = CS_INVALID_SOCKET; + conn->pipe.link.uds.closed = CM_TRUE; + conn->pipe.type = CS_TYPE_DOMAIN_SCOKET; + conn->session = NULL; + status_t ret = cs_connect_ex( + server_locator, &conn->pipe, NULL, (const char *)(server_locator + uds.len), (const char *)CM_NULL_TEXT.str); + if (ret != CM_SUCCESS) { + LOG_DEBUG_ERR("connect server failed, uds path:%s", server_locator); + return ret; + } + wr_init_packet(&conn->pack, conn->pipe.options); + + conn->flag = CM_TRUE; + + return CM_SUCCESS; +} +*/ +status_t wr_connect(const char *server_locator, wr_conn_opt_t *options, wr_conn_t *conn) +{ + if (server_locator == NULL) { + WR_THROW_ERROR(ERR_WR_UDS_INVALID_URL, "NULL", 0); + return CM_ERROR; + } + + if ((conn->flag == CM_TRUE) && (conn->pipe.link.uds.closed == CM_FALSE)) { + return CM_SUCCESS; + } + + conn->flag = CM_FALSE; + + conn->cli_vg_handles = NULL; + conn->pipe.options = 0; + int32 timeout = options != NULL ? options->timeout : g_wr_uds_conn_timeout; + conn->pipe.connect_timeout = timeout < 0 ? WR_UDS_CONNECT_TIMEOUT : timeout; + conn->pipe.socket_timeout = WR_UDS_SOCKET_TIMEOUT; + conn->pipe.link.tcp.sock = CS_INVALID_SOCKET; + conn->pipe.link.tcp.closed = CM_FALSE; + conn->pipe.type = CS_TYPE_TCP; + conn->session = NULL; + status_t ret = cs_connect( + server_locator, &conn->pipe, NULL); + if (ret != CM_SUCCESS) { + LOG_DEBUG_ERR("connect server failed, uds path:%s", server_locator); + return ret; + } + wr_init_packet(&conn->pack, conn->pipe.options); + + conn->flag = CM_TRUE; + + return CM_SUCCESS; +} + +void wr_disconnect(wr_conn_t *conn) +{ + wr_set_thv_run_ctx_item(WR_THV_RUN_CTX_ITEM_SESSION, NULL); + if (conn->flag == CM_TRUE) { + cs_disconnect(&conn->pipe); + wr_free_packet_buffer(&conn->pack); + conn->flag = CM_FALSE; + } + + return; +} + +status_t wr_set_session_id(wr_conn_t *conn, uint32 objectid) +{ + if (objectid >= wr_get_max_total_session_cnt()) { + LOG_RUN_ERR_INHIBIT(LOG_INHIBIT_LEVEL1, "objectid error, objectid is %u, max session cnt is %u.", objectid, + wr_get_max_total_session_cnt()); + return ERR_WR_SESSION_INVALID_ID; + } + conn->session = (wr_session_t *)ga_object_addr(GA_SESSION_POOL, objectid); + if (conn->session == NULL) { + LOG_RUN_ERR_INHIBIT(LOG_INHIBIT_LEVEL1, "Failed to get session, object id is %u.", objectid); + return ERR_WR_SESSION_INVALID_ID; + } + LOG_DEBUG_INF("wr set session id is %u, objectid is %u.", ((wr_session_t *)conn->session)->id, objectid); + wr_set_thv_run_ctx_item(WR_THV_RUN_CTX_ITEM_SESSION, conn->session); + return CM_SUCCESS; +} + +static status_t wr_set_server_info(wr_conn_t *conn, char *home, uint32 objectid, uint32 max_open_file) +{ + status_t status = wr_init_client(max_open_file, home); + WR_RETURN_IFERR3(status, LOG_RUN_ERR_INHIBIT(LOG_INHIBIT_LEVEL1, "wr client init failed."), wr_disconnect(conn)); + + status = wr_set_session_id(conn, objectid); + WR_RETURN_IFERR3(status, LOG_RUN_ERR_INHIBIT(LOG_INHIBIT_LEVEL1, "wr client failed to initialize session."), + wr_disconnect(conn)); + return CM_SUCCESS; +} + +status_t wr_cli_handshake(wr_conn_t *conn, uint32 max_open_file) +{ + conn->cli_info.cli_pid = cm_sys_pid(); + conn->cli_info.thread_id = cm_get_current_thread_id(); + + status_t status = cm_sys_process_start_time(conn->cli_info.cli_pid, &conn->cli_info.start_time); + if (status != CM_SUCCESS) { + LOG_RUN_ERR_INHIBIT(LOG_INHIBIT_LEVEL1, "Failed to get process start time pid %llu.\n", conn->cli_info.cli_pid); + return CM_ERROR; + } + LOG_DEBUG_INF("The process start time is:%lld.", conn->cli_info.start_time); + errno_t err; + err = strcpy_s(conn->cli_info.process_name, sizeof(conn->cli_info.process_name), cm_sys_program_name()); + if (err != EOK) { + LOG_DEBUG_ERR("System call strcpy_s error %d.", err); + return CM_ERROR; + } + conn->cli_info.connect_time = cm_clock_monotonic_now(); + wr_get_server_info_t output_info = {NULL, WR_INVALID_SESSIONID, 0}; + CM_RETURN_IFERR(wr_msg_interact(conn, WR_CMD_HANDSHAKE, (void *)&conn->cli_info, (void *)&output_info)); + if (conn->pack.head->version >= WR_VERSION_2) { + if (g_wr_server_pid == 0) { + g_wr_server_pid = output_info.server_pid; + } else if (g_wr_server_pid != output_info.server_pid) { + WR_THROW_ERROR(ERR_WR_SERVER_REBOOT); + return ERR_WR_SERVER_REBOOT; + } + } + return wr_set_server_info(conn, output_info.home, output_info.objectid, max_open_file); +} + +// NOTE:just for wrcmd because not support many threads in one process. +status_t wr_connect_ex(const char *server_locator, wr_conn_opt_t *options, wr_conn_t *conn) +{ + status_t status = CM_ERROR; + wr_env_t *wr_env = wr_get_env(); + wr_init_conn(conn); + do { + status = wr_connect("127.0.0.1:19225", options, conn); + WR_BREAK_IFERR2(status, LOG_RUN_ERR_INHIBIT(LOG_INHIBIT_LEVEL1, "wr client connet server failed.")); + uint32 max_open_file = WR_DEFAULT_OPEN_FILES_NUM; + conn->proto_version = WR_PROTO_VERSION; + status = wr_cli_handshake(conn, max_open_file); + WR_BREAK_IFERR3(status, LOG_RUN_ERR_INHIBIT(LOG_INHIBIT_LEVEL1, "wr client handshake to server failed."), + wr_disconnect(conn)); + wr_env->conn_count++; + } while (0); + return status; +} + +status_t wr_cli_session_lock(wr_conn_t *conn, wr_session_t *session) +{ + if (!cm_spin_timed_lock(&session->shm_lock, SESSION_LOCK_TIMEOUT)) { + LOG_RUN_ERR("Failed to lock session %u shm lock", session->id); + return CM_ERROR; + } + LOG_DEBUG_INF("Succeed to lock session %u shm lock", session->id); + if (session->cli_info.thread_id != conn->cli_info.thread_id || + session->cli_info.connect_time != conn->cli_info.connect_time) { + WR_THROW_ERROR_EX(ERR_WR_CONNECT_FAILED, + "session %u thread id is %u, connect_time is %llu, conn thread id is %u, connect_time is %llu", session->id, + session->cli_info.thread_id, session->cli_info.connect_time, conn->cli_info.thread_id, + conn->cli_info.connect_time); + LOG_RUN_ERR("Failed to check session %u, session thread id is %u, connect_time is %llu, conn thread id is %u, " + "connect_time is %llu", + session->id, session->cli_info.thread_id, session->cli_info.connect_time, conn->cli_info.thread_id, + conn->cli_info.connect_time); + cm_spin_unlock(&session->shm_lock); + LOG_DEBUG_INF("Succeed to unlock session %u shm lock", session->id); + return CM_ERROR; + } + return CM_SUCCESS; +} +void wr_disconnect_ex(wr_conn_t *conn) +{ + wr_env_t *wr_env = wr_get_env(); + + wr_disconnect(conn); + wr_latch_x(&wr_env->conn_latch); + if (wr_env->conn_count > 0) { + wr_env->conn_count--; + } + + if (wr_env->conn_count == 0) { + wr_destroy(); + } + uint32 count = wr_env->conn_count; + wr_unlatch(&wr_env->conn_latch); + LOG_DEBUG_INF("Remain conn count:%u when disconnect.", count); + + return; +} + +status_t wr_vfs_create_impl(wr_conn_t *conn, const char *dir_name) +{ + text_t text; + cm_str2text((char *)dir_name, &text); + if (text.len >= WR_MAX_NAME_LEN) { + WR_THROW_ERROR_EX( + ERR_WR_DIR_CREATE, "Length of dir name(%s) is too long, maximum is %u.", T2S(&text), WR_MAX_NAME_LEN); + return CM_ERROR; + } + WR_RETURN_IF_ERROR(wr_check_name(dir_name)); + LOG_DEBUG_INF("wr make dir entry, dir_name:%s", dir_name); + wr_make_dir_info_t send_info; + send_info.name = dir_name; + status_t status = wr_msg_interact(conn, WR_CMD_MKDIR, (void *)&send_info, NULL); + LOG_DEBUG_INF("wr make dir leave"); + return status; +} + +status_t wr_vfs_delete_impl(wr_conn_t *conn, const char *dir) +{ + WR_RETURN_IF_ERROR(wr_check_device_path(dir)); + LOG_DEBUG_INF("wr remove dir entry, dir:%s", dir); + wr_remove_dir_info_t send_info; + send_info.name = dir; + send_info.recursive = CM_TRUE; + status_t status = wr_msg_interact(conn, WR_CMD_RMDIR, (void *)&send_info, NULL); + LOG_DEBUG_INF("wr remove dir leave"); + return status; +} + +static wr_vfs_t *wr_open_dir_impl_core(wr_conn_t *conn, wr_find_node_t *find_node) +{ + wr_vg_info_item_t *vg_item = wr_find_vg_item(find_node->vg_name); + if (vg_item == NULL) { + LOG_RUN_ERR("Failed to find vg, %s.", find_node->vg_name); + WR_THROW_ERROR(ERR_WR_VG_NOT_EXIST, find_node->vg_name); + return NULL; + } + + WR_LOCK_VG_META_S_RETURN_NULL(vg_item, conn->session); + gft_node_t *node = wr_get_ft_node_by_ftid(conn->session, vg_item, find_node->ftid, CM_FALSE, CM_FALSE); + if (node == NULL) { + WR_THROW_ERROR(ERR_WR_INVALID_ID, "find_node ftid", *(uint64 *)&find_node->ftid); + WR_UNLOCK_VG_META_S(vg_item, conn->session); + return NULL; + } + wr_vfs_t *dir = (wr_vfs_t *)cm_malloc(sizeof(wr_vfs_t)); + if (dir == NULL) { + WR_UNLOCK_VG_META_S(vg_item, conn->session); + LOG_DEBUG_ERR("Failed to malloc."); + return NULL; + } + dir->cur_ftid = node->items.first; + dir->vg_item = vg_item; + dir->version = WR_GET_ROOT_BLOCK(vg_item->wr_ctrl)->ft_block.common.version; + dir->pftid = node->id; + WR_UNLOCK_VG_META_S(vg_item, conn->session); + + LOG_DEBUG_INF("wr open dir leave"); + return dir; +} + +wr_vfs_t *wr_open_dir_impl(wr_conn_t *conn, const char *dir_path, bool32 refresh_recursive) +{ + if (dir_path == NULL) { + return NULL; + } + LOG_DEBUG_INF("wr open dir entry, dir_path:%s", dir_path); + + wr_env_t *wr_env = wr_get_env(); + if (!wr_env->initialized) { + return NULL; + } + + // 1. PATH + if (wr_check_device_path(dir_path) != CM_SUCCESS) { + return NULL; + } + wr_find_node_t *find_node; + wr_open_dir_info_t send_info; + send_info.dir_path = dir_path; + send_info.refresh_recursive = refresh_recursive; + status_t status = wr_msg_interact(conn, WR_CMD_OPEN_DIR, (void *)&send_info, (void *)&find_node); + if (status != CM_SUCCESS) { + return NULL; + } + return wr_open_dir_impl_core(conn, find_node); +} + +gft_node_t *wr_read_dir_impl(wr_conn_t *conn, wr_vfs_t *dir, bool32 skip_delete) +{ + return NULL; +} + +status_t wr_close_dir_impl(wr_conn_t *conn, wr_vfs_t *dir) +{ + if (!dir || !dir->vg_item) { + return CM_ERROR; + } + + // close operation just free resource, no need check server if down. + wr_env_t *wr_env = wr_get_env(); + CM_RETURN_IF_FALSE(wr_env->initialized); + + wr_close_dir_info_t send_info; + send_info.pftid = *(uint64 *)&dir->pftid; + send_info.vg_name = dir->vg_item->vg_name; + send_info.vg_id = dir->vg_item->id; + status_t status = wr_msg_interact(conn, WR_CMD_CLOSE_DIR, (void *)&send_info, NULL); + WR_FREE_POINT(dir); + return status; +} + +status_t wr_create_file_impl(wr_conn_t *conn, const char *file_path, int flag) +{ + LOG_DEBUG_INF("wr create file entry, file path:%s, flag:%d", file_path, flag); + WR_RETURN_IF_ERROR(wr_check_device_path(file_path)); + wr_create_file_info_t send_info; + send_info.file_path = file_path; + send_info.flag = (uint32)flag; + status_t status = wr_msg_interact(conn, WR_CMD_CREATE_FILE, (void *)&send_info, NULL); + LOG_DEBUG_INF("wr create file leave"); + return status; +} + +status_t wr_remove_file_impl(wr_conn_t *conn, const char *file_path) +{ + LOG_DEBUG_INF("wr remove file entry, file path:%s", file_path); + WR_RETURN_IF_ERROR(wr_check_device_path(file_path)); + status_t status = wr_msg_interact(conn, WR_CMD_DELETE_FILE, (void *)file_path, NULL); + LOG_DEBUG_INF("wr remove file leave"); + return status; +} + +status_t wr_find_vg_by_file_path(const char *path, wr_vg_info_item_t **vg_item) +{ + wr_env_t *wr_env = wr_get_env(); + if (!wr_env->initialized) { + WR_THROW_ERROR(ERR_WR_ENV_NOT_INITIALIZED); + return CM_ERROR; + } + + uint32_t beg_pos = 0; + char vg_name[WR_MAX_NAME_LEN]; + status_t status = wr_get_name_from_path(path, &beg_pos, vg_name); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to get name from path:%s, status:%d.", path, status)); + + *vg_item = wr_find_vg_item(vg_name); + if (*vg_item == NULL) { + LOG_DEBUG_ERR("Failed to find VG:%s.", vg_name); + WR_THROW_ERROR(ERR_WR_VG_NOT_EXIST, vg_name); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t wr_get_ftid_by_path_on_server(wr_conn_t *conn, const char *path, ftid_t *ftid, char *vg_name) +{ + LOG_DEBUG_INF("begin to get ftid by path: %s", path); + text_t extra_info = CM_NULL_TEXT; + WR_RETURN_IF_ERROR(wr_msg_interact(conn, WR_CMD_GET_FTID_BY_PATH, (void *)path, (void *)&extra_info)); + + if (extra_info.len != sizeof(wr_find_node_t)) { + WR_THROW_ERROR(ERR_WR_CLI_EXEC_FAIL, wr_get_cmd_desc(WR_CMD_GET_FTID_BY_PATH), "get result length error"); + LOG_DEBUG_ERR("get result length error."); + return CM_ERROR; + } + wr_find_node_t find_node = *(wr_find_node_t *)extra_info.str; + *ftid = find_node.ftid; + errno_t err = strncpy_sp(vg_name, WR_MAX_NAME_LEN, find_node.vg_name, WR_MAX_NAME_LEN); + if (err != EOK) { + WR_THROW_ERROR(ERR_SYSTEM_CALL, err); + return CM_ERROR; + } + + LOG_DEBUG_INF("wr get node ftid: %s, vg: %s by path: %s", wr_display_metaid(*ftid), vg_name, path); + return CM_SUCCESS; +} + +gft_node_t *wr_get_node_by_path_impl(wr_conn_t *conn, const char *path) +{ + ftid_t ftid; + if (wr_check_device_path(path) != CM_SUCCESS) { + return NULL; + } + char vg_name[WR_MAX_NAME_LEN]; + if (wr_get_ftid_by_path_on_server(conn, path, &ftid, (char *)vg_name) != CM_SUCCESS) { + return NULL; + } + wr_vg_info_item_t *vg_item = wr_find_vg_item(vg_name); + if (vg_item == NULL) { + LOG_DEBUG_ERR("Failed to find vg,vg name %s.", vg_name); + WR_THROW_ERROR(ERR_WR_VG_NOT_EXIST, vg_name); + return NULL; + } + + WR_LOCK_VG_META_S_RETURN_NULL(vg_item, conn->session); + gft_node_t *node = wr_get_ft_node_by_ftid(conn->session, vg_item, ftid, CM_FALSE, CM_FALSE); + WR_UNLOCK_VG_META_S(vg_item, conn->session); + return node; +} + +status_t wr_init_file_context( + wr_file_context_t *context, gft_node_t *out_node, wr_vg_info_item_t *vg_item, wr_file_mode_e mode) +{ + context->flag = WR_FILE_CONTEXT_FLAG_USED; + context->offset = 0; + context->next = WR_INVALID_ID32; + context->node = out_node; + context->vg_item = vg_item; + context->vgid = vg_item->id; + context->fid = out_node->fid; + context->vol_offset = 0; + context->tid = cm_get_current_thread_id(); + if (strcpy_s(context->vg_name, WR_MAX_NAME_LEN, vg_item->vg_name) != EOK) { + return CM_ERROR; + } + context->mode = mode; + return CM_SUCCESS; +} + +/* +1 after extend success, will generate new linked list +context[file_run_ctx->files->group_num - 1] [0]->context[file_run_ctx->files->group_num - 1] +[1]->...->context[file_run_ctx->files->group_num - 1] [WR_FILE_CONTEXT_PER_GROUP - 1] +2 insert new linked list head into the old linked list +*/ +status_t wr_extend_files_context(wr_file_run_ctx_t *file_run_ctx) +{ + if (file_run_ctx->files.group_num == WR_MAX_FILE_CONTEXT_GROUP_NUM) { + WR_THROW_ERROR(ERR_INVALID_VALUE, "file group num", file_run_ctx->files.group_num); + LOG_RUN_ERR_INHIBIT( + LOG_INHIBIT_LEVEL1, "file context group exceeds upper limit %d", WR_MAX_FILE_CONTEXT_GROUP_NUM); + return CM_ERROR; + } + uint32 context_size = WR_FILE_CONTEXT_PER_GROUP * (uint32)sizeof(wr_file_context_t); + uint32 i = file_run_ctx->files.group_num; + file_run_ctx->files.files_group[i] = (wr_file_context_t *)cm_malloc(context_size); + if (file_run_ctx->files.files_group[i] == NULL) { + WR_THROW_ERROR(ERR_ALLOC_MEMORY, context_size, "wr extend files context"); + return CM_ERROR; + } + errno_t rc = memset_s(file_run_ctx->files.files_group[i], context_size, 0, context_size); + if (rc != EOK) { + WR_FREE_POINT(file_run_ctx->files.files_group[i]); + CM_THROW_ERROR(ERR_SYSTEM_CALL, rc); + return CM_ERROR; + } + file_run_ctx->files.group_num++; + wr_file_context_t *context = NULL; + for (uint32 j = 0; j < WR_FILE_CONTEXT_PER_GROUP; j++) { + context = &file_run_ctx->files.files_group[i][j]; + context->id = i * WR_FILE_CONTEXT_PER_GROUP + j; + if (j == WR_FILE_CONTEXT_PER_GROUP - 1) { + context->next = CM_INVALID_ID32; + } else { + context->next = context->id + 1; + } + } + file_run_ctx->file_free_first = (&file_run_ctx->files.files_group[file_run_ctx->files.group_num - 1][0])->id; + LOG_RUN_INF("Succeed to extend alloc open files, group num is %u, file free first is %u.", + file_run_ctx->files.group_num, file_run_ctx->file_free_first); + return CM_SUCCESS; +} + +status_t wr_open_file_inner(wr_vg_info_item_t *vg_item, gft_node_t *ft_node, wr_file_mode_e mode, int *handle) +{ + wr_env_t *wr_env = wr_get_env(); + wr_latch_x(&wr_env->latch); + wr_file_run_ctx_t *file_run_ctx = &wr_env->file_run_ctx; + if (file_run_ctx->has_opened_files >= file_run_ctx->max_open_file) { + wr_unlatch(&wr_env->latch); + LOG_RUN_ERR("The opened files %u has exceeded the max open file number %u.", file_run_ctx->has_opened_files, + file_run_ctx->max_open_file); + return CM_ERROR; + } + + if (file_run_ctx->file_free_first == WR_INVALID_ID32) { + status_t status = wr_extend_files_context(file_run_ctx); + if (status != CM_SUCCESS) { + wr_unlatch(&wr_env->latch); + LOG_RUN_ERR("Failed to extend files context."); + return CM_ERROR; + } + } + *handle = (int)file_run_ctx->file_free_first; + wr_file_context_t *context = wr_get_file_context_by_handle(file_run_ctx, *handle); + uint32 next = context->next; + status_t ret = wr_init_file_context(context, ft_node, vg_item, mode); + WR_RETURN_IFERR2(ret, wr_unlatch(&wr_env->latch)); + file_run_ctx->file_free_first = next; + file_run_ctx->has_opened_files++; + wr_unlatch(&wr_env->latch); + return CM_SUCCESS; +} + +status_t wr_open_file_on_server(wr_conn_t *conn, const char *file_path, int flag, wr_find_node_t **find_node) +{ + wr_open_file_info_t send_info; + send_info.file_path = file_path; + send_info.flag = flag; + return wr_msg_interact(conn, WR_CMD_OPEN_FILE, (void *)&send_info, (void *)find_node); +} + +status_t wr_open_file_impl(wr_conn_t *conn, const char *file_path, int flag, int *handle) +{ + status_t status = CM_ERROR; + gft_node_t *ft_node = NULL; + wr_find_node_t *find_node = NULL; + LOG_DEBUG_INF("wr begin to open file, file path:%s, flag:%d", file_path, flag); + WR_RETURN_IF_ERROR(wr_check_device_path(file_path)); + WR_RETURN_IF_ERROR(wr_open_file_on_server(conn, file_path, flag, &find_node)); + wr_vg_info_item_t *vg_item = wr_find_vg_item(find_node->vg_name); + if (vg_item == NULL) { + LOG_RUN_ERR("Failed to find vg, vg name %s.", find_node->vg_name); + WR_THROW_ERROR(ERR_WR_VG_NOT_EXIST, find_node->vg_name); + return CM_ERROR; + } + WR_LOCK_VG_META_S_RETURN_ERROR(vg_item, conn->session); + do { + ft_node = wr_get_ft_node_by_ftid(conn->session, vg_item, find_node->ftid, CM_FALSE, CM_FALSE); + if (ft_node == NULL) { + WR_THROW_ERROR(ERR_WR_INVALID_ID, "find_node ftid", *(uint64 *)&find_node->ftid); + status = CM_ERROR; + break; + } + status = wr_open_file_inner(vg_item, ft_node, WR_OPEN_MODE(flag), handle); + } while (0); + WR_UNLOCK_VG_META_S(vg_item, conn->session); + + if (status != CM_SUCCESS) { + // Try to close the handle opened on the server to avoid resource leakage. + // But here in theory it shouldn't depend on ft_node not being NULL + if (ft_node != NULL) { + (void)wr_close_file_on_server(conn, vg_item, ft_node->fid, ft_node->id); + } + return status; + } + LOG_DEBUG_INF("wr open file successfully, file_path:%s, flag:%d, handle:%d, fsize:%llu, fwritten_size:%llu", + file_path, flag, *handle, ft_node->size, ft_node->written_size); + return CM_SUCCESS; +} + +status_t wr_latch_context_by_handle( + wr_conn_t *conn, int32 handle, wr_file_context_t **context, wr_latch_mode_e latch_mode) +{ + wr_env_t *wr_env = wr_get_env(); + if (!wr_env->initialized) { + WR_THROW_ERROR(ERR_WR_ENV_NOT_INITIALIZED); + LOG_DEBUG_ERR("wr env not initialized."); + return CM_ERROR; + } + wr_file_run_ctx_t *file_run_ctx = &wr_env->file_run_ctx; + if (handle >= (int32)file_run_ctx->max_open_file || handle < 0) { + WR_THROW_ERROR( + ERR_WR_INVALID_PARAM, "value of handle must be a positive integer and less than max_open_file."); + LOG_DEBUG_ERR("File handle is invalid:%d.", handle); + return CM_ERROR; + } + + wr_file_context_t *file_cxt = wr_get_file_context_by_handle(file_run_ctx, handle); + wr_latch(&file_cxt->latch, latch_mode, ((wr_session_t *)conn->session)->id); + if (file_cxt->flag == WR_FILE_CONTEXT_FLAG_FREE) { + wr_unlatch(&file_cxt->latch); + LOG_DEBUG_ERR("Failed to r/w, file is closed, handle:%d, context id:%u.", handle, file_cxt->id); + return CM_ERROR; + } + + WR_ASSERT_LOG(handle == (int32)file_cxt->id, "handle %d not equal to file id %u", handle, file_cxt->id); + + if (file_cxt->node == NULL) { + wr_unlatch(&file_cxt->latch); + LOG_DEBUG_ERR("file node is null, handle:%d, context id:%u.", handle, file_cxt->id); + return CM_ERROR; + } + + *context = file_cxt; + return CM_SUCCESS; +} + +status_t wr_close_file_impl(wr_conn_t *conn, int handle) +{ + char *fname = NULL; + + LOG_DEBUG_INF("wr close file entry, handle:%d", handle); + + wr_file_context_t *context = NULL; + WR_RETURN_IF_ERROR(wr_latch_context_by_handle(conn, handle, &context, LATCH_MODE_EXCLUSIVE)); + fname = context->node->name; + + status_t ret = wr_close_file_on_server(conn, context->vg_item, context->fid, context->node->id); + if (ret != CM_SUCCESS) { + wr_unlatch(&context->latch); + LOG_DEBUG_INF("Failed to fclose, handle:%d, fname:%s, fid:%llu.", handle, fname, context->fid); + return ret; + } + context->flag = WR_FILE_CONTEXT_FLAG_FREE; + context->offset = 0; + context->node = NULL; + context->tid = 0; + wr_unlatch(&context->latch); + LOG_DEBUG_INF("Success to fclose, handle:%d, fname:%s, fid:%llu.", handle, fname, context->fid); + + /* release file context to freelist */ + wr_env_t *wr_env = wr_get_env(); + wr_latch_x(&wr_env->latch); + wr_file_run_ctx_t *file_run_ctx = &wr_env->file_run_ctx; + context->next = file_run_ctx->file_free_first; + file_run_ctx->file_free_first = context->id; + file_run_ctx->has_opened_files--; + wr_unlatch(&wr_env->latch); + return CM_SUCCESS; +} + +status_t wr_exist_impl(wr_conn_t *conn, const char *path, bool32 *result, gft_item_type_t *type) +{ + LOG_DEBUG_INF("wr exits file entry, name:%s", path); + WR_RETURN_IF_ERROR(wr_check_device_path(path)); + wr_exist_recv_info_t recv_info; + WR_RETURN_IF_ERROR(wr_msg_interact(conn, WR_CMD_EXIST, (void *)path, (void *)&recv_info)); + *result = (bool32)recv_info.result; + *type = (gft_item_type_t)recv_info.type; + LOG_DEBUG_INF("wr exits file or dir leave, name:%s, result:%d, type:%u", path, *result, *type); + return CM_SUCCESS; +} + +static status_t wr_validate_seek_origin(int origin, int64 offset, wr_file_context_t *context, int64 *new_offset) +{ + if (origin == SEEK_SET) { + if (offset > (int64)WR_MAX_FILE_SIZE) { + LOG_DEBUG_ERR("Invalid parameter offset:%lld, context offset:%lld.", offset, context->offset); + return CM_ERROR; + } + *new_offset = offset; + } else if (origin == SEEK_CUR) { + if (offset > (int64)WR_MAX_FILE_SIZE || context->offset > (int64)WR_MAX_FILE_SIZE || + offset + context->offset > (int64)WR_MAX_FILE_SIZE) { + LOG_DEBUG_ERR("Invalid parameter offset:%lld, context offset:%lld.", offset, context->offset); + return CM_ERROR; + } + *new_offset = context->offset + offset; + } else if (origin == SEEK_END || origin == WR_SEEK_MAXWR) { // for get alloced size, or actual used size + if (offset > 0) { + LOG_DEBUG_ERR("Invalid parameter offset:%lld, context offset:%lld.", offset, context->offset); + return CM_ERROR; + } + } else { + LOG_DEBUG_ERR("Invalid parameter origin:%d, when seek file.", origin); + return CM_ERROR; + } + return CM_SUCCESS; +} + +int64 wr_seek_file_impl_core(wr_rw_param_t *param, int64 offset, int origin) +{ + status_t status; + int64 new_offset = 0; + int64 size; + bool32 need_refresh = ((origin == SEEK_END) || (origin == WR_SEEK_MAXWR)); + + wr_conn_t *conn = param->conn; + int handle = param->handle; + wr_file_context_t *context = param->context; + + CM_ASSERT(handle == (int32)context->id); + + if (wr_validate_seek_origin(origin, offset, context, &new_offset) != CM_SUCCESS) { + WR_UNLOCK_VG_META_S(context->vg_item, conn->session); + return CM_ERROR; + } + + size = cm_atomic_get(&context->node->size); + if (!wr_is_fs_meta_valid(context->node) || new_offset > size || need_refresh) { + status = wr_check_apply_refresh_file(conn, context, 0); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to apply refresh file,fid:%llu.", context->fid)); + size = cm_atomic_get(&context->node->size); + + if (offset > size && param->is_read) { + LOG_DEBUG_ERR("Invalid parameter offset is greater than size, offset:%lld, new_offset:%lld," + " file size:%llu, vgid:%u, fid:%llu, node fid:%llu, need_refresh:%d.", + offset, new_offset, context->node->size, context->vg_item->id, context->fid, context->node->fid, + need_refresh); + WR_THROW_ERROR(ERR_WR_FILE_SEEK, context->vg_item->id, context->fid, offset, context->node->size); + WR_UNLOCK_VG_META_S(context->vg_item, conn->session); + return CM_ERROR; + } + LOG_DEBUG_INF("Apply to refresh file, offset:%lld, size:%lld, need_refresh:%d.", offset, size, need_refresh); + if (origin == SEEK_END) { + new_offset = (int64)context->node->written_size + offset; + } else if (origin == WR_SEEK_MAXWR) { + new_offset = (int64)context->node->written_size; + } + } + if (new_offset < 0) { + WR_THROW_ERROR(ERR_WR_FILE_SEEK, context->vg_item->id, context->fid, offset, context->node->size); + WR_UNLOCK_VG_META_S(context->vg_item, conn->session); + return CM_ERROR; + } + if (new_offset == 0) { + context->vol_offset = 0; + } + context->offset = new_offset; + LOG_DEBUG_INF("Success to seek(origin:%d) file:%s, offset:%lld, fsize:%llu, written_size:%llu.", origin, + context->node->name, new_offset, context->node->size, context->node->written_size); + return new_offset; +} + +void wr_init_rw_param( + wr_rw_param_t *param, wr_conn_t *conn, int handle, wr_file_context_t *ctx, int64 offset, bool32 atomic) +{ + param->conn = conn; + param->handle = handle; + param->wr_env = wr_get_env(); + param->context = ctx; + param->offset = offset; + param->atom_oper = atomic; + param->is_read = WR_FALSE; +} + +static int64 wr_seek_file_prepare( + wr_conn_t *conn, wr_file_context_t *context, wr_rw_param_t *param, int64 offset, int origin) +{ + WR_LOCK_VG_META_S_RETURN_ERROR(context->vg_item, conn->session); + int64 ret = wr_seek_file_impl_core(param, offset, origin); + if (ret == CM_ERROR) { + return CM_ERROR; + } + WR_UNLOCK_VG_META_S(context->vg_item, conn->session); + return ret; +} + +int64 wr_seek_file_impl(wr_conn_t *conn, int handle, int64 offset, int origin) +{ + LOG_DEBUG_INF("wr seek file entry, handle:%d, offset:%lld, origin:%d", handle, offset, origin); + + wr_file_context_t *context = NULL; + WR_RETURN_IF_ERROR(wr_latch_context_by_handle(conn, handle, &context, LATCH_MODE_EXCLUSIVE)); + + wr_rw_param_t param; + wr_init_rw_param(¶m, conn, handle, context, context->offset, WR_FALSE); + int64 new_offset = wr_seek_file_prepare(conn, context, ¶m, offset, origin); + wr_unlatch(&context->latch); + + LOG_DEBUG_INF("wr seek file leave, new_offset:%lld", new_offset); + return new_offset; +} + +static status_t wr_check_ready_fs_block(files_rw_ctx_t *rw_ctx, wr_fs_pos_desc_t *fs_pos) +{ + return CM_SUCCESS; +} + +status_t wr_read_write_file_core(wr_rw_param_t *param, void *buf, int32 size, int32 *read_size) +{ + status_t status = CM_SUCCESS; + return status; +} + +status_t wr_read_write_file(wr_conn_t *conn, int32 handle, void *buf, int32 size, int32 *read_size, bool32 is_read) +{ + status_t status; + wr_file_context_t *context = NULL; + wr_rw_param_t param; + + if (size < 0) { + LOG_DEBUG_ERR("File size is invalid: %d.", size); + return CM_ERROR; + } + LOG_DEBUG_INF("wr read write file entry, handle:%d, is_read:%u", handle, is_read); + + WR_RETURN_IF_ERROR(wr_latch_context_by_handle(conn, handle, &context, LATCH_MODE_EXCLUSIVE)); + bool mode_match = is_read ? (context->mode & WR_FILE_MODE_READ) : (context->mode & WR_FILE_MODE_WRITE); + if (!mode_match) { + wr_unlatch(&context->latch); + WR_THROW_ERROR(ERR_WR_FILE_RDWR_INSUFF_PER, is_read ? "read" : "write", context->mode); + return CM_ERROR; + } + wr_init_rw_param(¶m, conn, handle, context, context->offset, WR_FALSE); + param.is_read = is_read; + status = wr_read_write_file_core(¶m, buf, size, read_size); + wr_unlatch(&context->latch); + LOG_DEBUG_INF("wr read write file leave"); + + return status; +} + +status_t wr_write_file_impl(wr_conn_t *conn, int handle, const void *buf, int size) +{ + return wr_read_write_file(conn, handle, (void *)buf, size, NULL, WR_FALSE); +} + +status_t wr_read_file_impl(wr_conn_t *conn, int handle, void *buf, int size, int *read_size) +{ + if (read_size == NULL) { + return CM_ERROR; + } + + return wr_read_write_file(conn, handle, buf, size, read_size, WR_TRUE); +} + +static status_t wr_pwrite_file_prepare(wr_conn_t *conn, wr_file_context_t *context, long long offset) +{ + return CM_SUCCESS; +} + +status_t wr_pwrite_file_impl(wr_conn_t *conn, int handle, const void *buf, int size, long long offset) +{ + status_t status; + wr_file_context_t *context = NULL; + wr_rw_param_t param; + + CM_RETURN_IFERR(wr_latch_context_by_handle(conn, handle, &context, LATCH_MODE_SHARE)); + LOG_DEBUG_INF("wr pwrite file %s, handle:%d, offset:%lld, size:%d", context->node->name, handle, offset, size); + if (!(context->mode & WR_FILE_MODE_WRITE)) { + wr_unlatch(&context->latch); + WR_THROW_ERROR(ERR_WR_FILE_RDWR_INSUFF_PER, "pwrite", context->mode); + return CM_ERROR; + } + + wr_init_rw_param(¶m, conn, handle, context, offset, WR_TRUE); + param.is_read = WR_FALSE; + wr_set_conn_wait_event(conn, WR_PWRITE_SYN_META); + if (wr_pwrite_file_prepare(conn, context, offset) != CM_SUCCESS) { + wr_unset_conn_wait_event(conn); + wr_unlatch(&context->latch); + return CM_ERROR; + } + status = wr_read_write_file_core(¶m, (void *)buf, size, NULL); + wr_unset_conn_wait_event(conn); + wr_unlatch(&context->latch); + LOG_DEBUG_INF("wr pwrite file leave, result: %d", status); + + return status; +} + +static status_t wr_pread_file_prepare( + wr_conn_t *conn, wr_file_context_t *context, int size, long long offset, bool32 *read_end) +{ + *read_end = CM_FALSE; + WR_LOCK_VG_META_S_RETURN_ERROR(context->vg_item, conn->session); + status_t status = wr_check_refresh_file_by_offset(conn, context, offset, CM_TRUE); + if (status != CM_SUCCESS) { + return status; + } + if ((uint64)offset == context->node->size || size == 0) { + *read_end = CM_TRUE; + } + WR_UNLOCK_VG_META_S(context->vg_item, conn->session); + return CM_SUCCESS; +} + +status_t wr_pread_file_impl(wr_conn_t *conn, int handle, void *buf, int size, long long offset, int *read_size) +{ + status_t status; + wr_file_context_t *context = NULL; + wr_rw_param_t param; + + CM_RETURN_IFERR(wr_latch_context_by_handle(conn, handle, &context, LATCH_MODE_SHARE)); + LOG_DEBUG_INF( + "wr pread file entry, name:%s, handle:%d, offset:%lld, size:%d", context->node->name, handle, offset, size); + if (!(context->mode & WR_FILE_MODE_READ)) { + wr_unlatch(&context->latch); + WR_THROW_ERROR(ERR_WR_FILE_RDWR_INSUFF_PER, "pread", context->mode); + return CM_ERROR; + } + + wr_init_rw_param(¶m, conn, handle, context, offset, WR_TRUE); + param.is_read = WR_TRUE; + wr_set_conn_wait_event(conn, WR_PREAD_SYN_META); + do { + bool32 read_end = CM_FALSE; + status = wr_pread_file_prepare(conn, context, size, offset, &read_end); + WR_BREAK_IF_ERROR(status); + if (read_end) { + *read_size = 0; + break; + } + status = wr_read_write_file_core(¶m, buf, size, read_size); + } while (0); + wr_unset_conn_wait_event(conn); + wr_unlatch(&context->latch); + LOG_DEBUG_INF("wr pread file leave, result: %d", status); + return status; +} + +status_t wr_fallocate_impl(wr_conn_t *conn, int handle, int mode, long long int offset, long long int length) +{ + status_t status; + wr_file_context_t *context = NULL; + + if (mode < 0) { + LOG_DEBUG_ERR("File mode is invalid:%d.", mode); + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "mode must be a positive integer"); + return CM_ERROR; + } + + if (offset > (int64)WR_MAX_FILE_SIZE) { + LOG_DEBUG_ERR("Offset is invalid:%lld.", offset); + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "offset must less than WR_MAX_FILE_SIZE"); + return CM_ERROR; + } + + if (length < 0) { + LOG_DEBUG_ERR("File length is invalid:%lld.", length); + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "length must be a positive integer"); + return CM_ERROR; + } + + if (length > (int64)WR_MAX_FILE_SIZE) { + LOG_DEBUG_ERR("File length is invalid:%lld.", length); + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "length must less than WR_MAX_FILE_SIZE"); + return CM_ERROR; + } + + CM_RETURN_IFERR(wr_latch_context_by_handle(conn, handle, &context, LATCH_MODE_SHARE)); + LOG_DEBUG_INF("wr fallocate file, name:%s, handle:%d, mode:%d, offset:%lld, length:%lld", context->node->name, + handle, mode, offset, length); + if (!(context->mode & WR_FILE_MODE_WRITE)) { + wr_unlatch(&context->latch); + WR_THROW_ERROR(ERR_WR_FILE_RDWR_INSUFF_PER, "fallocate", context->mode); + return CM_ERROR; + } + + status = wr_apply_fallocate_file(conn, handle, mode, offset, length); + wr_unlatch(&context->latch); + + LOG_DEBUG_INF("wr fallocate file leave, result: %d", status); + return status; +} + +status_t wr_rename_file_impl(wr_conn_t *conn, const char *src, const char *dst) +{ + WR_RETURN_IFERR2(wr_check_device_path(src), LOG_DEBUG_ERR("old name path is invalid.")); + WR_RETURN_IFERR2(wr_check_device_path(dst), LOG_DEBUG_ERR("new name path is invalid.")); + LOG_DEBUG_INF("Rename file, old name path: %s, new name path: %s", src, dst); + wr_rename_file_info_t send_info; + send_info.src = src; + send_info.dst = dst; + WR_RETURN_IF_ERROR(wr_msg_interact(conn, WR_CMD_RENAME_FILE, (void *)&send_info, NULL)); + return CM_SUCCESS; +} + +status_t wr_truncate_impl(wr_conn_t *conn, int handle, long long int length) +{ + if (length < 0) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "length must be a positive integer"); + LOG_DEBUG_ERR("File length is invalid:%lld.", length); + return CM_ERROR; + } + + if (length > (int64)WR_MAX_FILE_SIZE) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "length must less than WR_MAX_FILE_SIZE"); + LOG_DEBUG_ERR("File length is invalid:%lld.", length); + return CM_ERROR; + } + + wr_file_context_t *context = NULL; + WR_RETURN_IF_ERROR(wr_latch_context_by_handle(conn, handle, &context, LATCH_MODE_EXCLUSIVE)); + + LOG_DEBUG_INF("Truncating file via handle(%d), file name: %s, node size: %lld, length: %lld.", handle, + context->node->name, context->node->size, length); + + wr_truncate_file_info_t send_info; + send_info.fid = context->fid; + send_info.ftid = *(uint64 *)&(context->node->id); + send_info.length = (uint64)length; + send_info.vg_name = context->vg_name; + send_info.vg_id = context->vgid; + status_t status = wr_msg_interact(conn, WR_CMD_TRUNCATE_FILE, (void *)&send_info, NULL); + wr_unlatch(&context->latch); + return status; +} + +void wr_heartbeat_entry(thread_t *thread) +{ + return; +} + +static status_t wr_init_err_proc( + wr_env_t *wr_env, bool32 detach, bool32 destroy, const char *errmsg, status_t errcode) +{ + if (detach == CM_TRUE) { + ga_detach_area(); + } + + if (destroy == CM_TRUE) { + cm_destroy_shm(); + } + WR_FREE_POINT(wr_env->file_run_ctx.files.files_group[0]); + wr_unlatch(&wr_env->latch); + + if (errmsg != NULL) { + LOG_DEBUG_ERR("init error: %s", errmsg); + } + + return errcode; +} + +static status_t wr_init_shm(wr_env_t *wr_env, char *home) +{ + status_t status = wr_set_cfg_dir(home, &wr_env->inst_cfg); + if (status != CM_SUCCESS) { + return wr_init_err_proc(wr_env, CM_FALSE, CM_FALSE, "Environment variant WR_HOME not found", status); + } + + status = wr_load_config(&wr_env->inst_cfg); + if (status != CM_SUCCESS) { + return wr_init_err_proc(wr_env, CM_FALSE, CM_FALSE, "load config failed", status); + } + + uint32 shm_key = (uint32)(wr_env->inst_cfg.params.shm_key << (uint8)WR_MAX_SHM_KEY_BITS) + + (uint32)wr_env->inst_cfg.params.inst_id; + status = cm_init_shm(shm_key); + if (status != CM_SUCCESS) { + return wr_init_err_proc(wr_env, CM_FALSE, CM_FALSE, "Failed to init shared memory", status); + } + + status = ga_attach_area(CM_SHM_ATTACH_RW); + if (status != CM_SUCCESS) { + return wr_init_err_proc(wr_env, CM_FALSE, CM_TRUE, "Failed to attach shared area", status); + } + return CM_SUCCESS; +} + +static status_t wr_init_files(wr_env_t *wr_env, uint32 max_open_files) +{ + wr_file_run_ctx_t *file_run_ctx = &wr_env->file_run_ctx; + file_run_ctx->max_open_file = max_open_files; + errno_t rc = memset_s(&file_run_ctx->files, sizeof(wr_file_context_group_t), 0, sizeof(wr_file_context_group_t)); + if (rc != EOK) { + CM_THROW_ERROR(ERR_SYSTEM_CALL, rc); + return wr_init_err_proc(wr_env, CM_TRUE, CM_TRUE, "memory init failed", CM_ERROR); + } + status_t status = wr_extend_files_context(file_run_ctx); + if (status != CM_SUCCESS) { + return wr_init_err_proc(wr_env, CM_TRUE, CM_TRUE, "extend file context failed", status); + } + return status; +} + +status_t wr_init_client(uint32 max_open_files, char *home) +{ + WR_STATIC_ASSERT(WR_BLOCK_SIZE / sizeof(gft_node_t) <= (1 << WR_MAX_BIT_NUM_ITEM)); + WR_STATIC_ASSERT(sizeof(wr_root_ft_block_t) == 256); + + if (max_open_files > WR_MAX_OPEN_FILES) { + WR_THROW_ERROR(ERR_INVALID_VALUE, "max_open_files", max_open_files); + return CM_ERROR; + } + + wr_env_t *wr_env = wr_get_env(); + if (wr_env->initialized) { + return CM_SUCCESS; + } + + wr_latch_x(&wr_env->latch); + if (wr_env->initialized) { +#ifdef ENABLE_WRTEST + if (wr_env->inittor_pid == getpid()) { +#endif + return wr_init_err_proc(wr_env, CM_FALSE, CM_FALSE, NULL, CM_SUCCESS); +#ifdef ENABLE_WRTEST + } else { + LOG_RUN_INF("wr client need re-initalization wr env, last init pid:%llu.", (uint64)wr_env->inittor_pid); + (void)wr_init_err_proc(wr_env, CM_TRUE, CM_TRUE, "need reinit by a new process", CM_SUCCESS); + + wr_env->initialized = CM_FALSE; + wr_env->inittor_pid = 0; + } +#endif + } + CM_RETURN_IFERR(wr_init_shm(wr_env, home)); + CM_RETURN_IFERR(wr_init_files(wr_env, max_open_files)); + + status_t status = cm_create_thread(wr_heartbeat_entry, SIZE_K(512), NULL, &wr_env->thread_heartbeat); + if (status != CM_SUCCESS) { + return wr_init_err_proc(wr_env, CM_TRUE, CM_TRUE, "WR failed to create heartbeat thread", status); + } + +#ifdef ENABLE_WRTEST + wr_env->inittor_pid = getpid(); +#endif + + wr_env->initialized = CM_TRUE; + wr_unlatch(&wr_env->latch); + + return CM_SUCCESS; +} + +void wr_destroy(void) +{ + wr_env_t *wr_env = wr_get_env(); + wr_latch_x(&wr_env->latch); + if (!wr_env->initialized) { + wr_unlatch(&wr_env->latch); + return; + } + + cm_close_thread_nowait(&wr_env->thread_heartbeat); + wr_file_run_ctx_t *file_run_ctx = &wr_env->file_run_ctx; + for (uint32 i = 0; i < file_run_ctx->files.group_num; i++) { + WR_FREE_POINT(file_run_ctx->files.files_group[i]); + } + ga_detach_area(); + wr_env->initialized = 0; + wr_unlatch(&wr_env->latch); +} + +status_t wr_get_fname_impl(int handle, char *fname, int fname_size) +{ + wr_env_t *wr_env = wr_get_env(); + if (!wr_env->initialized) { + WR_THROW_ERROR(ERR_WR_ENV_NOT_INITIALIZED); + return CM_ERROR; + } + wr_file_run_ctx_t *file_run_ctx = &wr_env->file_run_ctx; + if (handle < 0 || (uint32)handle >= file_run_ctx->max_open_file) { + WR_THROW_ERROR( + ERR_WR_INVALID_PARAM, "value of handle must be a positive integer and less than max_open_file."); + return CM_ERROR; + } + if (fname_size < 0) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "value of fname_size is a positive number."); + return CM_ERROR; + } + wr_file_context_t *context = wr_get_file_context_by_handle(file_run_ctx, handle); + WR_RETURN_IF_NULL(context->node); + int len = (fname_size > WR_MAX_NAME_LEN) ? WR_MAX_NAME_LEN : fname_size; + errno_t errcode = strcpy_s(fname, (size_t)len, context->node->name); + if (SECUREC_UNLIKELY(errcode != EOK)) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "value of fname_size is not large enough."); + return CM_ERROR; + } + return CM_SUCCESS; +} + +status_t wr_setcfg_impl(wr_conn_t *conn, const char *name, const char *value, const char *scope) +{ + WR_RETURN_IF_ERROR(wr_check_name(name)); + wr_setcfg_info_t send_info; + send_info.name = name; + send_info.value = value; + send_info.scope = scope; + status_t status = wr_msg_interact(conn, WR_CMD_SETCFG, (void *)&send_info, NULL); + LOG_DEBUG_INF("wr set cfg leave"); + return status; +} + +status_t wr_getcfg_impl(wr_conn_t *conn, const char *name, char *out_str, size_t str_len) +{ + WR_RETURN_IF_ERROR(wr_check_name(name)); + text_t extra_info = CM_NULL_TEXT; + WR_RETURN_IF_ERROR(wr_msg_interact(conn, WR_CMD_GETCFG, (void *)name, (void *)&extra_info)); + if (extra_info.len == 0) { + LOG_DEBUG_INF("Client get cfg is NULL."); + return CM_SUCCESS; + } + + errno_t err = strncpy_s(out_str, str_len, extra_info.str, extra_info.len); + if (SECUREC_UNLIKELY(err != EOK)) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "value of str_len is not large enough when getcfg."); + return CM_ERROR; + } + if (strlen(out_str) != 0 && cm_str_equal_ins(name, "SSL_PWD_CIPHERTEXT")) { + LOG_DEBUG_INF("Client get cfg is ***."); + } else { + LOG_DEBUG_INF("Client get cfg is %s.", (strlen(out_str) == 0) ? NULL : out_str); + } + return CM_SUCCESS; +} + +void wr_get_api_volume_error(void) +{ + int32 code = cm_get_error_code(); + // volume open/seek/read write fail for I/O, just exit + if (code == ERR_WR_VOLUME_SYSTEM_IO) { + LOG_RUN_ERR("[WR API] ABORT INFO : volume operate failed for I/O ERROR, errcode:%d.", code); + cm_fync_logfile(); + wr_exit(1); + } + return; +} + +status_t wr_get_inst_status_on_server(wr_conn_t *conn, wr_server_status_t *wr_status) +{ + if (wr_status == NULL) { + WR_THROW_ERROR_EX(ERR_WR_INVALID_PARAM, "wr_dir_item_t"); + return CM_ERROR; + } + text_t extra_info = CM_NULL_TEXT; + WR_RETURN_IF_ERROR(wr_msg_interact(conn, WR_CMD_GET_INST_STATUS, NULL, (void *)&extra_info)); + *wr_status = *(wr_server_status_t *)extra_info.str; + return CM_SUCCESS; +} + +status_t wr_get_time_stat_on_server(wr_conn_t *conn, wr_stat_item_t *time_stat, uint64 size) +{ + text_t stat_info = CM_NULL_TEXT; + WR_RETURN_IF_ERROR(wr_msg_interact(conn, WR_CMD_GET_TIME_STAT, NULL, (void *)&stat_info)); + for (uint64 i = 0; i < WR_EVT_COUNT; i++) { + time_stat[i] = *(wr_stat_item_t *)(stat_info.str + i * (uint64)sizeof(wr_stat_item_t)); + } + return CM_SUCCESS; +} + +status_t wr_set_main_inst_on_server(wr_conn_t *conn) +{ + return wr_msg_interact(conn, WR_CMD_SET_MAIN_INST, NULL, NULL); +} + +status_t wr_close_file_on_server(wr_conn_t *conn, wr_vg_info_item_t *vg_item, uint64 fid, ftid_t ftid) +{ + wr_close_file_info_t send_info; + send_info.fid = fid; + send_info.vg_name = vg_item->vg_name; + send_info.vg_id = vg_item->id; + send_info.ftid = *(uint64 *)&ftid; + return wr_msg_interact(conn, WR_CMD_CLOSE_FILE, (void *)&send_info, NULL); +} + +status_t wr_stop_server_impl(wr_conn_t *conn) +{ + return wr_msg_interact(conn, WR_CMD_STOP_SERVER, NULL, NULL); +} + +status_t wr_set_stat_info(wr_stat_info_t item, gft_node_t *node) +{ + item->type = (wr_item_type_t)node->type; + item->size = node->size; + item->written_size = node->written_size; + item->create_time = node->create_time; + item->update_time = node->update_time; + int32 errcode = memcpy_s(item->name, WR_MAX_NAME_LEN, node->name, WR_MAX_NAME_LEN); + if (SECUREC_UNLIKELY(errcode != EOK)) { + WR_THROW_ERROR(ERR_SYSTEM_CALL, errcode); + return WR_ERROR; + } + return WR_SUCCESS; +} + +status_t wr_fstat_impl(wr_conn_t *conn, int handle, wr_stat_info_t item) +{ + wr_file_context_t *context = NULL; + WR_RETURN_IF_ERROR(wr_latch_context_by_handle(conn, handle, &context, LATCH_MODE_SHARE)); + status_t ret = wr_set_stat_info(item, context->node); + wr_unlatch(&context->latch); + return ret; +} + +status_t wr_aio_check_need_updt_fs_aux(wr_rw_param_t *param, int32 size, bool32 *need_update) +{ + wr_conn_t *conn = param->conn; + wr_file_context_t *context = param->context; + long long offset = param->offset; + + *need_update = CM_FALSE; + if (context->node->min_inited_size >= (uint64)(offset + size)) { + return CM_SUCCESS; + } + + uint64 au_size = wr_get_vg_au_size(context->vg_item->wr_ctrl); + + wr_fs_pos_desc_t fs_pos = {0}; + files_rw_ctx_t rw_ctx; + rw_ctx.conn = conn; + rw_ctx.env = param->wr_env; + rw_ctx.file_ctx = context; + rw_ctx.handle = param->handle; + rw_ctx.read = CM_TRUE; // should NOT apply extend for aio post + + int64 top_size = (context->node->size > (param->offset + size)) ? (offset + size) : context->node->size; + int64 left_size = size; + int64 cur_size = 0; + + do { + int64 align_size = (int64)CM_CALC_ALIGN((uint64)(offset + 1), au_size); + if (offset + left_size > align_size) { + cur_size = align_size - offset; + } else { + cur_size = left_size; + } + + rw_ctx.offset = offset; + rw_ctx.size = (int32)cur_size; + + status_t status = wr_check_ready_fs_block(&rw_ctx, &fs_pos); + WR_RETURN_IF_ERROR(status); + if (!fs_pos.is_valid) { + LOG_RUN_ERR("Fail to find fs block for file:%s, fid:%llu, fti:%llu, cur offset:%llu, size:%lld," + "written_size:%llu, file size:%llu.", + context->node->name, context->node->fid, WR_ID_TO_U64(context->node->id), offset, cur_size, + context->node->written_size, (uint64)context->node->size); + return CM_ERROR; + } + + offset += cur_size; + left_size -= cur_size; + } while (offset < top_size); + + return CM_SUCCESS; +} + +status_t wr_aio_post_pwrite_file_impl(wr_conn_t *conn, int handle, long long offset, int size) +{ + return CM_SUCCESS; +} + +static status_t wr_get_phy_size_prepare(wr_conn_t *conn, wr_file_context_t *context, long long *size) +{ + *size = 0; + WR_LOCK_VG_META_S_RETURN_ERROR(context->vg_item, conn->session); + status_t status = wr_check_apply_refresh_file(conn, context, 0); + if (status != CM_SUCCESS) { + return status; + } + *size = cm_atomic_get(&context->node->size); + WR_UNLOCK_VG_META_S(context->vg_item, conn->session); + return CM_SUCCESS; +} + +status_t wr_get_phy_size_impl(wr_conn_t *conn, int handle, long long *size) +{ + wr_file_context_t *context = NULL; + WR_RETURN_IF_ERROR(wr_latch_context_by_handle(conn, handle, &context, LATCH_MODE_SHARE)); + + status_t status = wr_get_phy_size_prepare(conn, context, size); + if (status != WR_SUCCESS) { + LOG_DEBUG_ERR("Failed to apply refresh file,fid:%llu.", context->fid); + wr_unlatch(&context->latch); + return WR_ERROR; + } + *size = context->node->size; + wr_unlatch(&context->latch); + return status; +} + +static status_t wr_encode_setcfg(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + wr_setcfg_info_t *info = (wr_setcfg_info_t *)send_info; + CM_RETURN_IFERR(wr_put_str(pack, info->name)); + CM_RETURN_IFERR(wr_put_str(pack, info->value)); + CM_RETURN_IFERR(wr_put_str(pack, info->scope)); + return CM_SUCCESS; +} + +static status_t wr_encode_handshake(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + CM_RETURN_IFERR(wr_put_data(pack, send_info, sizeof(wr_cli_info_t))); + return CM_SUCCESS; +} + +static status_t wr_decode_handshake(wr_packet_t *ack_pack, void *ack) +{ + text_t ack_info = CM_NULL_TEXT; + CM_RETURN_IFERR(wr_get_text(ack_pack, &ack_info)); + if (ack_info.len == 0 || ack_info.len >= WR_MAX_PATH_BUFFER_SIZE) { + WR_THROW_ERROR(ERR_WR_CLI_EXEC_FAIL, wr_get_cmd_desc(WR_CMD_HANDSHAKE), "get home info length error"); + return CM_ERROR; + } + wr_get_server_info_t *output_info = (wr_get_server_info_t *)ack; + output_info->home = ack_info.str; + CM_RETURN_IFERR(wr_get_int32(ack_pack, (int32 *)&output_info->objectid)); + if (ack_pack->head->version >= WR_VERSION_2) { + CM_RETURN_IFERR(wr_get_int32(ack_pack, (int32 *)&output_info->server_pid)); + } + return CM_SUCCESS; +} + +static status_t wr_encode_exist(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + return wr_put_str(pack, (const char *)send_info); +} + +static status_t wr_decode_exist(wr_packet_t *ack_pack, void *ack) +{ + wr_exist_recv_info_t *info = (wr_exist_recv_info_t *)ack; + if (wr_get_int32(ack_pack, &(info->result)) != CM_SUCCESS) { + WR_THROW_ERROR(ERR_WR_CLI_EXEC_FAIL, wr_get_cmd_desc(WR_CMD_EXIST), "get result data error"); + LOG_DEBUG_ERR("get result data error."); + return CM_ERROR; + } + if (wr_get_int32(ack_pack, &(info->type)) != CM_SUCCESS) { + WR_THROW_ERROR(ERR_WR_CLI_EXEC_FAIL, wr_get_cmd_desc(WR_CMD_EXIST), "get type data error"); + LOG_DEBUG_ERR("get type data error."); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t wr_encode_getcfg(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + return wr_put_str(pack, (const char *)send_info); +} + +static status_t wr_decode_getcfg(wr_packet_t *ack_pack, void *ack) +{ + text_t *info = (text_t *)ack; + if (wr_get_text(ack_pack, info) != CM_SUCCESS) { + WR_THROW_ERROR(ERR_WR_CLI_EXEC_FAIL, wr_get_cmd_desc(WR_CMD_GETCFG), "get cfg connect error"); + return CM_ERROR; + } + if (info->len >= WR_MAX_PACKET_SIZE - sizeof(wr_packet_head_t) - sizeof(int32)) { + WR_THROW_ERROR(ERR_WR_CLI_EXEC_FAIL, wr_get_cmd_desc(WR_CMD_GETCFG), "get cfg length error"); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t wr_decode_get_inst_status(wr_packet_t *ack_pack, void *ack) +{ + text_t *info = (text_t *)ack; + if (wr_get_text(ack_pack, info) != CM_SUCCESS) { + WR_THROW_ERROR(ERR_WR_CLI_EXEC_FAIL, wr_get_cmd_desc(WR_CMD_GET_INST_STATUS), "get inst status error"); + return CM_ERROR; + } + if (info->len != sizeof(wr_server_status_t)) { + WR_THROW_ERROR( + ERR_WR_CLI_EXEC_FAIL, wr_get_cmd_desc(WR_CMD_GET_INST_STATUS), "get inst status length error"); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t wr_decode_get_time_stat(wr_packet_t *ack_pack, void *ack) +{ + text_t *time_stat = (text_t *)ack; + if (wr_get_text(ack_pack, time_stat) != CM_SUCCESS) { + WR_THROW_ERROR(ERR_WR_CLI_EXEC_FAIL, wr_get_cmd_desc(WR_CMD_GET_TIME_STAT), "get time stat error"); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t wr_encode_truncate_file(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + wr_truncate_file_info_t *info = (wr_truncate_file_info_t *)send_info; + CM_RETURN_IFERR(wr_put_int64(pack, info->fid)); + CM_RETURN_IFERR(wr_put_int64(pack, info->ftid)); + CM_RETURN_IFERR(wr_put_int64(pack, info->length)); + CM_RETURN_IFERR(wr_put_str(pack, info->vg_name)); + CM_RETURN_IFERR(wr_put_int32(pack, info->vg_id)); + return CM_SUCCESS; +} + +static status_t wr_encode_extend_file(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + wr_extend_info_t *info = (wr_extend_info_t *)send_info; + // 1. fid + CM_RETURN_IFERR(wr_put_int64(pack, info->fid)); + // 2. ftid + CM_RETURN_IFERR(wr_put_int64(pack, info->ftid)); + // 3. offset + CM_RETURN_IFERR(wr_put_int64(pack, (uint64)info->offset)); + // 4. size + CM_RETURN_IFERR(wr_put_int64(pack, (uint64)info->size)); + // 5. vg name + CM_RETURN_IFERR(wr_put_str(pack, info->vg_name)); + // 6. vgid + CM_RETURN_IFERR(wr_put_int32(pack, info->vg_id)); + return CM_SUCCESS; +} + +static status_t wr_encode_rename_file(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + wr_rename_file_info_t *info = (wr_rename_file_info_t *)send_info; + CM_RETURN_IFERR(wr_put_str(pack, info->src)); + CM_RETURN_IFERR(wr_put_str(pack, info->dst)); + return CM_SUCCESS; +} + +static status_t wr_encode_make_dir(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + wr_make_dir_info_t *info = (wr_make_dir_info_t *)send_info; + // 1. dir_name + CM_RETURN_IFERR(wr_put_str(pack, info->name)); + return CM_SUCCESS; +} + +static status_t wr_encode_remove_dir(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + wr_remove_dir_info_t *info = (wr_remove_dir_info_t *)send_info; + // 1. dir_name + CM_RETURN_IFERR(wr_put_str(pack, info->name)); + // 2. recursive -r + CM_RETURN_IFERR(wr_put_int32(pack, info->recursive)); + return CM_SUCCESS; +} + +static status_t wr_encode_open_dir(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + wr_open_dir_info_t *info = (wr_open_dir_info_t *)send_info; + /* 1. dir name */ + CM_RETURN_IFERR(wr_put_str(pack, info->dir_path)); + /* 2. flag */ + CM_RETURN_IFERR(wr_put_int32(pack, info->refresh_recursive)); + return CM_SUCCESS; +} + +static status_t wr_decode_open_dir(wr_packet_t *ack_pack, void *ack) +{ + CM_RETURN_IFERR(wr_get_data(ack_pack, sizeof(wr_find_node_t), (void **)ack)); + return CM_SUCCESS; +} + +static status_t wr_encode_open_file(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + wr_open_file_info_t *info = (wr_open_file_info_t *)send_info; + /* 1. file name */ + CM_RETURN_IFERR(wr_put_str(pack, info->file_path)); + /* 2. flag */ + CM_RETURN_IFERR(wr_put_int32(pack, (uint32)info->flag)); + return CM_SUCCESS; +} + +static status_t wr_encode_close_dir(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + wr_close_dir_info_t *info = (wr_close_dir_info_t *)send_info; + CM_RETURN_IFERR(wr_put_int64(pack, info->pftid)); + CM_RETURN_IFERR(wr_put_str(pack, info->vg_name)); + CM_RETURN_IFERR(wr_put_int32(pack, info->vg_id)); + return CM_SUCCESS; +} + +static status_t wr_encode_close_file(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + wr_close_file_info_t *info = (wr_close_file_info_t *)send_info; + CM_RETURN_IFERR(wr_put_int64(pack, info->fid)); + CM_RETURN_IFERR(wr_put_str(pack, info->vg_name)); + CM_RETURN_IFERR(wr_put_int32(pack, info->vg_id)); + CM_RETURN_IFERR(wr_put_int64(pack, info->ftid)); + return CM_SUCCESS; +} + +static status_t wr_encode_create_file(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + wr_create_file_info_t *info = (wr_create_file_info_t *)send_info; + CM_RETURN_IFERR(wr_put_str(pack, info->file_path)); + CM_RETURN_IFERR(wr_put_int32(pack, info->flag)); + return CM_SUCCESS; +} + +static status_t wr_encode_delete_file(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + return wr_put_str(pack, (const char *)send_info); +} + +static status_t wr_decode_open_file(wr_packet_t *ack_pack, void *ack) +{ + CM_RETURN_IFERR(wr_get_data(ack_pack, sizeof(wr_find_node_t), (void **)ack)); + return CM_SUCCESS; +} + +static status_t wr_encode_kickh(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + CM_RETURN_IFERR(wr_put_int64(pack, *(uint64 *)send_info)); + return CM_SUCCESS; +} + +static status_t wr_encode_fallocate_file(wr_conn_t *conn, wr_packet_t *pack, void *send_info) +{ + wr_fallocate_info_t *info = (wr_fallocate_info_t *)send_info; + CM_RETURN_IFERR(wr_put_int64(pack, info->fid)); + CM_RETURN_IFERR(wr_put_int64(pack, info->ftid)); + CM_RETURN_IFERR(wr_put_int64(pack, (uint64)info->offset)); + CM_RETURN_IFERR(wr_put_int64(pack, (uint64)info->size)); + CM_RETURN_IFERR(wr_put_int32(pack, info->vg_id)); + CM_RETURN_IFERR(wr_put_int32(pack, (uint32)info->mode)); + return CM_SUCCESS; +} + +typedef status_t (*wr_encode_packet_proc_t)(wr_conn_t *conn, wr_packet_t *pack, void *send_info); +typedef status_t (*wr_decode_packet_proc_t)(wr_packet_t *ack_pack, void *ack); +typedef struct st_wr_packet_proc { + wr_encode_packet_proc_t encode_proc; + wr_decode_packet_proc_t decode_proc; + char *cmd_info; +} wr_packet_proc_t; + +wr_packet_proc_t g_wr_packet_proc[WR_CMD_END] = {[WR_CMD_MKDIR] = {wr_encode_make_dir, NULL, "make dir"}, + [WR_CMD_RMDIR] = {wr_encode_remove_dir, NULL, "remove dir"}, + [WR_CMD_OPEN_DIR] = {wr_encode_open_dir, wr_decode_open_dir, "open dir"}, + [WR_CMD_CLOSE_DIR] = {wr_encode_close_dir, NULL, "close dir"}, + [WR_CMD_OPEN_FILE] = {wr_encode_open_file, wr_decode_open_file, "open file"}, + [WR_CMD_CLOSE_FILE] = {wr_encode_close_file, NULL, "close file"}, + [WR_CMD_CREATE_FILE] = {wr_encode_create_file, NULL, "create file"}, + [WR_CMD_DELETE_FILE] = {wr_encode_delete_file, NULL, "delete file"}, + [WR_CMD_EXTEND_FILE] = {wr_encode_extend_file, NULL, "extend file"}, + [WR_CMD_RENAME_FILE] = {wr_encode_rename_file, NULL, "rename file"}, + [WR_CMD_TRUNCATE_FILE] = {wr_encode_truncate_file, NULL, "truncate file"}, + [WR_CMD_KICKH] = {wr_encode_kickh, NULL, "kickh"}, + [WR_CMD_STOP_SERVER] = {NULL, NULL, "stop server"}, + [WR_CMD_SETCFG] = {wr_encode_setcfg, NULL, "setcfg"}, + [WR_CMD_SET_MAIN_INST] = {NULL, NULL, "set main inst"}, + [WR_CMD_HANDSHAKE] = {wr_encode_handshake, wr_decode_handshake, "handshake with server"}, + [WR_CMD_FALLOCATE_FILE] = {wr_encode_fallocate_file, NULL, "fallocate file"}, + [WR_CMD_EXIST] = {wr_encode_exist, wr_decode_exist, "exist"}, + [WR_CMD_GETCFG] = {wr_encode_getcfg, wr_decode_getcfg, "getcfg"}, + [WR_CMD_GET_INST_STATUS] = {NULL, wr_decode_get_inst_status, "get inst status"}, + [WR_CMD_GET_TIME_STAT] = {NULL, wr_decode_get_time_stat, "get time stat"}, +}; + +status_t wr_decode_packet(wr_packet_proc_t *make_proc, wr_packet_t *ack_pack, void *ack) +{ + if (ack == NULL || make_proc->decode_proc == NULL) { + return CM_SUCCESS; + } + wr_init_get(ack_pack); + status_t ret = make_proc->decode_proc(ack_pack, ack); + WR_RETURN_IFERR2(ret, LOG_DEBUG_ERR("Decode %s msg failed", make_proc->cmd_info)); + return ret; +} + +status_t wr_msg_interact(wr_conn_t *conn, uint8 cmd, void *send_info, void *ack) +{ + wr_packet_t *send_pack = &conn->pack; + wr_packet_t *ack_pack = &conn->pack; + wr_packet_proc_t *make_proc; + do { + wr_init_packet(&conn->pack, conn->pipe.options); + wr_init_set(&conn->pack, conn->proto_version); + send_pack->head->cmd = cmd; + send_pack->head->flags = 0; + make_proc = &g_wr_packet_proc[cmd]; + if (make_proc->encode_proc != NULL) { + WR_RETURN_IF_ERROR(make_proc->encode_proc(conn, send_pack, send_info)); + } + ack_pack = &conn->pack; + WR_RETURN_IF_ERROR(wr_call_ex(&conn->pipe, send_pack, ack_pack)); + + // check return state + if (ack_pack->head->result != CM_SUCCESS) { + int32 errcode = wr_get_pack_err(conn, ack_pack); + if (errcode == ERR_WR_VERSION_NOT_MATCH) { + continue; + } + return errcode; + } + break; + } while (1); + conn->server_version = wr_get_version(ack_pack); + conn->proto_version = MIN(WR_PROTO_VERSION, conn->server_version); + return wr_decode_packet(make_proc, ack_pack, ack); +} + +void wr_set_conn_wait_event(wr_conn_t *conn, wr_wait_event_e event) +{ + if (conn->session != NULL) { + wr_set_stat(&((wr_session_t *)conn->session)->stat_ctx, event); + } +} + +void wr_unset_conn_wait_event(wr_conn_t *conn) +{ + if (conn->session != NULL) { + wr_unset_stat(&((wr_session_t *)conn->session)->stat_ctx); + } +} + +status_t wr_msg_interact_with_stat(wr_conn_t *conn, uint8 cmd, void *send_info, void *ack) +{ + timeval_t begin_tv; + wr_begin_stat(&begin_tv); + status_t status = wr_msg_interact(conn, cmd, send_info, ack); + if (status == CM_SUCCESS && conn->session != NULL) { + wr_session_t *session = (wr_session_t *)conn->session; + wr_end_stat_ex(&session->stat_ctx, &session->wr_session_stat[session->stat_ctx.wait_event], &begin_tv); + } + return status; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/common_api/wr_api_impl.h b/src/common_api/wr_api_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..a86d0d52018d53bc75303f34ee6e8c41b17358d7 --- /dev/null +++ b/src/common_api/wr_api_impl.h @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_api_impl.h + * + * + * IDENTIFICATION + * src/common_api/wr_api_impl.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_API_IMPL_H__ +#define __WR_API_IMPL_H__ + +#include +#include +#include "wr_errno.h" +#include "wr_au.h" +#include "wr_interaction.h" +#include "wr_session.h" +#include "wr_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_wr_conn wr_conn_t; +typedef struct st_wr_conn_opt wr_conn_opt_t; + +typedef struct st_wr_rw_param { + wr_conn_t *conn; + int32 handle; + wr_env_t *wr_env; + wr_file_context_t *context; + int64 offset; + bool32 atom_oper; + bool32 is_read; +} wr_rw_param_t; + +typedef struct st_wr_load_ctrl_info { + const char *vg_name; + uint32 index; +} wr_load_ctrl_info_t; + +typedef struct st_wr_open_file_info { + const char *file_path; + int flag; +} wr_open_file_info_t; + +typedef struct st_wr_close_file_info { + uint64 fid; + const char *vg_name; + uint32 vg_id; + uint64 ftid; +} wr_close_file_info_t; + +typedef struct st_wr_create_file_info { + const char *file_path; + uint32 flag; +} wr_create_file_info_t; + +typedef struct st_wr_open_dir_info { + const char *dir_path; + bool32 refresh_recursive; +} wr_open_dir_info_t; + +typedef struct st_wr_close_dir_info { + uint64 pftid; + const char *vg_name; + uint32 vg_id; +} wr_close_dir_info_t; + +typedef struct st_wr_add_or_remove_info { + const char *vg_name; + const char *volume_name; +} wr_add_or_remove_info_t; + +typedef struct st_wr_extend_info { + uint64 fid; + uint64 ftid; + int64 offset; + int64 size; + const char *vg_name; + uint32 vg_id; +} wr_extend_info_t; + +typedef struct st_wr_rename_file_info { + const char *src; + const char *dst; +} wr_rename_file_info_t; + +typedef struct st_wr_make_dir_info { + const char *name; +} wr_make_dir_info_t; + +typedef struct st_wr_refresh_file_info { + uint64 fid; + uint64 ftid; + const char *vg_name; + uint32 vg_id; + int64 offset; +} wr_refresh_file_info_t; + +typedef struct st_wr_refresh_volume_info { + uint32 volume_id; + const char *vg_name; + uint32 vg_id; +} wr_refresh_volume_info_t; + +typedef struct st_wr_truncate_file_info { + uint64 fid; + uint64 ftid; + uint64 length; + const char *vg_name; + uint32 vg_id; +} wr_truncate_file_info_t; + +typedef struct st_wr_refresh_file_table_info { + uint64 block_id; + const char *vg_name; + uint32 vg_id; +} wr_refresh_file_table_info_t; + +typedef struct st_wr_update_written_size_info { + uint64 fid; + uint64 ftid; + uint32 vg_id; + uint64 offset; + uint64 size; +} wr_update_written_size_info_t; + +typedef struct st_wr_setcfg_info { + const char *name; + const char *value; + const char *scope; +} wr_setcfg_info_t; + +typedef struct st_wr_symlink_info { + const char *old_path; + const char *new_path; +} wr_symlink_info_t; + +typedef struct st_wr_remove_dir_info { + const char *name; + bool recursive; +} wr_remove_dir_info_t; + +typedef struct st_wr_get_server_info { + char *home; + uint32 objectid; + uint32 server_pid; +} wr_get_server_info_t; + +typedef struct st_wr_fallocate_info { + uint64 fid; + uint64 ftid; + int64 offset; + int64 size; + uint32 vg_id; + int32 mode; +} wr_fallocate_info_t; + +typedef struct st_wr_exist_recv_info { + int32 result; + int32 type; +} wr_exist_recv_info_t; + +#define WRAPI_BLOCK_SIZE 512 +#define WR_HOME "WR_HOME" +#define SYS_HOME "HOME" +#define WR_DEFAULT_UDS_PATH "UDS:/tmp/.wr_unix_d_socket" +#define SESSION_LOCK_TIMEOUT 500 // tickets + +status_t wr_kick_host_sync(wr_conn_t *conn, int64 kick_hostid); +status_t wr_alloc_conn(wr_conn_t **conn); +void wr_free_conn(wr_conn_t *conn); +status_t wr_connect(const char *server_locator, wr_conn_opt_t *options, wr_conn_t *conn); +void wr_disconnect(wr_conn_t *conn); + +// NOTE:just for wrcmd because not support many threads in one process. +status_t wr_connect_ex(const char *server_locator, wr_conn_opt_t *options, wr_conn_t *conn); +void wr_disconnect_ex(wr_conn_t *conn); +status_t wr_lock_vg_s(wr_vg_info_item_t *vg_item, wr_session_t *session); +status_t wr_cli_session_lock(wr_conn_t *conn, wr_session_t *session); +status_t wr_vfs_create_impl(wr_conn_t *conn, const char *dir_name); +status_t wr_vfs_delete_impl(wr_conn_t *conn, const char *dir); +wr_vfs_t *wr_open_dir_impl(wr_conn_t *conn, const char *dir_path, bool32 refresh_recursive); +gft_node_t *wr_read_dir_impl(wr_conn_t *conn, wr_vfs_t *dir, bool32 skip_delete); +status_t wr_close_dir_impl(wr_conn_t *conn, wr_vfs_t *dir); +status_t wr_create_file_impl(wr_conn_t *conn, const char *file_path, int flag); +status_t wr_remove_file_impl(wr_conn_t *conn, const char *file_path); +status_t wr_open_file_impl(wr_conn_t *conn, const char *file_path, int flag, int *handle); +status_t wr_close_file_impl(wr_conn_t *conn, int handle); +status_t wr_exist_impl(wr_conn_t *conn, const char *path, bool32 *result, gft_item_type_t *type); +int64 wr_seek_file_impl(wr_conn_t *conn, int handle, int64 offset, int origin); +status_t wr_write_file_impl(wr_conn_t *conn, int handle, const void *buf, int size); +status_t wr_read_file_impl(wr_conn_t *conn, int handle, void *buf, int size, int *read_size); +status_t wr_rename_file_impl(wr_conn_t *conn, const char *src, const char *dst); +status_t wr_truncate_impl(wr_conn_t *conn, int handle, long long int length); +status_t wr_fstat_impl(wr_conn_t *conn, int handle, wr_stat_info_t item); +status_t wr_set_stat_info(wr_stat_info_t item, gft_node_t *node); + +status_t wr_cli_handshake(wr_conn_t *conn, uint32 max_open_file); +status_t wr_init_client(uint32 max_open_files, char *home); +void wr_destroy(void); +status_t wr_get_fname_impl(int handle, char *fname, int fname_size); + +status_t wr_pwrite_file_impl(wr_conn_t *conn, int handle, const void *buf, int size, long long offset); +status_t wr_pread_file_impl(wr_conn_t *conn, int handle, void *buf, int size, long long offset, int *read_size); +status_t wr_get_addr_impl(wr_conn_t *conn, int32 handle, long long offset, char *pool_name, char *image_name, + char *obj_addr, unsigned int *obj_id, unsigned long int *obj_offset); +gft_node_t *wr_get_node_by_path_impl(wr_conn_t *conn, const char *path); +status_t wr_setcfg_impl(wr_conn_t *conn, const char *name, const char *value, const char *scope); +status_t wr_getcfg_impl(wr_conn_t *conn, const char *name, char *out_str, size_t str_len); +status_t wr_stop_server_impl(wr_conn_t *conn); +void wr_get_api_volume_error(void); +status_t wr_aio_post_pwrite_file_impl(wr_conn_t *conn, int handle, long long offset, int size); +status_t wr_get_phy_size_impl(wr_conn_t *conn, int handle, long long *size); +status_t wr_msg_interact(wr_conn_t *conn, uint8 cmd, void *send_info, void *ack); +status_t wr_fallocate_impl(wr_conn_t *conn, int handle, int mode, long long int offset, long long int length); + +void wr_set_conn_wait_event(wr_conn_t *conn, wr_wait_event_e event); +void wr_unset_conn_wait_event(wr_conn_t *conn); +status_t wr_msg_interact_with_stat(wr_conn_t *conn, uint8 cmd, void *send_info, void *ack); + +status_t wr_close_file_on_server(wr_conn_t *conn, wr_vg_info_item_t *vg_item, uint64 fid, ftid_t ftid); +status_t wr_get_inst_status_on_server(wr_conn_t *conn, wr_server_status_t *wr_status); +status_t wr_get_time_stat_on_server(wr_conn_t *conn, wr_stat_item_t *time_stat, uint64 size); +status_t wr_set_main_inst_on_server(wr_conn_t *conn); + +#define WR_SET_PTR_VALUE_IF_NOT_NULL(ptr, value) \ + do { \ + if (ptr) { \ + (*(ptr) = (value)); \ + } \ + } while (0) + +#define WR_LOCK_VG_META_S_RETURN_ERROR(vg_item, session) \ + do { \ + if (SECUREC_UNLIKELY(wr_lock_vg_s((vg_item), (session)) != CM_SUCCESS)) { \ + return CM_ERROR; \ + } \ + } while (0) + +#define WR_LOCK_VG_META_S_RETURN_NULL(vg_item, session) \ + do { \ + if (SECUREC_UNLIKELY(wr_lock_vg_s((vg_item), (session)) != CM_SUCCESS)) { \ + return NULL; \ + } \ + } while (0) + +#define WR_UNLOCK_VG_META_S(vg_item, session) \ + (void)wr_unlock_shm_meta_s_with_stack((session), (vg_item)->vg_latch, CM_FALSE) + +#ifdef __cplusplus +} +#endif + +#endif // __WR_API_IMPL_H__ diff --git a/src/common_api/wr_cli_conn.c b/src/common_api/wr_cli_conn.c new file mode 100644 index 0000000000000000000000000000000000000000..9e0cdb7f2c09b4d52dbf96ed5febc05c20536780 --- /dev/null +++ b/src/common_api/wr_cli_conn.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) Huawei Technologies Co.,Ltd. 2024-2024 all rigths reserved. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_cli_conn.c + * + * + * IDENTIFICATION + * src/common_api/wr_cli_conn.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_cli_conn.h" +#include "wr_api_impl.h" +#include "wr_malloc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +char g_wr_inst_path[CM_MAX_PATH_LEN] = {0}; +typedef struct st_wr_conn_info { + // protect connections + latch_t conn_latch; + uint32 conn_num; + bool32 isinit; + int32 timeout; // - 1: never time out +} wr_conn_info_t; +static wr_conn_info_t g_wr_conn_info = {{0, 0, 0, 0, 0}, 0, CM_FALSE, 0}; + +void wr_conn_release(pointer_t thv_addr) +{ + wr_conn_t *conn = (wr_conn_t *)thv_addr; + if (conn->pipe.link.uds.closed != CM_TRUE) { + wr_disconnect(conn); + cm_latch_x(&g_wr_conn_info.conn_latch, 1, NULL); + g_wr_conn_info.conn_num--; + if (g_wr_conn_info.conn_num == 0) { + wr_destroy(); + } + cm_unlatch(&g_wr_conn_info.conn_latch, NULL); + } + WR_FREE_POINT(conn); +} + +void wr_conn_opts_release(pointer_t thv_addr) +{ + WR_FREE_POINT(thv_addr); +} + +static thv_ctrl_t g_wr_thv_ctrls[] = { + {NULL, wr_conn_create, wr_conn_release}, + {NULL, wr_conn_opts_create, wr_conn_opts_release}, +}; + +void wr_clt_env_init(void) +{ + if (g_wr_conn_info.isinit == CM_FALSE) { + cm_latch_x(&g_wr_conn_info.conn_latch, 1, NULL); + if (g_wr_conn_info.isinit == CM_FALSE) { + status_t status = cm_launch_thv(g_wr_thv_ctrls, sizeof(g_wr_thv_ctrls) / sizeof(g_wr_thv_ctrls[0])); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("wr client initialization failed."); + cm_unlatch(&g_wr_conn_info.conn_latch, NULL); + return; + } + g_wr_conn_info.isinit = CM_TRUE; + } + cm_unlatch(&g_wr_conn_info.conn_latch, NULL); + } +} + +status_t wr_try_conn(wr_conn_opt_t *options, wr_conn_t *conn, const char *addr) +{ + // establish connection + status_t status = CM_ERROR; + cm_latch_x(&g_wr_conn_info.conn_latch, 1, NULL); + do { + // avoid buffer leak when disconnect + wr_free_packet_buffer(&conn->pack); + status = wr_connect(addr, options, conn); + WR_BREAK_IFERR2(status, LOG_RUN_ERR_INHIBIT(LOG_INHIBIT_LEVEL1, "wr client connet server failed.")); + uint32 max_open_file = WR_MAX_OPEN_FILES; + conn->proto_version = WR_PROTO_VERSION; + status = wr_cli_handshake(conn, max_open_file); + WR_BREAK_IFERR3(status, LOG_RUN_ERR_INHIBIT(LOG_INHIBIT_LEVEL1, "wr client handshake to server failed."), + wr_disconnect(conn)); + + g_wr_conn_info.conn_num++; + } while (0); + cm_unlatch(&g_wr_conn_info.conn_latch, NULL); + return status; +} + +status_t wr_conn_opts_create(pointer_t *result, const char *addr) +{ + wr_conn_opt_t *options = (wr_conn_opt_t *)cm_malloc(sizeof(wr_conn_opt_t)); + if (options == NULL) { + WR_THROW_ERROR(ERR_ALLOC_MEMORY, sizeof(wr_conn_opt_t), "wr_conn_opts_create"); + return CM_ERROR; + } + (void)memset_s(options, sizeof(wr_conn_opt_t), 0, sizeof(wr_conn_opt_t)); + *result = options; + return CM_SUCCESS; +} + +static status_t wr_conn_sync(wr_conn_opt_t *options, wr_conn_t *conn, const char *addr) +{ + status_t ret = CM_ERROR; + int timeout = (options != NULL ? options->timeout : g_wr_uds_conn_timeout); + do { + ret = wr_try_conn(options, conn, addr); + if (ret == CM_SUCCESS) { + break; + } + if (cm_get_os_error() == ENOENT) { + break; + } + } while (timeout == WR_CONN_NEVER_TIMEOUT); + return ret; +} + +status_t wr_conn_create(pointer_t *result, const char *addr) +{ + wr_conn_t *conn = (wr_conn_t *)cm_malloc(sizeof(wr_conn_t)); + if (conn == NULL) { + WR_THROW_ERROR(ERR_ALLOC_MEMORY, sizeof(wr_conn_t), "wr_conn_create"); + return CM_ERROR; + } + + (void)memset_s(conn, sizeof(wr_conn_t), 0, sizeof(wr_conn_t)); + + // init packet + wr_init_packet(&conn->pack, conn->pipe.options); + wr_conn_opt_t *options = NULL; + (void)cm_get_thv(GLOBAL_THV_OBJ1, CM_FALSE, (pointer_t *)&options, addr); + if (wr_conn_sync(options, conn, addr) != CM_SUCCESS) { + WR_THROW_ERROR(ERR_WR_CONNECT_FAILED, cm_get_os_error(), strerror(cm_get_os_error())); + WR_FREE_POINT(conn); + return CM_ERROR; + } +#ifdef ENABLE_WRTEST + conn->conn_pid = getpid(); +#endif + *result = conn; + return CM_SUCCESS; +} + +static status_t wr_get_conn(wr_conn_t **conn, const char *addr) +{ + cm_reset_error(); + wr_clt_env_init(); + if (cm_get_thv(GLOBAL_THV_OBJ0, CM_TRUE, (pointer_t *)conn, addr) != CM_SUCCESS) { + LOG_RUN_ERR("[WR API] ABORT INFO : wr server stoped, application need restart."); + cm_fync_logfile(); + wr_exit(1); + } + +#ifdef ENABLE_WRTEST + if ((*conn)->flag && (*conn)->conn_pid != getpid()) { + LOG_RUN_INF("wr client need re-connect, last conn pid:%llu.", (uint64)(*conn)->conn_pid); + wr_disconnect(*conn); + if (wr_conn_sync(NULL, *conn, addr) != CM_SUCCESS) { + LOG_RUN_ERR("[WR API] ABORT INFO: wr server stoped, application need restart."); + cm_fync_logfile(); + wr_exit(1); + } + (*conn)->conn_pid = getpid(); + } +#endif + + if ((*conn)->pipe.link.uds.closed) { + LOG_RUN_ERR("[WR API] ABORT INFO : wr server stoped, application need restart."); + cm_fync_logfile(); + wr_exit(1); + } + return CM_SUCCESS; +} + +status_t wr_enter_api(wr_conn_t **conn, const char *addr) +{ + status_t status = wr_get_conn(conn, addr); + if (status != CM_SUCCESS) { + return status; + } + while (wr_cli_session_lock((*conn), (*conn)->session) != CM_SUCCESS) { + wr_destroy_thv(GLOBAL_THV_OBJ0); + LOG_RUN_INF("Begin to reconnect wr server."); + status = wr_get_conn(conn, addr); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to reconnect wr server."); + return status; + } + } + return CM_SUCCESS; +} + +void wr_leave_api(wr_conn_t *conn, bool32 get_api_volume_error) +{ + cm_spin_unlock(&((wr_session_t *)(conn->session))->shm_lock); + LOG_DEBUG_INF("Succeed to unlock session %u shm lock", ((wr_session_t *)(conn->session))->id); + if (get_api_volume_error) { + wr_get_api_volume_error(); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/src/common_api/wr_cli_conn.h b/src/common_api/wr_cli_conn.h new file mode 100644 index 0000000000000000000000000000000000000000..f97b0cbd8674edd4915d2608e21f2daae5cb76e3 --- /dev/null +++ b/src/common_api/wr_cli_conn.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) Huawei Technologies Co.,Ltd. 2024-2024 all rigths reserved. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_cli_conn.h + * + * + * IDENTIFICATION + * src/common_api/wr_cli_conn.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_CLI_CONN_H__ +#define __WR_CLI_CONN_H__ + +#include +#include +#include "wr_errno.h" +#include "time.h" +#include "cm_types.h" +#include "wr_thv.h" +#include "wr_protocol.h" +#include "wr_session.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define HANDLE_VALUE(handle) ((handle) - (WR_HANDLE_BASE)) +#define DB_WR_DEFAULT_UDS_PATH "UDS:/tmp/.wr_unix_d_socket" +extern char g_wr_inst_path[CM_MAX_PATH_LEN]; +extern int32 g_wr_uds_conn_timeout; + +typedef struct st_wr_conn { + wr_packet_t pack; // for sending + cs_pipe_t pipe; + void *cli_vg_handles; + bool32 flag; + void *session; + uint32 server_version; + uint32 proto_version; +#ifdef ENABLE_WRTEST + pid_t conn_pid; +#endif + wr_cli_info_t cli_info; +} wr_conn_t; + +typedef struct st_wr_conn_opt { + int32 timeout; + char *user_name; +} wr_conn_opt_t; + +typedef struct st_wr_instance_handle { + wr_conn_t *conn; + char addr[CM_MAX_IP_LEN]; +} st_wr_instance_handle; + +status_t wr_conn_create(pointer_t *result, const char *addr); +status_t wr_conn_opts_create(pointer_t *result, const char *addr); +void wr_conn_opts_release(pointer_t thv_addr); +void wr_conn_release(pointer_t thv_addr); +status_t wr_try_conn(wr_conn_opt_t *options, wr_conn_t *conn, const char *addr); +void wr_clt_env_init(void); +status_t wr_enter_api(wr_conn_t **conn, const char *addr); +void wr_leave_api(wr_conn_t *conn, bool32 get_api_volume_error); + +#ifdef __cplusplus +} +#endif + + +#endif // __WR_CLI_CONN_H__ diff --git a/src/common_api/wr_interaction.c b/src/common_api/wr_interaction.c new file mode 100644 index 0000000000000000000000000000000000000000..dbe686ac4fd89b1a1a473fe0dd265228e04f4263 --- /dev/null +++ b/src/common_api/wr_interaction.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_interaction.c + * + * + * IDENTIFICATION + * src/common_api/wr_interaction.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_interaction.h" +#include "wr_thv.h" +#include "wr_cli_conn.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void wr_cli_get_err(wr_packet_t *pack, int32 *errcode, char **errmsg) +{ + wr_init_get(pack); + (void)wr_get_int32(pack, errcode); + (void)wr_get_str(pack, errmsg); + if (*errcode == ERR_WR_MES_ILL) { + LOG_RUN_ERR("[WR API] ABORT INFO : server broadcast failed, errcode:%d, errmsg:%s.", *errcode, *errmsg); + cm_fync_logfile(); + wr_exit(1); + } +} + +int32 wr_get_pack_err(wr_conn_t *conn, wr_packet_t *pack) +{ + int32 errcode = -1; + char *errmsg = NULL; + wr_cli_get_err(pack, &errcode, &errmsg); + if (errcode == ERR_WR_VERSION_NOT_MATCH) { + conn->server_version = wr_get_version(pack); + uint32 new_proto_version = MIN(WR_PROTO_VERSION, conn->server_version); + LOG_RUN_INF( + "[CHECK_PROTO]The client protocol version need be changed, old protocol version is %hhu, new protocol version is %hhu.", + conn->proto_version, new_proto_version); + conn->proto_version = new_proto_version; + // if msg version has changed, you need to put new version msg; + // if msg version has not changed, just change the proto_version and try again. + wr_set_version(&conn->pack, conn->proto_version); + wr_set_client_version(&conn->pack, WR_PROTO_VERSION); + return errcode; + } else { + WR_THROW_ERROR_EX(errcode, "%s", errmsg); + return CM_ERROR; + } +} + +#ifdef __cplusplus +} +#endif diff --git a/src/common_api/wr_interaction.h b/src/common_api/wr_interaction.h new file mode 100644 index 0000000000000000000000000000000000000000..8298918206910064722aa83f28e240f9912a6966 --- /dev/null +++ b/src/common_api/wr_interaction.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_interaction.h + * + * + * IDENTIFICATION + * src/common_api/wr_interaction.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_INTERACTION_H__ +#define __WR_INTERACTION_H__ + +#include +#include "wr_errno.h" +#include "wr_file_def.h" +#include "wr_protocol.h" +#include "wr_api.h" +#include "wr_session.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_wr_conn wr_conn_t; +int wr_get_pack_err(wr_conn_t *conn, wr_packet_t *pack); +void wr_cli_get_err(wr_packet_t *pack, int32 *errcode, char **errmsg); + +#ifdef __cplusplus +} +#endif + +#endif // __WR_INTERACTION_H__ diff --git a/src/interface/CMakeLists.txt b/src/interface/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3cdaf7f6bdf043f91f46ef1ef270312ce46419ad --- /dev/null +++ b/src/interface/CMakeLists.txt @@ -0,0 +1,49 @@ +## include +include_directories($ENV{JAVA_HOME}/include) +include_directories($ENV{JAVA_HOME}/include/linux) +include_directories(${WR_COMMON_PATH}) +include_directories(${WR_COMMON_PATH}/persist) +include_directories(${WR_LOG_PATH}) +include_directories(${WR_PARAMS_PATH}) +include_directories(${WR_COMMON_API_PATH}) +include_directories(${WR_INTERFACE_PATH}) +include_directories(${WR_HOTPATCH_PATH}) + +option(ENABLE_FUZZASAN OFF) +if (ENABLE_FUZZASAN) + add_compile_options(-fsanitize-coverage=trace-pc) +endif(ENABLE_FUZZASAN) + +## other dependency include +include_directories(${WR_SECUREC_INC_PATH}) +include_directories(${WR_OPENSSL_PATH}) +include_directories(${LIBAIO_INC_PATH}) +include_directories(${WR_CBB_PATH}) +include_directories(${LZ4_INC_PATH}) +## source + +aux_source_directory(${WR_COMMON_PATH} WR_COMMON_SRC) +aux_source_directory(${WR_COMMON_PATH}/persist WR_COMMON_SRC) +aux_source_directory(${WR_LOG_PATH} WR_LOG_SRC) +aux_source_directory(${WR_PARAMS_PATH} WR_PARAMS_SRC) +aux_source_directory(${WR_COMMON_API_PATH} WR_COMMON_API_SRC) +aux_source_directory(${WR_INTERFACE_PATH} WR_INTERFACE_SRC) +aux_source_directory(${WR_SER_PATH} WR_SER_SRC) + +set(COMMON_ALL_SRC + ${WR_COMMON_SRC} + ${WR_LOG_SRC} + ${WR_PARAMS_SRC} + ${WR_COMMON_API_SRC} + ${WR_INTERFACE_SRC} + ${WR_SER_SRC} + ) + +add_library(wrapi SHARED ${COMMON_ALL_SRC}) + +if (ENABLE_FUZZASAN) + target_link_libraries(wrapi PRIVATE pthread dl rt -Wl,--whole-archive ${vpp_libsecurec} ${HOTPATCH_DEPENDENCY_LIB} ${HOTPATCH_LDS} ${3rd_libssl} ${libz} ${lz4} ${fuzz_lib} -Wl,-Bstatic ${3rd_libccb} -Wl,-Bdynamic ${vpp_libipsi_crypto} -Wl,--no-whole-archive) +else() + target_link_libraries(wrapi PRIVATE pthread dl rt -Wl,--whole-archive ${vpp_libsecurec} ${HOTPATCH_DEPENDENCY_LIB} ${HOTPATCH_LDS} ${3rd_libssl} ${libz} ${lz4} -Wl,-Bstatic ${3rd_libccb} -Wl,-Bdynamic ${vpp_libipsi_crypto} -Wl,--no-whole-archive) +endif(ENABLE_FUZZASAN) + diff --git a/src/interface/wr_api.c b/src/interface/wr_api.c new file mode 100644 index 0000000000000000000000000000000000000000..e846ae249357f725fa30bb4c6774246aa557f424 --- /dev/null +++ b/src/interface/wr_api.c @@ -0,0 +1,890 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_api.c + * + * + * IDENTIFICATION + * src/interface/wr_api.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_api.h" +#include "cm_types.h" +#include "cm_thread.h" +#include "wr_malloc.h" +#include "wr_api_impl.h" +#include "cm_log.h" +#include "cm_timer.h" +#include "wr_cli_conn.h" + +#ifdef _WIN64 +#if !defined(__x86_64__) +#define __x86_64__ +#endif +#elif defined _WIN32 +#if !defined(__i386__) +#define __i386__ +#endif +#endif + +#ifdef WIN32 +typedef struct { + unsigned long sig[]; +} sigset_t; +#endif +#include "libaio.h" +#ifndef WIN32 +#include "config.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +void wr_set_default_conn_timeout(int timeout) +{ + if (timeout <= 0) { + g_wr_uds_conn_timeout = WR_CONN_NEVER_TIMEOUT; + return; + } + g_wr_uds_conn_timeout = timeout; +} + +int wr_create_instance(const char *addr, wr_instance_handle *inst_handle) +{ + if (addr == NULL || inst_handle == NULL) { + LOG_RUN_ERR("create instance get invalid parameter."); + return WR_ERROR; + } + + size_t addr_len = strlen(addr); + if (addr_len == 0 || addr_len >= CM_MAX_IP_LEN) { + LOG_RUN_ERR("invalid address length: %u", addr_len); + return WR_ERROR; + } + + st_wr_instance_handle *hdl = (st_wr_instance_handle*)malloc(sizeof(st_wr_instance_handle)); + if (hdl == NULL) { + LOG_RUN_ERR("failed to allocate memory for instance handle"); + return WR_ERROR; + } + hdl->conn = NULL; + errno_t err = memcpy_s(hdl->addr, addr_len + 1, addr, addr_len + 1); + if (err != EOK) { + LOG_RUN_ERR("Error occured when copying addr, errno code is %d.\n", err); + free(hdl); + return (int)err; + } + + status_t ret = wr_enter_api(&hdl->conn, addr); + if (ret != WR_SUCCESS) { + LOG_RUN_ERR("create instance get conn error."); + free(hdl); + return (int)ret; + } + *inst_handle = (wr_instance_handle)hdl; + return (int)ret; +} + +int wr_delete_instance(wr_instance_handle inst_handle) +{ + if (inst_handle != NULL) { + st_wr_instance_handle *hdl = (st_wr_instance_handle *)inst_handle; + if (hdl->conn != NULL) { + wr_leave_api(hdl->conn, WR_TRUE); + } + free(hdl); + } +} + +int wr_vfs_create(const char *vfs_name, wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("vfs create get conn error."); + return WR_ERROR; + } + status_t ret = wr_vfs_create_impl(hdl->conn, vfs_name); + return (int)ret; +} + +int wr_vfs_delete(const char *vfs_name, wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("dremove get conn error."); + return WR_ERROR; + } + status_t ret = wr_vfs_delete_impl(hdl->conn, vfs_name); + return (int)ret; +} + +int wr_vfs_mount(const char *vfs_name, wr_vfs_handle *vfs_handle, wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("wr_vfs_mount get conn error."); + return WR_ERROR; + } + wr_vfs_t *dir = wr_open_dir_impl(hdl->conn, vfs_name, CM_TRUE); + *vfs_handle = (wr_vfs_handle)dir; + return WR_SUCCESS; +} + +int wr_vfs_unmount(wr_vfs_handle vfs_handle, wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("wr_vfs_unmount get conn error."); + return WR_ERROR; + } + status_t ret = wr_close_dir_impl(hdl->conn, (wr_vfs_t *)vfs_handle); + return (int)ret; +} + +int wr_dread(wr_vfs_handle dir, wr_dir_item_t item, wr_dir_item_t *result, wr_instance_handle inst_handle) +{ + if (item == NULL || result == NULL) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "wr_dir_item_t"); + return WR_ERROR; + } + *result = NULL; + if (dir == NULL) { + return WR_SUCCESS; + } + + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("dread get conn error."); + return WR_ERROR; + } + + gft_node_t *node = wr_read_dir_impl(hdl->conn, (wr_vfs_t *)dir, CM_TRUE); + if (node == NULL) { + return WR_SUCCESS; + } + item->d_type = (wr_item_type_t)node->type; + int32 errcode = memcpy_s(item->d_name, WR_MAX_NAME_LEN, node->name, WR_MAX_NAME_LEN); + if (SECUREC_UNLIKELY(errcode != EOK)) { + WR_THROW_ERROR(ERR_SYSTEM_CALL, errcode); + return WR_ERROR; + } + *result = item; + return WR_SUCCESS; +} + +int wr_stat(const char *path, wr_stat_info_t item, wr_instance_handle inst_handle) +{ + if (item == NULL) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "wr_stat_info_t"); + return WR_ERROR; + } + timeval_t begin_tv; + wr_begin_stat(&begin_tv); + + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("stat get conn error."); + return WR_ERROR; + } + + gft_node_t *node = wr_get_node_by_path_impl(hdl->conn, path); + if (node == NULL) { + return WR_ERROR; + } + + int ret = wr_set_stat_info(item, node); + wr_session_end_stat(hdl->conn->session, &begin_tv, WR_STAT); + return ret; +} + +int wr_lstat(const char *path, wr_stat_info_t item, wr_instance_handle inst_handle) +{ + if (item == NULL) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "wr_stat_info_t"); + return WR_ERROR; + } + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("lstat get conn error."); + return WR_ERROR; + } + + gft_node_t *node = wr_get_node_by_path_impl(hdl->conn, path); + if (node == NULL) { + LOG_DEBUG_INF("lstat get node by path :%s error", path); + return WR_ERROR; + } + return wr_set_stat_info(item, node); +} + +int wr_fstat(int handle, wr_stat_info_t item, wr_instance_handle inst_handle) +{ + if (item == NULL) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "wr_stat_info_t"); + return WR_ERROR; + } + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("fstat get conn error."); + return WR_ERROR; + } + status_t ret = wr_fstat_impl(hdl->conn, HANDLE_VALUE(handle), item); + return (int)ret; +} + +int wr_file_create(const char *name, int flag, wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("fcreate get conn error."); + return WR_ERROR; + } + status_t ret = wr_create_file_impl(hdl->conn, name, flag); + return (int)ret; +} + +int wr_file_delete(const char *file, wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("fremove get conn error."); + return WR_ERROR; + } + status_t ret = wr_remove_file_impl(hdl->conn, file); + return (int)ret; +} + +int wr_file_open(const char *file, int flag, int *handle, wr_instance_handle inst_handle) +{ + timeval_t begin_tv; + *handle = -1; + + wr_begin_stat(&begin_tv); + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("fopen get conn error."); + return WR_ERROR; + } + + status_t ret = wr_open_file_impl(hdl->conn, file, flag, handle); + // if open fails, -1 is returned. DB determines based on -1 + if (ret == WR_SUCCESS) { + *handle += WR_HANDLE_BASE; + } + wr_session_end_stat(hdl->conn->session, &begin_tv, WR_FOPEN); + return (int)ret; +} + +int wr_get_inst_status(wr_server_status_t *wr_status, wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("get conn error when get inst status."); + return WR_ERROR; + } + status_t ret = wr_get_inst_status_on_server(hdl->conn, wr_status); + return (int)ret; +} + +int wr_is_maintain(unsigned int *is_maintain, wr_instance_handle inst_handle) +{ + if (is_maintain == NULL) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "expected is_maintain not a null pointer"); + return CM_ERROR; + } + wr_server_status_t wr_status = {0}; + status_t ret = wr_get_inst_status(&wr_status, inst_handle); + WR_RETURN_IFERR2(ret, LOG_DEBUG_ERR("get error when get inst status")); + *is_maintain = wr_status.is_maintain; + return CM_SUCCESS; +} + +int wr_set_main_inst(wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("get conn error when set main inst."); + return WR_ERROR; + } + status_t ret = wr_set_main_inst_on_server(hdl->conn); + return (int)ret; +} + +int wr_file_close(int handle, wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("fclose get conn error."); + return WR_ERROR; + } + + status_t ret = wr_close_file_impl(hdl->conn, HANDLE_VALUE(handle)); + return (int)ret; +} + +long long wr_fseek(int handle, long long offset, int origin, wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("fseek get conn error."); + return WR_ERROR; + } + + long long status = wr_seek_file_impl(hdl->conn, HANDLE_VALUE(handle), offset, origin); + return status; +} + +int wr_file_write(int handle, const void *buf, int size, wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("fwrite get conn error."); + return WR_ERROR; + } + + status_t ret = wr_write_file_impl(hdl->conn, HANDLE_VALUE(handle), buf, size); + return (int)ret; +} + +int wr_file_read(int handle, void *buf, int size, int *read_size, wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("fread get conn error."); + return WR_ERROR; + } + + status_t ret = wr_read_file_impl(hdl->conn, HANDLE_VALUE(handle), buf, size, read_size); + return (int)ret; +} + +int wr_file_pwrite(int handle, const void *buf, int size, long long offset, wr_instance_handle inst_handle) +{ + timeval_t begin_tv; + wr_begin_stat(&begin_tv); + if (size < 0) { + LOG_DEBUG_ERR("File size is invalid:%d.", size); + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "size must be a positive integer"); + return CM_ERROR; + } + if (offset > (int64)WR_MAX_FILE_SIZE) { + LOG_DEBUG_ERR("Invalid parameter offset:%lld.", offset); + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "offset must less than WR_MAX_FILE_SIZE"); + return CM_ERROR; + } + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("pwrite get conn error."); + return WR_ERROR; + } + + status_t ret = wr_pwrite_file_impl(hdl->conn, HANDLE_VALUE(handle), buf, size, offset); + if (ret == CM_SUCCESS) { + wr_session_end_stat(hdl->conn->session, &begin_tv, WR_PWRITE); + } + return (int)ret; +} + +int wr_file_pread(int handle, void *buf, int size, long long offset, int *read_size, wr_instance_handle inst_handle) +{ + timeval_t begin_tv; + wr_begin_stat(&begin_tv); + + if (read_size == NULL) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "read _size is NULL"); + return CM_ERROR; + } + if (size < 0) { + LOG_DEBUG_ERR("File size is invalid:%d.", size); + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "size must be a positive integer"); + return CM_ERROR; + } + if (offset > (int64)WR_MAX_FILE_SIZE) { + LOG_DEBUG_ERR("Invalid parameter offset:%lld.", offset); + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "offset must less than WR_MAX_FILE_SIZE"); + return CM_ERROR; + } + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("pread get conn error."); + return WR_ERROR; + } + + status_t ret = wr_pread_file_impl(hdl->conn, HANDLE_VALUE(handle), buf, size, offset, read_size); + if (ret == CM_SUCCESS) { + wr_session_end_stat(hdl->conn->session, &begin_tv, WR_PREAD); + } + return (int)ret; +} + +int wr_frename(const char *src, const char *dst, wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("frename get conn error."); + return WR_ERROR; + } + + status_t ret = wr_rename_file_impl(hdl->conn, src, dst); + return (int)ret; +} + +int wr_file_truncate(int handle, long long length, wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("ftruncate get conn error."); + return WR_ERROR; + } + status_t ret = wr_truncate_impl(hdl->conn, HANDLE_VALUE(handle), length); + return (int)ret; +} + + +static void wr_fsize_with_options(const char *fname, long long *fsize, int origin, wr_instance_handle inst_handle) +{ + int32 handle; + status_t status; + *fsize = CM_INVALID_INT64; + + if (fname == NULL) { + return; + } + + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("fszie with option get conn error."); + return; + } + + status = wr_open_file_impl(hdl->conn, fname, O_RDONLY, &handle); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Open file :%s failed.\n", fname); + return; + } + + *fsize = wr_seek_file_impl(hdl->conn, handle, 0, origin); + if (*fsize == CM_INVALID_INT64) { + LOG_DEBUG_ERR("Seek file :%s failed.\n", fname); + } + + (void)wr_close_file_impl(hdl->conn, handle); +} + +int wr_fsize_physical(int handle, long long *fsize, wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("fszie get conn error."); + return WR_ERROR; + } + status_t ret = wr_get_phy_size_impl(hdl->conn, HANDLE_VALUE(handle), fsize); + return (int)ret; +} + +void wr_fsize_maxwr(const char *fname, long long *fsize, wr_instance_handle inst_handle) +{ + wr_fsize_with_options(fname, fsize, WR_SEEK_MAXWR, inst_handle); +} + +void wr_get_error(int *errcode, const char **errmsg) +{ + cm_get_error(errcode, errmsg); +} + +int wr_get_fname(int handle, char *fname, int fname_size) +{ + status_t ret = wr_get_fname_impl(HANDLE_VALUE(handle), fname, fname_size); + wr_get_api_volume_error(); + return (int)ret; +} + +int wr_fallocate(int handle, int mode, long long offset, long long length, wr_instance_handle inst_handle) +{ + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("fallocate get conn error."); + return WR_ERROR; + } + status_t ret = wr_fallocate_impl(hdl->conn, HANDLE_VALUE(handle), mode, offset, length); + + return (int)ret; +} + +int wr_set_svr_path(const char *conn_path) +{ + if (conn_path == NULL) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "conn path"); + return WR_ERROR; + } + + size_t len = strlen(conn_path); + if (len == 0) { + WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, conn_path, ", conn path is empty"); + return WR_ERROR; + } else if (len > CM_MAX_PATH_LEN) { + WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, conn_path, ", conn path is too long"); + return WR_ERROR; + } + if (strcpy_s(g_wr_inst_path, CM_MAX_PATH_LEN, conn_path) != EOK) { + WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, conn_path, ", conn path copy fail"); + return WR_ERROR; + } + return WR_SUCCESS; +} + +void wr_register_log_callback(wr_log_output cb_log_output, unsigned int log_level) +{ + cm_log_param_instance()->log_write = (usr_cb_log_output_t)cb_log_output; + cm_log_param_instance()->log_level = log_level; +} + +void wr_set_log_level(unsigned int log_level) +{ + cm_log_param_instance()->log_level = log_level; +} + +static int32 init_single_logger_core(log_param_t *log_param, log_type_t log_id, char *file_name, uint32 file_name_len) +{ + int32 ret; + switch (log_id) { + case LOG_RUN: + ret = snprintf_s( + file_name, file_name_len, CM_MAX_FILE_NAME_LEN, "%s/WR/run/%s", log_param->log_home, "wr.rlog"); + break; + case LOG_DEBUG: + ret = snprintf_s( + file_name, file_name_len, CM_MAX_FILE_NAME_LEN, "%s/WR/debug/%s", log_param->log_home, "wr.dlog"); + break; + case LOG_ALARM: + ret = snprintf_s( + file_name, file_name_len, CM_MAX_FILE_NAME_LEN, "%s/WR/alarm/%s", log_param->log_home, "wr.alog"); + break; + case LOG_AUDIT: + ret = snprintf_s( + file_name, file_name_len, CM_MAX_FILE_NAME_LEN, "%s/WR/audit/%s", log_param->log_home, "wr.aud"); + break; + case LOG_BLACKBOX: + ret = snprintf_s( + file_name, file_name_len, CM_MAX_FILE_NAME_LEN, "%s/WR/blackbox/%s", log_param->log_home, "wr.blog"); + break; + default: + ret = 0; + break; + } + + return (ret != -1) ? WR_SUCCESS : ERR_WR_INIT_LOGGER_FAILED; +} + +static int32 init_single_logger(log_param_t *log_param, log_type_t log_id) +{ + char file_name[CM_FILE_NAME_BUFFER_SIZE] = {'\0'}; + CM_RETURN_IFERR(init_single_logger_core(log_param, log_id, file_name, CM_FILE_NAME_BUFFER_SIZE)); + (void)cm_log_init(log_id, (const char *)file_name); + cm_log_open_compress(log_id, WR_TRUE); + return WR_SUCCESS; +} + +void wr_refresh_logger(char *log_field, unsigned long long *value) +{ + if (log_field == NULL) { + return; + } + + if (strcmp(log_field, "LOG_LEVEL") == 0) { + cm_log_param_instance()->log_level = (uint32)(*value); + } else if (strcmp(log_field, "LOG_MAX_FILE_SIZE") == 0) { + cm_log_param_instance()->max_log_file_size = (uint64)(*value); + cm_log_param_instance()->max_audit_file_size = (uint64)(*value); + } else if (strcmp(log_field, "LOG_BACKUP_FILE_COUNT") == 0) { + cm_log_param_instance()->log_backup_file_count = (uint32)(*value); + cm_log_param_instance()->audit_backup_file_count = (uint32)(*value); + } +} + +int wr_init_logger( + char *log_home, unsigned int log_level, unsigned int log_backup_file_count, unsigned long long log_max_file_size) +{ + errno_t ret; + log_param_t *log_param = cm_log_param_instance(); + ret = memset_s(log_param, sizeof(log_param_t), 0, sizeof(log_param_t)); + if (ret != EOK) { + return ERR_WR_INIT_LOGGER_FAILED; + } + + log_param->log_level = log_level; + log_param->log_backup_file_count = log_backup_file_count; + log_param->audit_backup_file_count = log_backup_file_count; + log_param->max_log_file_size = log_max_file_size; + log_param->max_audit_file_size = log_max_file_size; + log_param->log_compressed = WR_TRUE; + if (log_param->log_compress_buf == NULL) { + log_param->log_compress_buf = malloc(CM_LOG_COMPRESS_BUFSIZE); + if (log_param->log_compress_buf == NULL) { + return ERR_WR_INIT_LOGGER_FAILED; + } + } + cm_log_set_file_permissions(600); + cm_log_set_path_permissions(700); + (void)cm_set_log_module_name("WR", sizeof("WR")); + ret = strcpy_sp(log_param->instance_name, CM_MAX_NAME_LEN, "WR"); + if (ret != EOK) { + return ERR_WR_INIT_LOGGER_FAILED; + } + + ret = strcpy_sp(log_param->log_home, CM_MAX_LOG_HOME_LEN, log_home); + if (ret != EOK) { + return ERR_WR_INIT_LOGGER_FAILED; + } + + CM_RETURN_IFERR(init_single_logger(log_param, LOG_RUN)); + CM_RETURN_IFERR(init_single_logger(log_param, LOG_DEBUG)); + CM_RETURN_IFERR(init_single_logger(log_param, LOG_ALARM)); + CM_RETURN_IFERR(init_single_logger(log_param, LOG_AUDIT)); + CM_RETURN_IFERR(init_single_logger(log_param, LOG_BLACKBOX)); + if (cm_start_timer(g_timer()) != CM_SUCCESS) { + return ERR_WR_INIT_LOGGER_FAILED; + } + log_param->log_instance_startup = (bool32)CM_TRUE; + + return WR_SUCCESS; +} + +int wr_set_conn_timeout(int32 timeout) +{ + if (timeout < 0 && timeout != WR_CONN_NEVER_TIMEOUT) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "invalid timeout when set connection timeout"); + return CM_ERROR; + } + g_wr_uds_conn_timeout = timeout; + return CM_SUCCESS; +} + +int wr_set_thread_conn_timeout(wr_conn_opt_t *thv_opts, int32 timeout) +{ + if (timeout < 0 && timeout != WR_CONN_NEVER_TIMEOUT) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "invalid timeout when set connection timeout"); + return CM_ERROR; + } + thv_opts->timeout = timeout; + return CM_SUCCESS; +} + +int wr_set_conn_opts(wr_conn_opt_key_e key, void *value, const char *addr) +{ + wr_clt_env_init(); + wr_conn_opt_t *thv_opts = NULL; + if (cm_get_thv(GLOBAL_THV_OBJ1, CM_TRUE, (pointer_t *)&thv_opts, addr) != CM_SUCCESS) { + return CM_ERROR; + } + switch (key) { + case WR_CONN_OPT_TIME_OUT: + return wr_set_thread_conn_timeout(thv_opts, *(int32 *)value); + default: + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "invalid key when set connection options"); + return CM_ERROR; + } +} + +int wr_aio_prep_pread(void *iocb, int handle, void *buf, size_t count, long long offset) +{ + return CM_SUCCESS; +} + +int wr_aio_prep_pwrite(void *iocb, int handle, void *buf, size_t count, long long offset) +{ + return CM_SUCCESS; +} + +int wr_aio_post_pwrite(void *iocb, int handle, size_t count, long long offset) +{ + return CM_SUCCESS; +} + +int wr_set_conf(const char *name, const char *value, const char *scope, wr_instance_handle inst_handle) +{ + if (name == NULL || value == NULL) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "invalid name or value when set cfg"); + return WR_ERROR; + } + if (cm_strcmpi(name, "_LOG_LEVEL") != 0 && cm_strcmpi(name, "_LOG_MAX_FILE_SIZE") != 0 && + cm_strcmpi(name, "_LOG_BACKUP_FILE_COUNT") != 0 && cm_strcmpi(name, "_AUDIT_MAX_FILE_SIZE") != 0 && + cm_strcmpi(name, "_AUDIT_BACKUP_FILE_COUNT") != 0 && cm_strcmpi(name, "_AUDIT_LEVEL") != 0) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "invalid name when set cfg"); + return WR_ERROR; + } + + char *tmp_scope = NULL; + if (scope == NULL) { + tmp_scope = (char *)"both"; + } else { + tmp_scope = (char *)scope; + } + + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("setcfg get conn error."); + return WR_ERROR; + } + + status_t ret = wr_setcfg_impl(hdl->conn, name, value, tmp_scope); + return (int)ret; +} + +int wr_get_conf(const char *name, char *value, int value_size, wr_instance_handle inst_handle) +{ + if (name == NULL) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "invalid name when get cfg"); + return WR_ERROR; + } + if (value_size <= 0) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "invalid value_size when get cfg"); + return WR_ERROR; + } + if (inst_handle == NULL) { + LOG_RUN_ERR("instance handle is NULL."); + return WR_ERROR; + } + st_wr_instance_handle *hdl = (st_wr_instance_handle*)inst_handle; + if (hdl->conn == NULL) { + LOG_RUN_ERR("getcfg get conn error."); + return WR_ERROR; + } + + status_t ret = wr_getcfg_impl(hdl->conn, name, value, (size_t)value_size); + return (int)ret; +} + +int wr_get_lib_version(void) +{ + return WR_LOCAL_MAJOR_VERSION * WR_LOCAL_MAJOR_VER_WEIGHT + WR_LOCAL_MINOR_VERSION * WR_LOCAL_MINOR_VER_WEIGHT + + WR_LOCAL_VERSION; +} + +void wr_show_version(char *version) +{ + if (snprintf_s(version, WR_VERSION_MAX_LEN, WR_VERSION_MAX_LEN - 1, "libwr.so %s", (char *)DEF_WR_VERSION) == + -1) { + cm_panic(0); + } +} + +#ifdef __cplusplus +} +#endif diff --git a/src/interface/wr_api.h b/src/interface/wr_api.h new file mode 100644 index 0000000000000000000000000000000000000000..584559209434dd7064abc18b03ebbdb1cc1d4211 --- /dev/null +++ b/src/interface/wr_api.h @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_api.h + * + * + * IDENTIFICATION + * src/interface/wr_api.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_API_H__ +#define __WR_API_H__ + +#include +#include +#include "wr_errno.h" +#include "time.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WIN32 +#if defined(WR_EXPORTS) +#define WR_DECLARE __declspec(dllexport) +#elif defined(WR_IMPORTS) +#define WR_DECLARE __declspec(dllimport) +#else +#define WR_DECLARE +#endif +#else +#define WR_DECLARE __attribute__((visibility("default"))) +#endif + +/* handle */ +struct __wr_dir; +typedef struct __wr_dir *wr_vfs_handle; + +struct __wr_instance_handle; +typedef struct __wr_instance_handle *wr_instance_handle; + +typedef enum en_wr_log_level { + WR_LOG_LEVEL_ERROR = 0, // error conditions + WR_LOG_LEVEL_WARN, // warning conditions + WR_LOG_LEVEL_INFO, // informational messages + WR_LOG_LEVEL_COUNT, +} wr_log_level_t; + +typedef enum en_wr_log_id { + WR_LOG_ID_RUN = 0, + WR_LOG_ID_DEBUG, + WR_LOG_ID_COUNT, +} wr_log_id_t; + +#define WR_SEEK_MAXWR 3 /* Used for seek actual file size for openGauss */ +#define WR_MAX_NAME_LEN 64 /* Consistent with wr_defs.h */ +#define WR_FILE_PATH_MAX_LENGTH (SIZE_K(1) + 1) /* Consistent with wr_defs.h */ +#define WR_MAX_VOLUME_PATH_LEN 64 /* Consistent with wr_defs.h */ + +/* make the wr handle start from this value, to be distinguished from file system handle value */ +#define WR_HANDLE_BASE 0x20000000 +#define WR_CONN_NEVER_TIMEOUT (-1) +#define WR_VERSION_MAX_LEN 256 + +typedef enum en_wr_item_type { + WR_PATH, + WR_FILE, + WR_LINK, + WR_LINK_TO_PATH, + WR_LINK_TO_FILE, +} wr_item_type_t; + +typedef struct st_wr_dirent { + wr_item_type_t d_type; + char d_name[WR_MAX_NAME_LEN]; +} wr_dirent_t; + +typedef enum en_wr_rdwr_type_e { + WR_STATUS_NORMAL = 0, + WR_STATUS_READONLY, + WR_STATUS_READWRITE, + WR_SERVER_STATUS_END, +} wr_rdwr_type_e; + +typedef enum en_wr_instance_status { + WR_STATUS_PREPARE = 0, + WR_STATUS_RECOVERY, + WR_STATUS_SWITCH, + WR_STATUS_OPEN, + WR_INSTANCE_STATUS_END, +} wr_instance_status_e; + +#define WR_MAX_STATUS_LEN 16 +typedef struct st_wr_server_status_t { + wr_instance_status_e instance_status_id; + char instance_status[WR_MAX_STATUS_LEN]; + wr_rdwr_type_e server_status_id; + char server_status[WR_MAX_STATUS_LEN]; + unsigned int local_instance_id; + unsigned int master_id; + unsigned int is_maintain; +} wr_server_status_t; + +typedef struct st_wr_stat { + unsigned long long size; + unsigned long long written_size; + time_t create_time; + time_t update_time; + char name[WR_MAX_NAME_LEN]; + wr_item_type_t type; +} wr_stat_t; + +typedef enum en_wr_conn_opt_key { + WR_CONN_OPT_TIME_OUT = 0, +} wr_conn_opt_key_e; +#define WR_LOCAL_MAJOR_VER_WEIGHT 1000000 +#define WR_LOCAL_MINOR_VER_WEIGHT 1000 +#define WR_LOCAL_MAJOR_VERSION 0 +#define WR_LOCAL_MINOR_VERSION 0 +#define WR_LOCAL_VERSION 5 + +// menas no need caller to write zero to init file content before read from the file +#define WR_FILE_FLAG_INNER_INITED 0x80000000 + +typedef struct st_wr_dirent *wr_dir_item_t; +typedef struct st_wr_stat *wr_stat_info_t; +typedef void (*wr_log_output)(wr_log_id_t log_type, wr_log_level_t log_level, const char *code_file_name, + unsigned int code_line_num, const char *module_name, const char *format, ...); +typedef void (*wr_exit_callback_t)(int exit_code); +// vfs +WR_DECLARE int wr_vfs_create(const char *vfs_name, wr_instance_handle inst_handle); +WR_DECLARE int wr_vfs_delete(const char *vfs_name, wr_instance_handle inst_handle); +WR_DECLARE int wr_vfs_mount(const char *vfs_name, wr_vfs_handle *vfs_handle, wr_instance_handle inst_handle); +WR_DECLARE int wr_vfs_unmount(wr_vfs_handle vfs_handle, wr_instance_handle inst_handle); + +WR_DECLARE int wr_dread(wr_vfs_handle dir, wr_dir_item_t item, wr_dir_item_t *result, wr_instance_handle inst_handle); +WR_DECLARE int wr_vfs_query_file_info(wr_vfs_handle dir, wr_dir_item_t item, wr_dir_item_t *result); +WR_DECLARE int wr_vfs_query_file_num(wr_vfs_handle dir, wr_dir_item_t item, wr_dir_item_t *result); + +// file +WR_DECLARE int wr_file_create(const char *name, int flag, wr_instance_handle inst_handle); +WR_DECLARE int wr_file_delete(const char *file, wr_instance_handle inst_handle); +WR_DECLARE int wr_file_open(const char *file, int flag, int *handle, wr_instance_handle inst_handle); +WR_DECLARE int wr_file_close(int handle, wr_instance_handle inst_handle); +WR_DECLARE long long wr_fseek(int handle, long long offset, int origin, wr_instance_handle inst_handle); +WR_DECLARE int wr_file_write(int handle, const void *buf, int size, wr_instance_handle inst_handle); +WR_DECLARE int wr_file_read(int handle, void *buf, int size, int *read_size, wr_instance_handle inst_handle); +WR_DECLARE int wr_file_rename(const char *src, const char *dst); +WR_DECLARE int wr_file_truncate(int handle, long long length, wr_instance_handle inst_handle); +WR_DECLARE int wr_file_size_physical(int handle, long long *fsize); +WR_DECLARE void wr_file_size_maxwr(const char *fname, long long *fsize); +WR_DECLARE int wr_file_pwrite(int handle, const void *buf, int size, long long offset, wr_instance_handle inst_handle); +WR_DECLARE int wr_file_pread(int handle, void *buf, int size, long long offset, int *read_size, wr_instance_handle inst_handle); +WR_DECLARE int wr_file_fallocate(int handle, int mode, long long offset, long long length); + +// aio +WR_DECLARE int wr_aio_prep_pread(void *iocb, int handle, void *buf, size_t count, long long offset); +WR_DECLARE int wr_aio_prep_pwrite(void *iocb, int handle, void *buf, size_t count, long long offset); +WR_DECLARE int wr_aio_post_pwrite(void *iocb, int handle, size_t count, long long offset); + +// log +WR_DECLARE void wr_get_error(int *errcode, const char **errmsg); +WR_DECLARE void wr_register_log_callback(wr_log_output cb_log_output, unsigned int log_level); +WR_DECLARE void wr_set_log_level(unsigned int log_level); +WR_DECLARE int wr_init_logger( + char *log_home, unsigned int log_level, unsigned int log_backup_file_count, unsigned long long log_max_file_size); +WR_DECLARE void wr_refresh_logger(char *log_field, unsigned long long *value); +// connection +WR_DECLARE int wr_set_svr_path(const char *conn_path); +WR_DECLARE int wr_set_conn_timeout(int timeout); +WR_DECLARE int wr_set_conn_opts(wr_conn_opt_key_e key, void *value, const char *addr); +WR_DECLARE void wr_set_default_conn_timeout(int timeout); +WR_DECLARE int wr_create_instance(const char *addr, wr_instance_handle *inst_handle); +WR_DECLARE int wr_delete_instance(wr_instance_handle inst_handle); +// instance param +WR_DECLARE int wr_set_main_inst(wr_instance_handle inst_handle); +WR_DECLARE int wr_disable_grab_lock(void); +WR_DECLARE int wr_enable_grab_lock(void); +WR_DECLARE int wr_get_inst_status(wr_server_status_t *wr_status, wr_instance_handle inst_handle); +WR_DECLARE int wr_is_maintain(unsigned int *is_maintain, wr_instance_handle inst_handle); + +WR_DECLARE int wr_stat(const char *path, wr_stat_info_t item, wr_instance_handle inst_handle); +WR_DECLARE int wr_lstat(const char *path, wr_stat_info_t item, wr_instance_handle inst_handle); +WR_DECLARE int wr_fstat(int handle, wr_stat_info_t item, wr_instance_handle inst_handle); + +// config +WR_DECLARE int wr_set_conf(const char *name, const char *value, const char *scope, wr_instance_handle inst_handle); +WR_DECLARE int wr_get_conf(const char *name, char *value, int value_size, wr_instance_handle inst_handle); +// version +WR_DECLARE int wr_get_lib_version(void); +WR_DECLARE void wr_show_version(char *version); +WR_DECLARE void wr_show_version(char *version); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/interface/wr_errno.h b/src/interface/wr_errno.h new file mode 100644 index 0000000000000000000000000000000000000000..63214b9d08095120a4b71544c50801be7a0ab82a --- /dev/null +++ b/src/interface/wr_errno.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_errno.h + * + * + * IDENTIFICATION + * src/interface/wr_errno.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_ERRNO_H__ +#define __WR_ERRNO_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define WR_SUCCESS 0 +#define WR_ERROR (-1) + +/** 1.WR range [2000, 2500] * + * 2.ERR_WR_SUBMODEL_ACTION_DETAIL, _DETAIL is optional which indicates the error cause. + */ +#define ERR_WR_FLOOR 2000 +// vg error [2000, 2050) +#define ERR_WR_VG_CREATE 2000 +#define ERR_WR_VG_LOCK 2010 +#define ERR_WR_VG_REMOVE 2020 +#define ERR_WR_VG_CHECK 2030 +#define ERR_WR_VG_CHECK_NOT_INIT 2031 +#define ERR_WR_VG_NOT_EXIST 2040 + +// volumn error [2050, 2130) +#define ERR_WR_VOLUME_SYSTEM_IO 2050 +#define ERR_WR_VOLUME_OPEN 2060 +#define ERR_WR_VOLUME_READ 2070 +#define ERR_WR_VOLUME_WRITE 2080 +#define ERR_WR_VOLUME_SEEK 2090 +#define ERR_WR_VOLUME_ADD 2100 +#define ERR_WR_VOLUME_EXISTED 2101 +#define ERR_WR_VOLUME_REMOVE 2110 +#define ERR_WR_VOLUME_NOEXIST 2111 +#define ERR_WR_VOLUME_REMOVE_NONEMPTY 2112 +#define ERR_WR_VOLUME_REMOVE_SUPER_BLOCK 2113 +#define ERR_WR_VOLUME_REPLACE 2114 +#define ERR_WR_VOLUME_FENCE_CHECK_COND 2120 + +// file error [2130, 2230) +#define ERR_WR_FILE_SEEK 2130 +#define ERR_WR_FILE_REMOVE 2140 +#define ERR_WR_FILE_REMOVE_OPENING 2141 +#define ERR_WR_FILE_REMOVE_SYSTEM 2142 +#define ERR_WR_FILE_RENAME 2150 +#define ERR_WR_FILE_RENAME_DIFF_VG 2151 +#define ERR_WR_FILE_RENAME_EXIST 2152 +#define ERR_WR_FILE_RENAME_OPENING_REMOTE 2153 +#define ERR_WR_FILE_CLOSE 2160 +#define ERR_WR_FILE_CREATE 2170 +#define ERR_WR_FILE_RDWR 2180 +#define ERR_WR_FILE_RDWR_INSUFF_PER 2181 +#define ERR_WR_FILE_NOT_EXIST 2190 +#define ERR_WR_FILE_OPENING_REMOTE 2191 +#define ERR_WR_FILE_TYPE_MISMATCH 2192 +#define ERR_WR_FILE_PATH_ILL 2193 +#define ERR_WR_FILE_INVALID_SIZE 2194 + +// dir error [2230, 2280) +#define ERR_WR_DIR_REMOVE 2230 +#define ERR_WR_DIR_REMOVE_NOT_EMPTY 2231 +#define ERR_WR_DIR_CREATE 2240 +#define ERR_WR_DIR_CREATE_DUPLICATED 2241 +// link error [2280, 2300) +#define ERR_WR_LINK_READ 2280 +#define ERR_WR_LINK_READ_NOT_LINK 2281 +#define ERR_WR_LINK_CREATE 2290 + +// config error [2300, 2320) +#define ERR_WR_CONFIG_FILE_OVERSIZED 2300 +#define ERR_WR_CONFIG_LOAD 2301 +#define ERR_WR_CONFIG_LINE_OVERLONG 2302 + +// redo error [2320, 2350) +#define ERR_WR_REDO_ILL 2320 + +// Basic Data Structure error [2350, 2400) +#define ERR_WR_OAMAP_INSERT 2350 +#define ERR_WR_OAMAP_INSERT_DUP_KEY 2351 +#define ERR_WR_OAMAP_FETCH 2352 +#define ERR_WR_SKLIST_ERR 2360 +#define ERR_WR_SKLIST_NOT_INIT 2361 +#define ERR_WR_SKLIST_NOT_EXIST 2362 +#define ERR_WR_SKLIST_EXIST 2363 +#define ERR_WR_SHM_CREATE 2370 +#define ERR_WR_SHM_CHECK 2371 +#define ERR_WR_SHM_LOCK 2372 +#define ERR_WR_SHM_LOCK_TIMEOUT 2373 +#define ERR_WR_GA_INIT 2380 +#define ERR_WR_GA_GET_ADDR 2381 +#define ERR_WR_GA_ALLOC_OBJECT 2382 +#define ERR_WR_SESSION_INVALID_ID 2390 +#define ERR_WR_SESSION_CREATE 2391 +#define ERR_WR_SESSION_EXTEND 2392 + +// other error [2400, 2500) +#define ERR_WR_INVALID_PARAM 2400 +#define ERR_WR_NO_SPACE 2401 +#define ERR_WR_ENV_NOT_INITIALIZED 2402 +#define ERR_WR_CLI_EXEC_FAIL 2403 +#define ERR_WR_FNODE_CHECK 2404 +#define ERR_WR_LOCK_TIMEOUT 2405 +#define ERR_WR_SERVER_IS_DOWN 2406 +#define ERR_WR_CHECK_SIZE 2407 +#define ERR_WR_MES_ILL 2408 +#define ERR_WR_STRING_TOO_LONG 2409 +#define ERR_WR_TCP_TIMEOUT_REMAIN 2410 +#define ERR_WR_UDS_INVALID_URL 2411 +#define ERR_WR_RECV_MSG_FAILED 2412 +#define ERR_WR_INIT_LOGGER_FAILED 2414 +#define ERR_WR_OUT_OF_MEM 2415 +#define ERR_WR_INVALID_ID 2416 +#define ERR_WR_PROCESS_REMOTE 2417 +#define ERR_WR_CONNECT_FAILED 2418 +#define ERR_WR_VERSION_NOT_MATCH 2419 +#define ERR_WR_INVALID_BLOCK_TYPE 2420 +#define ERR_WR_SERVER_REBOOT 2421 +#define ERR_WR_UNSUPPORTED_CMD 2422 + +#define ERR_WR_MASTER_CHANGE 2498 +#define ERR_WR_RECOVER_CAUSE_BREAK 2499 + +#define ERR_WR_CEIL 2500 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/log/wr_log.c b/src/log/wr_log.c new file mode 100644 index 0000000000000000000000000000000000000000..8eb494d0fbd616c0c584707c287d819d181d3a23 --- /dev/null +++ b/src/log/wr_log.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_log.c + * + * + * IDENTIFICATION + * src/log/wr_log.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_log.h" +#include "cm_num.h" +#include "wr_defs.h" +#include "wr_param.h" +#include "wr_param_verify.h" +#include "wr_session.h" +#include "cm_system.h" + +/* + * one error no corresponds to one error desc + * Attention: keep the array index same as error no + */ +const char *g_wr_error_desc[WR_ERROR_COUNT] = { + // Zenith File System, range [2000, 2500] + [ERR_WR_VG_CREATE] = "Create volume group %s failed, reason %s", + [ERR_WR_VG_LOCK] = "Lock volume group %s failed", + [ERR_WR_VG_REMOVE] = "Forbidden remove volume group's superblock", + [ERR_WR_VG_CHECK] = "Check volume group %s failed, reason %s", + [ERR_WR_VG_CHECK_NOT_INIT] = "The volume group has not been initialized.", + [ERR_WR_VG_NOT_EXIST] = "Failed to find volume group %s, please check vg config file.", + [ERR_WR_VOLUME_SYSTEM_IO] = "Failed to operate volume %s for system I/O error.", + [ERR_WR_VOLUME_OPEN] = "Open volume '%s' failed, reason %d", + [ERR_WR_VOLUME_READ] = "Read volume '%s' failed, volume id %d, reason %d", + [ERR_WR_VOLUME_WRITE] = "Write volume '%s' failed, volume id %d, reason %d", + [ERR_WR_VOLUME_SEEK] = "Seek volume '%s' failed, volume id %d, reason %d", + [ERR_WR_VOLUME_ADD] = "Failed to add volume %s, reason %s.", + [ERR_WR_VOLUME_EXISTED] = "Add/Replace an existed volume %s of volume-group %s failed", + [ERR_WR_VOLUME_NOEXIST] = "Remove/Replace a non-existent volume %s of volume-group %s failed", + [ERR_WR_VOLUME_REMOVE_NONEMPTY] = "Remove a nonempty volume %s failed", + [ERR_WR_VOLUME_REMOVE_SUPER_BLOCK] = "Remove super block %s failed", + [ERR_WR_VOLUME_REPLACE] = "Failed to replace volume %s, reason %s.", + [ERR_WR_FILE_SEEK] = "Failed to seek file, vgid:%u, fid:%llu, offset:%lld, file size:%llu", + [ERR_WR_FILE_REMOVE_OPENING] = "WR file is open", + [ERR_WR_FILE_REMOVE_SYSTEM] = "WR file %s is system file", + [ERR_WR_FILE_RENAME] = "Rename failed, reason %s", + [ERR_WR_FILE_RENAME_DIFF_VG] = "Failed to rename from vg %s to another vg %s, function not supported", + [ERR_WR_FILE_RENAME_EXIST] = "Rename failed, reason %s", + [ERR_WR_FILE_RENAME_OPENING_REMOTE] = "Failed to rename %s to %s, while source file is opend by other instance.", + [ERR_WR_FILE_CLOSE] = "Close file failed, reason %s", + [ERR_WR_FILE_CREATE] = "Create file failed, reason %s", + [ERR_WR_FILE_RDWR_INSUFF_PER] = "Insufficient permission to %s file, while the permission is %u.", + [ERR_WR_FILE_NOT_EXIST] = "The file %s of %s does not exist", + [ERR_WR_FILE_OPENING_REMOTE] = "The file is open in other inst: %hhu, command:%u exec failed.", + [ERR_WR_FILE_TYPE_MISMATCH] = "The type of directory link or file %s is not matched.", + [ERR_WR_FILE_PATH_ILL] = "Path %s decode error %s", + [ERR_WR_FILE_INVALID_SIZE] = "Invalid extend offset %lld, size %d.", + [ERR_WR_DIR_REMOVE_NOT_EMPTY] = "The dir is not empty, can not remove.", + [ERR_WR_DIR_CREATE_DUPLICATED] = "Make dir or Create file failed, %s has already existed", + [ERR_WR_LINK_READ_NOT_LINK] = "The path %s is not a soft link.", + [ERR_WR_LINK_CREATE] = "Failed to create symbolic link, reason %s", + [ERR_WR_CONFIG_FILE_OVERSIZED] = "The size of config file %s is too large", + [ERR_WR_CONFIG_LOAD] = "Please check wr_vg_conf.ini, reason %s", + [ERR_WR_CONFIG_LINE_OVERLONG] = "The length of row %d is too long", + [ERR_WR_REDO_ILL] = "WR redo log error, reason %s", + [ERR_WR_OAMAP_INSERT] = "Failed to insert hash map ", + [ERR_WR_OAMAP_INSERT_DUP_KEY] = "Hash map duplicated key", + [ERR_WR_OAMAP_FETCH] = "Failed to fetch hash map", + [ERR_WR_SKLIST_ERR] = "Error WR skip list.", + [ERR_WR_SKLIST_NOT_INIT] = "Error WR skip list not init.", + [ERR_WR_SKLIST_NOT_EXIST] = "Error WR skip list not exist.", + [ERR_WR_SKLIST_EXIST] = "Error WR skip list key value exist.", + [ERR_WR_SHM_CREATE] = "Failed to create shared memory, key=0x%08x, size=%llu", + [ERR_WR_SHM_CHECK] = "Failed to check shared memory ctrl, key=0x%08x, reason=%s", + [ERR_WR_SHM_LOCK] = "Failed to lock vg shared memory, reason=%s", + [ERR_WR_SHM_LOCK_TIMEOUT] = "Try to get shm lock timeout", + [ERR_WR_GA_INIT] = "WR ga init error, reason %s", + [ERR_WR_GA_GET_ADDR] = "WR ga get addr error, pool id %d, object id%u.", + [ERR_WR_GA_ALLOC_OBJECT] = "WR ga alloc object error, pool id %d.", + [ERR_WR_SESSION_INVALID_ID] = "Invalid session %d", + [ERR_WR_SESSION_CREATE] = "Create new WR session failed, no free sessions, %d sessions used.", + [ERR_WR_SESSION_EXTEND] = "Extend WR session failed, reason : %s.", + [ERR_WR_INVALID_PARAM] = "Invalid WR parameter: %s", + [ERR_WR_NO_SPACE] = "WR no space in the vg", + [ERR_WR_ENV_NOT_INITIALIZED] = "The WR env has not been initialized.", + [ERR_WR_CLI_EXEC_FAIL] = "WR client exec cmd '%s' failed, reason %s.", + [ERR_WR_FNODE_CHECK] = "WR fnode error, reason %s", + [ERR_WR_LOCK_TIMEOUT] = "WR lock timeout", + [ERR_WR_SERVER_IS_DOWN] = "WR server is down", + [ERR_WR_CHECK_SIZE] = "Failed to specify size %d which is not aligned with WR allocate-unit size %d", + [ERR_WR_MES_ILL] = "WR message contact error, reason %s", + [ERR_WR_STRING_TOO_LONG] = "The length(%u) of text can't be larger than %u, text = %s", + [ERR_WR_TCP_TIMEOUT_REMAIN] = "Waiting for request head(size) timeout, %d bytes remained", + [ERR_WR_UDS_INVALID_URL] = "Invalid unix domain socket url:%s, length %d. \ + Eg:server_locator=\"UDS:UNIX_emserver.domain\"", + [ERR_WR_RECV_MSG_FAILED] = "Recv msg failed, errcode:%d, inst:%u.", + [ERR_WR_INIT_LOGGER_FAILED] = "Log init failed.", + [ERR_WR_OUT_OF_MEM] = "Failed to apply for memory.", + [ERR_WR_INVALID_ID] = "Invalid %s id : %llu.", + [ERR_WR_PROCESS_REMOTE] = "Failed to process remote, errcode: %d, errmsg: %s.", + [ERR_WR_CONNECT_FAILED] = "Failed to connect wr server, errcode: %d, errmsg: %s.", + [ERR_WR_VERSION_NOT_MATCH] = + "[CHECK_PROTO]Protocol version need be changed, old protocol version is %u, new protocol version is %u.", + [ERR_WR_INVALID_BLOCK_TYPE] = "Get Invalid block type, expect type is %u, but the type in share memory is %u.", + [ERR_WR_SERVER_REBOOT] = "WR server has reboot or close, wr client need reboot or close.", + [ERR_WR_UNSUPPORTED_CMD] = + "Command \"%s\" is not supported in current version(%u) of wrserver, least supporting version is %u.", + [ERR_WR_VOLUME_FENCE_CHECK_COND] = "Fail to check fence cond:%s.", + [ERR_WR_MASTER_CHANGE] = "Master id has changed.", + [ERR_WR_RECOVER_CAUSE_BREAK] = "Req break by recovery.", +}; + +wr_log_def_t g_wr_cmd_log[] = { + {LOG_DEBUG, "debug/wrcmd.dlog"}, + {LOG_OPER, "oper/wrcmd.olog"}, + {LOG_RUN, "run/wrcmd.rlog"}, + {LOG_ALARM, "wrcmd_alarm.log"}, +}; + +wr_log_def_t g_wr_instance_log[] = { + {LOG_DEBUG, "debug/wrinstance.dlog"}, + {LOG_OPER, "oper/wrinstance.olog"}, + {LOG_RUN, "run/wrinstance.rlog"}, + {LOG_ALARM, "wrinstance_alarm.log"}, + {LOG_AUDIT, "audit/wrinstance.aud"}, + {LOG_BLACKBOX, "blackbox/wrinstance.blog"}, +}; + +uint32 g_wr_warn_id[] = { + WARN_WR_SPACEUSAGE_ID, +}; + +char *g_wr_warn_desc[] = { + "WRSpaceUsageUpToHWM", +}; + +#define WR_MAX_PRINT_LEVEL 4 +static char *g_wr_printf_tab[WR_MAX_PRINT_LEVEL] = {"", "\t", "\t\t", "\t\t\t"}; + +char *wr_get_print_tab(uint8 level) +{ + return g_wr_printf_tab[level]; +} + +wr_log_def_t *wr_get_instance_log_def() +{ + return g_wr_instance_log; +} +wr_log_def_t *wr_get_cmd_log_def() +{ + return g_wr_cmd_log; +} +uint32 wr_get_instance_log_def_count() +{ + return sizeof(g_wr_instance_log) / sizeof(wr_log_def_t); +} +uint32 wr_get_cmd_log_def_count() +{ + return sizeof(g_wr_cmd_log) / sizeof(wr_log_def_t); +} + +static status_t wr_init_log_file(log_param_t *log_param, wr_config_t *inst_cfg) +{ + int64 val_int64; + uint16 val_uint16; + char *value = NULL; + + value = cm_get_config_value(&inst_cfg->config, "_LOG_MAX_FILE_SIZE"); + status_t status = cm_str2size(value, &val_int64); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_LOG_MAX_FILE_SIZE")); + if (val_int64 < CM_MIN_LOG_FILE_SIZE || val_int64 > CM_MAX_LOG_FILE_SIZE) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_LOG_MAX_FILE_SIZE"); + return CM_ERROR; + } + log_param->max_log_file_size = (uint64)val_int64; + + value = cm_get_config_value(&inst_cfg->config, "_AUDIT_MAX_FILE_SIZE"); + status = cm_str2size(value, &val_int64); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_AUDIT_MAX_FILE_SIZE")); + if (val_int64 < CM_MIN_LOG_FILE_SIZE || val_int64 > CM_MAX_LOG_FILE_SIZE) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_AUDIT_MAX_FILE_SIZE"); + return CM_ERROR; + } + log_param->max_audit_file_size = (uint64)val_int64; + + value = cm_get_config_value(&inst_cfg->config, "_LOG_FILE_PERMISSIONS"); + status = cm_str2uint16(value, &val_uint16); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_LOG_FILE_PERMISSIONS")); + if (val_uint16 < CM_DEF_LOG_FILE_PERMISSIONS || val_uint16 > CM_MAX_LOG_PERMISSIONS) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_LOG_FILE_PERMISSIONS"); + return CM_ERROR; + } + cm_log_set_file_permissions(val_uint16); + + value = cm_get_config_value(&inst_cfg->config, "_LOG_PATH_PERMISSIONS"); + status = cm_str2uint16(value, &val_uint16); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_LOG_PATH_PERMISSIONS")); + if (val_uint16 < CM_DEF_LOG_PATH_PERMISSIONS || val_uint16 > CM_MAX_LOG_PERMISSIONS) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_LOG_PATH_PERMISSIONS"); + return CM_ERROR; + } + cm_log_set_path_permissions(val_uint16); + + return CM_SUCCESS; +} + +static status_t wr_init_log_home_ex(wr_config_t *inst_cfg, char *log_parm_value, char *log_param_name, char *log_dir) +{ + errno_t errcode = 0; + bool32 verify_flag = CM_FALSE; + // register error callback function + char *value = cm_get_config_value(&inst_cfg->config, log_param_name); + uint32 val_len = (value == NULL) ? 0 : (uint32)strlen(value); + if (val_len >= CM_MAX_LOG_HOME_LEN) { + WR_THROW_ERROR(ERR_INIT_LOGGER, "%s value: %s is out of range.", log_param_name, log_parm_value); + return CM_ERROR; + } + if (val_len > 0) { + errcode = strncpy_s(log_parm_value, CM_MAX_LOG_HOME_LEN, value, val_len); + securec_check_ret(errcode); + verify_flag = CM_TRUE; + } else { + char *home = wr_get_cfg_dir(inst_cfg); + if (snprintf_s(log_parm_value, CM_MAX_LOG_HOME_LEN, CM_MAX_LOG_HOME_LEN - 1, "%s/%s", home, log_dir) == -1) { + WR_ASSERT_LOG(0, "Init log dir:%s/%s failed.", home, log_dir); + } + } + status_t status = wr_verify_log_file_dir_name(log_parm_value); + WR_RETURN_IFERR2( + status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "failed to load params, invalid %s", log_param_name)); + if (verify_flag && wr_verify_log_file_real_path(log_parm_value) != CM_SUCCESS) { + WR_RETURN_IFERR2( + CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "failed to load params, invalid %s", log_param_name)); + } + return CM_SUCCESS; +} + +static status_t wr_init_log_home(wr_config_t *inst_cfg, log_param_t *log_param, char *alarm_dir) +{ + status_t status; + status = wr_init_log_home_ex(inst_cfg, log_param->log_home, "LOG_HOME", "log"); + if (status != CM_SUCCESS) { + return CM_ERROR; + } + status = wr_init_log_home_ex(inst_cfg, alarm_dir, "LOG_ALARM_HOME", "log/alarm"); + if (status != CM_SUCCESS) { + return CM_ERROR; + } + return CM_SUCCESS; +} +static status_t wr_load_log_compressed(wr_config_t *inst_cfg, log_param_t *log_param) +{ + char *value = cm_get_config_value(&inst_cfg->config, "LOG_COMPRESSED"); + if (cm_str_equal_ins(value, "TRUE")) { + log_param->log_compressed = CM_TRUE; + log_param->log_compress_buf = malloc(CM_LOG_COMPRESS_BUFSIZE); + if (log_param->log_compress_buf == NULL) { + log_param->log_compressed = CM_FALSE; + LOG_RUN_ERR("Failed to alloc compree buf when init log."); + WR_THROW_ERROR(ERR_WR_INIT_LOGGER_FAILED); + return CM_ERROR; + } + } else if (cm_str_equal_ins(value, "FALSE")) { + log_param->log_compressed = CM_FALSE; + log_param->log_compress_buf = NULL; + } else { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "LOG_COMPRESSED"); + return CM_ERROR; + } + LOG_RUN_INF("LOG_COMPRESSED = %u.", log_param->log_compressed); + return CM_SUCCESS; +} +static status_t wr_init_loggers_inner(wr_config_t *inst_cfg, log_param_t *log_param) +{ + uint32 val_uint32; + char *value = NULL; + + value = cm_get_config_value(&inst_cfg->config, "_LOG_BACKUP_FILE_COUNT"); + if (cm_str2uint32(value, &val_uint32) != CM_SUCCESS) { + CM_THROW_ERROR(ERR_INVALID_PARAM, "_LOG_BACKUP_FILE_COUNT"); + return CM_ERROR; +#ifdef OPENGAUSS + } else if (val_uint32 > CM_MAX_LOG_FILE_COUNT_LARGER) { +#else + } else if (val_uint32 > CM_MAX_LOG_FILE_COUNT) { +#endif + CM_THROW_ERROR(ERR_INVALID_PARAM, "_LOG_BACKUP_FILE_COUNT"); + return CM_ERROR; + } else { + log_param->log_backup_file_count = val_uint32; + } + + value = cm_get_config_value(&inst_cfg->config, "_AUDIT_BACKUP_FILE_COUNT"); + if (cm_str2uint32(value, &val_uint32) != CM_SUCCESS) { + CM_THROW_ERROR(ERR_INVALID_PARAM, "_AUDIT_BACKUP_FILE_COUNT"); + return CM_ERROR; +#ifdef OPENGAUSS + } else if (val_uint32 > CM_MAX_LOG_FILE_COUNT_LARGER) { +#else + } else if (val_uint32 > CM_MAX_LOG_FILE_COUNT) { +#endif + CM_THROW_ERROR(ERR_INVALID_PARAM, "_AUDIT_BACKUP_FILE_COUNT"); + return CM_ERROR; + } else { + log_param->audit_backup_file_count = val_uint32; + } + + status_t status = wr_init_log_file(log_param, inst_cfg); + WR_RETURN_IF_ERROR(status); + + value = cm_get_config_value(&inst_cfg->config, "_LOG_LEVEL"); + status = cm_str2uint32(value, (uint32 *)&log_param->log_level); + WR_RETURN_IFERR2(status, CM_THROW_ERROR(ERR_INVALID_PARAM, "_LOG_LEVEL")); + if (log_param->log_level > MAX_LOG_LEVEL) { + CM_THROW_ERROR(ERR_INVALID_PARAM, "_LOG_LEVEL"); + return CM_ERROR; + } + + value = cm_get_config_value(&inst_cfg->config, "_AUDIT_LEVEL"); + if (cm_str2uint32(value, (uint32 *)&log_param->audit_level) != CM_SUCCESS) { + CM_THROW_ERROR(ERR_INVALID_PARAM, "_AUDIT_LEVEL"); + return CM_ERROR; + } + if (log_param->audit_level > WR_AUDIT_ALL) { + CM_THROW_ERROR(ERR_INVALID_PARAM, "_AUDIT_LEVEL"); + return CM_ERROR; + } + return wr_load_log_compressed(inst_cfg, log_param); +} + +status_t wr_init_loggers(wr_config_t *inst_cfg, wr_log_def_t *log_def, uint32 log_def_count, char *name) +{ + char file_name[CM_FULL_PATH_BUFFER_SIZE]; + uint32 buffer_len = CM_FULL_PATH_BUFFER_SIZE; + log_param_t *log_param = cm_log_param_instance(); + log_param->log_level = 0; + char alarm_dir[CM_MAX_LOG_HOME_LEN]; + if (wr_init_log_home(inst_cfg, log_param, alarm_dir) != CM_SUCCESS) { + return CM_ERROR; + } + + if (wr_init_loggers_inner(inst_cfg, log_param) != CM_SUCCESS) { + return CM_ERROR; + } + + if (wr_init_log_file(log_param, inst_cfg) != CM_SUCCESS) { + return CM_ERROR; + } + + int32 ret; + for (size_t i = 0; i < log_def_count; i++) { + if (log_def[i].log_id == LOG_ALARM) { + ret = snprintf_s(file_name, buffer_len, (buffer_len - 1), "%s/%s", alarm_dir, log_def[i].log_filename); + } else { + ret = snprintf_s( + file_name, buffer_len, (buffer_len - 1), "%s/%s", log_param->log_home, log_def[i].log_filename); + } + WR_SECUREC_SS_RETURN_IF_ERROR(ret, CM_ERROR); + if (cm_log_init(log_def[i].log_id, file_name) != CM_SUCCESS) { + return CM_ERROR; + } + cm_log_open_compress(log_def[i].log_id, WR_TRUE); + } + log_param->log_instance_startup = CM_TRUE; + cm_init_error_handler(cm_set_log_error); + status_t status = cm_set_log_module_name(name, (int32)strlen(name)); + WR_RETURN_IF_ERROR(status); + errno_t rc = strcpy_sp(log_param->instance_name, CM_MAX_NAME_LEN, name); + if (rc != EOK) { + CM_THROW_ERROR(ERR_SYSTEM_CALL, rc); + return CM_ERROR; + } + LOG_RUN_INF("wr set log param _LOG_LEVEL, param_value = %u", log_param->log_level); + LOG_RUN_INF("wr set log param _AUDIT_LEVEL, param_value = %u", log_param->audit_level); + return CM_SUCCESS; +} + +static void sql_audit_init_assist( + wr_session_t *session, status_t status, wr_cmd_type_e cmd_type, wr_audit_assist_t *assist) +{ + int32 ret, tz_hour, tz_min; + const char *err_msg = NULL; + char *user_name = cm_sys_user_name(); + cs_get_remote_host(&session->pipe, assist->os_host); + MEMS_RETVOID_IFERR(strcpy_s(assist->db_user, CM_NAME_BUFFER_SIZE, (const char *)user_name)); + + // DATE + assist->tz = g_timer()->tz; + tz_hour = TIMEZONE_GET_HOUR(assist->tz); + tz_min = TIMEZONE_GET_MINUTE(assist->tz); + if (tz_hour >= 0) { + ret = snprintf_s(assist->date, CM_MAX_TIME_STRLEN, CM_MAX_TIME_STRLEN - 1, "UTC+%02d:%02d ", tz_hour, tz_min); + } else { + ret = snprintf_s(assist->date, CM_MAX_TIME_STRLEN, CM_MAX_TIME_STRLEN - 1, "UTC%02d:%02d ", tz_hour, tz_min); + } + if (ret == -1) { + WR_THROW_ERROR(ERR_SYSTEM_CALL, ret); + return; + } + + (void)cm_date2str( + g_timer()->now, "yyyy-mm-dd hh24:mi:ss.ff3", assist->date + ret, CM_MAX_TIME_STRLEN - (uint32)ret); + + // SESSIONID + assist->sid = (int32)session->id; + assist->session_id.str = assist->session_buf; + cm_int2text(assist->sid, &assist->session_id); + assist->session_id.str[assist->session_id.len] = '\0'; + + // RETURNCODE + assist->return_code.str = assist->return_code_buf; + assist->code = 0; + if (status != CM_SUCCESS) { + cm_get_error(&assist->code, &err_msg); + } + PRTS_RETVOID_IFERR( + snprintf_s(assist->return_code_buf, CM_MAX_NUMBER_LEN, CM_MAX_NUMBER_LEN - 1, "WR-%05d", assist->code)); + assist->return_code.len = (uint32)strlen(assist->return_code_buf); + assist->return_code.str[assist->return_code.len] = '\0'; +} + +static void sql_audit_create_message( + wr_audit_assist_t *assist, char *resource, char *action, char *log_msg, uint32 *log_msg_len) +{ + int32 ret = snprintf_s(log_msg, CM_T2S_LARGER_BUFFER_SIZE, CM_T2S_LARGER_BUFFER_SIZE - 1, + "SESSIONID:[%u] \"%s\" USER:[%u] \"%s\" HOST:[%u] \"%s\" " + "RESOURCE:[%u] \"%s\" ACTION:[%u] \"%s\" RETURNCODE:[%u] \"%s\" ", + assist->session_id.len, assist->session_id.str, // SESSIONID + (uint32)strlen(assist->db_user), assist->db_user, // USER + (uint32)strlen(assist->os_host), assist->os_host, // HOST + (uint32)strlen(resource), resource, // RESOURCE + (uint32)strlen(action), action, // ACTION + assist->return_code.len, assist->return_code.str); // RETURNCODE + if (SECUREC_UNLIKELY(ret == -1) || (uint32)(ret + 1) > CM_T2S_LARGER_BUFFER_SIZE) { + *log_msg_len = CM_T2S_LARGER_BUFFER_SIZE - 1; + log_msg[CM_T2S_LARGER_BUFFER_SIZE - 1] = '\0'; + return; + } + + *log_msg_len = (uint32)ret + 1; + log_msg[*log_msg_len - 1] = '\"'; + log_msg[*log_msg_len] = '\0'; +} + +static void sql_audit_log(wr_session_t *session, status_t status, uint8 cmd_type) +{ + wr_audit_assist_t assist = {0}; + char *log_msg = cm_get_t2s_addr(); + uint32 log_msg_len; + + sql_audit_init_assist(session, status, cmd_type, &assist); + sql_audit_create_message(&assist, session->audit_info.resource, session->audit_info.action, log_msg, &log_msg_len); + LOG_AUDIT("%s\nLENGTH: \"%u\"\n%s\n", assist.date, log_msg_len, log_msg); +} + +void sql_record_audit_log(void *sess, status_t status, uint8 cmd_type) +{ + if (cmd_type >= WR_CMD_QUERY_END) { + return; + } + wr_session_t *session = (wr_session_t *)sess; + uint32 audit_level = cm_log_param_instance()->audit_level; + if ((audit_level & WR_AUDIT_MODIFY) == 0 && cmd_type >= WR_CMD_MODIFY_BEGIN && cmd_type < WR_CMD_MODIFY_END) { + return; + } + if ((audit_level & WR_AUDIT_QUERY) == 0 && cmd_type >= WR_CMD_QUERY_BEGIN && cmd_type < WR_CMD_QUERY_END) { + return; + } + sql_audit_log(session, status, cmd_type); +} diff --git a/src/log/wr_log.h b/src/log/wr_log.h new file mode 100644 index 0000000000000000000000000000000000000000..5ab4aeb50c8dcb35baec4f853bf06b5de49ee837 --- /dev/null +++ b/src/log/wr_log.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_log.h + * + * + * IDENTIFICATION + * src/log/wr_log.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_LOG_H__ +#define __WR_LOG_H__ +#include "cm_log.h" +#include "cm_text.h" +#include "wr_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_wr_config wr_config_t; + +#define WR_AUDIT_ALL 255 + +#define WR_AUDIT_MODIFY 0x00000001 +#define WR_AUDIT_QUERY 0x00000002 + +typedef struct st_wr_log_def_t { + log_type_t log_id; + char log_filename[WR_MAX_NAME_LEN]; +} wr_log_def_t; + +typedef struct st_wr_audit_assist { + char date[CM_MAX_TIME_STRLEN]; + char session_buf[CM_MAX_NUMBER_LEN]; + char return_code_buf[CM_MAX_NUMBER_LEN]; + char os_host[CM_HOST_NAME_BUFFER_SIZE]; + char db_user[CM_NAME_BUFFER_SIZE]; + + text_t session_id; + text_t return_code; + + int32 sid; + int32 code; + int32 tz; +} wr_audit_assist_t; + +typedef struct st_wr_audit_info { + char *action; + char resource[WR_MAX_AUDIT_PATH_LENGTH]; +} wr_audit_info_t; + +#define WR_LOG_DEBUG_OP(user_fmt_str, ...) \ + do { \ + LOG_DEBUG_INF("[OP]" user_fmt_str, ##__VA_ARGS__); \ + } while (0) + +static inline void wr_print_detail_error() +{ + int32 errcode_print; + const char *errmsg_print = NULL; + cm_get_error(&errcode_print, &errmsg_print); + if (errcode_print != 0) { + (void)printf(" detail reason [%d] : %s\n", errcode_print, errmsg_print); + (void)fflush(stdout); + } + cm_reset_error(); +} +#define WR_PRINT_ERROR(fmt, ...) \ + do { \ + (void)printf(fmt, ##__VA_ARGS__); \ + LOG_DEBUG_ERR(fmt, ##__VA_ARGS__); \ + int32 errcode_print; \ + const char *errmsg_print = NULL; \ + cm_get_error(&errcode_print, &errmsg_print); \ + if (errcode_print != 0) { \ + (void)printf(" detail reason [%d] : %s\n", errcode_print, errmsg_print); \ + (void)fflush(stdout); \ + } \ + cm_reset_error(); \ + } while (0) + +#define WR_PRINT_RUN_ERROR(fmt, ...) \ + do { \ + (void)printf(fmt, ##__VA_ARGS__); \ + LOG_RUN_ERR(fmt, ##__VA_ARGS__); \ + int32 errcode_print; \ + const char *errmsg_print = NULL; \ + cm_get_error(&errcode_print, &errmsg_print); \ + if (errcode_print != 0) { \ + LOG_RUN_ERR(" detail reason [%d] : %s", errcode_print, errmsg_print); \ + (void)printf(" detail reason [%d] : %s\n", errcode_print, errmsg_print); \ + (void)fflush(stdout); \ + } \ + cm_reset_error(); \ + } while (0) + +#define WR_PRINT_INF(fmt, ...) \ + do { \ + (void)printf(fmt, ##__VA_ARGS__); \ + (void)fflush(stdout); \ + LOG_DEBUG_INF(fmt, ##__VA_ARGS__); \ + } while (0) + +#define WR_THROW_ERROR(error_no, ...) \ + do { \ + if (g_wr_error_desc[error_no] != NULL) \ + cm_set_error((char *)__FILE_NAME__, (uint32)__LINE__, (cm_errno_t)error_no, g_wr_error_desc[error_no], \ + ##__VA_ARGS__); \ + else \ + cm_set_error( \ + (char *)__FILE_NAME__, (uint32)__LINE__, (cm_errno_t)error_no, g_error_desc[error_no], ##__VA_ARGS__); \ + } while (0) + +#define WR_THROW_ERROR_EX(error_no, format, ...) \ + do { \ + cm_set_error((char *)__FILE_NAME__, (uint32)__LINE__, (cm_errno_t)error_no, format, ##__VA_ARGS__); \ + } while (0) + +/* + * warning id is composed of source + module + object + code + * source -- DN(10)/CM(11)/OM(12)/DM(20)/WR(30) + * module -- File(01)/Transaction(02)/HA(03)/Log(04)/Buffer(05)/Space(06)/Server(07) + * object -- Host Resource(01)/Run Environment(02)/Cluster Status(03)/ + * Instance Status(04)/Database Status(05)/Database Object(06) + * code -- 0001 and so on + */ +/* + * one warn must modify warn_id_t + * warn_name_t + * g_warn_id + * g_warning_desc + */ +typedef enum wr_warn_id { + WARN_WR_SPACEUSAGE_ID = 3006060001, +} wr_warn_id_t; + +typedef enum wr_warn_name { + WARN_WR_SPACEUSAGE, /* wr vg space */ +} wr_warn_name_t; + +typedef enum { WR_VG_SPACE_ALARM_INIT, WR_VG_SPACE_ALARM_HWM, WR_VG_SPACE_ALARM_LWM} wr_alarm_type_e; + +#define WR_ERROR_COUNT 3000 +extern const char *g_wr_error_desc[WR_ERROR_COUNT]; +extern char *g_wr_warn_desc[]; +extern uint32 g_wr_warn_id[]; +status_t wr_init_loggers(wr_config_t *inst_cfg, wr_log_def_t *log_def, uint32 log_def_count, char *name); +void sql_record_audit_log(void *sess, status_t status, uint8 cmd_type); +wr_log_def_t *wr_get_instance_log_def(); +wr_log_def_t *wr_get_cmd_log_def(); +uint32 wr_get_instance_log_def_count(); +uint32 wr_get_cmd_log_def_count(); + +char *wr_get_print_tab(uint8 level); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/params/wr_nodes_list.c b/src/params/wr_nodes_list.c new file mode 100644 index 0000000000000000000000000000000000000000..a54ccf6c02d19bcb0475798d5fad6a7824ddfa50 --- /dev/null +++ b/src/params/wr_nodes_list.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_nodes_list.c + * + * + * IDENTIFICATION + * src/params/wr_nodes_list.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_nodes_list.h" +#include "cm_log.h" +#include "cm_ip.h" +#include "cm_defs.h" +#include "cm_config.h" +#include "mes_interface.h" +#include "wr_param.h" +#include "wr_param_verify.h" +#include "wr_malloc.h" +#include "wr_errno.h" +#include "wr_log.h" +#include "wr_diskgroup.h" + +status_t wr_extract_nodes_list(char *nodes_list_str, wr_nodes_list_t *nodes_list) +{ + status_t status = cm_split_mes_urls(nodes_list->nodes, nodes_list->ports, nodes_list_str); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "WR_NODES_LIST format is wrong")); + int32 node_cnt = 0; + for (int i = 0; i < WR_MAX_INSTANCES; i++) { + if (nodes_list->ports[i] != 0) { + nodes_list->inst_map |= ((uint64)1 << i); + node_cnt++; + } + } + nodes_list->inst_cnt = (uint32)node_cnt; + LOG_RUN_INF("There are %d instances in incoming WR_NODES_LIST.", node_cnt); + return CM_SUCCESS; +} + +static status_t wr_alloc_and_extract_inst_addrs(char *nodes_list_str, uint32 *inst_cnt, mes_addr_t **inst_addrs) +{ + wr_nodes_list_t nodes_list; + securec_check_ret(memset_sp(&nodes_list, sizeof(wr_nodes_list_t), 0, sizeof(wr_nodes_list_t))); + CM_RETURN_IFERR(wr_extract_nodes_list(nodes_list_str, &nodes_list)); + size_t mes_addrs_size = nodes_list.inst_cnt * sizeof(mes_addr_t); + *inst_addrs = (mes_addr_t *)cm_malloc(mes_addrs_size); + if (*inst_addrs == NULL) { + WR_THROW_ERROR(ERR_ALLOC_MEMORY, mes_addrs_size, "wr_extract_inst_addrs"); + return CM_ERROR; + } + errno_t err = memset_sp(*inst_addrs, mes_addrs_size, 0, mes_addrs_size); + if (err != 0) { + CM_FREE_PTR(*inst_addrs); + CM_THROW_ERROR(ERR_SYSTEM_CALL, err); + return CM_ERROR; + } + mes_addr_t *inst_addr = &((*inst_addrs)[0]); + for (uint32 i = 0; i < WR_MAX_INSTANCES; ++i) { + if (nodes_list.ports[i] != 0) { + inst_addr->inst_id = i; + err = strcpy_sp(inst_addr->ip, sizeof(inst_addr->ip), nodes_list.nodes[i]); + if (err != EOK) { + CM_THROW_ERROR(ERR_SYSTEM_CALL, err); + CM_FREE_PTR(*inst_addrs); + return CM_ERROR; + } + inst_addr->port = nodes_list.ports[i]; + inst_addr->need_connect = CM_TRUE; + ++inst_addr; + } + } + *inst_cnt = nodes_list.inst_cnt; + return CM_SUCCESS; +} + +status_t wr_verify_nodes_list(void *lex, void *def) +{ + const char *nodes_list_str = (const char *)lex; + size_t len = strlen(nodes_list_str); + for (size_t i = 0; i < len; ++i) { + if ((nodes_list_str[i] != '|') && (!(CM_IS_DIGIT(nodes_list_str[i]))) && (nodes_list_str[i] != '.') && + (nodes_list_str[i] != ',')) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "WR_NODES_LIST contains invalid characters"); + return CM_ERROR; + } + } + + securec_check_ret(strcpy_sp(((wr_def_t *)def)->value, CM_PARAM_BUFFER_SIZE, nodes_list_str)); + return CM_SUCCESS; +} + +// addition or deletion of new instances is not allowed. +// only replacement of old instances is allowed. +static status_t check_nodes_list_validity(uint32 inst_cnt, const mes_addr_t *inst_addrs) +{ + if (inst_cnt != g_inst_cfg->params.nodes_list.inst_cnt) { + WR_THROW_ERROR( + ERR_WR_INVALID_PARAM, "instance_ids in WR_NODES_LIST are not allowed to be changed dynamically"); + return CM_ERROR; + } + for (uint32 i = 0; i < inst_cnt; ++i) { + uint32 inst_id = inst_addrs[i].inst_id; + if (inst_addrs[i].port == 0) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "IP ports in WR_NODES_LIST cannot be zero"); + return CM_ERROR; + } + // If some instance's IP port in params is 0, it doesnot exist in this cluster. + // Meantime, IP port of this instance in the new WR_NODES_LIST is not zero, which means + // the user is trying to add new instances. + if (g_inst_cfg->params.nodes_list.ports[inst_id] == 0) { + WR_THROW_ERROR( + ERR_WR_INVALID_PARAM, "instance_ids in WR_NODES_LIST are not allowed to be changed dynamically"); + return CM_ERROR; + } + } + LOG_RUN_INF("the user-inputted WR_NODES_LIST is valid."); + return CM_SUCCESS; +} + +static status_t modify_ips_in_params(uint32 inst_cnt, const mes_addr_t *inst_addrs) +{ + for (uint32 i = 0; i < inst_cnt; ++i) { + uint32 inst_id = inst_addrs[i].inst_id; + g_inst_cfg->params.nodes_list.ports[inst_id] = inst_addrs[i].port; + if (strcmp(g_inst_cfg->params.nodes_list.nodes[inst_id], inst_addrs[i].ip) != 0) { + securec_check_ret(strcpy_sp(g_inst_cfg->params.nodes_list.nodes[inst_id], CM_MAX_IP_LEN, inst_addrs[i].ip)); + } + } + return CM_SUCCESS; +} + +status_t wr_update_local_nodes_list(char *nodes_list_str) +{ + uint32 inst_cnt = 0; + mes_addr_t *inst_addrs = NULL; + CM_RETURN_IFERR(wr_alloc_and_extract_inst_addrs(nodes_list_str, &inst_cnt, &inst_addrs)); + CM_RETURN_IFERR(check_nodes_list_validity(inst_cnt, inst_addrs)); + status_t status = mes_update_instance(inst_cnt, inst_addrs); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to update local mes connections."); + CM_FREE_PTR(inst_addrs); + return status; + } + CM_RETURN_IFERR(modify_ips_in_params(inst_cnt, inst_addrs)); + LOG_RUN_INF("Success to update local mes connections."); + CM_FREE_PTR(inst_addrs); + return CM_SUCCESS; +} + +status_t wr_notify_wr_nodes_list(void *se, void *item, char *value) +{ + return wr_update_local_nodes_list(value); +} \ No newline at end of file diff --git a/src/params/wr_nodes_list.h b/src/params/wr_nodes_list.h new file mode 100644 index 0000000000000000000000000000000000000000..bcae8b3cf041b342491300b264ba773a5ec3f2d1 --- /dev/null +++ b/src/params/wr_nodes_list.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_nodes_list.h + * + * + * IDENTIFICATION + * src/params/wr_nodes_list.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_NODES_LIST_H__ +#define __WR_NODES_LIST_H__ + +#include "cm_types.h" +#include "cm_defs.h" +#include "wr_defs.h" + +typedef struct st_wr_nodes_list { + uint32 inst_cnt; + uint64 inst_map; + char nodes[WR_MAX_INSTANCES][CM_MAX_IP_LEN]; + uint16 ports[WR_MAX_INSTANCES]; +} wr_nodes_list_t; + +typedef struct st_wr_listen_addr { + char host[CM_MAX_IP_LEN]; + uint16 port; +} wr_listen_addr_t; + +status_t wr_extract_nodes_list(char *nodes_list_str, wr_nodes_list_t *nodes_list); +status_t wr_verify_nodes_list(void *lex, void *def); +status_t wr_notify_wr_nodes_list(void *se, void *item, char *value); + +#endif \ No newline at end of file diff --git a/src/params/wr_param.c b/src/params/wr_param.c new file mode 100644 index 0000000000000000000000000000000000000000..5affa25ee8fbeb4820769a752648a6bac2d05f59 --- /dev/null +++ b/src/params/wr_param.c @@ -0,0 +1,869 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_param.c + * + * + * IDENTIFICATION + * src/params/wr_param.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_errno.h" +#include "cm_num.h" +#include "cm_ip.h" +#include "cm_encrypt.h" +#include "cm_utils.h" +#include "wr_malloc.h" +#include "wr_param_verify.h" +#include "wr_fault_injection.h" +#include "wr_diskgroup.h" +#include "wr_param.h" +#include "wr_diskgroup.h" + +#ifdef __cplusplus +extern "C" { +#endif + +wr_config_t *g_inst_cfg = NULL; +static wr_config_t g_inst_cfg_inner = {0}; +wr_config_t *wr_get_g_inst_cfg() +{ + return &g_inst_cfg_inner; +} + +static config_item_t g_wr_params[] = { + /* name, isdefault, attr, default_value, value, runtime_value, description, range, datatype, comment, + id, effect, scale, verify, notify, notify_pfile, alias */ + {"SSL_CERT_NOTIFY_TIME", CM_TRUE, ATTR_READONLY, "30", NULL, NULL, "-", "[7,180]", "GS_TYPE_INTEGER", NULL, 0, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"WR_CM_SO_NAME", CM_TRUE, ATTR_READONLY, "", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 1, EFFECT_REBOOT, + CFG_INS, NULL, NULL, NULL, NULL}, + {"LOG_HOME", CM_TRUE, CM_TRUE, "", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 3, EFFECT_REBOOT, CFG_INS, NULL, + NULL, NULL, NULL}, + {"_LOG_BACKUP_FILE_COUNT", CM_TRUE, ATTR_NONE, "20", NULL, NULL, "-", "[0,128]", "GS_TYPE_INTEGER", NULL, 4, + EFFECT_REBOOT, CFG_INS, wr_verify_log_backup_file_count, wr_notify_log_backup_file_count, NULL, NULL}, + {"_LOG_MAX_FILE_SIZE", CM_TRUE, ATTR_NONE, "256M", NULL, NULL, "-", "[1M,4G]", "GS_TYPE_INTEGER", NULL, 5, + EFFECT_REBOOT, CFG_INS, wr_verify_log_file_size, wr_notify_log_file_size, NULL, NULL}, + {"INST_ID", CM_TRUE, ATTR_READONLY, "0", NULL, NULL, "-", "[0,64)", "GS_TYPE_INTEGER", NULL, 6, EFFECT_REBOOT, + CFG_INS, NULL, NULL, NULL, NULL}, + {"STORAGE_MODE", CM_TRUE, ATTR_READONLY, "DISK", NULL, NULL, "-", "CLUSTER_RAID,RAID,DISK", "GS_TYPE_VARCHAR", NULL, + 7, EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"_LOG_LEVEL", CM_TRUE, ATTR_NONE, "519", NULL, NULL, "-", "[0,4087]", "GS_TYPE_INTEGER", NULL, 8, + EFFECT_IMMEDIATELY, CFG_INS, wr_verify_log_level, wr_notify_log_level, NULL, NULL}, + {"MAX_SESSION_NUMS", CM_TRUE, ATTR_READONLY, "8192", NULL, NULL, "-", "[16,16320]", "GS_TYPE_INTEGER", NULL, 9, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"DISK_LOCK_INTERVAL", CM_TRUE, ATTR_READONLY, "100", NULL, NULL, "-", "[1,600000]", "GS_TYPE_INTEGER", NULL, 10, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"DLOCK_RETRY_COUNT", CM_TRUE, ATTR_READONLY, "50", NULL, NULL, "-", "[1,500000]", "GS_TYPE_INTEGER", NULL, 11, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"_AUDIT_BACKUP_FILE_COUNT", CM_TRUE, ATTR_NONE, "20", NULL, NULL, "-", "[0,128]", "GS_TYPE_INTEGER", NULL, 12, + EFFECT_REBOOT, CFG_INS, wr_verify_audit_backup_file_count, wr_notify_audit_backup_file_count, NULL, NULL}, + {"_AUDIT_MAX_FILE_SIZE", CM_TRUE, ATTR_NONE, "256M", NULL, NULL, "-", "[1M,4G]", "GS_TYPE_INTEGER", NULL, 13, + EFFECT_REBOOT, CFG_INS, wr_verify_audit_file_size, wr_notify_audit_file_size, NULL, NULL}, + {"_LOG_FILE_PERMISSIONS", CM_TRUE, ATTR_READONLY, "600", NULL, NULL, "-", "[600-777]", "GS_TYPE_INTEGER", NULL, 14, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"_LOG_PATH_PERMISSIONS", CM_TRUE, ATTR_READONLY, "700", NULL, NULL, "-", "[700-777]", "GS_TYPE_INTEGER", NULL, 15, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"SSL_PWD_CIPHERTEXT", CM_TRUE, ATTR_READONLY, "", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 16, EFFECT_REBOOT, + CFG_INS, NULL, NULL, NULL, NULL}, + {"_SHM_KEY", CM_TRUE, ATTR_READONLY, "1", NULL, NULL, "-", "[1,64]", "GS_TYPE_INTEGER", NULL, 17, EFFECT_REBOOT, + CFG_INS, NULL, NULL, NULL, NULL}, + {"WR_NODES_LIST", CM_TRUE, ATTR_NONE, "0:127.0.0.1:1611", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 18, + EFFECT_IMMEDIATELY, CFG_INS, wr_verify_nodes_list, wr_notify_wr_nodes_list, NULL, NULL}, + {"INTERCONNECT_TYPE", CM_TRUE, ATTR_READONLY, "TCP", NULL, NULL, "-", "TCP,RDMA", "GS_TYPE_VARCHAR", NULL, 19, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"INTERCONNECT_CHANNEL_NUM", CM_TRUE, ATTR_READONLY, "2", NULL, NULL, "-", "[1,32]", "GS_TYPE_INTEGER", NULL, 20, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"WORK_THREAD_COUNT", CM_TRUE, ATTR_READONLY, "8", NULL, NULL, "-", "[2,64]", "GS_TYPE_INTEGER", NULL, 21, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"RECV_MSG_POOL_SIZE", CM_TRUE, ATTR_READONLY, "48M", NULL, NULL, "-", "[9M,1G]", "GS_TYPE_INTEGER", NULL, 22, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"MES_ELAPSED_SWITCH", CM_TRUE, ATTR_READONLY, "FALSE", NULL, NULL, "-", "FALSE,TRUE", "GS_TYPE_BOOLEAN", NULL, 23, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"_DISK_LOCK_FILE_PATH", CM_TRUE, ATTR_READONLY, "/tmp", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 24, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"SSL_CA", CM_TRUE, ATTR_READONLY, "", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 25, EFFECT_REBOOT, CFG_INS, + NULL, NULL, NULL, NULL}, + {"SSL_KEY", CM_TRUE, ATTR_READONLY, "", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 26, EFFECT_REBOOT, CFG_INS, + NULL, NULL, NULL, NULL}, + {"SSL_CRL", CM_TRUE, ATTR_READONLY, "", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 27, EFFECT_REBOOT, CFG_INS, + NULL, NULL, NULL, NULL}, + {"SSL_CERT", CM_TRUE, ATTR_READONLY, "", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 28, EFFECT_REBOOT, CFG_INS, + NULL, NULL, NULL, NULL}, + {"SSL_CIPHER", CM_TRUE, ATTR_READONLY, "", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 29, EFFECT_REBOOT, + CFG_INS, NULL, NULL, NULL, NULL}, + {"POOL_NAMES", CM_TRUE, ATTR_READONLY, "", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 30, EFFECT_REBOOT, + CFG_INS, NULL, NULL, NULL, NULL}, + {"IMAGE_NAMES", CM_TRUE, ATTR_READONLY, "", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 31, EFFECT_REBOOT, + CFG_INS, NULL, NULL, NULL, NULL}, + {"VOLUME_TYPES", CM_TRUE, ATTR_READONLY, "", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 33, EFFECT_REBOOT, + CFG_INS, NULL, NULL, NULL, NULL}, + {"_AUDIT_LEVEL", CM_TRUE, ATTR_NONE, "1", NULL, NULL, "-", "[0,255]", "GS_TYPE_INTEGER", NULL, 34, + EFFECT_IMMEDIATELY, CFG_INS, wr_verify_audit_level, wr_notify_audit_level, NULL, NULL}, + {"SSL_PERIOD_DETECTION", CM_TRUE, ATTR_READONLY, "7", NULL, NULL, "-", "[1,180]", "GS_TYPE_INTEGER", NULL, 35, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"MES_WITH_IP", CM_TRUE, ATTR_READONLY, "FALSE", NULL, NULL, "-", "FALSE,TRUE", "GS_TYPE_BOOLEAN", NULL, 36, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"IP_WHITE_LIST_ON", CM_TRUE, ATTR_READONLY, "TRUE", NULL, NULL, "-", "FALSE,TRUE", "GS_TYPE_BOOLEAN", NULL, 37, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"IO_THREADS", CM_TRUE, ATTR_READONLY, "2", NULL, NULL, "-", "[1,8]", "GS_TYPE_INTEGER", NULL, 38, EFFECT_REBOOT, + CFG_INS, NULL, NULL, NULL, NULL}, + {"WORK_THREADS", CM_TRUE, ATTR_READONLY, "16", NULL, NULL, "-", "[16,128]", "GS_TYPE_INTEGER", NULL, 39, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"_BLACKBOX_DETAIL_ON", CM_TRUE, ATTR_NONE, "FALSE", NULL, NULL, "-", "FALSE,TRUE", "GS_TYPE_BOOLEAN", NULL, 40, + EFFECT_IMMEDIATELY, CFG_INS, wr_verify_blackbox_detail_on, wr_notify_blackbox_detail_on, NULL, NULL}, + {"CLUSTER_RUN_MODE", CM_TRUE, ATTR_NONE, "cluster_primary", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 41, + EFFECT_REBOOT, CFG_INS, wr_verify_cluster_run_mode, wr_notify_cluster_run_mode, NULL, NULL}, + {"XLOG_VG_ID", CM_TRUE, ATTR_READONLY, "1", NULL, NULL, "-", "[1,64]", "GS_TYPE_INTEGER", NULL, 42, EFFECT_REBOOT, + CFG_INS, NULL, NULL, NULL, NULL}, + {"MES_WAIT_TIMEOUT", CM_TRUE, ATTR_NONE, "10000", NULL, NULL, "-", "[500,30000]", "GS_TYPE_INTEGER", NULL, 43, + EFFECT_IMMEDIATELY, CFG_INS, wr_verify_mes_wait_timeout, wr_notify_mes_wait_timeout, NULL, NULL}, + {"_ENABLE_CORE_STATE_COLLECT", CM_TRUE, ATTR_NONE, "TRUE", NULL, NULL, "-", "[FALSE,TRUE]", "GS_TYPE_BOOLEAN", + NULL, 44, EFFECT_IMMEDIATELY, CFG_INS, wr_verify_enable_core_state_collect, + wr_notify_enable_core_state_collect, NULL, NULL}, + {"DELAY_CLEAN_INTERVAL", CM_TRUE, ATTR_NONE, "5", NULL, NULL, "-", "[5,1000000]", "GS_TYPE_INTEGER", NULL, 45, + EFFECT_IMMEDIATELY, CFG_INS, wr_verify_delay_clean_interval, wr_notify_delay_clean_interval, NULL, NULL}, + {"LOG_COMPRESSED", CM_TRUE, ATTR_READONLY, "FALSE", NULL, NULL, "-", "[FALSE,TRUE]", "GS_TYPE_BOOLEAN", NULL, 56, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"LOG_ALARM_HOME", CM_TRUE, ATTR_READONLY, "", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 59, EFFECT_REBOOT, + CFG_INS, NULL, NULL, NULL, NULL}, + {"VG_SPACE_USAGE_HWM", CM_TRUE, ATTR_READONLY, "80", NULL, NULL, "-", "[0, 100]", "GS_TYPE_INTEGER", NULL, 60, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"VG_SPACE_USAGE_LWM", CM_TRUE, ATTR_READONLY, "75", NULL, NULL, "-", "[0, 100]", "GS_TYPE_INTEGER", NULL, 61, + EFFECT_REBOOT, CFG_INS, NULL, NULL, NULL, NULL}, + {"LISTEN_ADDR", CM_TRUE, ATTR_READONLY, "127.0.0.1:1622", NULL, NULL, "-", "-", "GS_TYPE_VARCHAR", NULL, 62, EFFECT_REBOOT, + CFG_INS, NULL, NULL, NULL, NULL}, +}; + +static const char *g_wr_config_file = (const char *)"wr_inst.ini"; +#define WR_PARAM_COUNT (sizeof(g_wr_params) / sizeof(config_item_t)) + +static status_t wr_load_threadpool_cfg(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "IO_THREADS"); + int32 count = 0; + status_t status = cm_str2int(value, &count); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "IO_THREADS")); + + if (count < WR_MIN_IOTHREADS_CFG || count > WR_MAX_IOTHREADS_CFG) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "IO_THREADS"); + return CM_ERROR; + } + inst_cfg->params.iothread_count = (uint32)count; + + value = cm_get_config_value(&inst_cfg->config, "WORK_THREADS"); + status = cm_str2int(value, &count); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "WORK_THREADS")); + if (count < WR_MIN_WORKTHREADS_CFG || count > WR_MAX_WORKTHREADS_CFG) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "WORK_THREADS"); + return CM_ERROR; + } + inst_cfg->params.workthread_count = (uint32)count; + + return CM_SUCCESS; +} + +static status_t wr_load_session_cfg(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "MAX_SESSION_NUMS"); + int32 sessions; + status_t status = cm_str2int(value, &sessions); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "MAX_SESSION_NUMS")); + + if (sessions < WR_MIN_SESSIONID_CFG || sessions > WR_MAX_SESSIONS) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "MAX_SESSION_NUMS")); + } + + inst_cfg->params.cfg_session_num = (uint32)sessions; + return CM_SUCCESS; +} + +static status_t wr_load_disk_lock_file_path(wr_config_t *inst_cfg) +{ + int32 ret; + char *value = cm_get_config_value(&inst_cfg->config, "_DISK_LOCK_FILE_PATH"); + status_t status = wr_verify_lock_file_path(value); + WR_RETURN_IFERR2( + status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "failed to load params, invalid _DISK_LOCK_FILE_PATH")); + ret = snprintf_s(inst_cfg->params.disk_lock_file_path, WR_UNIX_PATH_MAX, WR_UNIX_PATH_MAX - 1, "%s", value); + if (ret == -1) { + WR_RETURN_IFERR2( + CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "failed to load params, invalid _DISK_LOCK_FILE_PATH")); + } + + return CM_SUCCESS; +} + +static status_t wr_load_storage_mode(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "STORAGE_MODE"); + if (cm_str_equal_ins(value, "CLUSTER_RAID")) { + inst_cfg->params.wr_mode = WR_MODE_CLUSTER_RAID; + } else if (cm_str_equal_ins(value, "SHARE_DISK")) { + inst_cfg->params.wr_mode = WR_MODE_SHARE_DISK; + } else if (cm_str_equal_ins(value, "DISK")) { + inst_cfg->params.wr_mode = WR_MODE_DISK; + } else { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, value)); + } + // _DISK_LOCK_FILE_PATH is only used when STORAGE_MODE=DISK. + // When STORAGE_MODE is SHARE_DISK or CLUSTER_RAID, _DISK_LOCK_FILE_PATH is loaded and verified, but not used. + CM_RETURN_IFERR(wr_load_disk_lock_file_path(inst_cfg)); + return CM_SUCCESS; +} + +static status_t wr_load_mes_pool_size(wr_config_t *inst_cfg) +{ + int64 mes_pool_size; + char *value = cm_get_config_value(&inst_cfg->config, "RECV_MSG_POOL_SIZE"); + status_t status = cm_str2size(value, &mes_pool_size); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "RECV_MSG_POOL_SIZE")); + + inst_cfg->params.mes_pool_size = (uint64)mes_pool_size; + if ((inst_cfg->params.mes_pool_size < WR_MIN_RECV_MSG_BUFF_SIZE) || + (inst_cfg->params.mes_pool_size > WR_MAX_RECV_MSG_BUFF_SIZE)) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "RECV_MSG_POOL_SIZE")); + } + LOG_RUN_INF("Cluster Raid mode, mes_pool_size = %lld.", mes_pool_size); + return CM_SUCCESS; +} + +static status_t wr_load_mes_url(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "WR_NODES_LIST"); + return wr_extract_nodes_list(value, &inst_cfg->params.nodes_list); +} + +static status_t wr_load_mes_conn_type(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "INTERCONNECT_TYPE"); + if (cm_str_equal_ins(value, "TCP")) { + inst_cfg->params.pipe_type = CS_TYPE_TCP; + } else if (cm_str_equal_ins(value, "RDMA")) { + inst_cfg->params.pipe_type = CS_TYPE_RDMA; + } else { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "INTERCONNECT_TYPE")); + } + LOG_RUN_INF("Cluster Raid mode, pipe type = %u.", inst_cfg->params.pipe_type); + return CM_SUCCESS; +} + +static status_t wr_load_mes_channel_num(wr_config_t *inst_cfg) +{ + uint32 channel_num; + char *value = cm_get_config_value(&inst_cfg->config, "INTERCONNECT_CHANNEL_NUM"); + status_t status = cm_str2uint32(value, &channel_num); + WR_RETURN_IFERR2( + status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "invalid parameter value of 'INTERCONNECT_CHANNEL_NUM'")); + + if (channel_num < CM_MES_MIN_CHANNEL_NUM || channel_num > CM_MES_MAX_CHANNEL_NUM) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "INTERCONNECT_CHANNEL_NUM")); + } + + inst_cfg->params.channel_num = channel_num; + LOG_RUN_INF("Cluster Raid mode, channel_num = %u.", inst_cfg->params.channel_num); + return CM_SUCCESS; +} + +static status_t wr_load_mes_work_thread_cnt(wr_config_t *inst_cfg) +{ + uint32 work_thread_cnt; + char *value = cm_get_config_value(&inst_cfg->config, "WORK_THREAD_COUNT"); + status_t status = cm_str2uint32(value, &work_thread_cnt); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "invalid parameter value of 'WORK_THREAD_COUNT'")); + + if (work_thread_cnt < WR_MIN_WORK_THREAD_COUNT || work_thread_cnt > WR_MAX_WORK_THREAD_COUNT) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "WORK_THREAD_COUNT")); + } + + inst_cfg->params.work_thread_cnt = work_thread_cnt; + LOG_RUN_INF("Cluster Raid mode, work_thread_cnt = %u.", inst_cfg->params.work_thread_cnt); + return CM_SUCCESS; +} + +static status_t wr_load_mes_elapsed_switch(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "MES_ELAPSED_SWITCH"); + if (cm_str_equal_ins(value, "TRUE")) { + inst_cfg->params.elapsed_switch = CM_TRUE; + } else if (cm_str_equal_ins(value, "FALSE")) { + inst_cfg->params.elapsed_switch = CM_FALSE; + } else { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "MES_ELAPSED_SWITCH")); + } + + LOG_RUN_INF("Cluster Raid mode, elapsed_switch = %u.", inst_cfg->params.elapsed_switch); + return CM_SUCCESS; +} + +static status_t wr_load_random_file(uchar *value, int32 value_len) +{ + char file_name[CM_FILE_NAME_BUFFER_SIZE]; + char dir_name[CM_FILE_NAME_BUFFER_SIZE]; + int32 handle; + int32 file_size; + PRTS_RETURN_IFERR(snprintf_s( + dir_name, CM_FILE_NAME_BUFFER_SIZE, CM_FILE_NAME_BUFFER_SIZE - 1, "%s/wr_protect", g_inst_cfg->home)); + if (!cm_dir_exist(dir_name)) { + WR_THROW_ERROR(ERR_WR_FILE_NOT_EXIST, "wr_protect", g_inst_cfg->home); + return CM_ERROR; + } + PRTS_RETURN_IFERR(snprintf_s(file_name, CM_FILE_NAME_BUFFER_SIZE, CM_FILE_NAME_BUFFER_SIZE - 1, "%s/wr_protect/%s", + g_inst_cfg->home, WR_FKEY_FILENAME)); + WR_RETURN_IF_ERROR(cs_ssl_verify_file_stat(file_name)); + WR_RETURN_IF_ERROR(cm_open_file_ex(file_name, O_SYNC | O_RDONLY | O_BINARY, S_IRUSR, &handle)); + status_t ret = cm_read_file(handle, value, value_len, &file_size); + cm_close_file(handle); + WR_RETURN_IF_ERROR(ret); + if (file_size < RANDOM_LEN + 1) { + LOG_DEBUG_ERR("Random component file %s is invalid, size is %d.", file_name, file_size); + return CM_ERROR; + } + return CM_SUCCESS; +} + +int32 wr_decrypt_pwd_cb(const char *cipher_text, uint32 cipher_len, char *plain_text, uint32 plain_len) +{ + if (cipher_text == NULL) { + WR_RETURN_IFERR3(CM_ERROR, CM_THROW_ERROR(ERR_INVALID_PARAM, "SSL_PWD_CIPHERTEXT"), + LOG_DEBUG_ERR("[WR] failed to decrypt SSL cipher: cipher is NULL")); + } + if (cipher_len == 0 || cipher_len >= WR_PARAM_BUFFER_SIZE) { + WR_RETURN_IFERR3(CM_ERROR, CM_THROW_ERROR(ERR_INVALID_PARAM, "SSL_PWD_CIPHERTEXT"), + LOG_DEBUG_ERR("[WR] failed to decrypt SSL cipher: cipher size [%u] is invalid.", cipher_len)); + } + if (plain_text == NULL) { + WR_RETURN_IFERR3(CM_ERROR, CM_THROW_ERROR(ERR_INVALID_PARAM, "SSL_PWD_CIPHERTEXT"), + LOG_DEBUG_ERR("[WR] failed to decrypt SSL cipher: plain is NULL")); + } + if (plain_len < CM_PASSWD_MAX_LEN) { + WR_RETURN_IFERR3(CM_ERROR, CM_THROW_ERROR(ERR_INVALID_PARAM, "SSL_PWD_CIPHERTEXT"), + LOG_DEBUG_ERR("[WR] failed to decrypt SSL cipher: plain len [%u] is invalid.", plain_len)); + } + cipher_t cipher; + if (cm_base64_decode(cipher_text, cipher_len, (uchar *)&cipher, (uint32)(sizeof(cipher_t) + 1)) == 0) { + WR_RETURN_IFERR3(CM_ERROR, CM_THROW_ERROR(ERR_INVALID_PARAM, "SSL_PWD_CIPHERTEXT"), + LOG_DEBUG_ERR("[WR] failed to decode SSL cipher.")); + } + if (cipher.cipher_len > 0) { + status_t status = wr_load_random_file(cipher.rand, (int32)sizeof(cipher.rand)); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_VALUE_ERROR, "[WR] load random component failed.")); + status = cm_decrypt_pwd(&cipher, (uchar *)plain_text, &plain_len); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_VALUE_ERROR, "[WR] failed to decrypt ssl pwd.")); + } else { + CM_THROW_ERROR(ERR_INVALID_PARAM, "SSL_PWD_CIPHERTEXT"); + LOG_DEBUG_ERR("[WR] failed to decrypt ssl pwd for the cipher len is invalid."); + return CM_ERROR; + } + return CM_SUCCESS; +} + +status_t wr_load_mes_ssl(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "SSL_CA"); + status_t status = wr_set_ssl_param("SSL_CA", value); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "SSL_CA")); + + value = cm_get_config_value(&inst_cfg->config, "SSL_KEY"); + status = wr_set_ssl_param("SSL_KEY", value); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "SSL_KEY")); + + value = cm_get_config_value(&inst_cfg->config, "SSL_CRL"); + status = wr_set_ssl_param("SSL_CRL", value); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "SSL_CRL")); + + value = cm_get_config_value(&inst_cfg->config, "SSL_CERT"); + status = wr_set_ssl_param("SSL_CERT", value); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "SSL_CERT")); + + value = cm_get_config_value(&inst_cfg->config, "SSL_CIPHER"); + status = wr_set_ssl_param("SSL_CIPHER", value); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "SSL_CIPHER")); + + value = cm_get_config_value(&inst_cfg->config, "SSL_CERT_NOTIFY_TIME"); + status = wr_set_ssl_param("SSL_CERT_NOTIFY_TIME", value); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "SSL_CERT_NOTIFY_TIME")); + uint32 alert_value; + status = cm_str2uint32(value, &alert_value); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "SSL_CERT_NOTIFY_TIME")); + value = cm_get_config_value(&inst_cfg->config, "SSL_PERIOD_DETECTION"); + status = cm_str2uint32(value, &inst_cfg->params.ssl_detect_day); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "SSL_PERIOD_DETECTION")); + if (inst_cfg->params.ssl_detect_day > WR_MAX_SSL_PERIOD_DETECTION || + inst_cfg->params.ssl_detect_day < WR_MIN_SSL_PERIOD_DETECTION) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "SSL_PERIOD_DETECTION"); + return CM_ERROR; + } + if (inst_cfg->params.ssl_detect_day > alert_value) { + WR_THROW_ERROR_EX(ERR_WR_INVALID_PARAM, + "SSL disabled: the value of SSL_PERIOD_DETECTION which is %u is " + "bigger than the value of SSL_CERT_NOTIFY_TIME which is %u.", + inst_cfg->params.ssl_detect_day, alert_value); + return CM_ERROR; + } + value = cm_get_config_value(&inst_cfg->config, "SSL_PWD_CIPHERTEXT"); + status = wr_set_ssl_param("SSL_PWD_CIPHERTEXT", value); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "SSL_PWD_CIPHERTEXT")); + + if (!CM_IS_EMPTY_STR(value)) { + return mes_register_decrypt_pwd(wr_decrypt_pwd_cb); + } + return CM_SUCCESS; +} + +static status_t wr_load_mes_wait_timeout(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "MES_WAIT_TIMEOUT"); + int32 timeout = 0; + status_t status = cm_str2int(value, &timeout); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "MES_WAIT_TIMEOUT")); + if (timeout < WR_MES_MIN_WAIT_TIMEOUT || timeout > WR_MES_MAX_WAIT_TIMEOUT) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "MES_WAIT_TIMEOUT"); + return CM_ERROR; + } + inst_cfg->params.mes_wait_timeout = (uint32)timeout; + return CM_SUCCESS; +} + +static status_t wr_load_mes_params(wr_config_t *inst_cfg) +{ + CM_RETURN_IFERR(wr_load_mes_url(inst_cfg)); + CM_RETURN_IFERR(wr_load_mes_conn_type(inst_cfg)); + CM_RETURN_IFERR(wr_load_mes_channel_num(inst_cfg)); + CM_RETURN_IFERR(wr_load_mes_work_thread_cnt(inst_cfg)); + CM_RETURN_IFERR(wr_load_mes_pool_size(inst_cfg)); + CM_RETURN_IFERR(wr_load_mes_elapsed_switch(inst_cfg)); + CM_RETURN_IFERR(wr_load_mes_ssl(inst_cfg)); + CM_RETURN_IFERR(wr_load_mes_wait_timeout(inst_cfg)); + return CM_SUCCESS; +} + +static status_t wr_load_disk_lock_interval(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "DISK_LOCK_INTERVAL"); + int32 lock_interval; + + status_t status = cm_str2int(value, &lock_interval); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "DISK_LOCK_INTERVAL")); + + if (lock_interval < WR_MIN_LOCK_INTERVAL || lock_interval > WR_MAX_LOCK_INTERVAL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "DISK_LOCK_INTERVAL")); + } + inst_cfg->params.lock_interval = lock_interval; + + return CM_SUCCESS; +} + +static status_t wr_load_dlock_retry_count(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "DLOCK_RETRY_COUNT"); + uint32 dlock_retry_count; + + status_t status = cm_str2uint32(value, &dlock_retry_count); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "DLOCK_RETRY_COUNT")); + + if (dlock_retry_count < WR_MIN_DLOCK_RETRY_COUNT || dlock_retry_count > WR_MAX_DLOCK_RETRY_COUNT) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "DLOCK_RETRY_COUNT")); + } + inst_cfg->params.dlock_retry_count = dlock_retry_count; + + return CM_SUCCESS; +} + +static status_t wr_load_cluster_run_mode(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "CLUSTER_RUN_MODE"); + + if (strcmp(value, "cluster_standby") == 0) { + inst_cfg->params.cluster_run_mode = CLUSTER_STANDBY; + LOG_RUN_INF("The cluster_run_mode is cluster_standby."); + } else if (strcmp(value, "cluster_primary") == 0) { + inst_cfg->params.cluster_run_mode = CLUSTER_PRIMARY; + LOG_RUN_INF("The cluster_run_mode is cluster_primary."); + } else { + WR_RETURN_IFERR2( + CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "failed to load params, invalid CLUSTER_RUN_MODE")); + } + return CM_SUCCESS; +} + +static status_t wr_load_listen_addr(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "LISTEN_ADDR"); + if (value == NULL) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "LISTEN_ADDR is not set"); + return CM_ERROR; + } + + char buffer[256]; + strncpy(buffer, value, sizeof(buffer) - 1); + buffer[sizeof(buffer) - 1] = '\0'; + + char *colon_pos = strchr(buffer, ':'); + if (colon_pos == NULL) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "LISTEN_ADDR format is invalid, expected IP:Port"); + return CM_ERROR; + } + + *colon_pos = '\0'; + char *ip = buffer; + char *port_str = colon_pos + 1; + + int port = atoi(port_str); + if (port <= 0 || port > 65535) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "Port number is invalid"); + return CM_ERROR; + } + + strncpy(inst_cfg->params.listen_addr.host, ip, sizeof(inst_cfg->params.listen_addr.host) - 1); + inst_cfg->params.listen_addr.host[sizeof(inst_cfg->params.listen_addr.host) - 1] = '\0'; + inst_cfg->params.listen_addr.port = port; + + return CM_SUCCESS; +} + +static status_t wr_load_xlog_vg_id(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "XLOG_VG_ID"); + int32 xlog_vg_id = 0; + status_t status = cm_str2int(value, &xlog_vg_id); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "XLOG_VG_ID")); + + /* the redo log of metadata in vg0, vg0 can not be synchronous copy disk */ + if (xlog_vg_id < 1 || xlog_vg_id > 64) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "XLOG_VG_ID")); + } + + inst_cfg->params.xlog_vg_id = (uint32)xlog_vg_id; + LOG_RUN_INF("The xlog vg id is %d.", inst_cfg->params.xlog_vg_id); + return CM_SUCCESS; +} + +status_t wr_set_cfg_dir(const char *home, wr_config_t *inst_cfg) +{ + char home_realpath[WR_MAX_PATH_BUFFER_SIZE]; + bool8 is_home_empty = (home == NULL || home[0] == '\0'); + if (is_home_empty) { + const char *home_env = getenv(WR_ENV_HOME); + if (home_env == NULL || home_env[0] == '\0') { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "invalid cfg dir")); + } + uint32 len = (uint32)strlen(home_env); + if (len >= WR_MAX_PATH_BUFFER_SIZE) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "invalid cfg dir len")); + } + status_t status = realpath_file(home_env, home_realpath, WR_MAX_PATH_BUFFER_SIZE); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "invalid cfg dir")); + + } else { + uint32 len = (uint32)strlen(home); + if (len >= WR_MAX_PATH_BUFFER_SIZE) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "invalid cfg dir"); + return CM_ERROR; + } + } + int32 iret_snprintf = snprintf_s(inst_cfg->home, WR_MAX_PATH_BUFFER_SIZE, WR_MAX_PATH_BUFFER_SIZE - 1, "%s", + is_home_empty ? home_realpath : home); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + + iret_snprintf = snprintf_s(inst_cfg->data_dir, WR_MAX_PATH_BUFFER_SIZE, WR_MAX_PATH_BUFFER_SIZE - 1, "%s/data", + is_home_empty ? home_realpath : home); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + g_inst_cfg = inst_cfg; + return CM_SUCCESS; +} + +static status_t wr_load_instance_id(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "INST_ID"); + status_t status = cm_str2bigint(value, &inst_cfg->params.inst_id); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "the value of 'INST_ID' is invalid")); + + if (inst_cfg->params.inst_id < WR_MIN_INST_ID || inst_cfg->params.inst_id >= WR_MAX_INST_ID) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "the value of 'INST_ID' is invalid")); + } + + LOG_RUN_INF("The instanceid is %lld.", inst_cfg->params.inst_id); + return CM_SUCCESS; +} + +static status_t wr_load_ip_white_list(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "IP_WHITE_LIST_ON"); + if (cm_str_equal_ins(value, "TRUE")) { + inst_cfg->params.ip_white_list_on = CM_TRUE; + } else if (cm_str_equal_ins(value, "FALSE")) { + inst_cfg->params.ip_white_list_on = CM_FALSE; + } else { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "value of IP_WHITE_LIST_ON is invalid")); + } + LOG_DEBUG_INF("IP_WHITE_LIST status: %u. (0: off, 1: on)", inst_cfg->params.ip_white_list_on); + return CM_SUCCESS; +} + +static status_t wr_load_mes_with_ip(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "MES_WITH_IP"); + if (cm_str_equal_ins(value, "TRUE")) { + inst_cfg->params.mes_with_ip = CM_TRUE; + } else if (cm_str_equal_ins(value, "FALSE")) { + inst_cfg->params.mes_with_ip = CM_FALSE; + } else { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "MES_WITH_IP")); + } + LOG_DEBUG_INF("MES_WITH_IP status: %u. (0: off, 1: on)", inst_cfg->params.mes_with_ip); + return CM_SUCCESS; +} + +static status_t wr_load_shm_key(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "_SHM_KEY"); + // 单个机器上最多允许(1<params.shm_key); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("invalid parameter value of '_SHM_KEY', value:%s.", value)); + + if (inst_cfg->params.shm_key < WR_MIN_SHM_KEY || inst_cfg->params.shm_key > WR_MAX_SHM_KEY) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "the value of '_SHM_KEY' is invalid")); + } + LOG_RUN_INF("_SHM_KEY is %u.", inst_cfg->params.shm_key); + return CM_SUCCESS; +} + +static status_t wr_load_blackbox_detail_on(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "_BLACKBOX_DETAIL_ON"); + return wr_load_blackbox_detail_on_inner(value, inst_cfg); +} + +static status_t wr_load_enable_core_state_collect(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "_ENABLE_CORE_STATE_COLLECT"); + return wr_load_enable_core_state_collect_inner(value, inst_cfg); +} + +status_t wr_load_delay_clean_interval_core(char *value, wr_config_t *inst_cfg) +{ + uint32 delay_clean_interval; + + status_t status = cm_str2uint32(value, &delay_clean_interval); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "DELAY_CLEAN_INTERVAL")); + + if (delay_clean_interval < WR_MIN_DELAY_CLEAN_INTERVAL || delay_clean_interval > WR_MAX_DELAY_CLEAN_INTERVAL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "DELAY_CLEAN_INTERVAL")); + } + inst_cfg->params.delay_clean_interval = delay_clean_interval; + LOG_RUN_INF("DELAY_CLEAN_INTERVAL = %u.", inst_cfg->params.delay_clean_interval); + return CM_SUCCESS; +} + +static status_t wr_load_delay_clean_interval(wr_config_t *inst_cfg) +{ + char *value = cm_get_config_value(&inst_cfg->config, "DELAY_CLEAN_INTERVAL"); + return wr_load_delay_clean_interval_core(value, inst_cfg); +} + +static status_t wr_load_space_usage(wr_config_t *inst_cfg) +{ + char *hwm_value = cm_get_config_value(&inst_cfg->config, "VG_SPACE_USAGE_HWM"); + char *lwm_value = cm_get_config_value(&inst_cfg->config, "VG_SPACE_USAGE_LWM"); + int32 hwm, lwm; + status_t status = cm_str2int(hwm_value, &hwm); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "VG_SPACE_USAGE_HWM")); + status = cm_str2int(lwm_value, &lwm); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "VG_SPACE_USAGE_LWM")); + if (hwm > WR_VG_USAGE_MAX) { + WR_RETURN_IFERR2( + CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "VG_SPACE_USAGE_HWM is greater than maximum 100")); + } + if (lwm < WR_VG_USAGE_MIN) { + WR_RETURN_IFERR2( + CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "VG_SPACE_USAGE_LWM is less than minimum 0")); + } + if (lwm > hwm) { + WR_RETURN_IFERR2( + CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "VG_SPACE_USAGE_LWM is greater than VG_SPACE_USAGE_HWM")); + } + inst_cfg->params.space_usage_hwm = (uint32)hwm; + inst_cfg->params.space_usage_lwm = (uint32)lwm; + return CM_SUCCESS; +} + +status_t wr_load_config(wr_config_t *inst_cfg) +{ + char file_name[WR_FILE_NAME_BUFFER_SIZE]; + errno_t ret = memset_sp(&inst_cfg->params, sizeof(wr_params_t), 0, sizeof(wr_params_t)); + if (ret != EOK) { + return CM_ERROR; + } + + // get config info + ret = snprintf_s(file_name, WR_FILE_NAME_BUFFER_SIZE, WR_FILE_NAME_BUFFER_SIZE - 1, "%s/cfg/%s", inst_cfg->home, + g_wr_config_file); + if (ret == -1) { + WR_RETURN_IFERR2( + CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "failed to load params, invalid config file path")); + } + + status_t status = cm_load_config(g_wr_params, WR_PARAM_COUNT, file_name, &inst_cfg->config, CM_FALSE); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "failed to load config")); + if (wr_is_server()) { + status = wr_init_loggers(inst_cfg, wr_get_instance_log_def(), wr_get_instance_log_def_count(), "wrserver"); + WR_RETURN_IFERR2(status, (void)printf("%s\nWR init loggers failed!\n", cm_get_errormsg(cm_get_error_code()))); + log_param_t *log_param = cm_log_param_instance(); + log_param->log_instance_starting = CM_TRUE; + } + CM_RETURN_IFERR(wr_load_instance_id(inst_cfg)); + CM_RETURN_IFERR(wr_load_storage_mode(inst_cfg)); + CM_RETURN_IFERR(wr_load_session_cfg(inst_cfg)); + CM_RETURN_IFERR(wr_load_disk_lock_interval(inst_cfg)); + CM_RETURN_IFERR(wr_load_dlock_retry_count(inst_cfg)); + CM_RETURN_IFERR(wr_load_mes_params(inst_cfg)); + CM_RETURN_IFERR(wr_load_shm_key(inst_cfg)); + CM_RETURN_IFERR(wr_load_mes_with_ip(inst_cfg)); + CM_RETURN_IFERR(wr_load_ip_white_list(inst_cfg)); + CM_RETURN_IFERR(wr_load_threadpool_cfg(inst_cfg)); + CM_RETURN_IFERR(wr_load_blackbox_detail_on(inst_cfg)); + CM_RETURN_IFERR(wr_load_cluster_run_mode(inst_cfg)); + CM_RETURN_IFERR(wr_load_listen_addr(inst_cfg)); + CM_RETURN_IFERR(wr_load_xlog_vg_id(inst_cfg)); + CM_RETURN_IFERR(wr_load_enable_core_state_collect(inst_cfg)); + CM_RETURN_IFERR(wr_load_delay_clean_interval(inst_cfg)); + CM_RETURN_IFERR(wr_load_space_usage(inst_cfg)); + + return CM_SUCCESS; +} + +status_t wr_set_ssl_param(const char *param_name, const char *param_value) +{ + if (param_name == NULL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "the ssl param name should not be null.")); + } + if ((cm_str_equal(param_name, "SSL_PWD_PLAINTEXT") || cm_str_equal(param_name, "SSL_PWD_CIPHERTEXT")) && + strlen(param_value) != 0) { + LOG_RUN_INF("wr set ssl param, param_name=%s param_value=%s", param_name, "***"); + } else { + LOG_RUN_INF("wr set ssl param, param_name=%s param_value=%s", param_name, param_value); + } + cbb_param_t param_type; + param_value_t out_value; + CM_RETURN_IFERR(mes_chk_md_param(param_name, param_value, ¶m_type, &out_value)); + status_t status = mes_set_md_param(param_type, &out_value); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, param_name)); + return CM_SUCCESS; +} + +void wr_ssl_ca_cert_expire(void) +{ + if ((g_timer()->systime / SECONDS_PER_DAY) % g_inst_cfg->params.ssl_detect_day == 0) { + (void)mes_chk_ssl_cert_expire(); + } +} + +static status_t wr_set_cfg_param_core(text_t *text, char *value, wr_def_t *def) +{ + bool32 force = CM_TRUE; + config_item_t *item = cm_get_config_item(&g_inst_cfg->config, text, CM_TRUE); + if (item == NULL || item->attr != ATTR_NONE) { + WR_RETURN_IFERR2(CM_ERROR, CM_THROW_ERROR(ERR_INVALID_PARAM, def->name)); + } + + if ((item->verify) && (item->verify((void *)value, (void *)def) != CM_SUCCESS)) { + return CM_ERROR; + } + + if (def->scope != CONFIG_SCOPE_DISK) { + if (item->notify && item->notify(NULL, (void *)item, def->value)) { + return CM_ERROR; + } + } else { + if (item->notify_pfile && item->notify_pfile(NULL, (void *)item, def->value)) { + return CM_ERROR; + } + } + + if (item->attr & ATTR_READONLY) { +#if defined(_DEBUG) || defined(DEBUG) || defined(DB_DEBUG_VERSION) + force = CM_TRUE; +#else + force = CM_FALSE; // can not alter parameter whose attr is readonly for release +#endif + } + if (cm_alter_config(&g_inst_cfg->config, def->name, def->value, def->scope, force) != CM_SUCCESS) { + return CM_ERROR; + } + LOG_RUN_INF("parameter %s has been changed successfully, new value is %s", def->name, value); + return CM_SUCCESS; +} + +static latch_t g_wr_set_cfg_latch = {0, 0, 0, 0, 0}; +status_t wr_set_cfg_param(char *name, char *value, char *scope) +{ + CM_ASSERT(name != NULL); + CM_ASSERT(value != NULL); + CM_ASSERT(scope != NULL); + + // 1. parse name + wr_def_t def; + text_t text = {.str = name, .len = (uint32)strlen(name)}; + if (text.len == 0) { + WR_RETURN_IFERR2(CM_ERROR, CM_THROW_ERROR(ERR_INVALID_PARAM, text.str)); + } + cm_trim_text(&text); + cm_text_upper(&text); + CM_RETURN_IFERR(cm_text2str(&text, def.name, CM_PARAM_BUFFER_SIZE)); + + // 2. parse scope + if (strcmp(scope, "memory") == 0) { + def.scope = CONFIG_SCOPE_MEMORY; + } else if (strcmp(scope, "pfile") == 0) { + def.scope = CONFIG_SCOPE_DISK; + } else { + def.scope = CONFIG_SCOPE_BOTH; + } + wr_latch_x(&g_wr_set_cfg_latch); + status_t status = wr_set_cfg_param_core(&text, value, &def); + wr_unlatch(&g_wr_set_cfg_latch); + return status; +} + +status_t wr_get_cfg_param(const char *name, char **value) +{ + CM_ASSERT(name != NULL); + wr_def_t def; + text_t text = {.str = (char *)name, .len = (uint32)strlen(name)}; + if (text.len == 0) { + WR_RETURN_IFERR2(CM_ERROR, CM_THROW_ERROR(ERR_INVALID_PARAM, text.str)); + } + + cm_trim_text(&text); + cm_text_upper(&text); + CM_RETURN_IFERR(cm_text2str(&text, def.name, CM_NAME_BUFFER_SIZE)); + + *value = cm_get_config_value(&g_inst_cfg->config, def.name); + if (*value == NULL) { + CM_THROW_ERROR(ERR_INVALID_VALUE, name); + return CM_ERROR; + } + + return CM_SUCCESS; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/params/wr_param.h b/src/params/wr_param.h new file mode 100644 index 0000000000000000000000000000000000000000..b83abb6ebe4b267cb39283adcd304d48bd0b8d8e --- /dev/null +++ b/src/params/wr_param.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_param.h + * + * + * IDENTIFICATION + * src/params/wr_param.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_PARAM_H__ +#define __WR_PARAM_H__ + +#include "wr_defs.h" +#include "wr_log.h" +#include "cm_config.h" +#include "cs_pipe.h" +#include "mes_metadata.h" +#include "mes_interface.h" +#include "wr_errno.h" +#include "wr_api.h" +#include "wr_nodes_list.h" +#ifdef __cplusplus +extern "C" { +#endif + +#define WR_MIN_WORK_THREAD_COUNT (2) +#define WR_MAX_WORK_THREAD_COUNT (64) +// for most time, standby nodes rerad meta from primary +#define WR_WORK_THREAD_LOAD_DATA_PERCENT 0.5 + +#define WR_MES_MAX_WAIT_TIMEOUT 30000 // 30s +#define WR_MES_MIN_WAIT_TIMEOUT 500 // 500ms + +#define WR_MIN_RECV_MSG_BUFF_SIZE (uint64) SIZE_M(9) +#define WR_MAX_RECV_MSG_BUFF_SIZE (uint64) SIZE_G(1) + +typedef enum en_wr_mode { + WR_MODE_UNKNOWN = 0, + WR_MODE_CLUSTER_RAID = 1, // MULTI DATANODE's RAID + WR_MODE_SHARE_DISK = 2, // SHARE DISK LOCK + WR_MODE_DISK = 3 // A DATANODE's DISK +} wr_mode_e; + +/* use for dorado cluster */ +typedef enum cluster_run_mode_t { CLUSTER_PRIMARY = 0, CLUSTER_STANDBY = 1 } cluster_run_mode_t; + +#if defined(_DEBUG) || defined(DEBUG) || defined(DB_DEBUG_VERSION) +#define WR_RECYLE_META_RANGE_MAX 10000U +#endif + +typedef struct st_wr_recycle_meta_pos { + uint32 hwm; // trigger to recycle, the unit is 0.01% + uint32 lwm; // mark to end recycle, the unit is 0.01% +} wr_recycle_meta_pos_t; + +typedef struct st_wr_params { + char *root_name; // root volume name + int64 inst_id; + char disk_lock_file_path[WR_UNIX_PATH_MAX]; + int32 wr_mode; + uint32 cfg_session_num; + int32 lock_interval; + uint32 dlock_retry_count; + + uint64 mes_pool_size; + wr_nodes_list_t nodes_list; + wr_listen_addr_t listen_addr; // listen addr + uint32 channel_num; + uint32 work_thread_cnt; + cs_pipe_type_t pipe_type; + bool32 elapsed_switch; + uint32 shm_key; + uint32 ssl_detect_day; + bool32 mes_with_ip; + bool32 ip_white_list_on; + uint32 iothread_count; + uint32 workthread_count; + uint32 xlog_vg_id; + bool32 blackbox_detail_on; + uint32 mes_wait_timeout; + bool32 enable_core_state_collect; + uint32 delay_clean_interval; + cluster_run_mode_t cluster_run_mode; + wr_recycle_meta_pos_t recyle_meta_pos; + uint32 space_usage_hwm; + uint32 space_usage_lwm; +} wr_params_t; + +typedef struct st_wr_config { + char home[WR_MAX_PATH_BUFFER_SIZE]; + char data_dir[WR_MAX_PATH_BUFFER_SIZE]; + config_t config; + wr_params_t params; +} wr_config_t; +extern wr_config_t *g_inst_cfg; +wr_config_t *wr_get_g_inst_cfg(); + +#define WR_UNIX_DOMAIN_SOCKET_NAME ".wr_unix_d_socket" +#define WR_MAX_SSL_PERIOD_DETECTION 180 +#define WR_MIN_SSL_PERIOD_DETECTION 1 + +status_t wr_load_config(wr_config_t *inst_cfg); +status_t wr_set_cfg_dir(const char *home, wr_config_t *inst_cfg); + +static inline int32 wr_storage_mode(wr_config_t *inst_cfg) +{ + return inst_cfg->params.wr_mode; +} + +static inline char *wr_get_cfg_dir(wr_config_t *inst_cfg) +{ + return inst_cfg->home; +} + +/* + * @brief set ssl relevant param + * @[in] param name(SSL_CA、SSL_KEY、SSL_PWD_PLAINTEXT、SSL_CERT). + * @[in] param value--ssl cert or ssl key + * @* @return CM_SUCCESS - success;otherwise: failed + */ +status_t wr_set_ssl_param(const char *param_name, const char *param_value); + +/* + * @brief get ssl relevant param + * @[in] param name(SSL_CA、SSL_KEY、SSL_PWD_PLAINTEXT、SSL_CERT). + * @[in]size--ssl cert or ssl key size + * @[out]param value--ssl cert or ssl key + * @* @return CM_SUCCESS - success;otherwise: failed + */ +inline status_t wr_get_ssl_param(const char *param_name, char *param_value, uint32 size) +{ + if (param_name == NULL) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "the ssl param name should not be null."); + return CM_ERROR; + } + return mes_get_md_param_by_name(param_name, param_value, size); +} +void wr_ssl_ca_cert_expire(void); + +status_t wr_set_cfg_param(char *name, char *value, char *scope); +status_t wr_get_cfg_param(const char *name, char **value); +status_t wr_load_delay_clean_interval_core(char *value, wr_config_t *inst_cfg); + +static inline status_t wr_load_blackbox_detail_on_inner(char *value, wr_config_t *inst_cfg) +{ + if (cm_str_equal_ins(value, "TRUE")) { + inst_cfg->params.blackbox_detail_on = CM_TRUE; + } else if (cm_str_equal_ins(value, "FALSE")) { + inst_cfg->params.blackbox_detail_on = CM_FALSE; + } else { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_BLACKBOX_DETAIL_ON"); + return CM_ERROR; + } + LOG_RUN_INF("_BLACKBOX_DETAIL_ON = %u.", inst_cfg->params.blackbox_detail_on); + return CM_SUCCESS; +} + +static inline status_t wr_load_enable_core_state_collect_inner(char *value, wr_config_t *inst_cfg) +{ + if (cm_str_equal_ins(value, "TRUE")) { + inst_cfg->params.enable_core_state_collect = CM_TRUE; + } else if (cm_str_equal_ins(value, "FALSE")) { + inst_cfg->params.enable_core_state_collect = CM_FALSE; + } else { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_ENABLE_CORE_STATE_COLLECT"); + return CM_ERROR; + } + LOG_RUN_INF("_ENABLE_CORE_STATE_COLLECT = %u.", inst_cfg->params.enable_core_state_collect); + return CM_SUCCESS; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/params/wr_param_verify.c b/src/params/wr_param_verify.c new file mode 100644 index 0000000000000000000000000000000000000000..8e9b62c01ab14b1fbb3ab1c41faecf0dd1cc40a2 --- /dev/null +++ b/src/params/wr_param_verify.c @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_param_verify.c + * + * + * IDENTIFICATION + * src/params/wr_param_verify.c + * + * ------------------------------------------------------------------------- + */ + +#include "cm_num.h" +#include "cm_utils.h" +#include "wr_defs.h" +#include "wr_errno.h" +#include "wr_param.h" +#include "wr_fault_injection.h" +#include "wr_ga.h" +#include "wr_param_verify.h" + +#ifdef __cplusplus +extern "C" { +#endif + +status_t wr_verify_log_level(void *lex, void *def) +{ + char *value = (char *)lex; + uint32 num; + text_t text = {.str = value, .len = (uint32)strlen(value)}; + cm_trim_text(&text); + status_t status = cm_text2uint32(&text, &num); + WR_RETURN_IFERR2(status, CM_THROW_ERROR(ERR_INVALID_PARAM, "_LOG_LEVEL")); + + if (num > MAX_LOG_LEVEL) { + WR_RETURN_IFERR2(CM_ERROR, CM_THROW_ERROR(ERR_INVALID_PARAM, "_LOG_LEVEL")); + } + + int32 iret_snprintf = + snprintf_s(((wr_def_t *)def)->value, CM_PARAM_BUFFER_SIZE, CM_PARAM_BUFFER_SIZE - 1, PRINT_FMT_UINT32, num); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + return CM_SUCCESS; +} + +status_t wr_notify_log_level(void *se, void *item, char *value) +{ + CM_RETURN_IFERR(cm_str2uint32(value, (uint32 *)&cm_log_param_instance()->log_level)); + return CM_SUCCESS; +} + +status_t wr_verify_enable_core_state_collect(void *lex, void *def) +{ + char *value = (char *)lex; + if (!cm_str_equal_ins(value, "TRUE") && !cm_str_equal_ins(value, "FALSE")) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_ENABLE_CORE_STATE_COLLECT")); + } + int32 iret_snprintf = + snprintf_s(((wr_def_t *)def)->value, CM_PARAM_BUFFER_SIZE, CM_PARAM_BUFFER_SIZE - 1, "%s", value); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + return CM_SUCCESS; +} + +status_t wr_notify_enable_core_state_collect(void *se, void *item, char *value) +{ + return wr_load_enable_core_state_collect_inner(value, g_inst_cfg); +} + +status_t wr_verify_blackbox_detail_on(void *lex, void *def) +{ + char *value = (char *)lex; + if (!cm_str_equal_ins(value, "TRUE") && !cm_str_equal_ins(value, "FALSE")) { + WR_RETURN_IFERR2(CM_ERROR, CM_THROW_ERROR(ERR_INVALID_PARAM, "_BLACKBOX_DETAIL_ON")); + } + int32 iret_snprintf = + snprintf_s(((wr_def_t *)def)->value, CM_PARAM_BUFFER_SIZE, CM_PARAM_BUFFER_SIZE - 1, "%s", value); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + return CM_SUCCESS; +} + +status_t wr_notify_blackbox_detail_on(void *se, void *item, char *value) +{ + return wr_load_blackbox_detail_on_inner(value, g_inst_cfg); +} + +status_t wr_verify_delay_clean_interval(void *lex, void *def) +{ + char *value = (char *)lex; + uint32 delay_clean_interval; + + status_t status = cm_str2uint32(value, &delay_clean_interval); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "DELAY_CLEAN_INTERVAL")); + if (delay_clean_interval < WR_MIN_DELAY_CLEAN_INTERVAL || delay_clean_interval > WR_MAX_DELAY_CLEAN_INTERVAL) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "DELAY_CLEAN_INTERVAL")); + } + + int32 iret_snprintf = snprintf_s(((wr_def_t *)def)->value, CM_PARAM_BUFFER_SIZE, CM_PARAM_BUFFER_SIZE - 1, + PRINT_FMT_UINT32, delay_clean_interval); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + return CM_SUCCESS; +} + +status_t wr_notify_delay_clean_interval(void *se, void *item, char *value) +{ + return wr_load_delay_clean_interval_core(value, g_inst_cfg); +} + +status_t wr_verify_lock_file_path(char *path) +{ + char input_path_buffer[WR_UNIX_PATH_MAX]; + char *input_path = NULL; + uint32 len; + len = (uint32)strlen(path); + if (len == 0 || len >= WR_UNIX_PATH_MAX) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_INVALID_FILE_NAME, path, WR_UNIX_PATH_MAX)); + } + + if (len == 1 && (path[0] == '.' || path[0] == '\t')) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_INVALID_DIR, path)); + } + + input_path = input_path_buffer; + MEMS_RETURN_IFERR(strcpy_s(input_path, WR_UNIX_PATH_MAX, path)); + if (len > 1 && (CM_IS_QUOTE_STRING(input_path[0], input_path[len - 1]))) { + input_path++; + len -= CM_SINGLE_QUOTE_LEN; + } + + if (len == 0 || input_path[0] == ' ') { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_INVALID_DIR, path)); + } + + input_path[len] = '\0'; + if (cm_check_exist_special_char(input_path, len)) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_INVALID_DIR, input_path)); + } + + char buffer_path[WR_UNIX_PATH_MAX]; + CM_RETURN_IFERR(realpath_file(input_path, buffer_path, WR_UNIX_PATH_MAX)); + if (!cm_dir_exist(input_path) || (access(buffer_path, W_OK | R_OK) != 0)) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_INVALID_DIR, input_path)); + } + return CM_SUCCESS; +} + +status_t wr_verify_log_file_dir_name(char *path) +{ + char input_path_buffer[CM_MAX_LOG_HOME_LEN]; + char *input_path = NULL; + uint32 len; + len = (uint32)strlen(path); + if (len == 0 || len >= CM_MAX_LOG_HOME_LEN) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_INVALID_FILE_NAME, path, CM_MAX_LOG_HOME_LEN)); + } + + if (len == 1 && (path[0] == '.' || path[0] == '\t')) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_INVALID_DIR, path)); + } + + input_path = input_path_buffer; + MEMS_RETURN_IFERR(strcpy_s(input_path, CM_MAX_LOG_HOME_LEN, path)); + if (len > 1 && (CM_IS_QUOTE_STRING(input_path[0], input_path[len - 1]))) { + input_path++; + len -= CM_SINGLE_QUOTE_LEN; + } + + if (len == 0 || input_path[0] == ' ') { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_INVALID_DIR, path)); + } + + input_path[len] = '\0'; + if (cm_check_exist_special_char(input_path, len)) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_INVALID_DIR, input_path)); + } + return CM_SUCCESS; +} + +status_t wr_verify_log_file_real_path(char *path) +{ + char real_path[CM_MAX_LOG_HOME_LEN] = {0}; + CM_RETURN_IFERR(realpath_file(path, real_path, CM_MAX_LOG_HOME_LEN)); + if (!cm_dir_exist(path) && cm_create_dir_ex(path) != CM_SUCCESS) { + WR_RETURN_IFERR2(CM_ERROR, CM_THROW_ERROR(ERR_INVALID_DIR, path)); + } + if (access(path, W_OK | R_OK) != 0) { + WR_RETURN_IFERR2(CM_ERROR, CM_THROW_ERROR(ERR_INVALID_DIR, path)); + } + return CM_SUCCESS; +} + +status_t wr_verify_log_file_size(void *lex, void *def) +{ + char *value = (char *)lex; + uint64 num; + text_t text = {.str = value, .len = (uint32)strlen(value)}; + cm_trim_text(&text); + + // The last char of _LOG_MAX_FILE_SIZE is size unit, which should not be checked for number. + char unit = text.str[text.len - 1]; + text.str[text.len - 1] = '\0'; + if (cm_check_is_number(text.str) != CM_SUCCESS) { + CM_THROW_ERROR_EX(ERR_VALUE_ERROR, "The text for _LOG_MAX_FILE_SIZE is not integer, text = %s", text.str); + return CM_ERROR; + } + text.str[text.len - 1] = unit; + + status_t status = cm_text2size(&text, (int64 *)&num); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_LOG_MAX_FILE_SIZE")); + if (num < CM_MIN_LOG_FILE_SIZE || num > CM_MAX_LOG_FILE_SIZE) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_LOG_MAX_FILE_SIZE"); + return CM_ERROR; + } + + int32 iret_snprintf = + snprintf_s(((wr_def_t *)def)->value, CM_PARAM_BUFFER_SIZE, CM_PARAM_BUFFER_SIZE - 1, "%s", T2S(&text)); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + return CM_SUCCESS; +} + +status_t wr_notify_log_file_size(void *se, void *item, char *value) +{ + CM_RETURN_IFERR(cm_str2size(value, (int64 *)&cm_log_param_instance()->max_log_file_size)); + return CM_SUCCESS; +} + +status_t wr_verify_log_backup_file_count(void *lex, void *def) +{ + char *value = (char *)lex; + uint32 num; + text_t text = {.str = value, .len = (uint32)strlen(value)}; + cm_trim_text(&text); + status_t status = cm_text2uint32(&text, &num); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_LOG_BACKUP_FILE_COUNT")); +#ifdef OPENGAUSS + if (num > CM_MAX_LOG_FILE_COUNT_LARGER) { +#else + if (num > CM_MAX_LOG_FILE_COUNT) { +#endif + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_LOG_BACKUP_FILE_COUNT"); + return CM_ERROR; + } + + int32 iret_snprintf = + snprintf_s(((wr_def_t *)def)->value, CM_PARAM_BUFFER_SIZE, CM_PARAM_BUFFER_SIZE - 1, PRINT_FMT_UINT32, num); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + return CM_SUCCESS; +} + +status_t wr_notify_log_backup_file_count(void *se, void *item, char *value) +{ + CM_RETURN_IFERR(cm_str2uint32(value, (uint32 *)&cm_log_param_instance()->log_backup_file_count)); + return CM_SUCCESS; +} + +status_t wr_verify_audit_backup_file_count(void *lex, void *def) +{ + char *value = (char *)lex; + uint32 num; + text_t text = {.str = value, .len = (uint32)strlen(value)}; + cm_trim_text(&text); + status_t status = cm_text2uint32(&text, &num); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_AUDIT_BACKUP_FILE_COUNT")); +#ifdef OPENGAUSS + if (num > CM_MAX_LOG_FILE_COUNT_LARGER) { +#else + if (num > CM_MAX_LOG_FILE_COUNT) { +#endif + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_AUDIT_BACKUP_FILE_COUNT"); + return CM_ERROR; + } + + int32 iret_snprintf = + snprintf_s(((wr_def_t *)def)->value, CM_PARAM_BUFFER_SIZE, CM_PARAM_BUFFER_SIZE - 1, PRINT_FMT_UINT32, num); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + return CM_SUCCESS; +} + +status_t wr_notify_audit_backup_file_count(void *se, void *item, char *value) +{ + CM_RETURN_IFERR(cm_str2uint32(value, (uint32 *)&cm_log_param_instance()->audit_backup_file_count)); + return CM_SUCCESS; +} + +status_t wr_verify_audit_file_size(void *lex, void *def) +{ + char *value = (char *)lex; + uint64 num; + text_t text = {.str = value, .len = (uint32)strlen(value)}; + cm_trim_text(&text); + + // The last char of _AUDIT_FILE_SIZE is size unit, which should not be checked for number. + char unit = text.str[text.len - 1]; + text.str[text.len - 1] = '\0'; + if (cm_check_is_number(text.str) != CM_SUCCESS) { + CM_THROW_ERROR_EX(ERR_VALUE_ERROR, "The text for _AUDIT_MAX_FILE_SIZE is not integer, text = %s", text.str); + return CM_ERROR; + } + text.str[text.len - 1] = unit; + + status_t status = cm_text2size(&text, (int64 *)&num); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_AUDIT_MAX_FILE_SIZE")); + if (num < CM_MIN_LOG_FILE_SIZE || num > CM_MAX_LOG_FILE_SIZE) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "_AUDIT_MAX_FILE_SIZE"); + return CM_ERROR; + } + + int32 iret_snprintf = + snprintf_s(((wr_def_t *)def)->value, CM_PARAM_BUFFER_SIZE, CM_PARAM_BUFFER_SIZE - 1, "%s", T2S(&text)); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + return CM_SUCCESS; +} + +status_t wr_notify_audit_file_size(void *se, void *item, char *value) +{ + CM_RETURN_IFERR(cm_str2size(value, (int64 *)&cm_log_param_instance()->max_audit_file_size)); + return CM_SUCCESS; +} + +status_t wr_verify_audit_level(void *lex, void *def) +{ + char *value = (char *)lex; + uint32 num; + text_t text = {.str = value, .len = (uint32)strlen(value)}; + cm_trim_text(&text); + status_t status = cm_text2uint32(&text, &num); + WR_RETURN_IFERR2(status, CM_THROW_ERROR(ERR_INVALID_PARAM, "_AUDIT_LEVEL")); + + if (num > WR_AUDIT_ALL) { + CM_THROW_ERROR(ERR_INVALID_PARAM, "_AUDIT_LEVEL"); + return CM_ERROR; + } + + int32 iret_snprintf = + snprintf_s(((wr_def_t *)def)->value, CM_PARAM_BUFFER_SIZE, CM_PARAM_BUFFER_SIZE - 1, PRINT_FMT_UINT32, num); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + return CM_SUCCESS; +} + +status_t wr_notify_audit_level(void *se, void *item, char *value) +{ + CM_RETURN_IFERR(cm_str2uint32(value, (uint32 *)&cm_log_param_instance()->audit_level)); + return CM_SUCCESS; +} + +status_t wr_verify_cluster_run_mode(void *lex, void *def) +{ + char *value = (char *)lex; + if (cm_strcmpi(value, "cluster_standby") != 0 && cm_strcmpi(value, "cluster_primary") != 0) { + WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "CLUSTER_RUN_MODE"); + return CM_ERROR; + } + + int32 iret_snprintf = + snprintf_s(((wr_def_t *)def)->value, CM_PARAM_BUFFER_SIZE, CM_PARAM_BUFFER_SIZE - 1, "%s", value); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + return CM_SUCCESS; +} + +status_t wr_notify_cluster_run_mode(void *se, void *item, char *value) +{ + if (cm_strcmpi(value, "cluster_standby") == 0) { + g_inst_cfg->params.cluster_run_mode = CLUSTER_STANDBY; + LOG_RUN_INF("The cluster_run_mode is cluster_standby."); + } else if (cm_strcmpi(value, "cluster_primary") == 0) { + g_inst_cfg->params.cluster_run_mode = CLUSTER_PRIMARY; + LOG_RUN_INF("The cluster_run_mode is cluster_primary."); + } else { + WR_RETURN_IFERR2( + CM_ERROR, WR_THROW_ERROR(ERR_WR_INVALID_PARAM, "failed to load params, invalid CLUSTER_RUN_MODE")); + } + return CM_SUCCESS; +} + +status_t wr_verify_mes_wait_timeout(void *lex, void *def) +{ + char *value = (char *)lex; + uint32 num; + text_t text = {.str = value, .len = (uint32)strlen(value)}; + cm_trim_text(&text); + status_t status = cm_text2uint32(&text, &num); + WR_RETURN_IFERR2(status, CM_THROW_ERROR(ERR_INVALID_PARAM, "MES_WAIT_TIMEOUT")); + + if (num > WR_MES_MAX_WAIT_TIMEOUT || num < WR_MES_MIN_WAIT_TIMEOUT) { + WR_RETURN_IFERR2(CM_ERROR, CM_THROW_ERROR(ERR_INVALID_PARAM, "MES_WAIT_TIMEOUT")); + } + + int32 iret_snprintf = + snprintf_s(((wr_def_t *)def)->value, CM_PARAM_BUFFER_SIZE, CM_PARAM_BUFFER_SIZE - 1, PRINT_FMT_UINT32, num); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + return CM_SUCCESS; +} + +status_t wr_notify_mes_wait_timeout(void *se, void *item, char *value) +{ + CM_RETURN_IFERR(cm_str2uint32(value, (uint32 *)&g_inst_cfg->params.mes_wait_timeout)); + return CM_SUCCESS; +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/params/wr_param_verify.h b/src/params/wr_param_verify.h new file mode 100644 index 0000000000000000000000000000000000000000..30633cdce044dcca127b28aae372cacad30ac6d1 --- /dev/null +++ b/src/params/wr_param_verify.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_param_verify.h + * + * + * IDENTIFICATION + * src/params/wr_param_verify.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_PARAM_VERIFY_H__ +#define __WR_PARAM_VERIFY_H__ + +#include "cm_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct st_wr_def { + config_scope_t scope; + char name[CM_NAME_BUFFER_SIZE]; + char value[CM_PARAM_BUFFER_SIZE]; +} wr_def_t; + +status_t wr_verify_log_level(void *lex, void *def); +status_t wr_notify_log_level(void *se, void *item, char *value); +status_t wr_verify_lock_file_path(char *path); +status_t wr_verify_log_file_dir_name(char *log_home); +status_t wr_verify_log_file_real_path(char *log_home); +status_t wr_verify_log_file_size(void *lex, void *def); +status_t wr_notify_log_file_size(void *se, void *item, char *value); +status_t wr_verify_log_backup_file_count(void *lex, void *def); +status_t wr_notify_log_backup_file_count(void *se, void *item, char *value); +status_t wr_verify_audit_backup_file_count(void *lex, void *def); +status_t wr_notify_audit_backup_file_count(void *se, void *item, char *value); +status_t wr_verify_audit_file_size(void *lex, void *def); +status_t wr_notify_audit_file_size(void *se, void *item, char *value); +status_t wr_verify_audit_level(void *lex, void *def); +status_t wr_notify_audit_level(void *se, void *item, char *value); +status_t wr_verify_enable_core_state_collect(void *lex, void *def); +status_t wr_notify_enable_core_state_collect(void *se, void *item, char *value); +status_t wr_verify_delay_clean_interval(void *lex, void *def); +status_t wr_notify_delay_clean_interval(void *se, void *item, char *value); +status_t wr_verify_cluster_run_mode(void *lex, void *def); +status_t wr_notify_cluster_run_mode(void *se, void *item, char *value); +status_t wr_verify_blackbox_detail_on(void *lex, void *def); +status_t wr_notify_blackbox_detail_on(void *se, void *item, char *value); +status_t wr_verify_mes_wait_timeout(void *lex, void *def); +status_t wr_notify_mes_wait_timeout(void *se, void *item, char *value); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/service/CMakeLists.txt b/src/service/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..12f7928c99e64ba5d0783bdef0b5effabf1831af --- /dev/null +++ b/src/service/CMakeLists.txt @@ -0,0 +1,38 @@ +## include +include_directories(${WR_COMMON_PATH}) +include_directories(${WR_COMMON_PATH}/persist) +include_directories(${WR_LOG_PATH}) +include_directories(${WR_PARAMS_PATH}) +include_directories(${WR_INTERFACE_PATH}) +include_directories(${WR_HOTPATCH_PATH}) + +option(ENABLE_FUZZASAN OFF) +if (ENABLE_FUZZASAN) + add_compile_options(-fsanitize-coverage=trace-pc) +endif(ENABLE_FUZZASAN) + +## other dependency include +include_directories(${WR_SECUREC_INC_PATH}) +include_directories(${WR_OPENSSL_PATH}) +include_directories(${WR_CBB_PATH}) +include_directories(${LZ4_INC_PATH}) +aux_source_directory(${WR_COMMON_PATH} COMMON_SRC) +aux_source_directory(${WR_COMMON_PATH}/persist COMMON_SRC) +aux_source_directory(${WR_LOG_PATH} LOG_SRC) +aux_source_directory(${WR_PARAMS_PATH} PARAMS_SRC) +aux_source_directory(${WR_SER_PATH} SER_SRC) + +set(COMMON_ALL_SRC + ${COMMON_SRC} + ${LOG_SRC} + ${PARAMS_SRC} + ${SER_SRC} + ) + +ADD_EXECUTABLE(wrserver ${COMMON_ALL_SRC}) + +if (ENABLE_FUZZASAN) + target_link_libraries(wrserver pthread dl rt -Wl,--whole-archive ${vpp_libsecurec} ${HOTPATCH_DEPENDENCY_LIB} ${HOTPATCH_LDS} ${3rd_libssl} ${libz} ${lz4} ${3rd_libccb} ${vpp_libipsi_crypto} ${fuzz_lib} -Wl,--no-whole-archive) +else() + target_link_libraries(wrserver pthread dl rt -Wl,--whole-archive ${vpp_libsecurec} ${HOTPATCH_DEPENDENCY_LIB} ${HOTPATCH_LDS} ${3rd_libssl} ${libz} ${lz4} ${3rd_libccb} ${vpp_libipsi_crypto} -Wl,--no-whole-archive) +endif(ENABLE_FUZZASAN) diff --git a/src/service/wr_instance.c b/src/service/wr_instance.c new file mode 100644 index 0000000000000000000000000000000000000000..82946b5e810e27990c2fd365c87381eb00bdd6e6 --- /dev/null +++ b/src/service/wr_instance.c @@ -0,0 +1,941 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_instance.c + * + * + * IDENTIFICATION + * src/service/wr_instance.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_ga.h" +#include "wr_shm.h" +#include "cm_timer.h" +#include "cm_error.h" +#include "cm_iofence.h" +#include "wr_errno.h" +#include "wr_defs.h" +#include "wr_api.h" +#include "wr_file.h" +#include "wr_malloc.h" +#include "wr_mes.h" +#include "wr_service.h" +#include "wr_instance.h" +#include "wr_reactor.h" +#include "wr_service.h" +#include "wr_zero.h" +#include "cm_utils.h" +#include "wr_thv.h" +#ifdef ENABLE_WRTEST +#include "wr_simulation_cm.h" +#endif +#include "wr_fault_injection.h" +#include "wr_nodes_list.h" + +#define WR_MAINTAIN_ENV "WR_MAINTAIN" +wr_instance_t g_wr_instance; + +static const char *const g_wr_lock_file = "wr.lck"; + +static void instance_set_pool_def(ga_pool_id_e pool_id, uint32 obj_count, uint32 obj_size, uint32 ex_max) +{ + ga_pool_def_t pool_def; + + CM_ASSERT(ex_max <= ((uint32)GA_MAX_EXTENDED_POOLS)); + pool_def.object_count = obj_count; + pool_def.object_size = obj_size; + pool_def.ex_max = ex_max; + + ga_set_pool_def(pool_id, &pool_def); +} + +status_t wr_lock_instance(void) +{ + char file_name[CM_FILE_NAME_BUFFER_SIZE]; + int iret_snprintf; + + iret_snprintf = snprintf_s(file_name, CM_FILE_NAME_BUFFER_SIZE, CM_FILE_NAME_BUFFER_SIZE - 1, "%s/%s", + g_wr_instance.inst_cfg.home, g_wr_lock_file); + WR_SECUREC_SS_RETURN_IF_ERROR(iret_snprintf, CM_ERROR); + + if (cm_open_file(file_name, O_CREAT | O_RDWR | O_BINARY, &g_wr_instance.lock_fd) != CM_SUCCESS) { + return CM_ERROR; + } + + if (cm_lock_fd(g_wr_instance.lock_fd, SPIN_SLEEP_TIME) != CM_SUCCESS) { + cm_close_file(g_wr_instance.lock_fd); + g_wr_instance.lock_fd = CM_INVALID_INT32; + return CM_ERROR; + } + + return CM_SUCCESS; +} + +static status_t instance_init_ga(wr_instance_t *inst) +{ + int32 ret; + ga_destroy_global_area(); + instance_set_pool_def(GA_INSTANCE_POOL, 1, sizeof(wr_share_vg_item_t), WR_MAX_VOLUME_GROUP_NUM - 1); + instance_set_pool_def( + GA_SESSION_POOL, WR_SESSION_NUM_PER_GROUP, sizeof(wr_session_t), GA_MAX_SESSION_EXTENDED_POOLS); + instance_set_pool_def(GA_8K_POOL, WR_MAX_MEM_BLOCK_SIZE / (WR_BLOCK_SIZE + WR_BLOCK_CTRL_SIZE), + WR_BLOCK_SIZE + WR_BLOCK_CTRL_SIZE, GA_MAX_8K_EXTENDED_POOLS); + instance_set_pool_def(GA_16K_POOL, WR_MAX_MEM_BLOCK_SIZE / (WR_FILE_SPACE_BLOCK_SIZE + WR_BLOCK_CTRL_SIZE), + WR_FILE_SPACE_BLOCK_SIZE + WR_BLOCK_CTRL_SIZE, GA_MAX_EXTENDED_POOLS); + instance_set_pool_def(GA_FS_AUX_POOL, WR_MAX_MEM_BLOCK_SIZE / (WR_FS_AUX_SIZE + WR_BLOCK_CTRL_SIZE), + WR_FS_AUX_SIZE + WR_BLOCK_CTRL_SIZE, GA_MAX_EXTENDED_POOLS); + instance_set_pool_def( + GA_SEGMENT_POOL, WR_MAX_VOLUME_GROUP_NUM, WR_BUCKETS_SIZE_PER_SEGMENT, WR_MAX_SEGMENT_NUM - 1); + ret = ga_create_global_area(); + WR_RETURN_IF_ERROR(ret); + LOG_RUN_INF("Init GA pool and area successfully."); + return CM_SUCCESS; +} + +static status_t wr_init_thread(wr_instance_t *inst) +{ + uint32 size = wr_get_uwression_startid(); + inst->threads = (thread_t *)cm_malloc(size * (uint32)sizeof(thread_t)); + if (inst->threads == NULL) { + return CM_ERROR; + } + errno_t errcode = + memset_s(inst->threads, (size * (uint32)sizeof(thread_t)), 0x00, (size * (uint32)sizeof(thread_t))); + securec_check_ret(errcode); + return CM_SUCCESS; +} + +bool32 wr_config_cm() +{ + wr_config_t *inst_cfg = wr_get_inst_cfg(); + char *value = cm_get_config_value(&inst_cfg->config, "WR_CM_SO_NAME"); + if (value == NULL || strlen(value) == 0 || strlen(value) >= WR_MAX_NAME_LEN) { + LOG_RUN_INF("wr cm config of WR_CM_SO_NAME is empty."); + return CM_FALSE; + } + return CM_TRUE; +} + +static status_t wr_init_inst_handle_session(wr_instance_t *inst) +{ + status_t status = wr_create_session(NULL, &inst->handle_session); + WR_RETURN_IFERR2(status, LOG_RUN_ERR("WR instance init create handle session fail!")); + return CM_SUCCESS; +} + +static status_t instance_init_core(wr_instance_t *inst) +{ + status_t status = wr_init_session_pool(wr_get_max_total_session_cnt()); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_GA_INIT, "WR instance failed to initialize sessions.")); + status = wr_init_thread(inst); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_GA_INIT, "WR instance failed to initialize thread.")); + status = wr_startup_mes(); + WR_RETURN_IFERR2(status, WR_THROW_ERROR(ERR_WR_GA_INIT, "WR instance failed to startup mes")); + status = wr_create_reactors(); + WR_RETURN_IFERR2(status, LOG_RUN_ERR("WR instance failed to start reactors!")); + status = wr_start_lsnr(inst); + WR_RETURN_IFERR2(status, LOG_RUN_ERR("WR instance failed to start lsnr!")); + status = wr_init_inst_handle_session(inst); + WR_RETURN_IFERR2(status, LOG_RUN_ERR("WR instance int handle session!")); + return CM_SUCCESS; +} + +static void wr_init_maintain(wr_instance_t *inst, wr_srv_args_t wr_args) +{ + if (wr_args.is_maintain) { + inst->is_maintain = true; + } else { + char *maintain_env = getenv(WR_MAINTAIN_ENV); + inst->is_maintain = (maintain_env != NULL && cm_strcmpi(maintain_env, "TRUE") == 0); + } + + if (inst->is_maintain) { + LOG_RUN_INF("WR_MAINTAIN is TRUE"); + } else { + LOG_RUN_INF("WR_MAINTAIN is FALSE"); + } +} + +static status_t instance_init(wr_instance_t *inst) +{ + status_t status = wr_lock_instance(); + WR_RETURN_IFERR2(status, LOG_RUN_ERR("Another wrinstance is running")); + uint32 shm_key = + (uint32)(inst->inst_cfg.params.shm_key << (uint8)WR_MAX_SHM_KEY_BITS) + (uint32)inst->inst_cfg.params.inst_id; + status = cm_init_shm(shm_key); + WR_RETURN_IFERR2(status, LOG_RUN_ERR("WR instance failed to initialize shared memory!")); + status = instance_init_ga(inst); + WR_RETURN_IFERR4(status, (void)del_shm_by_key(CM_SHM_CTRL_KEY), cm_destroy_shm(), + LOG_RUN_ERR("WR instance failed to initialize ga!")); + status = instance_init_core(inst); + if (status != CM_SUCCESS) { + (void)del_shm_by_key(CM_SHM_CTRL_KEY); + ga_detach_area(); + cm_destroy_shm(); + CM_FREE_PTR(g_wr_session_ctrl.sessions); + return CM_ERROR; + } + LOG_RUN_INF("WR instance begin to run."); + return CM_SUCCESS; +} + +static void wr_init_cluster_proto_ver(wr_instance_t *inst) +{ + for (uint32 i = 0; i < WR_MAX_INSTANCES; i++) { + inst->cluster_proto_vers[i] = WR_INVALID_VERSION; + } +} + +wr_instance_status_e wr_get_instance_status(void) +{ + return g_wr_instance.status; +} + +static status_t wr_save_process_pid(wr_config_t *inst_cfg) +{ +#ifndef WIN32 + char file_name[CM_FILE_NAME_BUFFER_SIZE] = {0}; + char dir_name[CM_FILE_NAME_BUFFER_SIZE] = {0}; + PRTS_RETURN_IFERR( + snprintf_s(dir_name, CM_FILE_NAME_BUFFER_SIZE, CM_FILE_NAME_BUFFER_SIZE - 1, "%s/process", inst_cfg->home)); + if (!cm_dir_exist(dir_name)) { + WR_RETURN_IF_ERROR(cm_create_dir(dir_name)); + } + PRTS_RETURN_IFERR(snprintf_s( + file_name, CM_FILE_NAME_BUFFER_SIZE, CM_FILE_NAME_BUFFER_SIZE - 1, "%s/%s", dir_name, "wr.process")); + pid_t pid = getpid(); + if (strlen(file_name) == 0) { + LOG_RUN_ERR("wrserver process path not existed"); + return CM_ERROR; + } + FILE *fp; + CM_RETURN_IFERR(cm_fopen(file_name, "w+", S_IRUSR | S_IWUSR, &fp)); + (void)cm_truncate_file(fp->_fileno, 0); + (void)cm_seek_file(fp->_fileno, 0, SEEK_SET); + int32 size = fprintf(fp, "%d", pid); + (void)fflush(stdout); + if (size < 0) { + LOG_RUN_ERR("write wrserver process failed, write size is %d.", size); + (void)fclose(fp); + return CM_ERROR; + } + (void)fclose(fp); +#endif + return CM_SUCCESS; +} + +status_t wr_startup(wr_instance_t *inst, wr_srv_args_t wr_args) +{ + status_t status; + errno_t errcode = memset_s(inst, sizeof(wr_instance_t), 0, sizeof(wr_instance_t)); + securec_check_ret(errcode); + + status = wr_init_zero_buf(); + WR_RETURN_IFERR2(status, WR_PRINT_RUN_ERROR("wr init zero buf fail.\n")); + + wr_init_cluster_proto_ver(inst); + inst->lock_fd = CM_INVALID_INT32; + wr_set_server_flag(); + regist_get_instance_status_proc(wr_get_instance_status); + status = wr_set_cfg_dir(wr_args.wr_home, &inst->inst_cfg); + WR_RETURN_IFERR2(status, WR_PRINT_RUN_ERROR("Environment variant WR_HOME not found!\n")); + status = cm_start_timer(g_timer()); + WR_RETURN_IFERR2(status, WR_PRINT_RUN_ERROR("Aborted due to starting timer thread.\n")); + status = wr_load_config(&inst->inst_cfg); + WR_RETURN_IFERR2(status, WR_PRINT_RUN_ERROR("Failed to load parameters!\n")); + status = wr_save_process_pid(&inst->inst_cfg); + WR_RETURN_IFERR2(status, WR_PRINT_RUN_ERROR("Save wrserver pid failed!\n")); + wr_init_maintain(inst, wr_args); + LOG_RUN_INF("WR instance begin to initialize."); + + status = instance_init(inst); + WR_RETURN_IFERR2(status, LOG_RUN_ERR("WR instance failed to initialized!")); + cm_set_shm_ctrl_flag(CM_SHM_CTRL_FLAG_TRUE); + inst->abort_status = CM_FALSE; + return CM_SUCCESS; +} + +static status_t wr_handshake_core(wr_session_t *session) +{ + wr_init_packet(&session->recv_pack, CM_FALSE); + wr_init_packet(&session->send_pack, CM_FALSE); + session->pipe.socket_timeout = (int32)CM_NETWORK_IO_TIMEOUT; + status_t status = wr_process_handshake_cmd(session, WR_CMD_HANDSHAKE); + return status; +} + +static status_t wr_handshake(wr_session_t *session) +{ + LOG_RUN_INF("[WR_CONNECT]session %u begin check protocal type.", session->id); + /* fetch protocol type */ + status_t status = wr_diag_proto_type(session); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("[WR_CONNECT]Failed to get protocol type!"); + return CM_ERROR; + } + status = wr_handshake_core(session); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("[WR_CONNECT]Failed to process get server info!"); + return CM_ERROR; + } + return status; +} + +static status_t wr_lsnr_proc(tcp_lsnr_t *lsnr, cs_pipe_t *pipe) +{ + wr_session_t *session = NULL; + status_t status; + status = wr_create_session(pipe, &session); + WR_RETURN_IFERR2(status, LOG_RUN_ERR("[WR_CONNECT] create session failed.\n")); + // process_handshake + status = wr_handshake(session); + WR_RETURN_IFERR3(status, LOG_RUN_ERR("[WR_CONNECT] handshake failed.\n"), wr_destroy_session(session)); + status = wr_reactors_add_session(session); + WR_RETURN_IFERR3(status, + LOG_RUN_ERR("[WR_CONNECT]Session:%u socket:%u closed.", session->id, pipe->link.uds.sock), + wr_destroy_session(session)); + LOG_RUN_INF("[WR_CONNECT]The client has connected, session %u.", session->id); + return CM_SUCCESS; +} + +status_t wr_start_lsnr(wr_instance_t *inst) +{ + WR_RETURN_IFERR2(strncpy_s(inst->lsnr.host[0], + WR_MAX_PATH_BUFFER_SIZE, + g_inst_cfg->params.listen_addr.host, + WR_MAX_PATH_BUFFER_SIZE), + LOG_RUN_ERR("wr_start_lsnr strncpy_s failed")); + inst->lsnr.host[1][0] = '\0'; + inst->lsnr.port = g_inst_cfg->params.listen_addr.port; + // return cs_start_uds_lsnr(&inst->lsnr, wr_lsnr_proc); + return cs_start_tcp_lsnr(&inst->lsnr, wr_lsnr_proc); +} + +status_t wr_init_cm(wr_instance_t *inst) +{ + inst->cm_res.is_valid = CM_FALSE; + inst->inst_work_status_map = 0; + wr_config_t *inst_cfg = wr_get_inst_cfg(); + char *value = cm_get_config_value(&inst_cfg->config, "WR_CM_SO_NAME"); + if (value == NULL || strlen(value) == 0) { + LOG_RUN_INF("wr cm config of WR_CM_SO_NAME is empty."); + return CM_SUCCESS; + } + + if (strlen(value) >= WR_MAX_NAME_LEN) { + LOG_RUN_ERR("wr cm config of WR_CM_SO_NAME is exceeds the max len %u.", WR_MAX_NAME_LEN - 1); + return CM_ERROR; + } +#ifdef ENABLE_WRTEST + WR_RETURN_IF_ERROR(wr_simulation_cm_res_mgr_init(value, &inst->cm_res.mgr, NULL)); +#else + WR_RETURN_IF_ERROR(cm_res_mgr_init(value, &inst->cm_res.mgr, NULL)); +#endif + status_t status = + (status_t)cm_res_init(&inst->cm_res.mgr, (unsigned int)inst->inst_cfg.params.inst_id, WR_CMS_RES_TYPE, NULL); +#ifdef ENABLE_WRTEST + WR_RETURN_IFERR2(status, wr_simulation_cm_res_mgr_uninit(&inst->cm_res.mgr)); +#else + WR_RETURN_IFERR2(status, cm_res_mgr_uninit(&inst->cm_res.mgr)); +#endif + inst->cm_res.is_valid = CM_TRUE; + return CM_SUCCESS; +} + +void wr_uninit_cm(wr_instance_t *inst) +{ + if (inst->cm_res.is_valid) { +#ifdef ENABLE_WRTEST + wr_simulation_cm_res_mgr_uninit(&inst->cm_res.mgr); +#else + cm_res_mgr_uninit(&inst->cm_res.mgr); +#endif + inst->cm_res.is_valid = CM_FALSE; + } +} + +void wr_free_log_ctrl() +{ + if (g_vgs_info == NULL) { + return; + } + for (uint32 i = 0; i < g_vgs_info->group_num; i++) { + wr_vg_info_item_t *vg_item = &g_vgs_info->volume_group[i]; + if (vg_item != NULL && vg_item->log_file_ctrl.log_buf != NULL) { + WR_FREE_POINT(vg_item->log_file_ctrl.log_buf); + } + } +} + +void wr_check_peer_by_inst(wr_instance_t *inst, uint64 inst_id) +{ + wr_config_t *inst_cfg = wr_get_inst_cfg(); + // Can't be myself + if (inst_id == (uint64)inst_cfg->params.inst_id) { + return; + } + + // Not cfg the inst + uint64 inst_mask = ((uint64)0x1 << inst_id); + if ((inst_cfg->params.nodes_list.inst_map & inst_mask) == 0) { + return; + } + + uint64 cur_inst_map = wr_get_inst_work_status(); + // Has connection + if ((cur_inst_map & inst_mask) != 0) { + return; + } + + wr_check_peer_inst(inst, inst_id); +} + +static void wr_check_peer_by_cm(wr_instance_t *inst) +{ + cm_res_mem_ctx_t res_mem_ctx; + if (cm_res_init_memctx(&res_mem_ctx) != CM_SUCCESS) { + return; + } + cm_res_stat_ptr_t res = cm_res_get_stat(&inst->cm_res.mgr, &res_mem_ctx); + if (res == NULL) { + cm_res_uninit_memctx(&res_mem_ctx); + return; + } + wr_config_t *inst_cfg = wr_get_inst_cfg(); + uint64 cur_inst_map = 0; + uint32 instance_count = 0; + if (cm_res_get_instance_count(&instance_count, &inst->cm_res.mgr, res) != CM_SUCCESS) { + cm_res_free_stat(&inst->cm_res.mgr, res); + cm_res_uninit_memctx(&res_mem_ctx); + return; + } + for (uint32_t idx = 0; idx < instance_count; idx++) { + const cm_res_inst_info_ptr_t inst_res = cm_res_get_instance_info(&inst->cm_res.mgr, res, idx); + if (inst_res == NULL) { + cm_res_free_stat(&inst->cm_res.mgr, res); + cm_res_uninit_memctx(&res_mem_ctx); + return; + } + + int res_instance_id = cm_res_get_inst_instance_id(&inst->cm_res.mgr, inst_res); + int is_work_member = cm_res_get_inst_is_work_member(&inst->cm_res.mgr, inst_res); + if (is_work_member == 0) { + LOG_RUN_INF("wr instance [%d] is not work member. May be kicked off by cm.", res_instance_id); + continue; + } + + uint64_t inst_mask = ((uint64)0x1 << res_instance_id); + if ((inst_cfg->params.nodes_list.inst_map & inst_mask) == 0) { + LOG_RUN_INF("wr instance [%d] is not in mes nodes cfg lists.", res_instance_id); + continue; + } + + int stat = cm_res_get_inst_stat(&inst->cm_res.mgr, inst_res); + if (stat != CM_RES_STATUS_ONLINE) { + LOG_RUN_INF("wr instance [%d] work stat [%d] not online.", res_instance_id, stat); + } + cur_inst_map |= ((uint64)0x1 << res_instance_id); + } + + wr_check_mes_conn(cur_inst_map); + cm_res_free_stat(&inst->cm_res.mgr, res); + cm_res_uninit_memctx(&res_mem_ctx); +} + +#ifdef ENABLE_WRTEST +static void wr_check_peer_by_simulation_cm(wr_instance_t *inst) +{ + if (g_simulation_cm.simulation) { + char *bitmap_online = inst->cm_res.mgr.cm_get_res_stat(); + uint64 cur_inst_map = 0; + (void)cm_str2bigint(bitmap_online, (int64 *)&cur_inst_map); + wr_check_mes_conn(cur_inst_map); + return; + } + wr_check_peer_by_cm(inst); + return; +} +#endif + +static void wr_check_peer_default() +{ + wr_check_mes_conn(WR_INVALID_ID64); +} + +void wr_init_cm_res(wr_instance_t *inst) +{ + wr_cm_res *cm_res = &inst->cm_res; + cm_spin_lock(&cm_res->init_lock, NULL); + if (cm_res->is_init) { + cm_spin_unlock(&cm_res->init_lock); + return; + } + status_t status = wr_init_cm(inst); + if (status == CM_SUCCESS) { + cm_res->is_init = CM_TRUE; + } + cm_spin_unlock(&cm_res->init_lock); + return; +} + +#ifdef ENABLE_WRTEST +status_t wr_get_cm_res_lock_owner(wr_cm_res *cm_res, uint32 *master_id) +{ + if (g_simulation_cm.simulation) { + int ret = cm_res_get_lock_owner(&cm_res->mgr, WR_CM_LOCK, master_id); + if (ret != CM_SUCCESS) { + return ret; + } + } else { + wr_config_t *inst_cfg = wr_get_inst_cfg(); + for (int i = 0; i < WR_MAX_INSTANCES; i++) { + if (inst_cfg->params.nodes_list.ports[i] != 0) { + *master_id = i; + LOG_RUN_INF_INHIBIT(LOG_INHIBIT_LEVEL5, "Set min id %u as master id.", i); + break; + } + } + LOG_RUN_INF_INHIBIT(LOG_INHIBIT_LEVEL5, "master_id is %u when get cm lock.", *master_id); + } + return CM_SUCCESS; +} +#else +status_t wr_get_cm_res_lock_owner(wr_cm_res *cm_res, uint32 *master_id) +{ + int ret = cm_res_get_lock_owner(&cm_res->mgr, WR_CM_LOCK, master_id); + if (ret == CM_RES_TIMEOUT) { + LOG_RUN_ERR("Try to get lock owner failed, cm error : %d.", ret); + return CM_ERROR; + } else if (ret == CM_RES_SUCCESS) { + return CM_SUCCESS; + } else { + *master_id = CM_INVALID_ID32; + LOG_RUN_ERR("Try to get lock owner failed, cm error : %d.", ret); + } + return CM_SUCCESS; +} +#endif +// get cm lock owner, if no owner, try to become.master_id can not be WR_INVALID_ID32. +status_t wr_get_cm_lock_owner(wr_instance_t *inst, bool32 *grab_lock, bool32 try_lock, uint32 *master_id) +{ + wr_config_t *inst_cfg = wr_get_inst_cfg(); + *master_id = WR_INVALID_ID32; + if (inst->is_maintain || inst->inst_cfg.params.nodes_list.inst_cnt <= 1) { + *grab_lock = CM_TRUE; + LOG_RUN_INF_INHIBIT(LOG_INHIBIT_LEVEL5, + "[RECOVERY]Set curr_id %u to be primary when wrserver is maintain or just one inst.", + (uint32)inst_cfg->params.inst_id); + *master_id = (uint32)inst_cfg->params.inst_id; + return CM_SUCCESS; + } + wr_cm_res *cm_res = &inst->cm_res; + if (!cm_res->is_init) { + return CM_SUCCESS; + } + status_t ret = CM_SUCCESS; + ret = wr_get_cm_res_lock_owner(cm_res, master_id); + WR_RETURN_IFERR2(ret, LOG_RUN_WAR("Failed to get cm lock owner, if WR is normal open ignore the log.")); + if (*master_id == WR_INVALID_ID32) { + if (!try_lock) { + return CM_ERROR; + } + if (inst->no_grab_lock) { + LOG_RUN_INF_INHIBIT(LOG_INHIBIT_LEVEL5, "[RECOVERY]No need to grab lock when inst %u is set no grab lock.", + (uint32)inst_cfg->params.inst_id); + wr_set_master_id(WR_INVALID_ID32); + return CM_ERROR; + } + ret = cm_res_lock(&cm_res->mgr, WR_CM_LOCK); + *grab_lock = ((int)ret == CM_RES_SUCCESS); + if (*grab_lock) { + *master_id = (uint32)inst->inst_cfg.params.inst_id; + LOG_RUN_INF("[RECOVERY]inst id %u succeed to get lock owner.", *master_id); + return CM_SUCCESS; + } + return CM_ERROR; + } + return CM_SUCCESS; +} + +void wr_recovery_when_primary(wr_session_t *session, wr_instance_t *inst, uint32 curr_id, bool32 grab_lock) +{ + bool32 first_start = CM_FALSE; + if (!grab_lock) { + first_start = (inst->status == WR_STATUS_PREPARE); + } + if (first_start) { + LOG_RUN_INF("[RECOVERY]inst %u is old main inst to do recovery.", curr_id); + } else { + LOG_RUN_INF("[RECOVERY]master_id is %u when get cm lock to do recovery.", curr_id); + } + + wr_instance_status_e old_status = inst->status; + inst->status = WR_STATUS_RECOVERY; + CM_MFENCE; + + if (old_status == WR_STATUS_OPEN && !first_start) { + wr_wait_session_pause(inst); + } + wr_wait_background_pause(inst); + + if (!first_start) { + wr_set_session_running(inst, session->id); + } + + // when current node is standby, and will change to primary, the status is from WR_STATUS_OPEN to + // WR_STATUS_RECOVERY, need to set the master id after the status finish + wr_set_master_id(curr_id); + wr_set_server_status_flag(WR_STATUS_READWRITE); + LOG_RUN_INF("[RECOVERY]inst %u set status flag %u when get cm lock.", curr_id, WR_STATUS_READWRITE); + // when primary, no need to check result + g_wr_instance.is_join_cluster = CM_TRUE; + inst->status = WR_STATUS_OPEN; +} + +void wr_recovery_when_standby(wr_session_t *session, wr_instance_t *inst, uint32 curr_id, uint32 master_id) +{ + uint32 old_master_id = wr_get_master_id(); + int32 old_status = wr_get_server_status_flag(); + if (old_master_id != master_id) { + wr_set_master_id(master_id); + wr_set_server_status_flag(WR_STATUS_READONLY); + LOG_RUN_INF("[RECOVERY]inst %u set status flag %u when not get cm lock.", curr_id, WR_STATUS_READONLY); + } + if (!wr_check_join_cluster()) { + wr_set_master_id(old_master_id); + wr_set_server_status_flag(old_status); + LOG_RUN_INF("[RECOVERY]inst %u reset status flag %d and master_id %u when join failed.", curr_id, old_status, + old_master_id); + return; + } + inst->status = WR_STATUS_OPEN; +} +/* + 1、old_master_id == master_id, just return; + 2、old_master_id != master_id, just indicates that the master has been reselected.so to judge whether recover. +*/ +void wr_get_cm_lock_and_recover_inner(wr_session_t *session, wr_instance_t *inst) +{ + cm_latch_x(&g_wr_instance.switch_latch, WR_DEFAULT_SESSIONID, LATCH_STAT(LATCH_SWITCH)); + uint32 old_master_id = wr_get_master_id(); + bool32 grab_lock = CM_FALSE; + uint32 master_id = WR_INVALID_ID32; + status_t status = wr_get_cm_lock_owner(inst, &grab_lock, CM_TRUE, &master_id); + if (status != CM_SUCCESS) { + cm_unlatch(&g_wr_instance.switch_latch, LATCH_STAT(LATCH_SWITCH)); + return; + } + if (master_id == WR_INVALID_ID32) { + LOG_RUN_WAR("[RECOVERY]cm is not init, just try again."); + cm_unlatch(&g_wr_instance.switch_latch, LATCH_STAT(LATCH_SWITCH)); + return; + } + wr_config_t *inst_cfg = wr_get_inst_cfg(); + uint32 curr_id = (uint32)inst_cfg->params.inst_id; + // master no change + if (old_master_id == master_id) { + // primary, no need check + if (master_id == curr_id) { + cm_unlatch(&g_wr_instance.switch_latch, LATCH_STAT(LATCH_SWITCH)); + return; + } + if (inst->is_join_cluster) { + cm_unlatch(&g_wr_instance.switch_latch, LATCH_STAT(LATCH_SWITCH)); + return; + } + } + // standby is started or masterid has been changed + if (master_id != curr_id) { + wr_recovery_when_standby(session, inst, curr_id, master_id); + cm_unlatch(&g_wr_instance.switch_latch, LATCH_STAT(LATCH_SWITCH)); + return; + } + /*1、grab lock success 2、set main,other switch lock 3、restart, lock no transfer*/ + wr_set_recover_thread_id(wr_get_current_thread_id()); + wr_recovery_when_primary(session, inst, curr_id, grab_lock); + wr_set_recover_thread_id(0); + cm_unlatch(&g_wr_instance.switch_latch, LATCH_STAT(LATCH_SWITCH)); +} + +#define WR_RECOVER_INTERVAL 500 +#define WR_SHORT_RECOVER_INTERVAL 100 +void wr_get_cm_lock_and_recover(thread_t *thread) +{ + cm_set_thread_name("recovery"); + uint32 work_idx = wr_get_recover_task_idx(); + wr_session_t *session = wr_get_reserv_session(work_idx); + wr_instance_t *inst = (wr_instance_t *)thread->argument; + while (!thread->closed) { + wr_get_cm_lock_and_recover_inner(session, inst); + if (inst->status == WR_STATUS_PREPARE) { + LOG_RUN_WAR("[RECOVERY]Try to sleep when in prepare status.\n"); + cm_sleep(WR_SHORT_RECOVER_INTERVAL); + } else { + cm_sleep(WR_RECOVER_INTERVAL); + } + } +} + +void wr_delay_clean_proc(thread_t *thread) +{ + cm_set_thread_name("delay_clean"); + uint32 work_idx = wr_get_delay_clean_task_idx(); + wr_session_ctrl_t *session_ctrl = wr_get_session_ctrl(); + wr_session_t *session = session_ctrl->sessions[work_idx]; + LOG_RUN_INF("Session[id=%u] is available for delay clean task.", session->id); + wr_config_t *inst_cfg = wr_get_inst_cfg(); + uint32 sleep_times = 0; + while (!thread->closed) { + if (sleep_times < inst_cfg->params.delay_clean_interval) { + cm_sleep(CM_SLEEP_1000_FIXED); + sleep_times++; + continue; + } + g_wr_instance.is_cleaning = CM_TRUE; + // WR_STATUS_OPEN for control with switchover + if (wr_need_exec_local() && wr_is_readwrite() && (g_wr_instance.status == WR_STATUS_OPEN)) { + //wr_delay_clean_all_vg(session); + } + g_wr_instance.is_cleaning = CM_FALSE; + sleep_times = 0; + } +} + +void wr_alarm_check_proc(thread_t *thread) +{ + cm_set_thread_name("alarm_check"); + uint32 sleep_times = 0; + uint32 work_idx = wr_get_alarm_check_task_idx(); + wr_session_ctrl_t *session_ctrl = wr_get_session_ctrl(); + wr_session_t *session = session_ctrl->sessions[work_idx]; + // for check other alarms + uint32 alarm_counts = WR_VG_ALARM_CHECK_COUNT; + while (!thread->closed) { + // only master node need alarm + if (sleep_times % WR_VG_ALARM_CHECK_COUNT == 0) { + g_wr_instance.is_checking = CM_TRUE; + wr_alarm_check_vg_usage(session); + g_wr_instance.is_checking = CM_FALSE; + } + cm_sleep(CM_SLEEP_500_FIXED); + sleep_times++; + sleep_times = sleep_times % alarm_counts; + } +} + +static void wr_check_peer_inst_inner(wr_instance_t *inst) +{ + /** + * During installation initialization, db_init depends on the WR server. However, the CMS is not started. + * Therefore, cm_init cannot be invoked during the WR server startup. + * Here, cm_init is invoked before the CM interface is invoked at first time. + */ + if (SECUREC_UNLIKELY(!inst->cm_res.is_init)) { + wr_init_cm_res(inst); + } + if (inst->cm_res.is_valid) { +#ifdef ENABLE_WRTEST + wr_check_peer_by_simulation_cm(inst); +#else + wr_check_peer_by_cm(inst); +#endif + return; + } + wr_check_peer_default(); +} + +void wr_check_peer_inst(wr_instance_t *inst, uint64 inst_id) +{ + wr_config_t *inst_cfg = wr_get_inst_cfg(); + if (inst_cfg->params.nodes_list.inst_cnt <= 1) { + return; + } + + uint64 inst_mask = ((uint64)0x1 << inst_id); + cm_spin_lock(&inst->inst_work_lock, NULL); + + // after lock, check again, other thd may get the lock, and init the map before + uint64 cur_inst_map = wr_get_inst_work_status(); + // has connection + if (inst_id != WR_INVALID_ID64 && (cur_inst_map & inst_mask) != 0) { + cm_spin_unlock(&inst->inst_work_lock); + return; + } + + wr_check_peer_inst_inner(inst); + cm_spin_unlock(&inst->inst_work_lock); +} + +uint64 wr_get_inst_work_status(void) +{ + return (uint64)cm_atomic_get((atomic_t *)&g_wr_instance.inst_work_status_map); +} + +void wr_set_inst_work_status(uint64 cur_inst_map) +{ + (void)cm_atomic_set((atomic_t *)&g_wr_instance.inst_work_status_map, (int64)cur_inst_map); +} + +bool32 wr_check_join_cluster() +{ + if (g_wr_instance.is_join_cluster) { + return CM_TRUE; + } + + if (wr_get_master_id() == g_wr_instance.inst_cfg.params.inst_id) { + g_wr_instance.is_join_cluster = CM_TRUE; + LOG_RUN_INF("Join cluster success by primary."); + } else { + // try register to new master to join + bool32 join_succ = CM_FALSE; + status_t status = wr_join_cluster(&join_succ); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Join cluster fail, wait next try."); + cm_reset_error(); + return CM_FALSE; + } + LOG_DEBUG_INF("Join cluster result [%u].", (uint32)join_succ); + if (!join_succ) { + return CM_FALSE; + } + g_wr_instance.is_join_cluster = CM_TRUE; + LOG_RUN_INF("Join cluster success by standby."); + } + + return CM_TRUE; +} + +static bool32 wr_find_unreg_volume(wr_session_t *session, char **dev, uint8 *vg_idx, uint8 *volume_id) +{ + for (uint32 i = 0; i < g_vgs_info->group_num; i++) { + for (uint32 j = 0; j < WR_MAX_VOLUMES; j++) { + if (g_vgs_info->volume_group[i].wr_ctrl->volume.defs[j].flag != VOLUME_PREPARE) { + continue; + } + wr_lock_vg_mem_and_shm_s(session, &g_vgs_info->volume_group[i]); + if (g_vgs_info->volume_group[i].wr_ctrl->volume.defs[j].flag != VOLUME_PREPARE) { + wr_unlock_vg_mem_and_shm(session, &g_vgs_info->volume_group[i]); + continue; + } + *dev = g_vgs_info->volume_group[i].wr_ctrl->volume.defs[j].name; + *vg_idx = (uint8)i; + *volume_id = (uint8)j; + wr_unlock_vg_mem_and_shm(session, &g_vgs_info->volume_group[i]); + return CM_TRUE; + } + } + return CM_FALSE; +} + +static bool32 wr_is_register(iof_reg_in_t *reg_info, int64 host_id) +{ + for (int32 i = 0; i < reg_info->key_count; i++) { + if (reg_info->reg_keys[i] == host_id + 1) { + return CM_TRUE; + } + } + return CM_FALSE; +} + +void wr_check_unreg_volume(wr_session_t *session) +{ + uint8 vg_idx, volume_id; + iof_reg_in_t reg_info; + (void)memset_s(®_info, sizeof(reg_info), 0, sizeof(reg_info)); + + bool32 is_unreg = wr_find_unreg_volume(session, ®_info.dev, &vg_idx, &volume_id); + if (!is_unreg) { + return; + } + status_t ret = cm_iof_inql(®_info); + if (ret != CM_SUCCESS) { + return; + } + bool32 remote = CM_FALSE; + wr_vg_info_item_t *vg_item = &g_vgs_info->volume_group[0]; + if (wr_lock_vg_storage_r(vg_item, vg_item->entry_path, g_inst_cfg) != CM_SUCCESS) { + return; + } + wr_lock_vg_mem_and_shm_s(session, vg_item); + ret = wr_load_vg_ctrl_part(vg_item, (int64)(WR_VOLUME_HEAD_SIZE - WR_DISK_UNIT_SIZE), + &vg_item->wr_ctrl->global_ctrl, WR_DISK_UNIT_SIZE, &remote); + wr_unlock_vg_mem_and_shm(session, vg_item); + (void)wr_unlock_vg_storage(vg_item, vg_item->entry_path, g_inst_cfg); + if (ret != CM_SUCCESS) { + return; + } + + bool32 is_reg = CM_FALSE; + for (uint8 i = 0; i < WR_MAX_INSTANCES; i++) { + is_reg = cm_bitmap64_exist(&vg_item->wr_ctrl->global_ctrl.cluster_node_info, i); + if (is_reg && !wr_is_register(®_info, i)) { + return; + } + } + + vg_item = &g_vgs_info->volume_group[vg_idx]; + wr_lock_vg_mem_and_shm_x(session, vg_item); + if (vg_item->wr_ctrl->volume.defs[volume_id].flag == VOLUME_FREE) { + wr_unlock_vg_mem_and_shm(session, vg_item); + return; + } + vg_item->wr_ctrl->volume.defs[volume_id].flag = VOLUME_OCCUPY; + ret = wr_update_volume_ctrl(vg_item); + wr_unlock_vg_mem_and_shm(session, vg_item); + if (ret != CM_SUCCESS) { + return; + } +} + +void wr_meta_syn_proc(thread_t *thread) +{ + cm_set_thread_name("meta_syn"); + wr_bg_task_info_t *bg_task_info = (wr_bg_task_info_t *)(thread->argument); + uint32 work_idx = wr_get_meta_syn_task_idx(bg_task_info->my_task_id); + wr_session_ctrl_t *session_ctrl = wr_get_session_ctrl(); + wr_session_t *session = session_ctrl->sessions[work_idx]; + while (!thread->closed) { + // WR_STATUS_OPEN for control with switchover + if (g_wr_instance.status == WR_STATUS_OPEN) { + (void)wr_meta_syn(session, bg_task_info); + } + cm_sleep(CM_SLEEP_10_FIXED); + } +} + +void wr_recycle_meta_proc(thread_t *thread) +{ + cm_set_thread_name("recycle_meta"); + + wr_bg_task_info_t *bg_task_info = (wr_bg_task_info_t *)(thread->argument); + wr_set_recycle_meta_args_to_vg(bg_task_info); + + uint32 work_idx = wr_get_recycle_meta_task_idx(bg_task_info->my_task_id); + wr_session_ctrl_t *session_ctrl = wr_get_session_ctrl(); + wr_session_t *session = session_ctrl->sessions[work_idx]; + date_t clean_time = cm_now(); + + while (!thread->closed) { + // WR_STATUS_OPEN for control with switchover + if (g_wr_instance.status == WR_STATUS_OPEN) { + wr_recycle_meta(session, bg_task_info, &clean_time); + cm_sleep(CM_SLEEP_10_FIXED); + continue; + } + cm_sleep(CM_SLEEP_10_FIXED); + } +} \ No newline at end of file diff --git a/src/service/wr_instance.h b/src/service/wr_instance.h new file mode 100644 index 0000000000000000000000000000000000000000..80085671f3870c3f57eae0e5ec3bd8ff5d2e1cf6 --- /dev/null +++ b/src/service/wr_instance.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_instance.h + * + * + * IDENTIFICATION + * src/service/wr_instance.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_INSTANCE_H__ +#define __WR_INSTANCE_H__ + +#include "cm_spinlock.h" +#include "cs_listener.h" +#include "wr_defs.h" +#include "wr_volume.h" +#include "wr_file.h" +#include "wr_session.h" +#include "wr_diskgroup.h" +#include "wr_param.h" +#include "cm_res_mgr.h" // for cm_res_mgr_t +#include "wr_reactor.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WR_MAX_INSTANCE_OPEN_FILES 1 +#define WR_LOGFILE_SIZE 10000 +#define WR_LOG_LEVEL 0xffffffff + +typedef enum { + CM_RES_SUCCESS = 0, + CM_RES_CANNOT_DO = 1, + CM_RES_DDB_FAILED = 2, + CM_RES_VERSION_WRONG = 3, + CM_RES_CONNECT_ERROR = 4, + CM_RES_TIMEOUT = 5, + CM_RES_NO_LOCK_OWNER = 6, +} cm_err_code; + +#define WR_CM_LOCK "wr cm lock" +#define WR_GET_CM_LOCK_LONG_SLEEP cm_sleep(500) + +typedef struct st_wr_cm_res { + spinlock_t init_lock; + bool8 is_init; + bool8 is_valid; + cm_res_mgr_t mgr; +} wr_cm_res; + +typedef struct st_wr_srv_args { + char wr_home[WR_MAX_PATH_BUFFER_SIZE]; + bool is_maintain; +} wr_srv_args_t; + +typedef struct st_wr_instance { + int32 lock_fd; + latch_t switch_latch; + wr_config_t inst_cfg; + wr_instance_status_e status; + tcp_lsnr_t lsnr; + latch_t tcp_lsnr_latch; + reactors_t reactors; + thread_t *threads; + int64 active_sessions; + bool32 abort_status; + wr_cm_res cm_res; + uint64 inst_work_status_map; // one bit one inst, bit value is 1 means inst ok, 0 means inst not ok + spinlock_t inst_work_lock; + int32 cluster_proto_vers[WR_MAX_INSTANCES]; + bool8 is_maintain; + bool8 is_cleaning; + bool8 no_grab_lock; + bool8 is_releasing_lock; + bool8 is_checking; + bool8 reserve[3]; + bool32 is_join_cluster; + wr_session_t *handle_session; + wr_bg_task_info_t syn_meta_task[WR_META_SYN_BG_TASK_NUM_MAX]; + +#if defined(_DEBUG) || defined(DEBUG) || defined(DB_DEBUG_VERSION) + void *fi_run_ctx; +#endif + wr_recycle_meta_t recycle_meta; +} wr_instance_t; + +status_t wr_lock_instance(void); +status_t wr_startup(wr_instance_t *inst, wr_srv_args_t wr_args); + +extern wr_instance_t g_wr_instance; +#define ZFS_INST (&g_wr_instance) +#define ZFS_CFG (&g_wr_instance.inst_cfg) + +status_t wr_start_lsnr(wr_instance_t *inst); +void wr_uninit_cm(wr_instance_t *inst); +void wr_check_peer_inst(wr_instance_t *inst, uint64 inst_id); +void wr_free_log_ctrl(); +status_t wr_alloc_vg_item_redo_log_buf(wr_vg_info_item_t *vg_item); +void wr_check_peer_by_inst(wr_instance_t *inst, uint64 inst_id); +uint64 wr_get_inst_work_status(void); +void wr_set_inst_work_status(uint64 cur_inst_map); +status_t wr_get_cm_lock_owner(wr_instance_t *inst, bool32 *grab_lock, bool32 try_lock, uint32 *master_id); +void wr_recovery_when_primary(wr_session_t *session, wr_instance_t *inst, uint32 curr_id, bool32 grab_lock); +status_t wr_get_cm_res_lock_owner(wr_cm_res *cm_res, uint32 *master_id); +void wr_get_cm_lock_and_recover(thread_t *thread); +void wr_delay_clean_proc(thread_t *thread); +void wr_hashmap_dynamic_extend_and_redistribute_proc(thread_t *thread); +bool32 wr_check_join_cluster(); +void wr_check_unreg_volume(wr_session_t *session); +void wr_meta_syn_proc(thread_t *thread); +void wr_recycle_meta_proc(thread_t *thread); +void wr_alarm_check_proc(thread_t *thread); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/service/wr_mes.c b/src/service/wr_mes.c new file mode 100644 index 0000000000000000000000000000000000000000..3aa5d161516ea579112a6fe7d639122b5361d95d --- /dev/null +++ b/src/service/wr_mes.c @@ -0,0 +1,1245 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_mes.c + * + * + * IDENTIFICATION + * src/service/wr_mes.c + * + * ------------------------------------------------------------------------- + */ + +#include "cm_types.h" +#include "cm_error.h" +#include "wr_malloc.h" +#include "wr_session.h" +#include "wr_file.h" +#include "wr_service.h" +#include "wr_instance.h" +#include "wr_api.h" +#include "wr_mes.h" +#include "wr_syn_meta.h" +#include "wr_thv.h" +#include "wr_fault_injection.h" +#include "wr_param_verify.h" + +void wr_proc_broadcast_req(wr_session_t *session, mes_msg_t *msg); +void wr_proc_syb2active_req(wr_session_t *session, mes_msg_t *msg); +void wr_proc_loaddisk_req(wr_session_t *session, mes_msg_t *msg); +void wr_proc_join_cluster_req(wr_session_t *session, mes_msg_t *msg); +void wr_proc_refresh_ft_by_primary_req(wr_session_t *session, mes_msg_t *msg); + +void wr_proc_normal_ack(wr_session_t *session, mes_msg_t *msg) +{ + wr_message_head_t *wr_head = (wr_message_head_t *)msg->buffer; + LOG_DEBUG_INF("[MES] Receive ack(%u),src inst(%u), dst inst(%u).", (uint32)(wr_head->wr_cmd), + (uint32)(wr_head->src_inst), (uint32)(wr_head->dst_inst)); +} + +wr_processor_t g_wr_processors[WR_CMD_CEIL] = { + [WR_CMD_REQ_BROADCAST] = {wr_proc_broadcast_req, CM_TRUE, CM_TRUE, MES_PRIORITY_ONE, "wr broadcast"}, + [WR_CMD_ACK_BROADCAST_WITH_MSG] = {wr_proc_normal_ack, CM_FALSE, CM_FALSE, MES_PRIORITY_ONE, + "wr broadcast ack with data"}, + [WR_CMD_REQ_SYB2ACTIVE] = {wr_proc_syb2active_req, CM_TRUE, CM_TRUE, MES_PRIORITY_ONE, + "wr standby to active req"}, + [WR_CMD_ACK_SYB2ACTIVE] = {wr_proc_normal_ack, CM_FALSE, CM_FALSE, MES_PRIORITY_ONE, "wr active to standby ack"}, + [WR_CMD_REQ_JOIN_CLUSTER] = {wr_proc_join_cluster_req, CM_TRUE, CM_TRUE, MES_PRIORITY_ONE, + "wr standby join in cluster to active req"}, + [WR_CMD_ACK_JOIN_CLUSTER] = {wr_proc_normal_ack, CM_FALSE, CM_FALSE, MES_PRIORITY_ONE, + "wr active proc join in cluster to standby ack"}, +}; + +static inline mes_priority_t wr_get_cmd_prio_id(wr_mes_command_t cmd) +{ + return g_wr_processors[cmd].prio_id; +} + +typedef void (*wr_remote_ack_proc)(wr_session_t *session, wr_remote_exec_succ_ack_t *remote_ack); +typedef struct st_wr_remote_ack_hdl { + wr_remote_ack_proc proc; +} wr_remote_ack_hdl_t; +void wr_process_remote_ack_for_get_ftid_by_path(wr_session_t *session, wr_remote_exec_succ_ack_t *remote_ack) +{ + wr_find_node_t *ft_node = (wr_find_node_t *)(remote_ack->body_buf + sizeof(uint32)); + wr_vg_info_item_t *vg_item = wr_find_vg_item(ft_node->vg_name); + (void)wr_get_ft_node_by_ftid(session, vg_item, ft_node->ftid, CM_TRUE, CM_FALSE); +} +static wr_remote_ack_hdl_t g_wr_remote_ack_handle[WR_CMD_TYPE_OFFSET(WR_CMD_END)] = { + [WR_CMD_TYPE_OFFSET(WR_CMD_GET_FTID_BY_PATH)] = {wr_process_remote_ack_for_get_ftid_by_path}, +}; + +static inline wr_remote_ack_hdl_t *wr_get_remote_ack_handle(int32 cmd) +{ + if (cmd >= WR_CMD_BEGIN && cmd < WR_CMD_END) { + return &g_wr_remote_ack_handle[WR_CMD_TYPE_OFFSET(cmd)]; + } + return NULL; +} + +static void wr_init_mes_head(wr_message_head_t *head, uint32 cmd, uint32 flags, uint16 src_inst, uint16 dst_inst, + uint32 size, uint32 version, ruid_type ruid) +{ + (void)memset_s(head, WR_MES_MSG_HEAD_SIZE, 0, WR_MES_MSG_HEAD_SIZE); + head->sw_proto_ver = WR_PROTO_VERSION; + head->msg_proto_ver = version; + head->size = size; + head->wr_cmd = cmd; + head->ruid = ruid; + head->src_inst = src_inst; + head->dst_inst = dst_inst; + head->flags = flags | wr_get_cmd_prio_id(cmd); +} + +static wr_bcast_ack_cmd_t wr_get_bcast_ack_cmd(wr_bcast_req_cmd_t bcast_op) +{ + switch (bcast_op) { + case BCAST_REQ_DEL_DIR_FILE: + return BCAST_ACK_DEL_FILE; + case BCAST_REQ_INVALIDATE_META: + return BCAST_ACK_INVALIDATE_META; + case BCAST_REQ_META_SYN: + return BCAST_ACK_META_SYN; + default: + LOG_RUN_ERR("Invalid broadcast request type"); + break; + } + return BCAST_ACK_END; +} +// warning: if add new broadcast req, please consider the impact of expired broadcast messages on the standby server +static void wr_proc_broadcast_req_inner(wr_session_t *session, wr_notify_req_msg_t *req) +{ + status_t status = CM_ERROR; + bool32 cmd_ack = CM_FALSE; + wr_notify_req_msg_ex_t *req_ex = NULL; + switch (req->type) { + case BCAST_REQ_DEL_DIR_FILE: + status = wr_check_open_file_remote(session, req->vg_name, req->ftid, &cmd_ack); + break; + case BCAST_REQ_INVALIDATE_META: + req_ex = (wr_notify_req_msg_ex_t *)req; + status = wr_invalidate_meta_remote( + session, (wr_invalidate_meta_msg_t *)req_ex->data, req_ex->data_size, &cmd_ack); + break; + case BCAST_REQ_META_SYN: + req_ex = (wr_notify_req_msg_ex_t *)req; + status = wr_meta_syn_remote(session, (wr_meta_syn_t *)req_ex->data, req_ex->data_size, &cmd_ack); + return; + default: + LOG_RUN_ERR("invalid broadcast req type"); + return; + } + if (cm_get_error_code() == ERR_WR_SHM_LOCK_TIMEOUT) { + LOG_RUN_ERR("broadcast is breaked by shm lock timeout."); + return; + } + wr_config_t *inst_cfg = wr_get_inst_cfg(); + wr_params_t *param = &inst_cfg->params; + wr_message_head_t *req_head = &req->wr_head; + uint16 dst_inst = req_head->src_inst; + uint16 src_inst = (uint16)param->inst_id; + uint32 version = req_head->msg_proto_ver; + ruid_type ruid = req_head->ruid; + wr_notify_ack_msg_t ack_check; + wr_init_mes_head(&ack_check.wr_head, WR_CMD_ACK_BROADCAST_WITH_MSG, 0, src_inst, dst_inst, + sizeof(wr_notify_ack_msg_t), version, ruid); + ack_check.type = wr_get_bcast_ack_cmd(req->type); + ack_check.result = status; + ack_check.cmd_ack = cmd_ack; + int ret = + mes_send_response(dst_inst, ack_check.wr_head.flags, ruid, (char *)&ack_check, sizeof(wr_notify_ack_msg_t)); + if (ret != CM_SUCCESS) { + LOG_DEBUG_ERR("[MES] send message failed, src inst(%hhu), dst inst(%hhu) ret(%d) ", src_inst, dst_inst, ret); + return; + } + WR_LOG_DEBUG_OP("[MES] Succeed to send message, notify %llu result: %u. cmd=%u, src_inst=%hhu, dst_inst=%hhu.", + req->ftid, cmd_ack, ack_check.wr_head.wr_cmd, ack_check.wr_head.src_inst, ack_check.wr_head.dst_inst); +} + +int32 wr_process_broadcast_ack(wr_notify_ack_msg_t *ack, wr_recv_msg_t *recv_msg_output) +{ + int32 ret = ERR_WR_MES_ILL; + switch (ack->type) { + case BCAST_ACK_DEL_FILE: + case BCAST_ACK_INVALIDATE_META: + case BCAST_ACK_META_SYN: + ret = ack->result; + // recv_msg_output->cmd_ack init-ed with the deault, if some node not the same with the default, let's cover + // the default value + if (ret == CM_SUCCESS && recv_msg_output->default_ack != ack->cmd_ack) { + recv_msg_output->cmd_ack = ack->cmd_ack; + } + break; + default: + LOG_DEBUG_ERR("invalid broadcast ack type"); + break; + } + return ret; +} + +static void wr_ack_version_not_match(wr_session_t *session, wr_message_head_t *req_head, uint32 version) +{ + wr_config_t *inst_cfg = wr_get_inst_cfg(); + wr_params_t *param = &inst_cfg->params; + uint16 dst_inst = req_head->src_inst; + uint16 src_inst = (uint16)param->inst_id; + ruid_type ruid = req_head->ruid; + wr_message_head_t ack_head; + uint32 cmd = (req_head->wr_cmd == WR_CMD_REQ_BROADCAST) ? WR_CMD_ACK_BROADCAST_WITH_MSG : WR_CMD_ACK_SYB2ACTIVE; + wr_init_mes_head(&ack_head, cmd, 0, src_inst, dst_inst, WR_MES_MSG_HEAD_SIZE, version, ruid); + ack_head.result = ERR_WR_VERSION_NOT_MATCH; + int ret = mes_send_response(dst_inst, ack_head.flags, ruid, (char *)&ack_head, WR_MES_MSG_HEAD_SIZE); + if (ret != CM_SUCCESS) { + LOG_DEBUG_ERR( + "send version not match message failed, src inst(%hhu), dst inst(%hhu) ret(%d)", src_inst, dst_inst, ret); + return; + } + LOG_RUN_INF("send version not match message succeed, src inst(%hhu), dst inst(%hhu), ack msg version (%hhu)", + src_inst, dst_inst, version); +} + +void wr_proc_broadcast_req(wr_session_t *session, mes_msg_t *msg) +{ + if (wr_need_exec_local()) { + LOG_RUN_INF("No need to solve broadcast msg when the current node is master."); + return; + } + if (msg->size < OFFSET_OF(wr_notify_req_msg_t, type)) { + LOG_DEBUG_ERR("invalid message req size"); + return; + } + wr_notify_req_msg_t *req = (wr_notify_req_msg_t *)msg->buffer; + LOG_DEBUG_INF("[MES] Try proc broadcast req, head cmd is %u, req cmd is %u.", req->wr_head.wr_cmd, req->type); + wr_proc_broadcast_req_inner(session, req); + return; +} + +static void wr_set_cluster_proto_vers(uint8 inst_id, uint32 version) +{ + if (inst_id >= WR_MAX_INSTANCES) { + LOG_DEBUG_ERR("Invalid request inst_id:%hhu, version is %u.", inst_id, version); + return; + } + bool32 set_flag = CM_FALSE; + do { + uint32 cur_version = (uint32)cm_atomic32_get((atomic32_t *)&g_wr_instance.cluster_proto_vers[inst_id]); + if (cur_version == version) { + break; + } + set_flag = cm_atomic32_cas( + (atomic32_t *)&g_wr_instance.cluster_proto_vers[inst_id], (int32)cur_version, (int32)version); + } while (!set_flag); +} + +static int wr_handle_broadcast_msg(mes_msg_list_t *responses, wr_recv_msg_t *recv_msg_output) +{ + int ret; + wr_message_head_t *ack_head; + uint32 src_inst; + for (uint32 i = 0; i < responses->count; i++) { + mes_msg_t *msg = &responses->messages[i]; + ack_head = (wr_message_head_t *)msg->buffer; + src_inst = responses->messages[i].src_inst; + wr_set_cluster_proto_vers((uint8)src_inst, ack_head->sw_proto_ver); + if (ack_head->result == ERR_WR_VERSION_NOT_MATCH) { + recv_msg_output->version_not_match_inst |= ((uint64)0x1 << src_inst); + continue; + } + if (ack_head->size < sizeof(wr_notify_ack_msg_t)) { + WR_THROW_ERROR(ERR_WR_MES_ILL, "msg len is invalid"); + return ERR_WR_MES_ILL; + } + wr_notify_ack_msg_t *ack = (wr_notify_ack_msg_t *)ack_head; + ret = wr_process_broadcast_ack(ack, recv_msg_output); + WR_RETURN_IFERR2(ret, WR_THROW_ERROR(ERR_WR_FILE_OPENING_REMOTE, ack_head->src_inst, ack_head->wr_cmd)); + } + return WR_SUCCESS; +} + +static void wr_release_broadcast_msg(mes_msg_list_t *responses) +{ + for (uint32 i = 0; i < responses->count; i++) { + mes_release_msg(&responses->messages[i]); + } +} + +static int wr_handle_recv_broadcast_msg( + ruid_type ruid, uint32 timeout, uint64 *succ_ack_inst, wr_recv_msg_t *recv_msg_output) +{ + mes_msg_list_t responses; + int ret = mes_broadcast_get_response(ruid, &responses, timeout); + if (ret != WR_SUCCESS) { + LOG_DEBUG_INF("[MES] Try broadcast get response failed, ret is %d, ruid is %llu.", ret, ruid); + return ret; + } + ret = wr_handle_broadcast_msg(&responses, recv_msg_output); + if (ret != WR_SUCCESS) { + wr_release_broadcast_msg(&responses); + LOG_DEBUG_INF("[MES] Try broadcast get response failed, ret is %d, ruid is %llu.", ret, ruid); + return ret; + } + // do not care ret, just check get ack msg + for (uint32 i = 0; i < responses.count; i++) { + uint32 src_inst = responses.messages[i].src_inst; + *succ_ack_inst |= ((uint64)0x1 << src_inst); + } + *succ_ack_inst = *succ_ack_inst & (~recv_msg_output->version_not_match_inst); + wr_release_broadcast_msg(&responses); + return ret; +} + +static void wr_handle_discard_recv_broadcast_msg(ruid_type ruid) +{ + mes_msg_list_t responses; + int ret = mes_broadcast_get_response(ruid, &responses, 0); + if (ret == CM_SUCCESS) { + wr_release_broadcast_msg(&responses); + } +} + +uint32 wr_get_broadcast_proto_ver(uint64 succ_inst) +{ + uint64 inst_mask; + uint64 cur_work_inst_map = wr_get_inst_work_status(); + uint64 need_send_inst = (~succ_inst & cur_work_inst_map); + uint32 inst_proto_ver; + uint32 broadcast_proto_vers = WR_PROTO_VERSION; + for (uint32 i = 0; i < WR_MAX_INSTANCES; i++) { + inst_mask = ((uint64)0x1 << i); + if ((need_send_inst & inst_mask) == 0) { + continue; + } + inst_proto_ver = (uint32)cm_atomic32_get((atomic32_t *)&g_wr_instance.cluster_proto_vers[i]); + if (inst_proto_ver == WR_INVALID_VERSION) { + continue; + } + broadcast_proto_vers = MIN(broadcast_proto_vers, inst_proto_ver); + } + return broadcast_proto_vers; +} + +void wr_get_valid_inst(uint64 valid_inst, uint32 *arr, uint32 count) +{ + uint32 i = 0; + for (uint32 j = 0; j < WR_MAX_INSTANCES; j++) { + if (WR_IS_INST_SEND(valid_inst, j)) { + arr[i] = j; + i++; + } + } +} + +#define WR_BROADCAST_MSG_TRY_MAX 5 +#define WR_BROADCAST_MSG_TRY_SLEEP_TIME 200 +static status_t wr_broadcast_msg_with_try(wr_message_head_t *wr_head, wr_recv_msg_t *recv_msg, unsigned int timeout) +{ + int32 ret = WR_SUCCESS; + + wr_config_t *inst_cfg = wr_get_inst_cfg(); + wr_params_t *param = &inst_cfg->params; + uint64 succ_req_inst = 0; + uint64 succ_ack_inst = 0; + uint32 i = 0; + // init last send err with all + uint64 cur_work_inst_map = wr_get_inst_work_status(); + uint64 snd_err_inst_map = (~recv_msg->succ_inst & cur_work_inst_map); + uint64 last_inst_inst_map = 0; + uint64 new_added_inst_map = 0; + uint64 valid_inst = 0; + uint64 valid_inst_mask = 0; + do { + // only send the last-send-failed and new added + cm_reset_error(); + valid_inst_mask = ((cur_work_inst_map & snd_err_inst_map) | new_added_inst_map); + valid_inst = (param->nodes_list.inst_map) & (~((uint64)0x1 << (uint64)(param->inst_id))) & valid_inst_mask; + valid_inst = (~recv_msg->version_not_match_inst & valid_inst); + if (valid_inst == 0) { + if (recv_msg->version_not_match_inst != 0) { + recv_msg->version_not_match_inst = 0; + return ERR_WR_VERSION_NOT_MATCH; + } + LOG_DEBUG_INF("[MES] No inst need to broadcast."); + return CM_SUCCESS; + } + LOG_DEBUG_INF("[MES] Try broadcast num is %u, head cmd is %u.", i, wr_head->wr_cmd); + uint32 count = cm_bitmap64_count(valid_inst); + uint32 valid_inst_arr[WR_MAX_INSTANCES] = {0}; + wr_get_valid_inst(valid_inst, valid_inst_arr, count); + (void)mes_broadcast_request_sp( + (inst_type *)valid_inst_arr, count, wr_head->flags, &wr_head->ruid, (char *)wr_head, wr_head->size); + succ_req_inst = valid_inst; + if (!recv_msg->ignore_ack) { + ret = wr_handle_recv_broadcast_msg(wr_head->ruid, timeout, &succ_ack_inst, recv_msg); + } else { + wr_handle_discard_recv_broadcast_msg(wr_head->ruid); + ret = CM_SUCCESS; + succ_ack_inst = succ_req_inst; + } + + uint64 succ_inst = valid_inst & succ_ack_inst; + LOG_DEBUG_INF( + "[MES] Try broadcast num is %u, valid_inst is %llu, succ_inst is %llu.", i, valid_inst, succ_inst); + if (succ_inst != 0) { + recv_msg->succ_inst = recv_msg->succ_inst | succ_inst; + } + if (ret == CM_SUCCESS && succ_req_inst == succ_ack_inst) { + if (recv_msg->version_not_match_inst != 0) { + recv_msg->version_not_match_inst = 0; + return ERR_WR_VERSION_NOT_MATCH; + } + return ret; + } + // ready for next try only new added and (send req failed or recv ack failed) + snd_err_inst_map = valid_inst_mask & (~(succ_req_inst & succ_ack_inst)); + last_inst_inst_map = cur_work_inst_map; + cur_work_inst_map = wr_get_inst_work_status(); + new_added_inst_map = (~last_inst_inst_map & cur_work_inst_map); + cm_sleep(WR_BROADCAST_MSG_TRY_SLEEP_TIME); + i++; + } while (i < WR_BROADCAST_MSG_TRY_MAX); + cm_reset_error(); + WR_THROW_ERROR(ERR_WR_MES_ILL, "Failed to broadcast msg with try."); + LOG_RUN_ERR("[WR] THROW UP ERROR WHEN BROADCAST FAILED, errcode:%d", cm_get_error_code()); + return CM_ERROR; +} + +static status_t wr_broadcast_msg(char *req_buf, uint32 size, wr_recv_msg_t *recv_msg, unsigned int timeout) +{ + return wr_broadcast_msg_with_try((wr_message_head_t *)req_buf, recv_msg, timeout); +} + +static bool32 wr_check_srv_status(mes_msg_t *msg) +{ + wr_message_head_t *wr_head = (wr_message_head_t *)(msg->buffer); + if (g_wr_instance.status != WR_STATUS_OPEN && wr_head->wr_cmd != WR_CMD_ACK_JOIN_CLUSTER) { + LOG_DEBUG_INF("[MES] Could not exec remote req for the wrserver is not open or msg not join cluster, src " + "node:%u, wait try again.", + (uint32)(wr_head->src_inst)); + return CM_FALSE; + } + return CM_TRUE; +} + +static status_t wr_prepare_ack_msg( + wr_session_t *session, status_t ret, char **ack_buf, uint32 *ack_size, uint32 version) +{ + int32 code; + const char *message = NULL; + wr_packet_t *send_pack = &session->send_pack; + + if (ret != CM_SUCCESS) { + wr_init_set(send_pack, version); + *ack_buf = WR_WRITE_ADDR(send_pack); + cm_get_error(&code, &message); + CM_RETURN_IFERR(wr_put_int32(send_pack, code)); + CM_RETURN_IFERR(wr_put_str(send_pack, message)); + } else { + *ack_buf = send_pack->buf + sizeof(wr_packet_head_t); + } + *ack_size = send_pack->head->size - sizeof(wr_packet_head_t); + return CM_SUCCESS; +} + +void wr_proc_remote_req_err(wr_session_t *session, wr_message_head_t *req_wr_head, unsigned char cmd, int32 ret) +{ + wr_message_head_t ack; + char *ack_buf = NULL; + uint32 ack_size = 0; + status_t status = wr_prepare_ack_msg(session, ret, &ack_buf, &ack_size, req_wr_head->msg_proto_ver); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("The wrserver prepare ack msg failed, src node:%u, dst node:%u.", req_wr_head->src_inst, + req_wr_head->dst_inst); + return; + } + uint16 src_inst = req_wr_head->dst_inst; + uint16 dst_inst = req_wr_head->src_inst; + ruid_type ruid = req_wr_head->ruid; + uint32 version = req_wr_head->msg_proto_ver; + wr_init_mes_head(&ack, cmd, 0, src_inst, dst_inst, ack_size + WR_MES_MSG_HEAD_SIZE, version, ruid); + ack.result = ret; + (void)mes_send_response_x(dst_inst, ack.flags, ruid, 2, &ack, WR_MES_MSG_HEAD_SIZE, ack_buf, ack_size); +} + +static status_t wr_process_remote_req_prepare(wr_session_t *session, mes_msg_t *msg, wr_processor_t *processor) +{ + wr_message_head_t *wr_head = (wr_message_head_t *)msg->buffer; + // ready the ack connection + wr_check_peer_by_inst(&g_wr_instance, wr_head->src_inst); + if (wr_head->wr_cmd != WR_CMD_REQ_BROADCAST && + (!wr_need_exec_local() || get_instance_status_proc() != WR_STATUS_OPEN)) { + LOG_RUN_ERR("Proc msg cmd:%u from remote node:%u fail, can NOT exec here.", (uint32)wr_head->wr_cmd, + wr_head->src_inst); + return CM_ERROR; + } + + if (wr_check_srv_status(msg) != CM_TRUE) { + LOG_RUN_WAR("Proc msg cmd:%u from remote node:%u fail, local status %u not open, wait try again.", + (uint32)wr_head->wr_cmd, wr_head->src_inst, g_wr_instance.status); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t wr_process_remote_ack_prepare(wr_session_t *session, mes_msg_t *msg, wr_processor_t *processor) +{ + if (wr_check_srv_status(msg) != CM_TRUE) { + wr_message_head_t *wr_head = (wr_message_head_t *)msg->buffer; + LOG_RUN_WAR("Proc msg cmd:%u from remote node:%u fail, local status %u not open, wait try again.", + (uint32)wr_head->wr_cmd, wr_head->src_inst, g_wr_instance.status); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static void wr_process_message(uint32 work_idx, ruid_type ruid, mes_msg_t *msg) +{ + cm_reset_error(); + + DDES_FAULT_INJECTION_ACTION_TRIGGER_CUSTOM( + WR_FI_MES_PROC_ENTER, cm_sleep(ddes_fi_get_entry_value(DDES_FI_TYPE_CUSTOM_FAULT))); + + wr_config_t *inst_cfg = wr_get_inst_cfg(); + uint32 mes_sess_cnt = inst_cfg->params.channel_num + inst_cfg->params.work_thread_cnt; + if (work_idx >= mes_sess_cnt) { + cm_panic(0); + } + if (msg->size < WR_MES_MSG_HEAD_SIZE) { + LOG_DEBUG_ERR("invalid message req size."); + return; + } + wr_message_head_t *wr_head = (wr_message_head_t *)msg->buffer; + LOG_DEBUG_INF("[MES] Proc msg cmd:%u, src node:%u, dst node:%u begin.", (uint32)(wr_head->wr_cmd), + (uint32)(wr_head->src_inst), (uint32)(wr_head->dst_inst)); + + wr_session_ctrl_t *session_ctrl = wr_get_session_ctrl(); + wr_session_t *session = session_ctrl->sessions[work_idx]; + status_t ret; + if (wr_head->size < WR_MES_MSG_HEAD_SIZE) { + LOG_DEBUG_ERR("Invalid message size"); + return; + } + wr_set_cluster_proto_vers((uint8)wr_head->src_inst, wr_head->sw_proto_ver); + if (wr_head->msg_proto_ver > WR_PROTO_VERSION) { + uint32 curr_proto_ver = MIN(wr_head->sw_proto_ver, WR_PROTO_VERSION); + wr_ack_version_not_match(session, wr_head, curr_proto_ver); + return; + } + if (wr_head->wr_cmd >= WR_CMD_CEIL) { + LOG_DEBUG_ERR("Invalid request received,cmd is %u.", (uint8)wr_head->wr_cmd); + return; + } + wr_init_packet(&session->recv_pack, CM_FALSE); + wr_init_packet(&session->send_pack, CM_FALSE); + wr_init_set(&session->send_pack, wr_head->msg_proto_ver); + session->proto_version = wr_head->msg_proto_ver; + LOG_DEBUG_INF( + "[MES] wr process message, cmd is %u, proto_version is %u.", wr_head->wr_cmd, wr_head->msg_proto_ver); + wr_processor_t *processor = &g_wr_processors[wr_head->wr_cmd]; + const char *error_message = NULL; + int32 error_code; + // from here, the proc need to give the ack and release message buf + while (CM_TRUE) { + cm_latch_s(&g_wr_instance.switch_latch, WR_DEFAULT_SESSIONID, CM_FALSE, LATCH_STAT(LATCH_SWITCH)); + if (processor->is_req) { + ret = wr_process_remote_req_prepare(session, msg, processor); + } else { + ret = wr_process_remote_ack_prepare(session, msg, processor); + } + if (ret != CM_SUCCESS) { + cm_unlatch(&g_wr_instance.switch_latch, LATCH_STAT(LATCH_SWITCH)); + return; + } + processor->proc(session, msg); + cm_get_error(&error_code, &error_message); + if (error_code == ERR_WR_SHM_LOCK_TIMEOUT) { + cm_unlatch(&g_wr_instance.switch_latch, LATCH_STAT(LATCH_SWITCH)); + LOG_RUN_INF("Try again if error is shm lock timeout."); + cm_reset_error(); + continue; + } + cm_unlatch(&g_wr_instance.switch_latch, LATCH_STAT(LATCH_SWITCH)); + break; + } + LOG_DEBUG_INF("[MES] Proc msg cmd:%u, src node:%u, dst node:%u end.", (uint32)(wr_head->wr_cmd), + (uint32)(wr_head->src_inst), (uint32)(wr_head->dst_inst)); +} + +// add function +static status_t wr_register_proc(void) +{ + mes_register_proc_func(wr_process_message); + return CM_SUCCESS; +} + +#define WR_MES_PRIO_CNT 2 +static status_t wr_set_mes_message_pool(unsigned long long recv_msg_buf_size, mes_profile_t *profile) +{ + LOG_DEBUG_INF("mes message pool size:%llu", recv_msg_buf_size); + int ret = CM_SUCCESS; + mes_msg_pool_attr_t *mpa = &profile->msg_pool_attr; + mpa->total_size = recv_msg_buf_size; + mpa->enable_inst_dimension = CM_FALSE; + mpa->buf_pool_count = WR_MSG_BUFFER_NO_CEIL; + + mpa->buf_pool_attr[WR_MSG_BUFFER_NO_0].buf_size = WR_FIRST_BUFFER_LENGTH; + mpa->buf_pool_attr[WR_MSG_BUFFER_NO_1].buf_size = WR_SECOND_BUFFER_LENGTH; + mpa->buf_pool_attr[WR_MSG_BUFFER_NO_2].buf_size = WR_THIRD_BUFFER_LENGTH; + mpa->buf_pool_attr[WR_MSG_BUFFER_NO_3].buf_size = WR_FOURTH_BUFFER_LENGTH; + + mes_msg_buffer_pool_attr_t *buf_pool_attr; + buf_pool_attr = &mpa->buf_pool_attr[WR_MSG_BUFFER_NO_3]; + buf_pool_attr->shared_pool_attr.queue_num = WR_MSG_FOURTH_BUFFER_QUEUE_NUM; + for (uint32 prio = 0; prio < profile->priority_cnt; prio++) { + buf_pool_attr->priority_pool_attr[prio].queue_num = WR_MSG_FOURTH_BUFFER_QUEUE_NUM; + } + + for (uint8 buf_pool_no = 0; buf_pool_no < mpa->buf_pool_count; buf_pool_no++) { + buf_pool_attr = &mpa->buf_pool_attr[buf_pool_no]; + buf_pool_attr->shared_pool_attr.queue_num = WR_MSG_BUFFER_QUEUE_NUM; + for (uint32 prio = 0; prio < profile->priority_cnt; prio++) { + buf_pool_attr->priority_pool_attr[prio].queue_num = WR_MSG_BUFFER_QUEUE_NUM; + } + } + + for (uint32 prio = 0; prio < profile->priority_cnt; prio++) { + mpa->max_buf_size[prio] = mpa->buf_pool_attr[WR_MSG_BUFFER_NO_3].buf_size; + } + + mes_msg_pool_minimum_info_t minimum_info ={0}; + ret = mes_get_message_pool_minimum_info(profile, CM_FALSE, &minimum_info); + if (ret != CM_SUCCESS) { + LOG_RUN_ERR("[WR] set mes message pool, get message pool minimum info failed"); + return ret; + } + // want fourth buf_pool smallest + double fourth_ratio = ((double)(minimum_info.buf_pool_minimum_size[WR_MSG_BUFFER_NO_3]) / + (mpa->total_size - minimum_info.metadata_size)) + + DBL_EPSILON; + mpa->buf_pool_attr[WR_MSG_BUFFER_NO_3].proportion = fourth_ratio; + + double left_ratio = 1 - fourth_ratio; + mpa->buf_pool_attr[WR_MSG_BUFFER_NO_0].proportion = WR_FIRST_BUFFER_RATIO * left_ratio; + mpa->buf_pool_attr[WR_MSG_BUFFER_NO_1].proportion = WR_SECOND_BUFFER_RATIO * left_ratio; + mpa->buf_pool_attr[WR_MSG_BUFFER_NO_2].proportion = + 1 - (mpa->buf_pool_attr[WR_MSG_BUFFER_NO_0].proportion + mpa->buf_pool_attr[WR_MSG_BUFFER_NO_1].proportion + + mpa->buf_pool_attr[WR_MSG_BUFFER_NO_3].proportion); + return CM_SUCCESS; +} + +static void wr_set_group_task_num(wr_config_t *wr_profile, mes_profile_t *mes_profile) +{ + uint32 work_thread_cnt_load_meta = + (uint32)(wr_profile->params.work_thread_cnt * WR_WORK_THREAD_LOAD_DATA_PERCENT); + if (work_thread_cnt_load_meta == 0) { + work_thread_cnt_load_meta = 1; + } + uint32 work_thread_cnt_comm = (wr_profile->params.work_thread_cnt - work_thread_cnt_load_meta); + mes_profile->send_directly = CM_TRUE; + mes_profile->send_task_count[MES_PRIORITY_ZERO] = 0; + mes_profile->work_task_count[MES_PRIORITY_ZERO] = work_thread_cnt_load_meta; + mes_profile->recv_task_count[MES_PRIORITY_ZERO] = + MAX(1, (uint32)(work_thread_cnt_load_meta * WR_RECV_WORK_THREAD_RATIO)); + + mes_profile->send_task_count[MES_PRIORITY_ONE] = 0; + mes_profile->work_task_count[MES_PRIORITY_ONE] = work_thread_cnt_comm; + mes_profile->recv_task_count[MES_PRIORITY_ONE] = + MAX(1, (uint32)(work_thread_cnt_comm * WR_RECV_WORK_THREAD_RATIO)); +} + +static status_t wr_set_mes_profile(mes_profile_t *profile) +{ + errno_t errcode = memset_sp(profile, sizeof(mes_profile_t), 0, sizeof(mes_profile_t)); + securec_check_ret(errcode); + + wr_config_t *inst_cfg = wr_get_inst_cfg(); + profile->inst_id = (uint32)inst_cfg->params.inst_id; + profile->pipe_type = (mes_pipe_type_t)inst_cfg->params.pipe_type; + profile->channel_cnt = inst_cfg->params.channel_num; + profile->conn_created_during_init = 0; + profile->mes_elapsed_switch = inst_cfg->params.elapsed_switch; + profile->mes_with_ip = inst_cfg->params.mes_with_ip; + profile->ip_white_list_on = inst_cfg->params.ip_white_list_on; + profile->inst_cnt = inst_cfg->params.nodes_list.inst_cnt; + uint32 inst_cnt = 0; + for (uint32 i = 0; i < WR_MAX_INSTANCES; i++) { + uint64_t inst_mask = ((uint64)0x1 << i); + if ((inst_cfg->params.nodes_list.inst_map & inst_mask) == 0) { + continue; + } + errcode = strncpy_s(profile->inst_net_addr[inst_cnt].ip, CM_MAX_IP_LEN, inst_cfg->params.nodes_list.nodes[i], + strlen(inst_cfg->params.nodes_list.nodes[i])); + if (errcode != EOK) { + WR_RETURN_IFERR2(CM_ERROR, WR_THROW_ERROR(ERR_SYSTEM_CALL, (errcode))); + } + profile->inst_net_addr[inst_cnt].port = inst_cfg->params.nodes_list.ports[i]; + profile->inst_net_addr[inst_cnt].need_connect = CM_TRUE; + profile->inst_net_addr[inst_cnt].inst_id = i; + inst_cnt++; + if (inst_cnt == inst_cfg->params.nodes_list.inst_cnt) { + break; + } + } + profile->priority_cnt = WR_MES_PRIO_CNT; + profile->frag_size = WR_FOURTH_BUFFER_LENGTH; + profile->max_wait_time = inst_cfg->params.mes_wait_timeout; + profile->connect_timeout = (int)CM_CONNECT_TIMEOUT; + profile->socket_timeout = (int)CM_NETWORK_IO_TIMEOUT; + + wr_set_group_task_num(inst_cfg, profile); + status_t status = wr_set_mes_message_pool(inst_cfg->params.mes_pool_size, profile); + if (status != CM_SUCCESS) { + return status; + } + profile->tpool_attr.enable_threadpool = CM_FALSE; + return CM_SUCCESS; +} + +static status_t wr_create_mes_session(void) +{ + wr_config_t *inst_cfg = wr_get_inst_cfg(); + uint32 mes_sess_cnt = inst_cfg->params.channel_num + inst_cfg->params.work_thread_cnt; + wr_session_ctrl_t *session_ctrl = wr_get_session_ctrl(); + cm_spin_lock(&session_ctrl->lock, NULL); + if (session_ctrl->used_count > 0) { + WR_RETURN_IFERR3(CM_ERROR, + LOG_RUN_ERR("wr_create_mes_session failed, mes must occupy first %u sessions.", mes_sess_cnt), + cm_spin_unlock(&session_ctrl->lock)); + } + for (uint32 i = 0; i < mes_sess_cnt; i++) { + wr_session_t *session = session_ctrl->sessions[i]; + session->is_direct = CM_TRUE; + session->is_closed = CM_FALSE; + session->is_used = CM_FALSE; + } + session_ctrl->used_count = mes_sess_cnt; + cm_spin_unlock(&session_ctrl->lock); + return CM_SUCCESS; +} + +status_t wr_startup_mes(void) +{ + if (g_wr_instance.is_maintain) { + return CM_SUCCESS; + } + wr_config_t *inst_cfg = wr_get_inst_cfg(); + if (inst_cfg->params.nodes_list.inst_cnt <= 1) { + return CM_SUCCESS; + } + + status_t status = wr_register_proc(); + WR_RETURN_IFERR2(status, LOG_RUN_ERR("wr_register_proc failed.")); + + mes_profile_t profile; + status = wr_set_mes_profile(&profile); + WR_RETURN_IFERR2(status, LOG_RUN_ERR("wr_set_mes_profile failed.")); + + status = wr_create_mes_session(); + WR_RETURN_IFERR2(status, LOG_RUN_ERR("wr_set_mes_profile failed.")); + + regist_invalidate_other_nodes_proc(wr_invalidate_other_nodes); + regist_broadcast_check_file_open_proc(wr_broadcast_check_file_open); + regist_meta_syn2other_nodes_proc(wr_syn_data2other_nodes); + return mes_init(&profile); +} + +void wr_stop_mes(void) +{ + if (g_wr_instance.is_maintain) { + return; + } + wr_config_t *inst_cfg = wr_get_inst_cfg(); + if (g_inst_cfg != NULL && inst_cfg->params.nodes_list.inst_cnt <= 1) { + return; + } + mes_uninit(); +} + +status_t wr_notify_sync(char *buffer, uint32 size, wr_recv_msg_t *recv_msg) +{ + CM_ASSERT(buffer != NULL); + CM_ASSERT(size < SIZE_K(1)); + wr_config_t *inst_cfg = wr_get_inst_cfg(); + uint32 timeout = inst_cfg->params.mes_wait_timeout; + status_t status = wr_broadcast_msg(buffer, size, recv_msg, timeout); + return status; +} + +status_t wr_notify_sync_ex(char *buffer, uint32 size, wr_recv_msg_t *recv_msg) +{ + CM_ASSERT(buffer != NULL); + wr_config_t *inst_cfg = wr_get_inst_cfg(); + uint32 timeout = inst_cfg->params.mes_wait_timeout; + status_t status = wr_broadcast_msg(buffer, size, recv_msg, timeout); + return status; +} + +status_t wr_notify_expect_bool_ack(wr_vg_info_item_t *vg_item, wr_bcast_req_cmd_t cmd, uint64 ftid, bool32 *cmd_ack) +{ + if (g_wr_instance.is_maintain) { + return CM_SUCCESS; + } + wr_recv_msg_t recv_msg = {CM_TRUE, *cmd_ack, WR_PROTO_VERSION, 0, 0, CM_FALSE, *cmd_ack}; + recv_msg.broadcast_proto_ver = wr_get_broadcast_proto_ver(0); + wr_notify_req_msg_t req; + status_t ret; + wr_config_t *inst_cfg = wr_get_inst_cfg(); + wr_params_t *param = &inst_cfg->params; + do { + req.ftid = ftid; + req.type = cmd; + errno_t err = strncpy_s(req.vg_name, WR_MAX_NAME_LEN, vg_item->vg_name, strlen(vg_item->vg_name)); + if (err != EOK) { + WR_THROW_ERROR(ERR_SYSTEM_CALL, err); + return CM_ERROR; + } + LOG_DEBUG_INF("[MES] notify other wr instance to do cmd %u, ftid:%llu in vg:%s.", cmd, ftid, vg_item->vg_name); + wr_init_mes_head(&req.wr_head, WR_CMD_REQ_BROADCAST, 0, (uint16)param->inst_id, CM_INVALID_ID16, + sizeof(wr_notify_req_msg_t), recv_msg.broadcast_proto_ver, 0); + ret = wr_notify_sync((char *)&req, req.wr_head.size, &recv_msg); + if (ret == ERR_WR_VERSION_NOT_MATCH) { + uint32 new_proto_ver = wr_get_broadcast_proto_ver(recv_msg.succ_inst); + LOG_RUN_INF("[CHECK_PROTO]broadcast msg proto version has changed, old is %hhu, new is %hhu", + recv_msg.broadcast_proto_ver, new_proto_ver); + recv_msg.broadcast_proto_ver = new_proto_ver; + recv_msg.version_not_match_inst = 0; + // if msg has been changed, need rewrite req + continue; + } else { + break; + } + } while (CM_TRUE); + if (ret != CM_SUCCESS) { + LOG_RUN_ERR("[WR]: Failed to notify other wr instance, cmd: %u, file: %llu, vg: %s, errcode:%d, " + "OS errno:%d, OS errmsg:%s.", + cmd, ftid, vg_item->vg_name, cm_get_error_code(), errno, strerror(errno)); + return CM_ERROR; + } + *cmd_ack = recv_msg.cmd_ack; + return ret; +} + +status_t wr_notify_data_expect_bool_ack( + wr_vg_info_item_t *vg_item, wr_bcast_req_cmd_t cmd, char *data, uint32 size, bool32 *cmd_ack) +{ + if (g_wr_instance.is_maintain) { + return CM_SUCCESS; + } + wr_recv_msg_t recv_msg = {CM_TRUE, CM_TRUE, WR_PROTO_VERSION, 0, 0, CM_FALSE, CM_TRUE}; + if (cmd_ack) { + recv_msg.cmd_ack = *cmd_ack; + recv_msg.default_ack = *cmd_ack; + } else { + recv_msg.ignore_ack = CM_TRUE; + } + recv_msg.broadcast_proto_ver = wr_get_broadcast_proto_ver(0); + wr_notify_req_msg_ex_t req; + status_t status; + wr_config_t *inst_cfg = wr_get_inst_cfg(); + wr_params_t *param = &inst_cfg->params; + do { + req.type = cmd; + errno_t err = memcpy_s(req.data, sizeof(req.data), data, size); + if (err != EOK) { + WR_THROW_ERROR(ERR_SYSTEM_CALL, err); + return CM_ERROR; + } + req.data_size = size; + LOG_DEBUG_INF("notify other wr instance to do cmd %u, in vg:%s.", cmd, vg_item->vg_name); + wr_init_mes_head(&req.wr_head, WR_CMD_REQ_BROADCAST, 0, (uint16)param->inst_id, CM_INVALID_ID16, + (OFFSET_OF(wr_notify_req_msg_ex_t, data) + size), recv_msg.broadcast_proto_ver, 0); + status = wr_notify_sync_ex((char *)&req, req.wr_head.size, &recv_msg); + if (status == ERR_WR_VERSION_NOT_MATCH) { + uint32 new_proto_ver = wr_get_broadcast_proto_ver(recv_msg.succ_inst); + LOG_RUN_INF("[CHECK_PROTO]broadcast msg proto version has changed, old is %hhu, new is %hhu", + recv_msg.broadcast_proto_ver, new_proto_ver); + recv_msg.broadcast_proto_ver = new_proto_ver; + recv_msg.version_not_match_inst = 0; + // if msg need changed, need rewrite req + continue; + } else { + break; + } + } while (CM_TRUE); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("[WR] Failed to notify other wr instance, cmd: %u, vg%s, errcode:%d, " + "OS errno:%d, OS errmsg:%s.", + cmd, vg_item->vg_name, cm_get_error_code(), errno, strerror(errno)); + return CM_ERROR; + } + if (cmd_ack) { + *cmd_ack = recv_msg.cmd_ack; + } + return status; +} + +status_t wr_invalidate_other_nodes( + wr_vg_info_item_t *vg_item, char *meta_info, uint32 meta_info_size, bool32 *cmd_ack) +{ + return wr_notify_data_expect_bool_ack(vg_item, BCAST_REQ_INVALIDATE_META, meta_info, meta_info_size, cmd_ack); +} + +status_t wr_broadcast_check_file_open(wr_vg_info_item_t *vg_item, uint64 ftid, bool32 *cmd_ack) +{ + return wr_notify_expect_bool_ack(vg_item, BCAST_REQ_DEL_DIR_FILE, ftid, cmd_ack); +} + +status_t wr_syn_data2other_nodes(wr_vg_info_item_t *vg_item, char *meta_syn, uint32 meta_syn_size, bool32 *cmd_ack) +{ + return wr_notify_data_expect_bool_ack(vg_item, BCAST_REQ_META_SYN, meta_syn, meta_syn_size, cmd_ack); +} + +static void wr_check_inst_conn(uint32_t id, uint64 old_inst_stat, uint64 cur_inst_stat) +{ + if (old_inst_stat == cur_inst_stat) { + return; + } + if (old_inst_stat == 0) { + (void)mes_connect_instance(id); + } else { + (void)mes_disconnect_instance(id); + } +} + +void wr_check_mes_conn(uint64 cur_inst_map) +{ + wr_config_t *inst_cfg = wr_get_inst_cfg(); + + uint64 old_inst_map = wr_get_inst_work_status(); + if (old_inst_map == cur_inst_map) { + return; + } + wr_set_inst_work_status(cur_inst_map); + uint32 inst_cnt = 0; + for (uint32_t id = 0; id < WR_MAX_INSTANCES; id++) { + if (id == inst_cfg->params.inst_id) { + continue; + } + uint64_t inst_mask = ((uint64)0x1 << id); + if ((inst_cfg->params.nodes_list.inst_map & inst_mask) == 0) { + continue; + } + wr_check_inst_conn(id, (old_inst_map & inst_mask), (cur_inst_map & inst_mask)); + inst_cnt++; + if (inst_cnt == inst_cfg->params.nodes_list.inst_cnt) { + break; + } + } +} + +static uint32 wr_get_remote_proto_ver(uint32 remoteid) +{ + if (remoteid >= WR_MAX_INSTANCES) { + LOG_DEBUG_ERR("Invalid remote id:%u.", remoteid); + return WR_PROTO_VERSION; + } + uint32 remote_proto_ver = (uint32)cm_atomic32_get((atomic32_t *)&g_wr_instance.cluster_proto_vers[remoteid]); + if (remote_proto_ver == WR_INVALID_VERSION) { + return WR_PROTO_VERSION; + } + remote_proto_ver = MIN(remote_proto_ver, WR_PROTO_VERSION); + return remote_proto_ver; +} + +static int wr_get_mes_response(ruid_type ruid, mes_msg_t *response, int timeout_ms) +{ + int ret = mes_get_response(ruid, response, timeout_ms); + if (ret == CM_SUCCESS) { + wr_message_head_t *ack_head = (wr_message_head_t *)response->buffer; + if (ack_head->size < WR_MES_MSG_HEAD_SIZE) { + LOG_RUN_ERR("Invalid message size"); + WR_THROW_ERROR(ERR_WR_MES_ILL, "msg len is invalid"); + mes_release_msg(response); + return ERR_WR_MES_ILL; + } + wr_set_cluster_proto_vers((uint8)ack_head->src_inst, ack_head->sw_proto_ver); + } + return ret; +} + +status_t wr_exec_sync(wr_session_t *session, uint32 remoteid, uint32 currtid, status_t *remote_result) +{ + status_t ret = CM_ERROR; + wr_message_head_t wr_head; + mes_msg_t msg; + wr_message_head_t *ack_head = NULL; + wr_config_t *inst_cfg = wr_get_inst_cfg(); + uint32 timeout = inst_cfg->params.mes_wait_timeout; + uint32 new_proto_ver = wr_get_version(&session->recv_pack); + do { + uint32 buf_size = WR_MES_MSG_HEAD_SIZE + session->recv_pack.head->size; + // 1.init mes head, wr head, wrbody + wr_init_mes_head( + &wr_head, WR_CMD_REQ_SYB2ACTIVE, 0, (uint16)currtid, (uint16)remoteid, buf_size, new_proto_ver, 0); + // 2. send request to remote + ret = mes_send_request_x(wr_head.dst_inst, wr_head.flags, &wr_head.ruid, 2, &wr_head, WR_MES_MSG_HEAD_SIZE, + session->recv_pack.buf, session->recv_pack.head->size); + char *err_msg = "The wr server fails to send messages to the remote node"; + WR_RETURN_IFERR2(ret, LOG_RUN_ERR("%s, src node(%u), dst node(%u).", err_msg, currtid, remoteid)); + // 3. receive msg from remote + ret = wr_get_mes_response(wr_head.ruid, &msg, timeout); + WR_RETURN_IFERR2( + ret, LOG_RUN_ERR("wr server receive msg from remote failed, src node:%u, dst node:%u, cmd:%u.", currtid, + remoteid, session->recv_pack.head->cmd)); + // 4. attach remote execution result + ack_head = (wr_message_head_t *)msg.buffer; + if (ack_head->result == ERR_WR_VERSION_NOT_MATCH) { + session->client_version = wr_get_client_version(&session->recv_pack); + new_proto_ver = MIN(ack_head->sw_proto_ver, WR_PROTO_VERSION); + new_proto_ver = MIN(new_proto_ver, session->client_version); + session->proto_version = new_proto_ver; + if (session->proto_version != wr_get_version(&session->recv_pack)) { + LOG_RUN_INF("[CHECK_PROTO]The client protocol version need be changed, old protocol version is %u, new " + "protocol version is %u", + wr_get_version(&session->recv_pack), session->proto_version); + WR_THROW_ERROR( + ERR_WR_VERSION_NOT_MATCH, wr_get_version(&session->recv_pack), session->proto_version); + *remote_result = ERR_WR_VERSION_NOT_MATCH; + mes_release_msg(&msg); + return ret; + } else { + wr_head.msg_proto_ver = new_proto_ver; + // if msg version has changed, please motify your change + mes_release_msg(&msg); + continue; + } + } else { + break; + } + } while (CM_TRUE); + // errcode|errmsg + // data + *remote_result = ack_head->result; + uint32 body_size = ack_head->size - WR_MES_MSG_HEAD_SIZE; + if (*remote_result != CM_SUCCESS) { + if (ack_head->size < sizeof(wr_remote_exec_fail_ack_t)) { + WR_RETURN_IFERR3(CM_ERROR, WR_THROW_ERROR(ERR_WR_MES_ILL, "msg len is invalid"), mes_release_msg(&msg)); + } + wr_remote_exec_fail_ack_t *fail_ack = (wr_remote_exec_fail_ack_t *)msg.buffer; + WR_THROW_ERROR(ERR_WR_PROCESS_REMOTE, fail_ack->err_code, fail_ack->err_msg); + } else if (body_size > 0) { + wr_remote_exec_succ_ack_t *succ_ack = (wr_remote_exec_succ_ack_t *)msg.buffer; + LOG_DEBUG_INF("[MES] wr server receive msg from remote node, cmd:%u, ack to cli data size:%u.", + session->recv_pack.head->cmd, body_size); + wr_remote_ack_hdl_t *handle = wr_get_remote_ack_handle(session->recv_pack.head->cmd); + if (handle != NULL) { + handle->proc(session, succ_ack); + } + // do not parse the format + ret = wr_put_data(&session->send_pack, succ_ack->body_buf, body_size); + } + mes_release_msg(&msg); + return ret; +} + +status_t wr_exec_on_remote(uint8 cmd, char *req, int32 req_size, char *ack, int ack_size, status_t *remote_result) +{ + status_t ret = CM_ERROR; + wr_message_head_t *wr_head = (wr_message_head_t *)req; + wr_message_head_t *ack_head = NULL; + wr_session_t *session = NULL; + uint32 remoteid = WR_INVALID_ID32; + uint32 currid = WR_INVALID_ID32; + wr_config_t *inst_cfg = wr_get_inst_cfg(); + uint32 timeout = inst_cfg->params.mes_wait_timeout; + mes_msg_t msg; + if (wr_create_session(NULL, &session) != CM_SUCCESS) { + LOG_RUN_ERR("Exec cmd:%u on remote node create session fail.", (uint32)cmd); + return CM_ERROR; + } + + WR_RETURN_IF_ERROR(wr_get_exec_nodeid(session, &currid, &remoteid)); + + LOG_DEBUG_INF("[MES] Exec cmd:%u on remote node:%u begin.", (uint32)cmd, remoteid); + do { + uint32 proto_ver = wr_get_remote_proto_ver(remoteid); + // 1. init msg head + wr_init_mes_head(wr_head, cmd, 0, (uint16)currid, (uint16)remoteid, req_size, proto_ver, 0); + // 2. send request to remote + ret = mes_send_request(remoteid, wr_head->flags, &wr_head->ruid, req, wr_head->size); + if (ret != CM_SUCCESS) { + LOG_RUN_ERR("Exec cmd:%u on remote node:%u send msg fail.", (uint32)cmd, remoteid); + wr_destroy_session(session); + return ERR_WR_MES_ILL; + } + // 3. receive msg from remote + ret = wr_get_mes_response(wr_head->ruid, &msg, timeout); + if (ret != CM_SUCCESS) { + LOG_RUN_ERR("Exec cmd:%u on remote node:%u recv msg fail.", (uint32)cmd, remoteid); + wr_destroy_session(session); + return ERR_WR_MES_ILL; + } + ack_head = (wr_message_head_t *)msg.buffer; + if (ack_head->result == ERR_WR_VERSION_NOT_MATCH) { + // if msg version has changed, please motify your change + mes_release_msg(&msg); + continue; + } + break; + } while (CM_TRUE); + // 4. attach remote execution result + *remote_result = ack_head->result; + LOG_DEBUG_INF("[MES] wr server receive msg from remote node, cmd:%u, ack to cli data size:%hu, remote_result:%u.", + ack_head->wr_cmd, ack_head->size, (uint32)*remote_result); + if (*remote_result != CM_SUCCESS) { + if (ack_head->size < sizeof(wr_remote_exec_fail_ack_t)) { + WR_THROW_ERROR(ERR_WR_MES_ILL, "msg len is invalid"); + WR_RETURN_IFERR3(CM_ERROR, wr_destroy_session(session), mes_release_msg(&msg)); + } + wr_remote_exec_fail_ack_t *fail_ack = (wr_remote_exec_fail_ack_t *)msg.buffer; + WR_THROW_ERROR(ERR_WR_PROCESS_REMOTE, fail_ack->err_code, fail_ack->err_msg); + } else { + if (ack_head->size != ack_size) { + WR_THROW_ERROR(ERR_WR_MES_ILL, "msg len is invalid"); + WR_RETURN_IFERR3(CM_ERROR, wr_destroy_session(session), mes_release_msg(&msg)); + } + errno_t err = memcpy_s(ack, (size_t)ack_size, msg.buffer, (size_t)ack_head->size); + if (err != EOK) { + CM_THROW_ERROR(ERR_SYSTEM_CALL, err); + ret = CM_ERROR; + } + } + + mes_release_msg(&msg); + wr_destroy_session(session); + LOG_DEBUG_INF("[MES] Exec cmd:%u on remote node:%u end.", (uint32)cmd, remoteid); + return ret; +} + +void wr_proc_syb2active_req(wr_session_t *session, mes_msg_t *msg) +{ + wr_message_head_t req_head = *(wr_message_head_t *)(msg->buffer); + uint32 size = req_head.size - WR_MES_MSG_HEAD_SIZE; + uint16 srcid = req_head.src_inst; + uint16 dstid = req_head.dst_inst; + ruid_type ruid = req_head.ruid; + if (size > WR_MAX_PACKET_SIZE) { + LOG_DEBUG_ERR( + "The wr server receive msg from remote failed, src node:%u, dst node:%u, size is %u.", srcid, dstid, size); + return; + } + LOG_DEBUG_INF("[MES] The wr server receive messages from remote node, src node:%u, dst node:%u.", srcid, dstid); + errno_t errcode = memcpy_s(session->recv_pack.buf, size, msg->buffer + WR_MES_MSG_HEAD_SIZE, size); + if (errcode != EOK) { + LOG_DEBUG_ERR("The wr server memcpy msg failed, src node:%u, dst node:%u.", srcid, dstid); + return; + } + status_t ret = wr_proc_standby_req(session); + char *body_buf = NULL; + uint32 body_size = 0; + status_t status = wr_prepare_ack_msg(session, ret, &body_buf, &body_size, req_head.msg_proto_ver); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("The wr server prepare ack msg failed, src node:%u, dst node:%u.", srcid, dstid); + return; + } + LOG_DEBUG_INF( + "[MES] The wr server send messages to the remote node, src node:%u, dst node:%u, cmd:%u,ack size:%u.", srcid, + dstid, session->send_pack.head->cmd, body_size); + wr_message_head_t ack; + wr_init_mes_head( + &ack, WR_CMD_ACK_SYB2ACTIVE, 0, dstid, srcid, body_size + WR_MES_MSG_HEAD_SIZE, req_head.msg_proto_ver, ruid); + ack.result = ret; + ret = mes_send_response_x(ack.dst_inst, ack.flags, ack.ruid, 2, &ack, WR_MES_MSG_HEAD_SIZE, body_buf, body_size); + if (ret != CM_SUCCESS) { + LOG_DEBUG_ERR("The wr server fails to send messages to the remote node, src node:%u, dst node:%u.", + (uint32)(ack.src_inst), (uint32)(ack.dst_inst)); + return; + } + LOG_DEBUG_INF("[MES] The wr server send messages to the remote node success, src node:%u, dst node:%u.", + (uint32)(ack.src_inst), (uint32)(ack.dst_inst)); +} + +status_t wr_send2standby(big_packets_ctrl_t *ack, const char *buf) +{ + wr_message_head_t *wr_head = &ack->wr_head; + status_t ret = mes_send_response_x(wr_head->dst_inst, wr_head->flags, wr_head->ruid, 2, ack, + sizeof(big_packets_ctrl_t), buf, wr_head->size - sizeof(big_packets_ctrl_t)); + if (ret != CM_SUCCESS) { + LOG_RUN_ERR("The wrserver fails to send messages to the remote node, src node:%u, dst node:%u.", + (uint32)(wr_head->src_inst), (uint32)(wr_head->dst_inst)); + return ret; + } + + LOG_DEBUG_INF("[MES] The wr server send messages to the remote node success, src node:%u, dst node:%u.", + (uint32)(wr_head->src_inst), (uint32)(wr_head->dst_inst)); + return ret; +} + +status_t wr_join_cluster(bool32 *join_succ) +{ + *join_succ = CM_FALSE; + + LOG_DEBUG_INF("[MES] Try join cluster begin."); + + wr_join_cluster_req_t req; + wr_config_t *cfg = wr_get_inst_cfg(); + req.reg_id = (uint32)(cfg->params.inst_id); + + status_t remote_result; + wr_join_cluster_ack_t ack; + status_t ret = wr_exec_on_remote(WR_CMD_REQ_JOIN_CLUSTER, (char *)&req, sizeof(wr_join_cluster_req_t), + (char *)&ack, sizeof(wr_join_cluster_ack_t), &remote_result); + if (ret != CM_SUCCESS || remote_result != CM_SUCCESS) { + LOG_RUN_ERR("Try join cluster exec fail."); + return CM_ERROR; + } + if (ack.is_reg) { + *join_succ = CM_TRUE; + } + + LOG_DEBUG_INF("[MES] Try join cluster exec result:%u.", (uint32)*join_succ); + return CM_SUCCESS; +} + +void wr_proc_join_cluster_req(wr_session_t *session, mes_msg_t *msg) +{ + wr_message_head_t *req_head = (wr_message_head_t *)msg->buffer; + if (req_head->size != sizeof(wr_join_cluster_req_t)) { + LOG_RUN_ERR("Proc join cluster from remote node:%u check req msg fail.", (uint32)(req_head->src_inst)); + return; + } + + wr_join_cluster_req_t *req = (wr_join_cluster_req_t *)msg->buffer; + uint16 dst_inst = req_head->src_inst; + uint16 src_inst = req_head->dst_inst; + uint32 version = req_head->msg_proto_ver; + ruid_type ruid = req_head->ruid; + // please solve with your proto_ver + LOG_DEBUG_INF( + "[MES] Proc join cluster from remote node:%u reg node:%u begin.", (uint32)(req_head->src_inst), req->reg_id); + + // only in the work_status map can join the cluster + + wr_join_cluster_ack_t ack; + wr_init_mes_head( + &ack.ack_head, WR_CMD_ACK_JOIN_CLUSTER, 0, src_inst, dst_inst, sizeof(wr_join_cluster_ack_t), version, ruid); + ack.is_reg = CM_FALSE; + ack.ack_head.result = CM_SUCCESS; + uint64 work_status = wr_get_inst_work_status(); + uint64 inst_mask = ((uint64)0x1 << req->reg_id); + if (work_status & inst_mask) { + ack.is_reg = CM_TRUE; + } + + LOG_DEBUG_INF("[MES] Proc join cluster from remote node:%u, reg node:%u, is_reg:%u.", (uint32)(req_head->src_inst), + req->reg_id, (uint32)ack.is_reg); + int send_ret = mes_send_response(dst_inst, ack.ack_head.flags, ruid, (char *)&ack, ack.ack_head.size); + if (send_ret != CM_SUCCESS) { + LOG_RUN_ERR("Proc join cluster from remote node:%u, reg node:%u send ack fail.", (uint32)dst_inst, req->reg_id); + return; + } + + LOG_DEBUG_INF("[MES] Proc join cluster from remote node:%u, reg node:%u send ack size:%u end.", (uint32)dst_inst, + req->reg_id, ack.ack_head.size); +} diff --git a/src/service/wr_mes.h b/src/service/wr_mes.h new file mode 100644 index 0000000000000000000000000000000000000000..1f645e1fed1a657e37e848f9b45aaaf399aef867 --- /dev/null +++ b/src/service/wr_mes.h @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_mes.h + * + * + * IDENTIFICATION + * src/service/wr_mes.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_MES_H__ +#define __WR_MES_H__ + +#include "mes_interface.h" +#include "wr_file_def.h" +#include "wr_session.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum en_wr_mes_command { + WR_CMD_REQ_BROADCAST = 0, + WR_CMD_ACK_BROADCAST_WITH_MSG, + WR_CMD_REQ_SYB2ACTIVE, /* Request command from the standby node to the active node */ + WR_CMD_ACK_SYB2ACTIVE, + WR_CMD_REQ_JOIN_CLUSTER, + WR_CMD_ACK_JOIN_CLUSTER, + WR_CMD_CEIL, +} wr_mes_command_t; + +typedef enum en_wr_msg_buffer_number { + WR_MSG_BUFFER_NO_0 = 0, + WR_MSG_BUFFER_NO_1, + WR_MSG_BUFFER_NO_2, + WR_MSG_BUFFER_NO_3, + WR_MSG_BUFFER_NO_CEIL +} wr_msg_buffer_number_e; + +#define WR_MES_THREAD_NUM 2 +#define WR_MES_TRY_TIMES 100 +#define WR_BROADCAST_WAIT_INFINITE (0xFFFFFFFF) +#define WR_IS_INST_SEND(bits, id) (((bits) >> (id)) & 0x1) +#define WR_MSG_BUFFER_QUEUE_NUM (8) +#define WR_MSG_FOURTH_BUFFER_QUEUE_NUM (1) +#define WR_FIRST_BUFFER_LENGTH (256) +#define WR_SECOND_BUFFER_LENGTH (SIZE_K(1) + 256) +#define WR_THIRD_BUFFER_LENGTH (SIZE_K(32) + 256) +#define WR_FOURTH_BUFFER_LENGTH (WR_LOADDISK_BUFFER_SIZE + 256) +#define WR_CKPT_NOTIFY_TASK_RATIO (1.0f / 4) +#define WR_CLEAN_EDP_TASK_RATIO (1.0f / 4) +#define WR_TXN_INFO_TASK_RATIO (1.0f / 16) +#define WR_RECV_WORK_THREAD_RATIO (1.0f / 4) +#define WR_FIRST_BUFFER_RATIO ((double)1.0 / 8) +#define WR_SECOND_BUFFER_RATIO ((double)3.0 / 8) +#define WR_THIRDLY_BUFFER_RATIO ((double)1.0 / 2) + +typedef void (*wr_message_proc_t)(wr_session_t *session, mes_msg_t *msg); +typedef struct st_processor_func { + wr_mes_command_t cmd_type; + wr_message_proc_t proc; + bool32 is_enqueue_work_thread; // Whether to let the worker thread process + const char *func_name; +} processor_func_t; + +typedef struct st_wr_processor { + wr_message_proc_t proc; + bool32 is_enqueue; + bool32 is_req; + mes_priority_t prio_id; + char *name; +} wr_processor_t; + +typedef struct st_wr_mes_actnode { + bool8 is_active; + uint8 node_id; + uint16 rsvd; + uint32 node_rsn; +} wr_mes_actnode_t; + +typedef struct st_wr_mes_actlist { + uint32 count; + wr_mes_actnode_t node[0]; +} wr_mes_actlist_t; +// clang-format off +typedef enum st_wr_bcast_req_cmd { + BCAST_REQ_DEL_DIR_FILE = 0, + BCAST_REQ_INVALIDATE_META, + BCAST_REQ_META_SYN, + BCAST_REQ_END +} wr_bcast_req_cmd_t; + +typedef enum st_wr_bcast_ack_cmd { + BCAST_ACK_DEL_FILE = 0, + BCAST_ACK_INVALIDATE_META, + BCAST_ACK_META_SYN, + BCAST_ACK_END +} wr_bcast_ack_cmd_t; + +// clang-format on +typedef struct st_wr_bcast_req { + wr_bcast_req_cmd_t type; + char buffer[4]; +} wr_bcast_req_t; + +typedef struct st_wr_recv_msg { + bool32 handle_recv_msg; + bool32 cmd_ack; + uint32 broadcast_proto_ver; + uint64 version_not_match_inst; + uint64 succ_inst; + bool32 ignore_ack; + bool32 default_ack; +} wr_recv_msg_t; + +typedef struct st_wr_message_head { + uint32 msg_proto_ver; + uint32 sw_proto_ver; + uint16 src_inst; + uint16 dst_inst; + uint32 wr_cmd; + uint32 size; + uint32 flags; + ruid_type ruid; + int32 result; + uint8 reserve[64]; +} wr_message_head_t; + +typedef struct st_wr_notify_req_msg { + wr_message_head_t wr_head; + wr_bcast_req_cmd_t type; + uint64 ftid; + char vg_name[WR_MAX_NAME_LEN]; +} wr_notify_req_msg_t; + +typedef struct st_wr_notify_req_msg_ex { + wr_message_head_t wr_head; + wr_bcast_req_cmd_t type; + uint32 data_size; + char data[WR_MAX_META_BLOCK_SIZE]; +} wr_notify_req_msg_ex_t; +typedef struct st_wr_notify_ack_msg { + wr_message_head_t wr_head; + wr_bcast_ack_cmd_t type; + int32 result; + bool32 cmd_ack; +} wr_notify_ack_msg_t; + +typedef struct st_wr_remote_exec_succ_ack { + wr_message_head_t ack_head; + char body_buf[4]; +} wr_remote_exec_succ_ack_t; + +typedef struct st_wr_remote_exec_fail_ack { + wr_message_head_t ack_head; + int32 err_code; + char err_msg[4]; +} wr_remote_exec_fail_ack_t; + +typedef struct st_big_packets_ctrl { + wr_message_head_t wr_head; + uint32 offset; + uint32 cursize; + uint32 totalsize; + uint16 seq; + uint8 endflag; + uint8 reseved; +} big_packets_ctrl_t; + +typedef struct st_loaddisk_req { + wr_message_head_t wr_head; + uint32 volumeid; + uint32 size; + uint64 offset; + char vg_name[WR_MAX_NAME_LEN]; +} wr_loaddisk_req_t; + +typedef struct st_join_cluster_req { + wr_message_head_t wr_head; + uint32 reg_id; +} wr_join_cluster_req_t; + +typedef struct st_join_cluster_ack { + wr_message_head_t ack_head; + bool32 is_reg; +} wr_join_cluster_ack_t; + +typedef struct st_refresh_ft_req { + wr_message_head_t wr_head; + wr_block_id_t blockid; + uint32 vgid; + char vg_name[WR_MAX_NAME_LEN]; +} wr_refresh_ft_req_t; + +typedef struct st_refresh_ft_ack { + wr_message_head_t ack_head; + bool32 is_ok; +} wr_refresh_ft_ack_t; + +typedef struct st_get_ft_block_req { + wr_message_head_t wr_head; + char path[WR_FILE_PATH_MAX_LENGTH]; + gft_item_type_t type; +} wr_get_ft_block_req_t; + +typedef struct st_get_ft_block_ack { + wr_message_head_t ack_head; + wr_block_id_t node_id; + wr_block_id_t parent_node_id; + char vg_name[WR_MAX_NAME_LEN]; + char block[WR_BLOCK_SIZE]; + char parent_block[WR_BLOCK_SIZE]; +} wr_get_ft_block_ack_t; + +#define WR_MES_MSG_HEAD_SIZE (sizeof(wr_message_head_t)) +uint32 wr_get_broadcast_proto_ver(uint64 succ_inst); +status_t wr_notify_sync(char *buffer, uint32 size, wr_recv_msg_t *recv_msg); +status_t wr_notify_sync_ex(char *buffer, uint32 size, wr_recv_msg_t *recv_msg); + +status_t wr_exec_sync(wr_session_t *session, uint32 remoteid, uint32 currtid, status_t *remote_result); +status_t wr_notify_expect_bool_ack(wr_vg_info_item_t *vg_item, wr_bcast_req_cmd_t cmd, uint64 ftid, bool32 *cmd_ack); +status_t wr_notify_data_expect_bool_ack( + wr_vg_info_item_t *vg_item, wr_bcast_req_cmd_t cmd, char *data, uint32 size, bool32 *cmd_ack); + +status_t wr_invalidate_other_nodes( + wr_vg_info_item_t *vg_item, char *meta_info, uint32 meta_info_size, bool32 *cmd_ack); +status_t wr_broadcast_check_file_open(wr_vg_info_item_t *vg_item, uint64 ftid, bool32 *cmd_ack); +status_t wr_syn_data2other_nodes(wr_vg_info_item_t *vg_item, char *meta_syn, uint32 meta_syn_size, bool32 *cmd_ack); + +void wr_check_mes_conn(uint64 cur_inst_map); +status_t wr_startup_mes(void); +void wr_stop_mes(void); +int32 wr_process_broadcast_ack(wr_notify_ack_msg_t *ack, wr_recv_msg_t *recv_msg_output); +void wr_proc_broadcast_req(wr_session_t *session, mes_msg_t *msg); +void wr_proc_syb2active_req(wr_session_t *session, mes_msg_t *msg); +void wr_proc_loaddisk_req(wr_session_t *session, mes_msg_t *msg); +void wr_proc_join_cluster_req(wr_session_t *session, mes_msg_t *msg); +void wr_proc_refresh_ft_by_primary_req(wr_session_t *session, mes_msg_t *msg); + +status_t wr_send2standby(big_packets_ctrl_t *ack, const char *buf); +status_t wr_join_cluster(bool32 *join_succ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/service/wr_reactor.c b/src/service/wr_reactor.c new file mode 100644 index 0000000000000000000000000000000000000000..89cb89caacc2d3810f7673e1582390f8f036899e --- /dev/null +++ b/src/service/wr_reactor.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2023 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_reactor.c + * + * + * IDENTIFICATION + * src/service/wr_reactor.c + * + * ------------------------------------------------------------------------- + */ +#include "cm_epoll.h" +#include "wr_reactor.h" +#include "wr_instance.h" +#include "wr_service.h" + +#ifdef __cplusplus +extern "C" { +#endif + +status_t wr_reactor_set_oneshot(wr_session_t *session) +{ + struct epoll_event ev; + int fd = (int)session->pipe.link.uds.sock; + + ev.events = EPOLLIN | EPOLLONESHOT; + ev.data.ptr = session; + reactor_t *reactor = (reactor_t *)(session->reactor); + if (epoll_ctl(reactor->epollfd, EPOLL_CTL_MOD, fd, &ev) != 0) { + return CM_ERROR; + } + return CM_SUCCESS; +} + +static wr_workthread_t *wr_reactor_get_workthread(reactor_t *reactor) +{ + uint32 pos = 0; + for (pos = 0; pos < reactor->workthread_count; pos++) { + if (reactor->workthread_ctx[pos].status == THREAD_STATUS_IDLE && + reactor->workthread_ctx[pos].thread_obj->task == NULL) { + break; + } + } + + if (pos == reactor->workthread_count) { + return NULL; + } + + reactor->workthread_ctx[pos].status = THREAD_STATUS_PROCESSSING; + return &reactor->workthread_ctx[pos]; +} + +static void wr_reactor_session_entry(void *param) +{ + wr_workthread_t *workthread_ctx = (wr_workthread_t *)param; + pooling_thread_t *thread_obj = workthread_ctx->thread_obj; + wr_session_t *session = (wr_session_t *)workthread_ctx->current_session; + LOG_DEBUG_INF("session %u with workthread %u begin.", session->id, thread_obj->spid); + + if (session->is_closed) { + wr_clean_reactor_session(session); + LOG_DEBUG_WAR("session %u is closed.", session->id); + return; + } + wr_init_packet(&session->recv_pack, CM_FALSE); + wr_init_packet(&session->send_pack, CM_FALSE); + session->pipe.socket_timeout = (int32)CM_SOCKET_TIMEOUT; + (void)wr_process_single_cmd(&session); + // do NOT add any code after here, and can not use any data of wr_workthread_t from here + if (session != NULL) { + if (wr_reactor_set_oneshot(session) != CM_SUCCESS) { + LOG_RUN_ERR("[reactor] set oneshot flag of socket failed, session %u, reactor %u, os error %d", session->id, + ((reactor_t *)session->reactor)->id, cm_get_sock_error()); + } + } +} + +void wr_reactor_attach_workthread(wr_session_t *session) +{ + reactor_t *reactor = (reactor_t *)session->reactor; + if (reactor == NULL) { + return; + } + while (CM_TRUE) { + cm_thread_lock(&reactor->lock); + wr_workthread_t *workthread_ctx = wr_reactor_get_workthread(reactor); + if (workthread_ctx != NULL) { + workthread_ctx->task.action = wr_reactor_session_entry; + workthread_ctx->current_session = session; + workthread_ctx->task.param = workthread_ctx; + session->workthread_ctx = workthread_ctx; + cm_dispatch_pooling_thread(workthread_ctx->thread_obj, &workthread_ctx->task); + LOG_DEBUG_INF("[reactor] attach workthread %u to session %u sucessfully, active_sessions is %lld.", workthread_ctx->thread_obj->spid, + session->id, g_wr_instance.active_sessions); + break; + } + if (reactor->status != REACTOR_STATUS_RUNNING || reactor->iothread.closed) { + break; + } + cm_thread_unlock(&reactor->lock); + cm_event_wait(&reactor->idle_evnt); + } + cm_thread_unlock(&reactor->lock); +} + +static inline void wr_reset_workthread_ctx(wr_workthread_t *workthread_ctx) +{ + workthread_ctx->task.action = NULL; + workthread_ctx->current_session = NULL; + workthread_ctx->task.param = NULL; + workthread_ctx->status = THREAD_STATUS_IDLE; +} + +static inline void wr_session_detach_workthread_inner(wr_session_t *session) +{ + wr_workthread_t *workthread_ctx = (wr_workthread_t *)session->workthread_ctx; + session->workthread_ctx = NULL; + session->status = WR_SESSION_STATUS_IDLE; + LOG_DEBUG_INF("[reactor] detach workthread %u to session %u sucessfully, active_sessions is %lld.", + workthread_ctx->thread_obj->spid, session->id, g_wr_instance.active_sessions); + return; +} + +void wr_session_detach_workthread(wr_session_t *session) +{ + wr_workthread_t *workthread_ctx = (wr_workthread_t *)session->workthread_ctx; + reactor_t *reactor = (reactor_t *)session->reactor; + wr_session_detach_workthread_inner(session); + cm_thread_lock(&reactor->lock); + wr_reset_workthread_ctx(workthread_ctx); + cm_thread_unlock(&reactor->lock); + cm_event_notify(&reactor->idle_evnt); +} + +static void wr_reactor_poll_events(reactor_t *reactor) +{ + wr_session_t *sess = NULL; + int loop, nfds; + struct epoll_event events[WR_EV_WAIT_NUM]; + struct epoll_event *ev = NULL; + + if (reactor->status != REACTOR_STATUS_RUNNING) { + return; + } + + nfds = epoll_wait(reactor->epollfd, events, WR_EV_WAIT_NUM, WR_EV_WAIT_TIMEOUT); + if (nfds == -1) { + if (errno != EINTR) { + LOG_RUN_ERR("Failed to wait for connection request, OS error:%d", cm_get_os_error()); + } + return; + } + + if (nfds == 0) { + return; + } + + for (loop = 0; loop < nfds; ++loop) { + ev = &events[loop]; + sess = (wr_session_t *)ev->data.ptr; + if (reactor->status != REACTOR_STATUS_RUNNING) { + if (wr_reactor_set_oneshot(sess) != CM_SUCCESS) { + LOG_RUN_ERR("[reactor] set oneshot flag of socket failed, session %u, " + "reactor %u, os error %d, event %u", + sess->id, reactor->id, cm_get_sock_error(), ev->events); + } + continue; + } + + wr_reactor_attach_workthread(sess); + } +} + +static void wr_reactor_entry(thread_t *thread) +{ + reactor_t *reactor = (reactor_t *)thread->argument; + cm_set_thread_name("reactor"); + LOG_RUN_INF("reactor thread[%d] started.", reactor->id); + while (!thread->closed) { + wr_reactor_poll_events(reactor); + if (reactor->status == REACTOR_STATUS_PAUSING) { + reactor->status = REACTOR_STATUS_PAUSED; + } + } + LOG_RUN_INF("reactor thead[%d] closed.", reactor->id); + (void)epoll_close(reactor->epollfd); +} + +static status_t wr_reactor_start_threadpool(reactor_t *reactor) +{ + // init thread pool + cm_init_thread_pool(&reactor->workthread_pool); + cm_init_thread_lock(&reactor->lock); + status_t ret = cm_create_thread_pool(&reactor->workthread_pool, SIZE_K(512), reactor->workthread_count); + if (ret != CM_SUCCESS) { + LOG_RUN_ERR("[reactor] failed to create reactor work thread pool, errno %d", cm_get_os_error()); + return ret; + } + + pooling_thread_t *poolingthread = NULL; + for (uint32 pos = 0; pos < reactor->workthread_count; pos++) { + if (cm_get_idle_pooling_thread(&reactor->workthread_pool, &poolingthread) != CM_SUCCESS) { + LOG_RUN_ERR("[reactor] failed to get idle work thread pool, errno %d", cm_get_os_error()); + return CM_ERROR; + } + reactor->workthread_ctx[pos].thread_obj = poolingthread; + reactor->workthread_ctx[pos].status = THREAD_STATUS_IDLE; + reactor->workthread_ctx[pos].task.action = NULL; + reactor->workthread_ctx[pos].task.param = NULL; + } + + return CM_SUCCESS; +} + +static status_t wr_reactors_start() +{ + reactor_t *reactor = NULL; + reactors_t *pool = &g_wr_instance.reactors; + for (uint32 i = 0; i < pool->reactor_count; i++) { + reactor = &pool->reactor_arr[i]; + reactor->id = i; + reactor->workthread_count = g_wr_instance.inst_cfg.params.workthread_count; + if (cm_event_init(&reactor->idle_evnt) != CM_SUCCESS) { + LOG_RUN_ERR("[reactor] failed to init reactor idle event, errno %d", cm_get_os_error()); + return CM_ERROR; + } + if (wr_reactor_start_threadpool(reactor) != CM_SUCCESS) { + return CM_ERROR; + } + reactor->epollfd = epoll_create1(0); + if (reactor->epollfd == -1) { + LOG_RUN_ERR("[reactor] failed to create epoll fd, errno %d", cm_get_os_error()); + return CM_ERROR; + } + reactor->status = REACTOR_STATUS_RUNNING; + if (cm_create_thread(wr_reactor_entry, SIZE_K(512), reactor, &reactor->iothread) != CM_SUCCESS) { + LOG_RUN_ERR("[reactor] failed to create reactor thread, errno %d", cm_get_os_error()); + return CM_ERROR; + } + } + return CM_SUCCESS; +} + +status_t wr_create_reactors() +{ + reactors_t *pool = &g_wr_instance.reactors; + (void)cm_atomic_set(&pool->roudroubin, 0); + pool->reactor_count = g_wr_instance.inst_cfg.params.iothread_count; + size_t size = sizeof(reactor_t) * pool->reactor_count; + if ((size == 0) || (size / sizeof(reactor_t) != pool->reactor_count)) { + CM_THROW_ERROR(ERR_ALLOC_MEMORY, (uint64)0, "creating reactors"); + return CM_ERROR; + } + + pool->reactor_arr = (reactor_t *)malloc(size); + if (pool->reactor_arr == NULL) { + CM_THROW_ERROR(ERR_ALLOC_MEMORY, (uint64)size, "creating reactors"); + return CM_ERROR; + } + + errno_t err = memset_s(pool->reactor_arr, size, 0, size); + if (err != EOK) { + CM_FREE_PTR(pool->reactor_arr); + CM_THROW_ERROR(ERR_SYSTEM_CALL, (err)); + return CM_ERROR; + } + if (wr_reactors_start() != CM_SUCCESS) { + wr_destroy_reactors(); + return CM_ERROR; + } + + return CM_SUCCESS; +} + +void wr_pause_reactors() +{ + reactors_t *pool = &g_wr_instance.reactors; + reactor_t *reactor = NULL; + if (pool->reactor_arr == NULL) { + return; + } + for (uint32 i = 0; i < pool->reactor_count; i++) { + reactor = &pool->reactor_arr[i]; + reactor->status = REACTOR_STATUS_PAUSING; + while (reactor->status != REACTOR_STATUS_PAUSED && !reactor->iothread.closed) { + cm_sleep(5); + } + } +} + +void wr_continue_reactors() +{ + reactors_t *pool = &g_wr_instance.reactors; + reactor_t *reactor = NULL; + if (pool->reactor_arr == NULL) { + return; + } + + for (uint32 i =0; i < pool->reactor_count; i++) { + reactor = &pool->reactor_arr[i]; + reactor->status = REACTOR_STATUS_RUNNING; + } +} + +void wr_destroy_reactors() +{ + reactor_t *reactor = NULL; + reactors_t *pool = &g_wr_instance.reactors; + if (pool->reactor_arr == NULL) { + return; + } + for (uint32 pos = 0; pos < pool->reactor_count; pos++) { + reactor = &pool->reactor_arr[pos]; + (void)epoll_close(reactor->epollfd); + if (reactor->iothread.closed == CM_FALSE) { + cm_close_thread(&reactor->iothread); + } + reactor->status = REACTOR_STATUS_STOPPED; + cm_destroy_thread_pool(&reactor->workthread_pool); + } + pool->reactor_count = 0; + CM_FREE_PTR(pool->reactor_arr); +} + +status_t wr_reactors_add_session(wr_session_t *session) +{ + reactors_t *pool = &g_wr_instance.reactors; + uint32_t reactor_idx = cm_atomic_inc(&pool->roudroubin) % pool->reactor_count; + reactor_t *reactor = &pool->reactor_arr[reactor_idx]; + session->reactor = reactor; + struct epoll_event ev; + int fd = (int)session->pipe.link.uds.sock; + + (void)cm_atomic32_inc(&reactor->session_count); + ev.events = EPOLLIN | EPOLLONESHOT; + ev.data.ptr = session; + if (epoll_ctl(reactor->epollfd, EPOLL_CTL_ADD, fd, &ev) != 0) { + LOG_RUN_ERR("[reactor] add session to reactor failed, session %u, reactor %u, os error %d", session->id, + reactor->id, cm_get_sock_error()); + (void)cm_atomic32_dec(&reactor->session_count); + return CM_ERROR; + } + + session->reactor_added = CM_TRUE; + LOG_DEBUG_INF("[reactor] add session %u to reactor %u sucessfully, current session count %d", session->id, + reactor->id, reactor->session_count); + return CM_SUCCESS; +} + +void wr_reactors_del_session(wr_session_t *session) +{ + int fd = (int)session->pipe.link.uds.sock; + reactor_t *reactor = (reactor_t *)session->reactor; + (void)epoll_ctl(reactor->epollfd, EPOLL_CTL_DEL, fd, NULL); + + (void)cm_atomic32_dec(&reactor->session_count); + session->reactor_added = CM_FALSE; + session->reactor = NULL; + LOG_DEBUG_INF("[reactor] delete session %u to reactor %u sucessfully, current session count %d", session->id, + reactor->id, reactor->session_count); +} + +void wr_clean_reactor_session(wr_session_t *session) +{ + wr_workthread_t *workthread_ctx = (wr_workthread_t *)session->workthread_ctx; + wr_reactors_del_session(session); + wr_session_detach_workthread_inner(session); + wr_release_session_res(session); + // must be the last step + wr_reset_workthread_ctx(workthread_ctx); +} + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/service/wr_reactor.h b/src/service/wr_reactor.h new file mode 100644 index 0000000000000000000000000000000000000000..02be9c0bb36976c6b87be6e035c1fef2e52b2b19 --- /dev/null +++ b/src/service/wr_reactor.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_reactor.h + * + * + * IDENTIFICATION + * src/service/wr_reactor.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_REACTOR_H__ +#define __WR_REACTOR_H__ + +#include "cm_defs.h" +#include "cm_error.h" +#include "cm_queue.h" +#include "cm_sync.h" +#include "cm_thread_pool.h" +#include "cm_spinlock.h" +#include "cm_thread.h" +#include "wr_defs.h" +#include "wr_session.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WR_EV_WAIT_NUM 256 +#define WR_EV_WAIT_TIMEOUT 16 + +typedef struct st_wr_session wr_session_t; +struct st_reactor; +struct st_wr_workthread; + +typedef struct st_wr_workthread { + pooling_thread_t *thread_obj; + void *current_session; + thread_task_t task; + thread_stat_t status; +} wr_workthread_t; + +typedef enum en_reactor_status { + REACTOR_STATUS_RUNNING, + REACTOR_STATUS_PAUSING, + REACTOR_STATUS_PAUSED, + REACTOR_STATUS_STOPPED, +} reactor_status_t; + +typedef struct st_reactor { + uint32 id; + thread_t iothread; + int epollfd; + atomic32_t session_count; + reactor_status_t status; + uint32 workthread_count; + cm_event_t idle_evnt; + thread_lock_t lock; + cm_thread_pool_t workthread_pool; + wr_workthread_t workthread_ctx[WR_MAX_WORKTHREADS_CFG]; +} reactor_t; + +typedef struct st_reactors { + uint32 reactor_count; + atomic_t roudroubin; + reactor_t *reactor_arr; +} reactors_t; + +status_t wr_create_reactors(); +void wr_destroy_reactors(); +status_t wr_reactors_add_session(wr_session_t *session); +void wr_reactors_del_session(wr_session_t *session); +status_t wr_reactor_set_oneshot(wr_session_t *session); +void wr_reactor_attach_workthread(wr_session_t *session); +void wr_session_detach_workthread(wr_session_t *session); +void wr_clean_reactor_session(wr_session_t *session); +void wr_pause_reactors(); +void wr_continue_reactors(); + +#ifdef __cplusplus +} +#endif + +#endif // __WR_REACTOR_H__ \ No newline at end of file diff --git a/src/service/wr_service.c b/src/service/wr_service.c new file mode 100644 index 0000000000000000000000000000000000000000..3033d54a43eefe9742ae3c69dca1649c7df33402 --- /dev/null +++ b/src/service/wr_service.c @@ -0,0 +1,1118 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_service.c + * + * + * IDENTIFICATION + * src/service/wr_service.c + * + * ------------------------------------------------------------------------- + */ + +#include "wr_service.h" +#include "cm_system.h" +#include "wr_instance.h" +#include "wr_io_fence.h" +#include "wr_malloc.h" +#include "wr_open_file.h" +#include "wr_srv_proc.h" +#include "wr_mes.h" +#include "wr_api.h" +#include "wr_thv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static inline bool32 wr_need_exec_remote(bool32 exec_on_active, bool32 local_req) +{ + wr_config_t *cfg = wr_get_inst_cfg(); + uint32 master_id = wr_get_master_id(); + uint32 curr_id = (uint32)(cfg->params.inst_id); + return ((curr_id != master_id) && (exec_on_active) && (local_req == CM_TRUE)); +} + +static uint32 wr_get_master_proto_ver(void) +{ + uint32 master_id = wr_get_master_id(); + if (master_id >= WR_MAX_INSTANCES) { + return WR_PROTO_VERSION; + } + uint32 master_proto_ver = (uint32)cm_atomic32_get((atomic32_t *)&g_wr_instance.cluster_proto_vers[master_id]); + if (master_proto_ver == WR_INVALID_VERSION) { + return WR_PROTO_VERSION; + } + master_proto_ver = MIN(master_proto_ver, WR_PROTO_VERSION); + return master_proto_ver; +} + +status_t wr_get_exec_nodeid(wr_session_t *session, uint32 *currid, uint32 *remoteid) +{ + wr_config_t *cfg = wr_get_inst_cfg(); + *currid = (uint32)(cfg->params.inst_id); + *remoteid = wr_get_master_id(); + while (*remoteid == WR_INVALID_ID32) { + if (get_instance_status_proc() == WR_STATUS_RECOVERY) { + WR_THROW_ERROR(ERR_WR_RECOVER_CAUSE_BREAK); + LOG_RUN_ERR_INHIBIT(LOG_INHIBIT_LEVEL1, "Master id is invalid."); + return CM_ERROR; + } + *remoteid = wr_get_master_id(); + cm_sleep(WR_PROCESS_GET_MASTER_ID); + } + LOG_DEBUG_INF("Start processing remote requests(%d), remote node(%u),current node(%u).", + (session->recv_pack.head == NULL) ? -1 : session->recv_pack.head->cmd, *remoteid, *currid); + return CM_SUCCESS; +} + +#define WR_PROCESS_REMOTE_INTERVAL 50 +static status_t wr_process_remote(wr_session_t *session) +{ + uint32 remoteid = WR_INVALID_ID32; + uint32 currid = WR_INVALID_ID32; + status_t ret = CM_ERROR; + WR_RETURN_IF_ERROR(wr_get_exec_nodeid(session, &currid, &remoteid)); + + LOG_DEBUG_INF("Start processing remote requests(%d), remote node(%u),current node(%u).", + session->recv_pack.head->cmd, remoteid, currid); + status_t remote_result = CM_ERROR; + while (CM_TRUE) { + if (get_instance_status_proc() == WR_STATUS_RECOVERY) { + WR_THROW_ERROR(ERR_WR_RECOVER_CAUSE_BREAK); + LOG_RUN_INF("Req break by recovery"); + return CM_ERROR; + } + + ret = wr_exec_sync(session, remoteid, currid, &remote_result); + if (ret != CM_SUCCESS) { + LOG_DEBUG_ERR( + "End of processing the remote request(%d) failed, remote node(%u),current node(%u), result code(%d).", + session->recv_pack.head->cmd, remoteid, currid, ret); + if (session->recv_pack.head->cmd == WR_CMD_SWITCH_LOCK) { + return ret; + } + cm_sleep(WR_PROCESS_REMOTE_INTERVAL); + WR_RETURN_IF_ERROR(wr_get_exec_nodeid(session, &currid, &remoteid)); + if (currid == remoteid) { + WR_THROW_ERROR(ERR_WR_MASTER_CHANGE); + LOG_RUN_INF("Req break if currid is equal to remoteid, just try again."); + return CM_ERROR; + } + continue; + } + break; + } + LOG_DEBUG_INF("The remote request(%d) is processed successfully, remote node(%u),current node(%u), result(%u).", + session->recv_pack.head->cmd, remoteid, currid, remote_result); + return remote_result; +} + +status_t wr_diag_proto_type(wr_session_t *session) +{ + link_ready_ack_t ack; + uint32 proto_code = 0; + int32 size; + char buffer[sizeof(version_proto_code_t)] = {0}; + version_proto_code_t version_proto_code = {0}; + + status_t ret = cs_read_bytes(&session->pipe, buffer, sizeof(version_proto_code_t), &size); + WR_RETURN_IFERR2(ret, LOG_RUN_ERR("Instance recieve protocol failed, errno:%d.", errno)); + + if (size == sizeof(version_proto_code_t)) { + version_proto_code = *(version_proto_code_t*)buffer; + proto_code = version_proto_code.proto_code; + } else if (size == sizeof(proto_code)) { + proto_code = *(uint32 *)buffer; + } else { + LOG_RUN_ERR("wr_diag_proto_type invalid size[%u].", size); + } + LOG_RUN_INF("wr_diag_proto_type proto_code=%u.", proto_code); + + if (proto_code != CM_PROTO_CODE) { + LOG_RUN_ERR("Instance recieve invalid protocol:%u.", proto_code); + return CM_ERROR; + } + + session->proto_type = PROTO_TYPE_GS; + ack.endian = (IS_BIG_ENDIAN ? (uint8)1 : (uint8)0); + ack.version = CS_LOCAL_VERSION; + return cs_send_bytes(&session->pipe, (char *)&ack, sizeof(link_ready_ack_t)); +} + +// TODO: 后期考虑启用 +static void wr_clean_open_files(wr_session_t *session) +{ + if (cm_sys_process_alived(session->cli_info.cli_pid, session->cli_info.start_time)) { + LOG_DEBUG_INF("Process:%s is alive, pid:%llu, start_time:%lld.", session->cli_info.process_name, + session->cli_info.cli_pid, session->cli_info.start_time); + return; + } + + LOG_RUN_INF("Clean open files for pid:%llu.", session->cli_info.cli_pid); +} + +void wr_release_session_res(wr_session_t *session) +{ + wr_server_session_lock(session); + wr_clean_session_latch(session, CM_FALSE); + wr_clean_open_files(session); + wr_destroy_session_inner(session); + cm_spin_unlock(&session->shm_lock); + LOG_DEBUG_INF("Succeed to unlock session %u shm lock", session->id); + cm_spin_unlock(&session->lock); +} + +status_t wr_process_single_cmd(wr_session_t **session) +{ + status_t status = wr_process_command(*session); + if ((*session)->is_closed) { + LOG_RUN_INF("Session:%u end to do service, thread id is %u, connect time is %llu, try to clean source.", + (*session)->id, (*session)->cli_info.thread_id, (*session)->cli_info.connect_time); + wr_clean_reactor_session(*session); + *session = NULL; + } else { + wr_session_detach_workthread(*session); + } + return status; +} + +static void wr_return_error(wr_session_t *session) +{ + int32 code; + const char *message = NULL; + wr_packet_t *send_pack = NULL; + + CM_ASSERT(session != NULL); + send_pack = &session->send_pack; + wr_init_set(send_pack, session->proto_version); + send_pack->head->cmd = session->recv_pack.head->cmd; + send_pack->head->result = (uint8)CM_ERROR; + send_pack->head->flags = 0; + cm_get_error(&code, &message); + // volume open/seek/read write fail for I/O, just abort + if (code == ERR_WR_VOLUME_SYSTEM_IO) { + LOG_RUN_ERR("[WR] ABORT INFO: volume operate failed for I/O ERROR, errcode:%d.", code); + cm_fync_logfile(); + wr_exit(1); + } + (void)wr_put_int32(send_pack, (uint32)code); + (void)wr_put_str_with_cutoff(send_pack, message); + status_t status = wr_write(&session->pipe, send_pack); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to reply,size:%u, cmd:%u.", send_pack->head->size, send_pack->head->cmd); + } + cm_reset_error(); +} + +static void wr_return_success(wr_session_t *session) +{ + CM_ASSERT(session != NULL); + status_t status; + wr_packet_t *send_pack = NULL; + send_pack = &session->send_pack; + send_pack->head->cmd = session->recv_pack.head->cmd; + send_pack->head->result = (uint8)CM_SUCCESS; + send_pack->head->flags = 0; + wr_set_version(send_pack, session->proto_version); + wr_set_client_version(send_pack, session->client_version); + + status = wr_write(&session->pipe, send_pack); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to reply message,size:%u, cmd:%u.", send_pack->head->size, send_pack->head->cmd); + } +} + +static status_t wr_set_audit_resource(char *resource, uint32 audit_type, const char *format, ...) +{ + if ((cm_log_param_instance()->audit_level & audit_type) == 0) { + return CM_SUCCESS; + } + va_list args; + va_start(args, format); + int32 ret = + vsnprintf_s(resource, (size_t)WR_MAX_AUDIT_PATH_LENGTH, (size_t)(WR_MAX_AUDIT_PATH_LENGTH - 1), format, args); + WR_SECUREC_SS_RETURN_IF_ERROR(ret, CM_ERROR); + va_end(args); + return CM_SUCCESS; +} + +static status_t wr_process_mkdir(wr_session_t *session) +{ + char *dir = NULL; + + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &dir)); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, "%s", dir)); + WR_LOG_DEBUG_OP("Begin to mkdir:%s", dir); + status_t status = wr_make_dir(session, (const char *)dir); + if (status == CM_SUCCESS) { + LOG_DEBUG_INF("Succeed to mkdir:%s", dir); + return status; + } + LOG_DEBUG_ERR("Failed to mkdir:%s", dir); + return status; +} + +static status_t wr_process_rmdir(wr_session_t *session) +{ + char *dir = NULL; + int32 recursive = 0; + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &dir)); + WR_RETURN_IF_ERROR(wr_get_int32(&session->recv_pack, &recursive)); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, "%s", dir)); + WR_LOG_DEBUG_OP("Begin to rmdir:%s.", dir); + char path[WR_FILE_PATH_MAX_LENGTH]; + snprintf(path, WR_FILE_PATH_MAX_LENGTH, "%s/%s", g_inst_cfg->data_dir, dir); + status_t status = wr_filesystem_rmdir(path); + if (status == CM_SUCCESS) { + LOG_DEBUG_INF("Succeed to rmdir:%s", dir); + return status; + } + LOG_DEBUG_ERR("Failed to rmdir:%s", dir); + return status; +} +// TODO: walsender && walreceiver +static status_t wr_process_create_file(wr_session_t *session) +{ + char *file_ptr = NULL; + text_t text; + text_t sub = CM_NULL_TEXT; + int32 flag; + + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &file_ptr)); + WR_RETURN_IF_ERROR(wr_get_int32(&session->recv_pack, &flag)); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, "%s", file_ptr)); + + cm_str2text(file_ptr, &text); + bool32 result = cm_fetch_rtext(&text, '/', '\0', &sub); + WR_RETURN_IF_FALSE2( + result, WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, sub.str, ", which is not a complete absolute path name.")); + if (text.len == 0) { + WR_THROW_ERROR(ERR_WR_FILE_CREATE, "file name is null."); + return CM_ERROR; + } + result = (bool32)(text.len < WR_MAX_NAME_LEN); + WR_RETURN_IF_FALSE2(result, WR_THROW_ERROR(ERR_WR_FILE_PATH_ILL, text.str, "name length should less than 64.")); + + char parent_str[WR_FILE_PATH_MAX_LENGTH]; + char name_str[WR_MAX_NAME_LEN]; + WR_RETURN_IF_ERROR(cm_text2str(&sub, parent_str, sizeof(parent_str))); + WR_RETURN_IF_ERROR(cm_text2str(&text, name_str, sizeof(name_str))); + + WR_LOG_DEBUG_OP("Begin to create file:%s in path:%s.", name_str, parent_str); + status_t status = wr_create_file(session, (const char *)parent_str, (const char *)name_str, flag); + if (status == CM_SUCCESS) { + LOG_DEBUG_INF("Succeed to create file:%s in path:%s", name_str, parent_str); + return status; + } + LOG_DEBUG_ERR("Failed to create file:%s in path:%s", name_str, parent_str); + return status; +} + +static status_t wr_process_delete_file(wr_session_t *session) +{ + char *name = NULL; + wr_init_get(&session->recv_pack); + status_t status = wr_get_str(&session->recv_pack, &name); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("delete file get file name failed.")); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, "%s", name)); + WR_LOG_DEBUG_OP("Begin to rm file:%s", name); + char path[WR_FILE_PATH_MAX_LENGTH]; + snprintf(path, WR_FILE_PATH_MAX_LENGTH, "%s/%s", g_inst_cfg->data_dir, name); + status = wr_filesystem_rm(path); + if (status == CM_SUCCESS) { + LOG_DEBUG_INF("Succeed to rm file:%s", name); + return status; + } + LOG_DEBUG_ERR("Failed to rm file:%s", name); + return status; +} + +static status_t wr_process_exist(wr_session_t *session) +{ + bool32 result = CM_FALSE; + gft_item_type_t type; + char *name = NULL; + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &name)); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_QUERY, "%s", name)); + WR_RETURN_IF_ERROR(wr_exist_item(session, (const char *)name, &result, &type)); + + WR_RETURN_IF_ERROR(wr_put_int32(&session->send_pack, (uint32)result)); + WR_RETURN_IF_ERROR(wr_put_int32(&session->send_pack, (uint32)type)); + return CM_SUCCESS; +} + +static status_t wr_process_open_file(wr_session_t *session) +{ + char *name = NULL; + int32 flag; + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &name)); + WR_RETURN_IF_ERROR(wr_get_int32(&session->recv_pack, &flag)); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, "%s", name)); + wr_find_node_t find_info; + status_t status = wr_open_file(session, (const char *)name, flag, &find_info); + if (status == CM_SUCCESS) { + WR_RETURN_IF_ERROR(wr_put_data(&session->send_pack, &find_info, sizeof(wr_find_node_t))); + } + return status; +} + +static status_t wr_process_close_file(wr_session_t *session) +{ + uint64 fid; + char *vg_name = NULL; + uint32 vgid; + ftid_t ftid; + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&fid)); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &vg_name)); + WR_RETURN_IF_ERROR(wr_get_int32(&session->recv_pack, (int32 *)&vgid)); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&ftid)); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, + "vg_name:%s, fid:%llu, ftid:%llu", vg_name, fid, *(uint64 *)&ftid)); + + wr_vg_info_item_t *vg_item = wr_find_vg_item(vg_name); + bool32 result = (bool32)(vg_item != NULL); + WR_RETURN_IF_FALSE2(result, WR_THROW_ERROR(ERR_WR_VG_NOT_EXIST, vg_name)); + + WR_LOG_DEBUG_OP("Begin to close file, fid:%llu, %s", fid, wr_display_metaid(ftid)); + WR_RETURN_IF_ERROR(wr_close_file(session, vg_item, *(uint64 *)&ftid)); + LOG_DEBUG_INF("Succeed to close file, ftid:%s, fid:%llu, vg: %s, session pid:%llu.", wr_display_metaid(ftid), fid, + vg_item->vg_name, session->cli_info.cli_pid); + return CM_SUCCESS; +} + +static status_t wr_process_open_dir(wr_session_t *session) +{ + char *name = NULL; + int32 refresh_recursive; + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &name)); + WR_RETURN_IF_ERROR(wr_get_int32(&session->recv_pack, &refresh_recursive)); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, "%s", name)); + wr_find_node_t find_info; + WR_LOG_DEBUG_OP("Begin to open dir:%s, is_refresh:%d", name, refresh_recursive); + status_t status = wr_open_dir(session, (const char *)name, (bool32)refresh_recursive, &find_info); + if (status == CM_SUCCESS) { + WR_RETURN_IF_ERROR(wr_put_data(&session->send_pack, &find_info, sizeof(wr_find_node_t))); + LOG_DEBUG_INF("Succeed to open dir:%s, ftid: %s", name, wr_display_metaid(find_info.ftid)); + return status; + } + LOG_DEBUG_ERR("Failed to open dir:%s", name); + return status; +} + +static status_t wr_process_close_dir(wr_session_t *session) +{ + uint64 ftid; + char *vg_name = NULL; + uint32 vgid; + + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&ftid)); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &vg_name)); + WR_RETURN_IF_ERROR(wr_get_int32(&session->recv_pack, (int32 *)&vgid)); + WR_RETURN_IF_ERROR(wr_set_audit_resource( + session->audit_info.resource, WR_AUDIT_MODIFY, "vg_name:%s, ftid:%llu", vg_name, *(uint64 *)&ftid)); + WR_LOG_DEBUG_OP("Begin to close dir, ftid:%llu, vg:%s.", ftid, vg_name); + wr_close_dir(session, vg_name, ftid); + return CM_SUCCESS; +} + +static status_t wr_process_extending_file(wr_session_t *session) +{ + wr_node_data_t node_data; + + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&node_data.fid)); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&node_data.ftid)); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, &node_data.offset)); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, &node_data.size)); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &node_data.vg_name)); + WR_RETURN_IF_ERROR(wr_get_int32(&session->recv_pack, (int32 *)&node_data.vgid)); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, + "extend vg_name:%s, fid:%llu, ftid:%llu, offset:%lld, size:%lld", node_data.vg_name, node_data.fid, + *(uint64 *)&node_data.ftid, node_data.offset, node_data.size)); + + return wr_extend(session, &node_data); +} + +static status_t wr_process_fallocate_file(wr_session_t *session) +{ + wr_node_data_t node_data; + + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&node_data.fid)); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&node_data.ftid)); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, &node_data.offset)); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, &node_data.size)); + WR_RETURN_IF_ERROR(wr_get_int32(&session->recv_pack, (int32 *)&node_data.vgid)); + WR_RETURN_IF_ERROR(wr_get_int32(&session->recv_pack, (int32 *)&node_data.mode)); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, + "fallocate vg_id:%u, fid:%llu, ftid:%llu, offset:%lld, size:%lld, mode:%d", node_data.vgid, node_data.fid, + *(uint64 *)&node_data.ftid, node_data.offset, node_data.size, node_data.mode)); + + LOG_DEBUG_INF("fallocate vg_id:%u, fid:%llu, ftid:%llu, offset:%lld, size:%lld, mode:%d", node_data.vgid, + node_data.fid, *(uint64 *)&node_data.ftid, node_data.offset, node_data.size, node_data.mode); + + return wr_do_fallocate(session, &node_data); +} + +static status_t wr_process_truncate_file(wr_session_t *session) +{ + uint64 fid; + ftid_t ftid; + int64 length; + uint32 vgid; + char *vg_name = NULL; + + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&fid)); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&ftid)); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&length)); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &vg_name)); + WR_RETURN_IF_ERROR(wr_get_int32(&session->recv_pack, (int32 *)&vgid)); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, + "vg_name:%s, fid:%llu, ftid:%llu, length:%lld", vg_name, fid, *(uint64 *)&ftid, length)); + LOG_DEBUG_INF("Truncate file ft id:%llu, length:%lld", *(uint64 *)&ftid, length); + return wr_truncate(session, fid, ftid, length, vg_name); +} + +static status_t wr_process_refresh_file(wr_session_t *session) +{ + uint64 fid; + ftid_t ftid; + uint32 vgid; + int64 offset; + + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&fid)); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&ftid)); + char *name_str = NULL; + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &name_str)); + WR_RETURN_IF_ERROR(wr_get_int32(&session->recv_pack, (int32 *)&vgid)); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&offset)); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, + "vg_name:%s, offset:%lld, fid:%llu, ftid:%llu", name_str, offset, fid, *(uint64 *)&ftid)); + + return wr_refresh_file(session, fid, ftid, name_str, offset); +} + +static status_t wr_process_handshake(wr_session_t *session) +{ + wr_init_get(&session->recv_pack); + session->client_version = wr_get_version(&session->recv_pack); + uint32 current_proto_ver = wr_get_master_proto_ver(); + session->proto_version = MIN(session->client_version, current_proto_ver); + wr_cli_info_t *cli_info; + WR_RETURN_IF_ERROR(wr_get_data(&session->recv_pack, sizeof(wr_cli_info_t), (void **)&cli_info)); + errno_t errcode; + cm_spin_lock(&session->lock, NULL); + errcode = memcpy_s(&session->cli_info, sizeof(wr_cli_info_t), cli_info, sizeof(wr_cli_info_t)); + cm_spin_unlock(&session->lock); + securec_check_ret(errcode); + LOG_RUN_INF( + "[WR_CONNECT]The client has connected, session id:%u, pid:%llu, process name:%s.st_time:%lld, objectid:%u", + session->id, session->cli_info.cli_pid, session->cli_info.process_name, session->cli_info.start_time, + session->objectid); + char *server_home = wr_get_cfg_dir(ZFS_CFG); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_QUERY, "%s", server_home)); + LOG_RUN_INF("[WR_CONNECT]Server home is %s, when get home.", server_home); + uint32 server_pid = getpid(); + text_t data; + cm_str2text(server_home, &data); + data.len++; // for keeping the '\0' + WR_RETURN_IF_ERROR(wr_put_text(&session->send_pack, &data)); + WR_RETURN_IF_ERROR(wr_put_int32(&session->send_pack, session->objectid)); + if (session->proto_version >= WR_VERSION_2) { + WR_RETURN_IF_ERROR(wr_put_int32(&session->send_pack, server_pid)); + } + return CM_SUCCESS; +} + +static status_t wr_process_rename(wr_session_t *session) +{ + char *src = NULL; + char *dst = NULL; + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &src)); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &dst)); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, "%s, %s", src, dst)); + return wr_rename_file(session, src, dst); +} + +status_t wr_process_update_file_written_size(wr_session_t *session) +{ + uint64 fid; + int64 offset; + int64 size; + wr_block_id_t ftid; + uint32 vg_id; + + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&fid)); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&ftid)); + WR_RETURN_IF_ERROR(wr_get_int32(&session->recv_pack, (int32 *)&vg_id)); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&offset)); + WR_RETURN_IF_ERROR(wr_get_int64(&session->recv_pack, (int64 *)&size)); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, + "vg_id:%u, fid:%llu, ftid:%llu, offset:%lld, size:%lld", vg_id, fid, *(uint64 *)&ftid, offset, size)); + return wr_update_file_written_size(session, vg_id, offset, size, ftid, fid); +} + +#define WR_SERVER_STATUS_OFFSET(i) ((uint32)(i) - (uint32)WR_STATUS_NORMAL) +static char *g_wr_instance_rdwr_type[WR_SERVER_STATUS_OFFSET(WR_SERVER_STATUS_END)] = { + [WR_SERVER_STATUS_OFFSET(WR_STATUS_NORMAL)] = "NORMAL", + [WR_SERVER_STATUS_OFFSET(WR_STATUS_READONLY)] = "READONLY", + [WR_SERVER_STATUS_OFFSET(WR_STATUS_READWRITE)] = "READWRITE", +}; + +char *wr_get_wr_server_status(int32 server_status) +{ + if (server_status < WR_STATUS_NORMAL || server_status > WR_STATUS_READWRITE) { + return "unknown"; + } + return g_wr_instance_rdwr_type[WR_SERVER_STATUS_OFFSET(server_status)]; +} + +#define WR_INSTANCE_STATUS_OFFSET(i) ((uint32)(i) - (uint32)WR_STATUS_PREPARE) +static char *g_wr_instance_status_desc[WR_INSTANCE_STATUS_OFFSET(WR_INSTANCE_STATUS_END)] = { + [WR_INSTANCE_STATUS_OFFSET(WR_STATUS_PREPARE)] = "prepare", + [WR_INSTANCE_STATUS_OFFSET(WR_STATUS_RECOVERY)] = "recovery", + [WR_INSTANCE_STATUS_OFFSET(WR_STATUS_SWITCH)] = "switch", + [WR_INSTANCE_STATUS_OFFSET(WR_STATUS_OPEN)] = "open", +}; + +char *wr_get_wr_instance_status(int32 instance_status) +{ + if (instance_status < WR_STATUS_PREPARE || instance_status > WR_STATUS_OPEN) { + return "unknown"; + } + return g_wr_instance_status_desc[WR_INSTANCE_STATUS_OFFSET(instance_status)]; +} + +// get wrserver status:open, recovery or switch +static status_t wr_process_get_inst_status(wr_session_t *session) +{ + wr_server_status_t *wr_status = NULL; + WR_RETURN_IF_ERROR( + wr_reserv_text_buf(&session->send_pack, (uint32)sizeof(wr_server_status_t), (char **)&wr_status)); + + wr_status->instance_status_id = g_wr_instance.status; + wr_status->server_status_id = wr_get_server_status_flag(); + wr_status->local_instance_id = g_wr_instance.inst_cfg.params.inst_id; + wr_status->master_id = wr_get_master_id(); + wr_status->is_maintain = g_wr_instance.is_maintain; + char *wr_instance_status = wr_get_wr_instance_status(wr_status->instance_status_id); + errno_t errcode = strcpy_s(wr_status->instance_status, WR_MAX_STATUS_LEN, wr_instance_status); + MEMS_RETURN_IFERR(errcode); + + char *wr_server_status = wr_get_wr_server_status(wr_status->server_status_id); + errcode = strcpy_s(wr_status->server_status, WR_MAX_STATUS_LEN, wr_server_status); + MEMS_RETURN_IFERR(errcode); + + WR_RETURN_IF_ERROR(wr_set_audit_resource( + session->audit_info.resource, WR_AUDIT_MODIFY, "status:%s", wr_status->instance_status)); + WR_LOG_DEBUG_OP("Server status is %s.", wr_status->instance_status); + return CM_SUCCESS; +} +static status_t wr_process_get_time_stat(wr_session_t *session) +{ + uint64 size = sizeof(wr_stat_item_t) * WR_EVT_COUNT; + wr_stat_item_t *time_stat = NULL; + WR_RETURN_IF_ERROR(wr_reserv_text_buf(&session->send_pack, (uint32)size, (char **)&time_stat)); + + errno_t errcode = memset_s(time_stat, (size_t)size, 0, (size_t)size); + securec_check_ret(errcode); + wr_session_ctrl_t *session_ctrl = wr_get_session_ctrl(); + wr_session_t *tmp_session = NULL; + cm_spin_lock(&session_ctrl->lock, NULL); + for (uint32 i = 0; i < session_ctrl->alloc_sessions; i++) { + tmp_session = session_ctrl->sessions[i]; + if (tmp_session->is_used && !tmp_session->is_closed) { + for (uint32 j = 0; j < WR_EVT_COUNT; j++) { + int64 count = (int64)tmp_session->wr_session_stat[j].wait_count; + int64 total_time = (int64)tmp_session->wr_session_stat[j].total_wait_time; + int64 max_sgl_time = (int64)tmp_session->wr_session_stat[j].max_single_time; + + time_stat[j].wait_count += count; + time_stat[j].total_wait_time += total_time; + time_stat[j].max_single_time = (atomic_t)MAX((int64)time_stat[j].max_single_time, max_sgl_time); + + (void)cm_atomic_add(&tmp_session->wr_session_stat[j].wait_count, -count); + (void)cm_atomic_add(&tmp_session->wr_session_stat[j].total_wait_time, -total_time); + (void)cm_atomic_cas(&tmp_session->wr_session_stat[j].max_single_time, max_sgl_time, 0); + } + } + } + cm_spin_unlock(&session_ctrl->lock); + + return CM_SUCCESS; +} + +void wr_wait_session_pause(wr_instance_t *inst) +{ + tcp_lsnr_t *lsnr = &inst->lsnr; + LOG_DEBUG_INF("Begin to set session paused."); + cs_pause_tcp_lsnr(lsnr); + wr_pause_reactors(); + while (inst->active_sessions != 0) { + cm_sleep(1); + } + LOG_DEBUG_INF("Succeed to pause all session."); +} + +void wr_wait_background_pause(wr_instance_t *inst) +{ + LOG_DEBUG_INF("Begin to set background paused."); + while (inst->is_cleaning || inst->is_checking) { + cm_sleep(1); + } + LOG_DEBUG_INF("Succeed to pause background task."); +} + +void wr_set_session_running(wr_instance_t *inst, uint32 sid) +{ + LOG_DEBUG_INF("Begin to set session running."); + cm_latch_x(&inst->tcp_lsnr_latch, sid, NULL); + if (inst->abort_status) { + LOG_RUN_INF("wrserver is aborting, no need to set sessions running."); + cm_unlatch(&inst->tcp_lsnr_latch, NULL); + return; + } + tcp_lsnr_t *lsnr = &inst->lsnr; + wr_continue_reactors(); + lsnr->status = LSNR_STATUS_RUNNING; + cm_unlatch(&inst->tcp_lsnr_latch, NULL); + LOG_DEBUG_INF("Succeed to run all sessions."); +} + +static status_t wr_process_setcfg(wr_session_t *session) +{ + char *name = NULL; + char *value = NULL; + char *scope = NULL; + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &name)); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &value)); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &scope)); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, "%s", name)); + + return wr_set_cfg_param(name, value, scope); +} + +static status_t wr_process_getcfg(wr_session_t *session) +{ + char *name = NULL; + char *value = NULL; + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_get_str(&session->recv_pack, &name)); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_QUERY, "%s", name)); + + WR_RETURN_IF_ERROR(wr_get_cfg_param(name, &value)); + if (strlen(value) != 0 && cm_str_equal_ins(name, "SSL_PWD_CIPHERTEXT")) { + WR_LOG_DEBUG_OP("Server value is ***, when get cfg."); + } else { + WR_LOG_DEBUG_OP("Server value is %s, when get cfg.", value); + } + text_t data; + cm_str2text(value, &data); + // SSL default value is NULL + if (value != NULL) { + data.len++; // for keeping the '\0' + } + return wr_put_text(&session->send_pack, &data); +} + +static status_t wr_process_stop_server(wr_session_t *session) +{ + wr_init_get(&session->recv_pack); + WR_RETURN_IF_ERROR(wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, "%u", session->id)); + g_wr_instance.abort_status = CM_TRUE; + + return CM_SUCCESS; +} + +// process switch lock,just master id can do +static status_t wr_process_switch_lock_inner(wr_session_t *session, uint32 switch_id) +{ + wr_config_t *inst_cfg = wr_get_inst_cfg(); + uint32 curr_id = (uint32)inst_cfg->params.inst_id; + uint32 master_id = wr_get_master_id(); + if ((uint32)switch_id == master_id) { + LOG_RUN_INF("[SWITCH]switchid is equal to current master_id, which is %u.", master_id); + return CM_SUCCESS; + } + if (master_id != curr_id) { + LOG_RUN_ERR("[SWITCH]current id is %u, just master id %u can do switch lock.", curr_id, master_id); + return CM_ERROR; + } + wr_wait_session_pause(&g_wr_instance); + g_wr_instance.status = WR_STATUS_SWITCH; + wr_wait_background_pause(&g_wr_instance); +#ifdef ENABLE_WRTEST + wr_set_server_status_flag(WR_STATUS_READONLY); + LOG_RUN_INF("[SWITCH]inst %u set status flag %u when trans lock.", curr_id, WR_STATUS_READONLY); + wr_set_master_id((uint32)switch_id); + wr_set_session_running(&g_wr_instance, session->id); + g_wr_instance.status = WR_STATUS_OPEN; +#endif + status_t ret = CM_SUCCESS; + // trans lock + if (g_wr_instance.cm_res.is_valid) { + wr_set_server_status_flag(WR_STATUS_READONLY); + LOG_RUN_INF("[SWITCH]inst %u set status flag %u when trans lock.", curr_id, WR_STATUS_READONLY); + ret = cm_res_trans_lock(&g_wr_instance.cm_res.mgr, WR_CM_LOCK, (uint32)switch_id); + if (ret != CM_SUCCESS) { + wr_set_session_running(&g_wr_instance, session->id); + wr_set_server_status_flag(WR_STATUS_READWRITE); + LOG_RUN_INF("[SWITCH]inst %u set status flag %u when failed to trans lock.", curr_id, WR_STATUS_READWRITE); + g_wr_instance.status = WR_STATUS_OPEN; + LOG_RUN_ERR("[SWITCH]cm do switch lock failed from %u to %u.", curr_id, master_id); + return ret; + } + wr_set_master_id((uint32)switch_id); + wr_set_session_running(&g_wr_instance, session->id); + g_wr_instance.status = WR_STATUS_OPEN; + } else { + wr_set_session_running(&g_wr_instance, session->id); + g_wr_instance.status = WR_STATUS_OPEN; + LOG_RUN_ERR("[SWITCH]Only with cm can switch lock."); + return CM_ERROR; + } + LOG_RUN_INF( + "[SWITCH]Old main server %u switch lock to new main server %u successfully.", curr_id, (uint32)switch_id); + return CM_SUCCESS; +} + +static status_t wr_process_switch_lock(wr_session_t *session) +{ + int32 switch_id; + wr_init_get(&session->recv_pack); + if (wr_get_int32(&session->recv_pack, &switch_id) != CM_SUCCESS) { + return CM_ERROR; + } + cm_unlatch(&g_wr_instance.switch_latch, LATCH_STAT(LATCH_SWITCH)); // when mes process req, will latch s + cm_latch_x(&g_wr_instance.switch_latch, session->id, LATCH_STAT(LATCH_SWITCH)); + wr_set_recover_thread_id(wr_get_current_thread_id()); + status_t ret = wr_process_switch_lock_inner(session, (uint32)switch_id); + wr_set_recover_thread_id(0); + // no need to unlatch, for wr_process_message will + return ret; +} +/* + 1 curr_id == master_id, just return success; + 2 curr_id != master_id, just send message to master_id to do switch lock + then master_id to do: + (1) set status switch + (2) lsnr pause + (3) trans lock +*/ +static status_t wr_process_remote_switch_lock(wr_session_t *session, uint32 curr_id, uint32 master_id) +{ + wr_instance_status_e old_status = g_wr_instance.status; + g_wr_instance.status = WR_STATUS_SWITCH; + uint32 current_proto_ver = wr_get_master_proto_ver(); + wr_init_set(&session->recv_pack, current_proto_ver); + session->recv_pack.head->cmd = WR_CMD_SWITCH_LOCK; + session->recv_pack.head->flags = 0; + LOG_RUN_INF("[SWITCH] Try to switch lock to %u by %u.", curr_id, master_id); + (void)wr_put_int32(&session->recv_pack, curr_id); + status_t status = wr_process_remote(session); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("[SWITCH] Failed to switch lock to %u by %u.", curr_id, master_id); + g_wr_instance.status = old_status; + } + return status; +} + +static status_t wr_process_set_main_inst(wr_session_t *session) +{ + status_t status = CM_ERROR; + wr_config_t *cfg = wr_get_inst_cfg(); + uint32 curr_id = (uint32)(cfg->params.inst_id); + uint32 master_id; + WR_RETURN_IF_ERROR( + wr_set_audit_resource(session->audit_info.resource, WR_AUDIT_MODIFY, "set %u as master", curr_id)); + while (CM_TRUE) { + master_id = wr_get_master_id(); + if (master_id == curr_id) { + session->recv_pack.head->cmd = WR_CMD_SET_MAIN_INST; + LOG_RUN_INF("[SWITCH] Main server %u is set successfully by %u.", curr_id, master_id); + return CM_SUCCESS; + } + if (get_instance_status_proc() == WR_STATUS_RECOVERY) { + session->recv_pack.head->cmd = WR_CMD_SET_MAIN_INST; + WR_THROW_ERROR(ERR_WR_RECOVER_CAUSE_BREAK); + LOG_RUN_INF("[SWITCH] Set main inst break by recovery"); + return CM_ERROR; + } + if (!cm_latch_timed_x( + &g_wr_instance.switch_latch, session->id, WR_PROCESS_REMOTE_INTERVAL, LATCH_STAT(LATCH_SWITCH))) { + LOG_RUN_INF("[SWITCH] Spin switch lock timed out, just continue."); + continue; + } + status = wr_process_remote_switch_lock(session, curr_id, master_id); + if (status != CM_SUCCESS) { + cm_unlatch(&g_wr_instance.switch_latch, LATCH_STAT(LATCH_SWITCH)); + if (cm_get_error_code() == ERR_WR_RECOVER_CAUSE_BREAK) { + session->recv_pack.head->cmd = WR_CMD_SET_MAIN_INST; + LOG_RUN_INF("[SWITCH] Try set main break because master id is invalid."); + return CM_ERROR; + } + cm_sleep(WR_PROCESS_REMOTE_INTERVAL); + continue; + } + break; + } + session->recv_pack.head->cmd = WR_CMD_SET_MAIN_INST; + wr_set_recover_thread_id(wr_get_current_thread_id()); + g_wr_instance.status = WR_STATUS_RECOVERY; + wr_set_master_id(curr_id); + status = wr_refresh_meta_info(session); + if (status != CM_SUCCESS) { + g_wr_instance.status = WR_STATUS_OPEN; + cm_unlatch(&g_wr_instance.switch_latch, LATCH_STAT(LATCH_SWITCH)); + LOG_RUN_ERR("[WR][SWITCH] ABORT INFO: wr instance %u refresh meta failed, result(%d).", curr_id, status); + cm_fync_logfile(); + wr_exit(1); + } + wr_set_server_status_flag(WR_STATUS_READWRITE); + LOG_RUN_INF("[SWITCH] inst %u set status flag %u when set main inst.", curr_id, WR_STATUS_READWRITE); + g_wr_instance.status = WR_STATUS_OPEN; + wr_set_recover_thread_id(0); + LOG_RUN_INF("[SWITCH] Main server %u is set successfully by %u.", curr_id, master_id); + cm_unlatch(&g_wr_instance.switch_latch, LATCH_STAT(LATCH_SWITCH)); + return CM_SUCCESS; +} + + +static wr_cmd_hdl_t g_wr_cmd_handle[WR_CMD_TYPE_OFFSET(WR_CMD_END)] = { + // modify + [WR_CMD_TYPE_OFFSET(WR_CMD_MKDIR)] = {WR_CMD_MKDIR, wr_process_mkdir, NULL, CM_TRUE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_RMDIR)] = {WR_CMD_RMDIR, wr_process_rmdir, NULL, CM_TRUE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_OPEN_DIR)] = {WR_CMD_OPEN_DIR, wr_process_open_dir, NULL, CM_FALSE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_CLOSE_DIR)] = {WR_CMD_CLOSE_DIR, wr_process_close_dir, NULL, CM_FALSE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_OPEN_FILE)] = {WR_CMD_OPEN_FILE, wr_process_open_file, NULL, CM_FALSE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_CLOSE_FILE)] = {WR_CMD_CLOSE_FILE, wr_process_close_file, NULL, CM_FALSE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_CREATE_FILE)] = {WR_CMD_CREATE_FILE, wr_process_create_file, NULL, CM_TRUE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_DELETE_FILE)] = {WR_CMD_DELETE_FILE, wr_process_delete_file, NULL, CM_TRUE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_EXTEND_FILE)] = {WR_CMD_EXTEND_FILE, wr_process_extending_file, NULL, CM_TRUE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_RENAME_FILE)] = {WR_CMD_RENAME_FILE, wr_process_rename, NULL, CM_TRUE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_REFRESH_FILE)] = {WR_CMD_REFRESH_FILE, wr_process_refresh_file, NULL, CM_FALSE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_TRUNCATE_FILE)] = {WR_CMD_TRUNCATE_FILE, wr_process_truncate_file, NULL, CM_TRUE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_FALLOCATE_FILE)] = {WR_CMD_FALLOCATE_FILE, wr_process_fallocate_file, NULL, CM_TRUE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_STOP_SERVER)] = {WR_CMD_STOP_SERVER, wr_process_stop_server, NULL, CM_FALSE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_SETCFG)] = {WR_CMD_SETCFG, wr_process_setcfg, NULL, CM_FALSE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_SET_MAIN_INST)] = {WR_CMD_SET_MAIN_INST, wr_process_set_main_inst, NULL, CM_FALSE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_SWITCH_LOCK)] = {WR_CMD_SWITCH_LOCK, wr_process_switch_lock, NULL, CM_FALSE}, + // query + [WR_CMD_TYPE_OFFSET(WR_CMD_HANDSHAKE)] = {WR_CMD_HANDSHAKE, wr_process_handshake, NULL, CM_FALSE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_EXIST)] = {WR_CMD_EXIST, wr_process_exist, NULL, CM_FALSE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_GETCFG)] = {WR_CMD_GETCFG, wr_process_getcfg, NULL, CM_FALSE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_GET_INST_STATUS)] = {WR_CMD_GET_INST_STATUS, wr_process_get_inst_status, NULL, + CM_FALSE}, + [WR_CMD_TYPE_OFFSET(WR_CMD_GET_TIME_STAT)] = {WR_CMD_GET_TIME_STAT, wr_process_get_time_stat, NULL, CM_FALSE}, +}; + +wr_cmd_hdl_t g_wr_remote_handle = {WR_CMD_EXEC_REMOTE, wr_process_remote, NULL, CM_FALSE}; + +static wr_cmd_hdl_t *wr_get_cmd_handle(int32 cmd) +{ + if (cmd >= WR_CMD_BEGIN && cmd < WR_CMD_END) { + return &g_wr_cmd_handle[WR_CMD_TYPE_OFFSET(cmd)]; + } + return NULL; +} + +static status_t wr_check_proto_version(wr_session_t *session) +{ + session->client_version = wr_get_client_version(&session->recv_pack); + uint32 current_proto_ver = wr_get_master_proto_ver(); + current_proto_ver = MIN(current_proto_ver, session->client_version); + session->proto_version = current_proto_ver; + if (session->proto_version != wr_get_version(&session->recv_pack)) { + LOG_RUN_INF("[CHECK_PROTO]The client protocol version need be changed, old protocol version is %u, new " + "protocol version is %u.", + wr_get_version(&session->recv_pack), session->proto_version); + WR_THROW_ERROR(ERR_WR_VERSION_NOT_MATCH, wr_get_version(&session->recv_pack), session->proto_version); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t wr_exec_cmd(wr_session_t *session, bool32 local_req) +{ + WR_LOG_DEBUG_OP( + "Receive command:%d, server status is %d.", session->recv_pack.head->cmd, (int32)g_wr_instance.status); + // remote req need process for proto_version + session->proto_version = wr_get_version(&session->recv_pack); + wr_cmd_hdl_t *handle = wr_get_cmd_handle(session->recv_pack.head->cmd); + + if ((handle == NULL) || (handle->proc == NULL)) { + LOG_DEBUG_ERR("the req cmd: %d is not valid.", session->recv_pack.head->cmd); + return CM_ERROR; + } + + status_t status; + do { + cm_reset_error(); + wr_inc_active_sessions(session); + if (wr_can_cmd_type_no_open(session->recv_pack.head->cmd)) { + status = handle->proc(session); + } else if (!wr_need_exec_remote(handle->exec_on_active, local_req)) { + // if cur node is standby, may reset it to recovery to do recovery + if (g_wr_instance.status != WR_STATUS_OPEN && g_wr_instance.status != WR_STATUS_PREPARE) { + LOG_RUN_INF("Req forbided by recovery for cmd:%u", (uint32)session->recv_pack.head->cmd); + wr_dec_active_sessions(session); + cm_sleep(WR_PROCESS_REMOTE_INTERVAL); + continue; + } + status = handle->proc(session); + } else { + status = g_wr_remote_handle.proc(session); + } + wr_dec_active_sessions(session); + if (status != CM_SUCCESS && + (cm_get_error_code() == ERR_WR_RECOVER_CAUSE_BREAK || cm_get_error_code() == ERR_WR_MASTER_CHANGE)) { + LOG_RUN_INF("Req breaked by error %d for cmd:%u", cm_get_error_code(), session->recv_pack.head->cmd); + cm_sleep(WR_PROCESS_REMOTE_INTERVAL); + continue; + } + break; + } while (CM_TRUE); + + session->audit_info.action = wr_get_cmd_desc(session->recv_pack.head->cmd); + + if (local_req) { + sql_record_audit_log(session, status, session->recv_pack.head->cmd); + } + return status; +} + +void wr_process_cmd_wait_be_open(wr_session_t *session) +{ + while (g_wr_instance.status != WR_STATUS_OPEN) { + WR_GET_CM_LOCK_LONG_SLEEP; + LOG_RUN_INF("The status %d of instance %lld is not open, just wait.\n", (int32)g_wr_instance.status, + wr_get_inst_cfg()->params.inst_id); + } +} + +status_t wr_process_command(wr_session_t *session) +{ + status_t status = CM_SUCCESS; + bool32 ready = CM_FALSE; + + cm_reset_error(); + if (cs_wait(&session->pipe, CS_WAIT_FOR_READ, WR_WAIT_TIMEOUT, &ready) != CM_SUCCESS) { + session->is_closed = CM_TRUE; + return CM_ERROR; + } + + if (ready == CM_FALSE) { + return CM_SUCCESS; + } + wr_init_set(&session->send_pack, session->proto_version); + status = wr_read(&session->pipe, &session->recv_pack, CM_FALSE); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to read message sent by %s.", session->cli_info.process_name); + session->is_closed = CM_TRUE; + return CM_ERROR; + } + status = wr_check_proto_version(session); + if (status != CM_SUCCESS) { + wr_return_error(session); + return CM_ERROR; + } + + if (!wr_can_cmd_type_no_open(session->recv_pack.head->cmd)) { + wr_process_cmd_wait_be_open(session); + } + + status = wr_exec_cmd(session, CM_TRUE); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to execute command:%d.", session->recv_pack.head->cmd); + wr_return_error(session); + return CM_ERROR; + } else { + wr_return_success(session); + } + return CM_SUCCESS; +} + +status_t wr_proc_standby_req(wr_session_t *session) +{ + if (wr_is_readonly() == CM_TRUE && !wr_need_exec_local()) { + wr_config_t *cfg = wr_get_inst_cfg(); + uint32 id = (uint32)(cfg->params.inst_id); + LOG_RUN_ERR("The local node(%u) is in readonly state and cannot execute remote requests.", id); + return CM_ERROR; + } + + return wr_exec_cmd(session, CM_FALSE); +} + +status_t wr_process_handshake_cmd(wr_session_t *session, wr_cmd_type_e cmd) +{ + status_t status = CM_ERROR; + bool32 ready = CM_FALSE; + do { + cm_reset_error(); + if (cs_wait(&session->pipe, CS_WAIT_FOR_READ, session->pipe.socket_timeout, &ready) != CM_SUCCESS) { + LOG_RUN_ERR("[WR_CONNECT]session %u wait handshake cmd %u failed.", session->id, cmd); + return CM_ERROR; + } + if (ready == CM_FALSE) { + LOG_RUN_ERR("[WR_CONNECT]session %u wait handshake cmd %u timeout.", session->id, cmd); + return CM_ERROR; + } + wr_init_set(&session->send_pack, session->proto_version); + status = wr_read(&session->pipe, &session->recv_pack, CM_FALSE); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("[WR_CONNECT]session %u read handshake cmd %u msg failed.", session->id, cmd); + return CM_ERROR; + } + status = wr_check_proto_version(session); + if (status != CM_SUCCESS) { + wr_return_error(session); + continue; + } + break; + } while (CM_TRUE); + if (session->recv_pack.head->cmd != cmd) { + LOG_RUN_ERR("[WR_CONNECT]session %u wait handshake cmd %u, but get msg cmd %u.", session->id, cmd, + session->recv_pack.head->cmd); + return CM_ERROR; + } + status = wr_exec_cmd(session, CM_TRUE); + if (status != CM_SUCCESS) { + LOG_RUN_ERR( + "[WR_CONNECT]Failed to execute command:%d, session %u.", session->recv_pack.head->cmd, session->id); + wr_return_error(session); + return CM_ERROR; + } else { + wr_return_success(session); + } + return status; +} +#ifdef __cplusplus +} +#endif diff --git a/src/service/wr_service.h b/src/service/wr_service.h new file mode 100644 index 0000000000000000000000000000000000000000..08d11cbb1dc35e25e41cacf56aae7dce6734d933 --- /dev/null +++ b/src/service/wr_service.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_service.h + * + * + * IDENTIFICATION + * src/service/wr_service.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef __WR_SERVICE_H__ +#define __WR_SERVICE_H__ +#include "wr_latch.h" +#include "wr_session.h" +#include "wr_instance.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef status_t (*wr_srv_proc)(wr_session_t *session); +typedef status_t (*wr_srv_proc_err)(wr_session_t *session); + +typedef struct st_wr_cmd_hdl { + int32 cmd; + wr_srv_proc proc; + wr_srv_proc_err proc_err; + bool32 exec_on_active; +} wr_cmd_hdl_t; + +#define WR_PROCESS_GET_MASTER_ID 50 +static inline void wr_inc_active_sessions(wr_session_t *session) +{ + if (session->recv_pack.head->cmd != WR_CMD_SWITCH_LOCK) { + (void)cm_atomic_inc(&g_wr_instance.active_sessions); + LOG_DEBUG_INF("session:%u inc active_sessions to:%lld for cmd:%u", session->id, g_wr_instance.active_sessions, + (uint32)session->recv_pack.head->cmd); + } +} + +static inline void wr_dec_active_sessions(wr_session_t *session) +{ + if (session->recv_pack.head->cmd != WR_CMD_SWITCH_LOCK) { + (void)cm_atomic_dec(&g_wr_instance.active_sessions); + LOG_DEBUG_INF("session:%u dec active_sessions to:%lld for cmd:%u", session->id, g_wr_instance.active_sessions, + (uint32)session->recv_pack.head->cmd); + } +} + +status_t wr_get_exec_nodeid(wr_session_t *session, uint32 *currid, uint32 *remoteid); +void wr_wait_session_pause(wr_instance_t *inst); +void wr_wait_background_pause(wr_instance_t *inst); +void wr_set_session_running(wr_instance_t *inst, uint32 sid); +status_t wr_diag_proto_type(wr_session_t *session); +status_t wr_process_handshake_cmd(wr_session_t *session, wr_cmd_type_e cmd); +status_t wr_process_command(wr_session_t *session); +status_t wr_proc_standby_req(wr_session_t *session); +status_t wr_process_single_cmd(wr_session_t **session); +void wr_release_session_res(wr_session_t *session); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/service/wr_srv_proc.c b/src/service/wr_srv_proc.c new file mode 100644 index 0000000000000000000000000000000000000000..2d5d12c3b658d77ea9383aa000edcba029821cdd --- /dev/null +++ b/src/service/wr_srv_proc.c @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_srv_proc.c + * + * + * IDENTIFICATION + * src/service/wr_srv_proc.c + * + * ------------------------------------------------------------------------- + */ +#include "wr_errno.h" +#include "wr_redo.h" +#include "wr_open_file.h" +#include "wr_file.h" +#include "wr_mes.h" +#include "wr_srv_proc.h" +#include "wr_instance.h" +#include "wr_thv.h" +#include "wr_filesystem.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static status_t wr_check_two_path_in_same_vg(const char *path1, const char *path2, char *vg_name) +{ + uint32 beg_pos1 = 0; + uint32 beg_pos2 = 0; + char vg_name1[WR_MAX_NAME_LEN] = {0}; + + status_t ret = wr_get_name_from_path(path1, &beg_pos1, vg_name1); + WR_RETURN_IFERR2(ret, LOG_DEBUG_ERR("Failed to get name from path %s,%d.", path1, ret)); + + ret = wr_get_name_from_path(path2, &beg_pos2, vg_name); + WR_RETURN_IFERR2(ret, LOG_DEBUG_ERR("Failed to get name from path %s,%d.", path2, ret)); + + if ((beg_pos1 != beg_pos2) || (cm_strcmpni(vg_name1, vg_name, strlen(vg_name1)) != 0)) { + WR_THROW_ERROR(ERR_WR_FILE_RENAME_DIFF_VG, vg_name1, vg_name); + return CM_ERROR; + } + + return CM_SUCCESS; +} + +static status_t wr_rename_file_check( + wr_session_t *session, const char *src, const char *dst, wr_vg_info_item_t **vg_item, gft_node_t **out_node) +{ + status_t status = wr_check_file(*vg_item); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to check file,errcode:%d.", cm_get_error_code())); + + wr_check_dir_output_t output_info = {out_node, NULL, NULL, CM_TRUE}; + wr_vg_info_item_t *file_vg_item = *vg_item; + output_info.item = &file_vg_item; + status = wr_check_dir(session, src, GFT_FILE, &output_info, CM_TRUE); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("Failed to check dir,errcode:%d.", cm_get_error_code())); + + gft_node_t *out_node_tmp = NULL; + wr_check_dir_output_t output_info_tmp = {&out_node_tmp, NULL, NULL, CM_TRUE}; + if (wr_check_dir(session, dst, GFT_FILE, &output_info_tmp, CM_TRUE) != CM_SUCCESS) { + int32 errcode = cm_get_error_code(); + if (errcode != ERR_WR_FILE_NOT_EXIST) { + return CM_ERROR; + } + cm_reset_error(); + } else { + WR_THROW_ERROR(ERR_WR_FILE_RENAME_EXIST, "cannot rename a existed file."); + return CM_ERROR; + } + + if (file_vg_item->id != (*vg_item)->id) { + wr_unlock_vg_mem_and_shm(session, *vg_item); + *vg_item = file_vg_item; + wr_lock_vg_mem_and_shm_x(session, *vg_item); + } + return CM_SUCCESS; +} + +status_t wr_rename_file_put_redo_log(wr_session_t *session, gft_node_t *out_node, const char *dst_name, + wr_vg_info_item_t *vg_item, wr_config_t *inst_cfg) +{ + wr_redo_rename_t redo; + redo.node = *out_node; + errno_t err = snprintf_s(redo.name, WR_MAX_NAME_LEN, strlen(dst_name), "%s", dst_name); + bool32 result = (bool32)(err != -1); + WR_RETURN_IF_FALSE2(result, WR_THROW_ERROR(ERR_SYSTEM_CALL, err)); + + err = snprintf_s(redo.old_name, WR_MAX_NAME_LEN, strlen(out_node->name), "%s", out_node->name); + result = (bool32)(err != -1); + WR_RETURN_IF_FALSE2(result, WR_THROW_ERROR(ERR_SYSTEM_CALL, err)); + + err = snprintf_s(out_node->name, WR_MAX_NAME_LEN, strlen(dst_name), "%s", dst_name); + result = (bool32)(err != -1); + WR_RETURN_IF_FALSE2(result, WR_THROW_ERROR(ERR_SYSTEM_CALL, err)); + + wr_put_log(session, vg_item, WR_RT_RENAME_FILE, &redo, sizeof(redo)); + + if (wr_process_redo_log(session, vg_item) != CM_SUCCESS) { + wr_unlock_vg_mem_and_shm(session, vg_item); + LOG_RUN_ERR("[WR] ABORT INFO: redo log process failed, errcode:%d, OS errno:%d, OS errmsg:%s.", + cm_get_error_code(), errno, strerror(errno)); + cm_fync_logfile(); + wr_exit(1); + } + return CM_SUCCESS; +} + +status_t wr_rename_file_check_path_and_name( + wr_session_t *session, const char *src_path, const char *dst_path, char *vg_name, char *dst_name) +{ + CM_RETURN_IFERR(wr_check_two_path_in_same_vg(src_path, dst_path, vg_name)); + text_t dst_name_text; + CM_RETURN_IFERR(wr_check_rename_path(session, src_path, dst_path, &dst_name_text)); + CM_RETURN_IFERR(cm_text2str(&dst_name_text, dst_name, WR_MAX_NAME_LEN)); + status_t status = wr_check_name(dst_name); + WR_RETURN_IFERR2(status, LOG_DEBUG_ERR("The name %s is invalid.", dst_path)); + + return CM_SUCCESS; +} + +status_t wr_check_vg_ft_dir(wr_session_t *session, wr_vg_info_item_t **vg_item, const char *path, + gft_item_type_t type, gft_node_t **node, gft_node_t **parent_node) +{ + CM_RETURN_IFERR(wr_check_file(*vg_item)); + + wr_vg_info_item_t *tmp_vg_item = *vg_item; + wr_check_dir_output_t output_info = {node, &tmp_vg_item, parent_node, CM_TRUE}; + status_t status = wr_check_dir(session, path, type, &output_info, CM_TRUE); + if (status != CM_SUCCESS) { + LOG_DEBUG_ERR("Failed to check dir, errcode: %d.", status); + return status; + } + if (tmp_vg_item->id != (*vg_item)->id) { + wr_unlock_vg_mem_and_shm(session, *vg_item); + *vg_item = tmp_vg_item; + wr_lock_vg_mem_and_shm_x(session, *vg_item); + } + return CM_SUCCESS; +} + +static bool32 wr_has_children_nodes(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node) +{ + if (node->items.count == 0) { + return CM_FALSE; + } + gft_node_t *sub_node = wr_get_ft_node_by_ftid(session, vg_item, node->items.first, CM_TRUE, CM_FALSE); + while (sub_node != NULL) { + if ((sub_node->flags & WR_FT_NODE_FLAG_DEL) == 0) { + return CM_TRUE; + } + if (wr_cmp_auid(sub_node->next, WR_INVALID_ID64)) { + break; + } + sub_node = wr_get_ft_node_by_ftid(session, vg_item, sub_node->next, CM_TRUE, CM_FALSE); + } + return CM_FALSE; +} + +static inline status_t wr_mark_delete_flag_core(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node) +{ + wr_set_node_flag(session, vg_item, node, CM_TRUE, WR_FT_NODE_FLAG_DEL); + LOG_DEBUG_INF("File : %s successfully marked for deletion", node->name); + return CM_SUCCESS; +} + +static status_t wr_mark_delete_flag_r(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node) +{ + if ((node->flags & WR_FT_NODE_FLAG_SYSTEM) != 0) { + WR_THROW_ERROR(ERR_WR_FILE_REMOVE_SYSTEM, node->name); + LOG_DEBUG_ERR("Failed to rm dir %s, can not rm system dir.", node->name); + return CM_ERROR; + } + if (!wr_is_last_tree_node(node)) { + gft_node_t *sub_node = wr_get_ft_node_by_ftid(session, vg_item, node->items.first, CM_TRUE, CM_FALSE); + while (sub_node != NULL) { + if ((sub_node->flags & WR_FT_NODE_FLAG_DEL) == 0) { + CM_RETURN_IFERR(wr_mark_delete_flag_r(session, vg_item, sub_node)); + } + sub_node = wr_get_next_node(session, vg_item, sub_node); + } + } + if ((node->flags & WR_FT_NODE_FLAG_DEL) != 0) { + LOG_DEBUG_INF("File: %s has been marked for deletion, nothing need to do.", node->name); + return CM_SUCCESS; + } + return wr_mark_delete_flag_core(session, vg_item, node); +} + +static status_t wr_mark_delete_flag( + wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node, const char *dir_name, bool recursive) +{ + LOG_DEBUG_INF( + "Mark delete flag for file or dir %s, fid:%llu, ftid: %s.", dir_name, node->fid, wr_display_metaid(node->id)); + if ((node->flags & WR_FT_NODE_FLAG_DEL) != 0) { + LOG_DEBUG_INF("File: %s has been marked for deletion, nothing need to do.", node->name); + return CM_SUCCESS; + } + bool32 has_sub_file = CM_FALSE; + status_t status = CM_ERROR; + if (node->type == GFT_PATH) { + has_sub_file = wr_has_children_nodes(session, vg_item, node); + } + + if (has_sub_file) { + if (!recursive) { + WR_THROW_ERROR_EX(ERR_WR_DIR_REMOVE_NOT_EMPTY, "Failed to rm dir %s, which has sub node.", dir_name); + return CM_ERROR; + } + status = wr_mark_delete_flag_r(session, vg_item, node); + } else { + return wr_mark_delete_flag_core(session, vg_item, node); + } + return status; +} + +static status_t wr_rm_dir_file_inner(wr_session_t *session, wr_vg_info_item_t **vg_item, gft_node_t **node, + const char *dir_name, gft_item_type_t type, bool32 recursive) +{ + gft_node_t *parent_node = NULL; + status_t status = wr_check_vg_ft_dir(session, vg_item, dir_name, type, node, &parent_node); + WR_RETURN_IF_ERROR(status); + if (((*node)->flags & WR_FT_NODE_FLAG_SYSTEM) != 0) { + WR_THROW_ERROR(ERR_WR_FILE_REMOVE_SYSTEM, dir_name); + LOG_DEBUG_ERR("Failed to rm dir %s, can not rm system dir.", dir_name); + return CM_ERROR; + } + + return wr_mark_delete_flag(session, *vg_item, *node, dir_name, recursive); +} + +static status_t wr_rm_dir_file(wr_session_t *session, const char *dir_name, gft_item_type_t type, bool32 recursive) +{ + CM_ASSERT(dir_name != NULL); + + gft_node_t *node = NULL; + char name[WR_MAX_NAME_LEN]; + wr_vg_info_item_t *vg_item = NULL; + CM_RETURN_IFERR(wr_find_vg_by_dir(dir_name, name, &vg_item)); + + wr_lock_vg_mem_and_shm_x(session, vg_item); + wr_init_vg_cache_node_info(vg_item); + status_t status = wr_rm_dir_file_inner(session, &vg_item, &node, dir_name, type, recursive); + if (status != CM_SUCCESS) { + wr_rollback_mem_update(session, vg_item); + wr_unlock_vg_mem_and_shm(session, vg_item); + LOG_RUN_ERR("Failed to remove dir or file, name : %s.", dir_name); + return status; + } + + if (wr_process_redo_log(session, vg_item) != CM_SUCCESS) { + wr_unlock_vg_mem_and_shm(session, vg_item); + LOG_RUN_ERR("[WR] ABORT INFO: redo log process failed, errcode:%d, OS errno:%d, OS errmsg:%s.", + cm_get_error_code(), errno, strerror(errno)); + cm_fync_logfile(); + wr_exit(1); + } + + LOG_RUN_INF("Succeed to rm dir or file:%s in vg:%s.", dir_name, vg_item->vg_name); + wr_unlock_vg_mem_and_shm(session, vg_item); + return CM_SUCCESS; +} + +static status_t wr_rm_dir_file_in_rename( + wr_session_t *session, wr_vg_info_item_t **vg_item, const char *dir_name, gft_item_type_t type, bool32 recursive) +{ + CM_ASSERT(dir_name != NULL); + gft_node_t *node = NULL; + + status_t status = wr_rm_dir_file_inner(session, vg_item, &node, dir_name, type, recursive); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Failed to remove dir or file, name : %s.", dir_name); + return status; + } + LOG_RUN_INF("Succeed to rm dir or file:%s in vg:%s in rename.", dir_name, (*vg_item)->vg_name); + return CM_SUCCESS; +} + +static status_t wr_rename_file_inner(wr_session_t *session, wr_vg_info_item_t **vg_item, wr_config_t *inst_cfg, + const char *src, const char *dst, const char *dst_name) +{ + gft_node_t *out_node = NULL; + status_t ret = wr_rename_file_check(session, src, dst, vg_item, &out_node); + if (ret != CM_SUCCESS) { + return ret; + } + + return wr_rename_file_put_redo_log(session, out_node, dst_name, *vg_item, inst_cfg); +} + +status_t wr_rename_file(wr_session_t *session, const char *src, const char *dst) +{ + char vg_name[WR_MAX_NAME_LEN]; + char dst_name[WR_MAX_NAME_LEN]; + CM_RETURN_IFERR(wr_rename_file_check_path_and_name(session, src, dst, vg_name, dst_name)); + wr_vg_info_item_t *vg_item = wr_find_vg_item(vg_name); + if (vg_item == NULL) { + WR_THROW_ERROR(ERR_WR_VG_NOT_EXIST, vg_name); + return CM_ERROR; + } + if (cm_str_equal(src, dst)) { + WR_THROW_ERROR(ERR_WR_FILE_RENAME, "src name is the same as dst."); + return CM_ERROR; + } + wr_config_t *inst_cfg = wr_get_inst_cfg(); + wr_lock_vg_mem_and_shm_x(session, vg_item); + status_t ret = wr_rename_file_inner(session, &vg_item, inst_cfg, src, dst, dst_name); + if (ret == CM_SUCCESS) { + wr_unlock_vg_mem_and_shm(session, vg_item); + return ret; + } + wr_init_vg_cache_node_info(vg_item); + + // error_handle: rollback memory + wr_rollback_mem_update(session, vg_item); + int32 err_code = cm_get_error_code(); + if (err_code != ERR_WR_FILE_RENAME_EXIST) { + wr_unlock_vg_mem_and_shm(session, vg_item); + return ret; + } + + cm_reset_error(); + ret = wr_rm_dir_file_in_rename(session, &vg_item, dst, GFT_FILE, CM_FALSE); + if (ret != CM_SUCCESS) { + wr_rollback_mem_update(session, vg_item); + wr_unlock_vg_mem_and_shm(session, vg_item); + return ret; + } + wr_init_vg_cache_node_info(vg_item); + + ret = wr_rename_file_inner(session, &vg_item, inst_cfg, src, dst, dst_name); + if (ret != CM_SUCCESS) { + wr_rollback_mem_update(session, vg_item); + } + wr_init_vg_cache_node_info(vg_item); + + wr_unlock_vg_mem_and_shm(session, vg_item); + return ret; +} + +status_t wr_remove_dir(wr_session_t *session, const char *dir, bool32 recursive) +{ + return wr_rm_dir_file(session, dir, GFT_PATH, recursive); +} + +status_t wr_remove_file(wr_session_t *session, const char *file) +{ + return wr_rm_dir_file(session, file, GFT_FILE, CM_FALSE); +} + +status_t wr_make_dir(wr_session_t *session, const char *dir_name) +{ + char path[WR_FILE_PATH_MAX_LENGTH]; + snprintf(path, WR_FILE_PATH_MAX_LENGTH, "%s/%s", g_inst_cfg->data_dir, dir_name); + return wr_filesystem_mkdir(path, 0777); +} + +status_t wr_create_file(wr_session_t *session, const char *parent, const char *name, int32 flag) +{ + char path[WR_FILE_PATH_MAX_LENGTH]; + snprintf(path, WR_FILE_PATH_MAX_LENGTH, "%s/%s/%s", g_inst_cfg->data_dir, parent, name); + return wr_filesystem_touch(path); +} + +void wr_clean_open_files_in_vg(wr_session_t *session, wr_vg_info_item_t *vg_item, uint64 pid) +{ + wr_open_file_info_t *open_file = NULL; + wr_latch_x2(&vg_item->open_file_latch, session->id); + bilist_node_t *curr_node = cm_bilist_head(&vg_item->open_file_list); + bilist_node_t *next_node = NULL; + while (curr_node != NULL) { + next_node = curr_node->next; + open_file = BILIST_NODE_OF(wr_open_file_info_t, curr_node, link); + if (open_file->pid == pid) { + wr_free_open_file_node(curr_node, &vg_item->open_file_list); + } + curr_node = next_node; + } + wr_unlatch(&vg_item->open_file_latch); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/service/wr_srv_proc.h b/src/service/wr_srv_proc.h new file mode 100644 index 0000000000000000000000000000000000000000..5d19aa2d52287bad7255099b15295e315fc32493 --- /dev/null +++ b/src/service/wr_srv_proc.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wr_srv_proc.h + * + * + * IDENTIFICATION + * src/service/wr_srv_proc.h + * + * ------------------------------------------------------------------------- + */ +#ifndef __WR_SRV_PROC_H__ +#define __WR_SRV_PROC_H__ + +#include +#include "wr_session.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WR_REMOVE_DIR_NEED_NODE_NUM 2 + +status_t wr_rename_file(wr_session_t *session, const char *src, const char *dst); +// only rm empty dir +status_t wr_remove_dir(wr_session_t *session, const char *dir, bool32 recursive); +status_t wr_remove_file(wr_session_t *session, const char *file); +status_t wr_remove_link(wr_session_t *session, const char *file); +status_t wr_remove_dir_file_by_node(wr_session_t *session, wr_vg_info_item_t *vg_item, gft_node_t *node); +void wr_clean_open_files_in_vg(wr_session_t *session, wr_vg_info_item_t *vg_item, uint64 pid); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/service/wrserver.c b/src/service/wrserver.c new file mode 100644 index 0000000000000000000000000000000000000000..effb3d1a292b61413edc4c692d4c171e2b8c2ab6 --- /dev/null +++ b/src/service/wrserver.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * WR is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * wrserver.c + * + * + * IDENTIFICATION + * src/service/wrserver.c + * + * ------------------------------------------------------------------------- + */ + +#include +#include +#ifndef WIN32 +#include +#include +#endif +#include "cm_types.h" +#include "cm_signal.h" +#include "cm_utils.h" +#include "wr_errno.h" +#include "wr_shm.h" +#include "wr_instance.h" +#include "wr_mes.h" +#include "wr_zero.h" +#include "cm_utils.h" +#include "wr_meta_buf.h" +#include "wr_syn_meta.h" +#include "wr_thv.h" + +#ifndef _NSIG +#define MAX_SIG_NUM 32 +#else +#define MAX_SIG_NUM _NSIG +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +static void wr_close_background_task(wr_instance_t *inst) +{ + uint32 bg_task_base_id = wr_get_uwression_startid() - (uint32)WR_BACKGROUND_TASK_NUM; + for (uint32 i = 0; i < WR_BACKGROUND_TASK_NUM; i++) { + uint32 bg_task_id = bg_task_base_id + i; + if (inst->threads[bg_task_id].id != 0) { + cm_close_thread(&inst->threads[bg_task_id]); + } + } +} + +static void wr_close_thread(wr_instance_t *inst) +{ + // pause lsnr thread + tcp_lsnr_t *lsnr = &inst->lsnr; + cm_latch_x(&inst->tcp_lsnr_latch, WR_DEFAULT_SESSIONID, NULL); + cs_pause_tcp_lsnr(lsnr); + cm_unlatch(&inst->tcp_lsnr_latch, NULL); + // close worker thread + wr_destroy_reactors(); + + if (inst->threads != NULL) { + wr_close_background_task(inst); + WR_FREE_POINT(inst->threads); + } + + // close lsnr thread + cs_stop_tcp_lsnr(lsnr); + lsnr->status = LSNR_STATUS_STOPPED; + + // close time thread, should at end, no timer, no time + cm_close_timer(g_timer()); +} + +static void wr_clean_server() +{ + wr_close_thread(&g_wr_instance); + wr_stop_mes(); + wr_uninit_cm(&g_wr_instance); + wr_free_log_ctrl(); + if (g_wr_instance.lock_fd != CM_INVALID_INT32) { + (void)cm_unlock_fd(g_wr_instance.lock_fd); + cm_close_file(g_wr_instance.lock_fd); + } + CM_FREE_PTR(cm_log_param_instance()->log_compress_buf); + wr_uninit_zero_buf(); + CM_FREE_PTR(g_wr_session_ctrl.sessions); +} + +static void handle_main_wait(void) +{ + int64 periods = 0; + uint32 interval = 500; + do { + if (g_wr_instance.abort_status == CM_TRUE) { + break; + } + if (!g_wr_instance.is_maintain) { + wr_check_peer_inst(&g_wr_instance, WR_INVALID_ID64); + } + if (periods == MILLISECS_PER_SECOND * SECONDS_PER_DAY / interval) { + periods = 0; + wr_ssl_ca_cert_expire(); + } + + wr_clean_all_sessions_latch(); + cm_sleep(interval); + periods++; + } while (CM_TRUE); + wr_clean_server(); +} + +static status_t wr_recovery_background_task(wr_instance_t *inst) +{ + LOG_RUN_INF("create wr recovery background task."); + uint32 recovery_thread_id = wr_get_uwression_startid() - (uint32)WR_BACKGROUND_TASK_NUM; + status_t status = cm_create_thread( + wr_get_cm_lock_and_recover, 0, &g_wr_instance, &(g_wr_instance.threads[recovery_thread_id])); + return status; +} + +static status_t wr_delay_clean_background_task(wr_instance_t *inst) +{ + LOG_RUN_INF("create wr delay clean background task."); + uint32 delay_clean_idx = wr_get_delay_clean_task_idx(); + status_t status = + cm_create_thread(wr_delay_clean_proc, 0, &g_wr_instance, &(g_wr_instance.threads[delay_clean_idx])); + return status; +} + +static status_t wr_init_background_tasks(void) +{ + status_t status = wr_recovery_background_task(&g_wr_instance); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Create wr recovery background task failed."); + return status; + } + + status = wr_delay_clean_background_task(&g_wr_instance); + if (status != CM_SUCCESS) { + LOG_RUN_ERR("Create wr delay clean background task failed."); + return status; + } + return status; +} + +typedef status_t (*wr_srv_arg_parser)(int argc, char **argv, int *argIdx, wr_srv_args_t *wr_args); +typedef struct st_wr_srv_arg_handler { + char name[WR_MAX_PATH_BUFFER_SIZE]; + wr_srv_arg_parser parser; +} wr_srv_arg_handler_t; + +status_t wr_srv_parse_home(int argc, char **argv, int *argIdx, wr_srv_args_t *wr_args) +{ + if ((*argIdx + 1) >= argc || argv[*argIdx + 1] == NULL) { + (void)printf("-D should specified home path.\n"); + return CM_ERROR; + } + char *home = (char *)argv[*argIdx + 1]; + uint32 len = (uint32)strlen(home); + if (len == 0 || len >= WR_MAX_PATH_BUFFER_SIZE) { + (void)printf("the len of path specified by -D is invalid.\n"); + return CM_ERROR; + } + if (realpath_file(home, wr_args->wr_home, WR_MAX_PATH_BUFFER_SIZE) != CM_SUCCESS) { + (void)printf("The path specified by -D is invalid.\n"); + return CM_ERROR; + } + if (!cm_dir_exist(wr_args->wr_home) || (access(wr_args->wr_home, R_OK) != 0)) { + (void)printf("The path specified by -D is invalid.\n"); + return CM_ERROR; + } + (*argIdx)++; + return CM_SUCCESS; +} + +status_t wr_srv_parse_maintain(int argc, char **argv, int *argIdx, wr_srv_args_t *wr_args) +{ + wr_args->is_maintain = true; + return CM_SUCCESS; +} + +wr_srv_arg_handler_t g_wr_args_handler[] = {{"-D", wr_srv_parse_home}, {"-M", wr_srv_parse_maintain}}; + +status_t wr_srv_parse_one_agr(int argc, char **argv, wr_srv_args_t *wr_args, int *argIdx) +{ + int support_args_count = sizeof(g_wr_args_handler) / sizeof(g_wr_args_handler[0]); + for (int support_idx = 0; support_idx < support_args_count; support_idx++) { + if (cm_str_equal(argv[*argIdx], g_wr_args_handler[support_idx].name)) { + return g_wr_args_handler[support_idx].parser(argc, argv, argIdx, wr_args); + } + } + (void)printf("invalid argument: %s\n", argv[*argIdx]); + return CM_ERROR; +} + +status_t wr_srv_parse_agrs(int argc, char **argv, wr_srv_args_t *wr_args) +{ + status_t ret; + for (int i = 1; i < argc; i++) { + ret = wr_srv_parse_one_agr(argc, argv, wr_args, &i); + if (ret != CM_SUCCESS) { + return ret; + } + } + return CM_SUCCESS; +} + +static void wr_srv_usage() +{ + (void)printf("Usage:\n" + " wrserver [-h]\n" + " wrserver [-D wr_home_path]\n" + "Option:\n" + "\t -M WR_MAINTAIN mode.\n" + "\t -h show the help information.\n" + "\t -D specify wr server home path.\n"); +} + +int main(int argc, char **argv) +{ +#ifndef WIN32 + // check root + if (geteuid() == 0 || getuid() != geteuid()) { + (void)printf("The root user is not permitted to execute the wrserver " + "and the real uids must be the same as the effective uids.\n"); + (void)fflush(stdout); + return CM_ERROR; + } +#endif + + if (argc == 2) { + if (cm_str_equal(argv[1], "-h")) { + wr_srv_usage(); + return CM_SUCCESS; + } + } + wr_srv_args_t wr_args; + errno_t errcode = memset_s(&wr_args, sizeof(wr_args), 0, sizeof(wr_args)); + securec_check_ret(errcode); + if (wr_srv_parse_agrs(argc, argv, &wr_args) != CM_SUCCESS) { + (void)fflush(stdout); + wr_exit(CM_ERROR); + } +#ifndef WIN32 + sigset_t sign_old_mask; + (void)sigprocmask(0, NULL, &sign_old_mask); + (void)sigprocmask(SIG_UNBLOCK, &sign_old_mask, NULL); +#endif + if (wr_startup(&g_wr_instance, wr_args) != CM_SUCCESS) { + (void)printf("wr failed to startup.\n"); + fflush(stdout); + wr_clean_server(); + LOG_RUN_ERR("wr failed to startup."); + wr_exit(CM_ERROR); + } + if (wr_init_background_tasks() != CM_SUCCESS) { + (void)printf("WR SERVER END.\n"); + fflush(stdout); + wr_clean_server(); + LOG_RUN_ERR("wr failed to startup."); + LOG_RUN_INF("WR SERVER STARTED.\n"); + wr_exit(CM_ERROR); + } + (void)printf("WR SERVER STARTED.\n"); + LOG_RUN_INF("WR SERVER STARTED.\n"); + log_param_t *log_param = cm_log_param_instance(); + log_param->log_instance_starting = CM_FALSE; + handle_main_wait(); + (void)printf("WR SERVER END.\n"); + LOG_RUN_INF("WR SERVER END.\n"); + return 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/test/demo/test1.c b/test/demo/test1.c new file mode 100644 index 0000000000000000000000000000000000000000..a86ab0adfb1a4a6ef0f1c1e51ed04d0d957e98c6 --- /dev/null +++ b/test/demo/test1.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include +#include +#include "wr_api.h" + +/* gcc 1.c -I /home/czk/bianyi/WalRecord/src/interface -lwrapi -L /home/czk/bianyi/WalRecord/output/lib */ + +int main(void) { + bool result = false; + int fd = -1; + int errorcode = 0; + const char *errormsg = NULL; + char *fileName = "+data/test"; + char *targetName = "+data/name"; + ret = wr_fcreate(fileName, 0777) + if (ret != 0) { + wr_get_error(&errorcode, &errormsg); + printf("%d : %s\n", errorcode, errormsg); + } + + printf("%lld\n", ret); + return 0; +} \ No newline at end of file diff --git a/test/gtest/CMakeLists.txt b/test/gtest/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..efb6c97dc5aed1d6839389612bb4bd880ba1d083 --- /dev/null +++ b/test/gtest/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.10) + +# 项目名称 +project(WrApiTest) + +# 设置 C++ 标准 +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +find_package(GTest REQUIRED) + +# 包含头文件目录 +include_directories(${GTEST_INCLUDE_DIRS}) +include_directories(../../src/interface) + +link_directories(../../output/lib) + +# 添加测试源文件 +add_executable(test_wr_api test_wr_api.cc) + +# 链接 Google Test 库和项目库 +target_link_libraries(test_wr_api ${GTEST_LIBRARIES} pthread wrapi) + +# 启用测试 +enable_testing() + +# 添加测试 +add_test(NAME WrApiTest COMMAND test_wr_api) \ No newline at end of file diff --git a/test/gtest/build.sh b/test/gtest/build.sh new file mode 100644 index 0000000000000000000000000000000000000000..c8d698173695790c6d4bbe85f11d57059481e4af --- /dev/null +++ b/test/gtest/build.sh @@ -0,0 +1,2 @@ +cmake . +make \ No newline at end of file diff --git a/test/gtest/test_wr_api.cc b/test/gtest/test_wr_api.cc new file mode 100644 index 0000000000000000000000000000000000000000..a711e5a1d1772eb468ec4acbed52ec8d46cf6e4d --- /dev/null +++ b/test/gtest/test_wr_api.cc @@ -0,0 +1,107 @@ +#include +extern "C" { +#include "wr_api.h" +#include "wr_errno.h" +} +#define TEST_LOG_DIR "./test_log" +#define TEST_DIR "testdir1" +#define ONE_GB 1024 * 1024 * 1024 +int errorcode = 0; +const char *errormsg = NULL; +wr_instance_handle *g_inst_handle; + +TEST(WrApiTest, TestInitLogger) { + int result = wr_init_logger(TEST_LOG_DIR, 255, 100, ONE_GB); + if (result != WR_SUCCESS) { + printf("wr_init_logger failed, result: %d\n", result); + } + EXPECT_EQ(result, WR_SUCCESS); +} + +TEST(WrApiTest, TestInitLoggerNegative) { + // Negative test case: invalid log directory + int result = wr_init_logger(NULL, 255, 100, ONE_GB); + EXPECT_NE(result, WR_SUCCESS); +} + +TEST(WrApiTest, TestWrCreateInstance) { + int result = wr_create_instance("20.20.20.135:15430", g_inst_handle); + if (result != 0) { + wr_get_error(&errorcode, &errormsg); + printf("%d : %s\n", errorcode, errormsg); + } + EXPECT_EQ(result, WR_SUCCESS); +} + +TEST(WrApiTest, TestWrVfsCreate) { + int result = wr_vfs_create(TEST_DIR, *g_inst_handle); + if (result != 0) { + wr_get_error(&errorcode, &errormsg); + printf("%d : %s\n", errorcode, errormsg); + } + EXPECT_EQ(result, WR_SUCCESS); +} + +TEST(WrApiTest, TestWrVfsCreateNegative) { + // Negative test case: create directory with invalid name + int result = wr_vfs_create("", NULL); + EXPECT_NE(result, WR_SUCCESS); +} + +TEST(WrApiTest, TestWrVfsCreateFile) { + char *path = (char *)malloc(strlen(TEST_DIR) + strlen("/testfile1") + 1); + strcpy(path, TEST_DIR); + strcat(path, "/testfile1"); + int result = wr_file_create(path, 0); + if (result != 0) { + wr_get_error(&errorcode, &errormsg); + printf("%d : %s\n", errorcode, errormsg); + } + EXPECT_EQ(result, WR_SUCCESS); + free(path); +} + +TEST(WrApiTest, TestWrVfsCreateFileNegative) { + // Negative test case: create file with invalid path + int result = wr_file_create(NULL, 0); + EXPECT_NE(result, WR_SUCCESS); +} + +TEST(WrApiTest, TestWrVfsDeleteFile) { + char *path = (char *)malloc(strlen(TEST_DIR) + strlen("/testfile1") + 1); + strcpy(path, TEST_DIR); + strcat(path, "/testfile1"); + int result = wr_file_delete(path); + if (result != 0) { + wr_get_error(&errorcode, &errormsg); + printf("%d : %s\n", errorcode, errormsg); + } + EXPECT_EQ(result, WR_SUCCESS); + free(path); +} + +TEST(WrApiTest, TestWrVfsDeleteFileNegative) { + // Negative test case: delete non-existent file + int result = wr_file_delete("non_existent_file"); + EXPECT_NE(result, WR_SUCCESS); +} + +TEST(WrApiTest, TestWrVfsDelete) { + int result = wr_vfs_delete(TEST_DIR); + if (result != 0) { + wr_get_error(&errorcode, &errormsg); + printf("%d : %s\n", errorcode, errormsg); + } + EXPECT_EQ(result, WR_SUCCESS); +} + +TEST(WrApiTest, TestWrVfsDeleteNegative) { + // Negative test case: delete non-existent directory + int result = wr_vfs_delete("non_existent_dir"); + EXPECT_NE(result, WR_SUCCESS); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/test/test_home/cfg/wr_inst.ini b/test/test_home/cfg/wr_inst.ini new file mode 100644 index 0000000000000000000000000000000000000000..8ffe531fb787cdd6a58ad12187c61b1658e0c77c --- /dev/null +++ b/test/test_home/cfg/wr_inst.ini @@ -0,0 +1,7 @@ +INST_ID=0 +STORAGE_MODE=SHARE_DISK +_SHM_KEY=6 +_LOG_LEVEL=255 +WR_NODES_LIST=0:127.0.0.1:19228 +LISTEN_ADDR=127.0.0.1:19225 +#WR_CM_SO_NAME=libclient.so diff --git a/test/test_home/data/testdir/testfile b/test/test_home/data/testdir/testfile new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/test_home/test_env b/test/test_home/test_env new file mode 100644 index 0000000000000000000000000000000000000000..83f1b35f23714e465c86f116f82d9ec59aa37e2f --- /dev/null +++ b/test/test_home/test_env @@ -0,0 +1,4 @@ +export CODE_HOME= +export PATH=$CODE_HOME/output/bin/:$PATH +export LD_LIBRARY_PATH=$CODE_HOME/output/lib:$LD_LIBRARY_PATH +export WR_HOME=$CODE_HOME/test/test_home \ No newline at end of file