diff --git a/deps/oblib/src/common/CMakeLists.txt b/deps/oblib/src/common/CMakeLists.txt index 7b26ad459e..0998cc7f4e 100644 --- a/deps/oblib/src/common/CMakeLists.txt +++ b/deps/oblib/src/common/CMakeLists.txt @@ -23,6 +23,8 @@ ob_set_subtarget(oblib_common common ob_target_specific.cpp ob_timeout_ctx.cpp ob_zone_type.cpp + ob_version_def.cpp + ob_tenant_data_version_mgr.cpp ) ob_set_subtarget(oblib_common common_mixed diff --git a/deps/oblib/src/common/ob_record_header.cpp b/deps/oblib/src/common/ob_record_header.cpp index f81de45502..66afca7fd7 100644 --- a/deps/oblib/src/common/ob_record_header.cpp +++ b/deps/oblib/src/common/ob_record_header.cpp @@ -276,6 +276,7 @@ DEFINE_DESERIALIZE(ObRecordHeader) } else if (OB_FAIL(serialization::decode_i64(buf, data_len, pos, &data_checksum_))) { COMMON_LOG(WARN, "encode data failed..", KP(buf), K_(data_checksum), K(ret)); } + // 后续新增成员时,应该使用header_length_作为反序列化长度的限制,以保证升级兼容 return ret; } diff --git a/deps/oblib/src/common/ob_tenant_data_version_mgr.cpp b/deps/oblib/src/common/ob_tenant_data_version_mgr.cpp new file mode 100644 index 0000000000..4e32df9f5f --- /dev/null +++ b/deps/oblib/src/common/ob_tenant_data_version_mgr.cpp @@ -0,0 +1,572 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * 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 PubL v2 for more details. + */ + +#include "common/ob_tenant_data_version_mgr.h" +#include "common/ob_record_header.h" + +#define DV_ILOG_F(fmt, args...) COMMON_LOG(INFO, "[DATA_VERSION] " fmt, ##args) +#define DV_TLOG(fmt, args...) COMMON_LOG(TRACE, "[DATA_VERSION] " fmt, ##args) + +namespace oceanbase +{ +namespace common +{ + +ObTenantDataVersionMgr& ObTenantDataVersionMgr::get_instance() +{ + static ObTenantDataVersionMgr mgr; + return mgr; +} + +int ObTenantDataVersionMgr::init(bool enable_compatible_monotonic) +{ + int ret = OB_SUCCESS; + + if (OB_UNLIKELY(is_inited_)) { + ret = OB_INIT_TWICE; + } else if (OB_FAIL(map_.create(TENANT_DATA_VERSION_BUCKET_NUM, lib::ObLabel("TenantDVMap")))) { + COMMON_LOG(WARN, "fail to create TenantDataVersionMgr map", K(ret)); + } else { + is_inited_ = true; + mock_data_version_ = 0; + enable_compatible_monotonic_ = enable_compatible_monotonic; + } + + return ret; +} + +int ObTenantDataVersionMgr::get(const uint64_t tenant_id, uint64_t &data_version) const +{ + int ret = OB_SUCCESS; + ObTenantDataVersion *version = NULL; + data_version = 0; + + if (OB_UNLIKELY(mock_data_version_ != 0)) { + data_version = ATOMIC_LOAD(&mock_data_version_); + DV_TLOG("mock_data_version is set", K(tenant_id), K(data_version)); + } else if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + COMMON_LOG(WARN, "ObTenantDataVersionMgr doesn't init", K(ret), K(tenant_id)); + } else if (OB_FAIL(map_.get_refactored(tenant_id, version))) { + if (OB_HASH_NOT_EXIST == ret) { + if (is_sys_tenant(tenant_id) || is_meta_tenant(tenant_id)) { + data_version = LAST_BARRIER_DATA_VERSION; + ret = OB_SUCCESS; + COMMON_LOG(WARN, "data_version fallback to LAST_BARRIER_DATA_VERSION", + K(tenant_id), K(data_version)); + } else { + ret = OB_ENTRY_NOT_EXIST; + } + } else { + COMMON_LOG(WARN, "fail to get data_version", K(ret), K(tenant_id)); + } + } else if (NULL == version) { + ret = OB_ERR_UNEXPECTED; + COMMON_LOG(WARN, "data_version is NULL", K(ret)); + } else if (version->is_removed()) { + ret = OB_ENTRY_NOT_EXIST; + } else { + data_version = version->get_version(); + } + + return ret; +} + +int ObTenantDataVersionMgr::set(const uint64_t tenant_id, const uint64_t data_version) +{ + int ret = OB_SUCCESS; + ObTenantDataVersion *version = NULL; + bool need_to_set = false; + + if (OB_UNLIKELY(mock_data_version_ != 0)) { + // do nothing + DV_TLOG("mock_data_version is set", K(tenant_id), K(data_version), K(mock_data_version_)); + } else if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + COMMON_LOG(WARN, "ObTenantDataVersionMgr doesn't init", K(ret), + K(tenant_id)); + } else if (OB_FAIL(map_.get_refactored(tenant_id, version))) { + if (OB_HASH_NOT_EXIST == ret) { + need_to_set = true; + ret = OB_SUCCESS; + } else { + COMMON_LOG(WARN, "fail to get data_version", K(ret), K(tenant_id)); + } + } else if (NULL == version) { + ret = OB_ERR_UNEXPECTED; + COMMON_LOG(WARN, "data_version is NULL", K(ret)); + } else if (version->is_removed() || data_version <= version->get_version()) { + // if the tenant is dropped or the new data_version is smaller, then + // no need to set + } else { + need_to_set = true; + } + + if (OB_SUCC(ret) && need_to_set) { + SpinWLockGuard guard(lock_); + if (OB_FAIL(set_(tenant_id, data_version))) { + COMMON_LOG(WARN, "fail to set data_version", K(ret), K(tenant_id), K(data_version)); + } + } + + return ret; +} + +int ObTenantDataVersionMgr::remove(const uint64_t tenant_id) +{ + int ret = OB_SUCCESS; + ObTenantDataVersion *version = NULL; + const int64_t remove_ts = ObTimeUtility::current_time(); + + SpinWLockGuard guard(lock_); + + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + COMMON_LOG(WARN, "ObTenantDataVersionMgr doesn't init", K(ret), K(tenant_id)); + } else if (OB_FAIL(map_.get_refactored(tenant_id, version))) { + if (OB_ENTRY_NOT_EXIST == ret) { + ret = OB_SUCCESS; + } else { + COMMON_LOG(WARN, "fail to get data_version", K(ret), K(tenant_id)); + } + } else if (NULL == version) { + ret = OB_ERR_UNEXPECTED; + COMMON_LOG(WARN, "data_version is NULL", K(ret)); + } else if (version->is_removed()) { + // already removed + } else if (OB_FAIL(remove_and_dump_to_file_(tenant_id, remove_ts))) { + COMMON_LOG(WARN, "fail to dump data_version file", K(ret), K(tenant_id)); + } else { + version->set_removed(true, remove_ts); + DV_ILOG_F("Tenant DATA_VERSION is removed", K(ret), K(tenant_id), K(remove_ts), K(*version)); + } + + return ret; +} + +int ObTenantDataVersionMgr::load_from_file() +{ + int ret = OB_SUCCESS; + int fd = 0; + const char *file_path = TENANT_DATA_VERSION_FILE_PATH; + SpinWLockGuard guard(lock_); + + if (OB_UNLIKELY(!is_inited_)) { + ret = OB_NOT_INIT; + COMMON_LOG(WARN, "ObTenantDataVersionMgr doesn't init", K(ret)); + } else if ((fd = ::open(file_path, O_RDONLY)) < 0) { + if (ENOENT != errno) { + ret = OB_IO_ERROR; + COMMON_LOG(WARN, "fail to open data_version file", K(ret), K(errno), K(file_path)); + } else { + // when errno is ENOENT, the file does not exist + COMMON_LOG(WARN, "data_version file doesn't exist, skip load"); + } + } else { + char *load_buf = NULL; + int64_t buf_size = TENANT_DATA_VERSION_FILE_MAX_SIZE; + PageArena<> pa; + + if (OB_ISNULL(load_buf = pa.alloc(buf_size))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + COMMON_LOG(ERROR, "fail to alloc buf", K(ret), K(buf_size)); + } else { + size_t read_len = ::read(fd, load_buf, buf_size); + if (read_len < 0) { + ret = OB_IO_ERROR; + COMMON_LOG(WARN, "fail to read data_version file", K(ret), K(read_len), K(errno), K(fd)); + } else { + // deserialize header + // checksum check + // load data_version + ObRecordHeader header; + int64_t pos = 0; + if (OB_FAIL(header.deserialize(load_buf, read_len, pos))) { + COMMON_LOG(ERROR, "deserialize header failed", K(ret), K(read_len), K(pos)); + } else { + const int64_t header_length = header.header_length_; + const int64_t data_length = read_len - header_length; + const char *const p_data = load_buf + header_length; + if (data_length <= 0 || data_length != header.data_zlength_) { + ret = OB_INVALID_DATA; + COMMON_LOG(ERROR, "invalid data length", K(ret), K(header_length), + K(data_length), K(buf_size), K(read_len), K(header)); + } else if (OB_FAIL(header.check_header_checksum())) { + COMMON_LOG(ERROR, "check header checksum failed", K(ret), K(header)); + } else if (OB_CONFIG_MAGIC != header.magic_) { + ret = OB_INVALID_DATA; + COMMON_LOG(ERROR, "check magic number failed", K(ret), + K_(header.magic)); + } else if (OB_FAIL(header.check_payload_checksum(p_data, data_length))) { + COMMON_LOG(ERROR, "check data checksum failed", K(ret)); + } else { + while (OB_SUCC(ret)) { + ret = load_data_version_(load_buf, pos); + } + if (OB_ITER_END == ret) { + ret = OB_SUCCESS; + } + } + } + } + } + if (0 != close(fd)) { + if (OB_SUCC(ret)) { + ret = OB_IO_ERROR; + COMMON_LOG(WARN, "fail to close data_version file fd", K(ret), K(errno), K(fd)); + } + } + } + + COMMON_LOG(INFO, "[DATA_VERSION] load data_version file", K(ret), K(map_.size())); + + return ret; +} + +int ObTenantDataVersionMgr::set_(const uint64_t tenant_id, + const uint64_t data_version) +{ + int ret = OB_SUCCESS; + ObTenantDataVersion *version = NULL; + bool need_to_insert = false; + uint64_t old_version = 0; + + if (OB_FAIL(map_.get_refactored(tenant_id, version))) { + if (OB_HASH_NOT_EXIST == ret) { + need_to_insert = true; + version = NULL; + old_version = 0; + ret = OB_SUCCESS; + } else { + COMMON_LOG(WARN, "fail to get result from data_version_map", K(ret), + K(tenant_id), K(data_version)); + } + } else if (NULL == version) { + ret = OB_ERR_UNEXPECTED; + COMMON_LOG(WARN, "data_version is NULL", K(ret)); + } else { + old_version = version->get_version(); + } + + if (OB_SUCC(ret)) { + if (OB_NOT_NULL(version) && (version->is_removed() || data_version <= old_version)) { + COMMON_LOG(INFO, + "tenant is removed or new data_version is not bigger than old " + "value, no need to update tenant data_version", K(tenant_id), + "is_removed", version->is_removed(), + "old_version", old_version, + "new_version", data_version); + } else if (OB_FAIL(set_and_dump_to_file_(tenant_id, data_version, need_to_insert))) { + COMMON_LOG(WARN, "fail to dump data_version file", K(ret), K(tenant_id)); + } else { + if (need_to_insert) { + void *version_buf = NULL; + if (OB_ISNULL(version_buf = allocator_.alloc(sizeof(ObTenantDataVersion)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + COMMON_LOG(ERROR, "fail to alloc buf", K(ret), K(tenant_id), + K(sizeof(ObTenantDataVersion))); + } else if (FALSE_IT(version = new (version_buf) ObTenantDataVersion(data_version))) { + + } else if (OB_FAIL(map_.set_refactored(tenant_id, version))) { + COMMON_LOG(WARN, "fail to set data_version", K(ret), K(tenant_id)); + } + } else { + version->set_version(data_version); + } + + DV_ILOG_F("Tenant DATA_VERSION is changed", K(ret), K(tenant_id), "old_version", old_version, + "new_version", data_version); + } + } + + return ret; +} + +int ObTenantDataVersionMgr::set_and_dump_to_file_(const uint64_t tenant_id, + const uint64_t data_version, + const bool need_to_insert) { + int ret = OB_SUCCESS; + ObRecordHeader header; + int64_t header_length = header.get_serialize_size(); + char *dump_buf = NULL; + // we may need to insert a new entry to the map, so map_size + 1 to ensure the memory is enough + int64_t buf_length = header_length + (map_.size() + 1) * ObTenantDataVersion::MAX_DUMP_BUF_SIZE; + PageArena<> pa; + + if (OB_ISNULL(dump_buf = pa.alloc(buf_length))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + COMMON_LOG(ERROR, "fail to alloc buf", K(ret), K(tenant_id), K(buf_length)); + } else { + int64_t pos = 0; + const int64_t data_pos = pos + header_length; + pos += header_length; + ObTenantDataVersionMap::const_iterator it = map_.begin(); + for (; it != map_.end() && OB_SUCC(ret); ++it) { + const uint64_t iter_tenant_id = it->first; + const ObTenantDataVersion *iter_version = it->second; + if (OB_ISNULL(iter_version)) { + ret = OB_ERR_UNEXPECTED; + COMMON_LOG(WARN, "iter_version is null", K(iter_tenant_id)); + } else if (iter_tenant_id == tenant_id) { + if (OB_FAIL(dump_data_version_( + dump_buf, buf_length, pos, iter_tenant_id, + iter_version->is_removed(), + iter_version->get_remove_timestamp(), + data_version))) { + COMMON_LOG(WARN, "fail to dump data_version", K(ret), + K(iter_tenant_id), K(data_version), K(*iter_version)); + } + } else { + if (OB_FAIL(dump_data_version_(dump_buf, buf_length, pos, iter_tenant_id, + iter_version->is_removed(), + iter_version->get_remove_timestamp(), + iter_version->get_version()))) { + COMMON_LOG(WARN, "fail to dump data_version", K(ret), + K(iter_tenant_id), K(*iter_version)); + } + } + } + if (OB_SUCC(ret) && need_to_insert) { + if (OB_FAIL(dump_data_version_(dump_buf, buf_length, pos, tenant_id, + false /*removed*/, 0 /*remove_ts*/, + data_version))) { + COMMON_LOG(WARN, "fail to dump data_version", K(ret), K(tenant_id), K(data_version)); + } + } + if (OB_FAIL(ret)) { + + } else if (OB_FAIL(write_to_file_(dump_buf, buf_length, pos - data_pos))) { + COMMON_LOG(WARN, "fail to write data_version file", K(ret), K(tenant_id)); + } + } + + return ret; +} + +int ObTenantDataVersionMgr::remove_and_dump_to_file_(const uint64_t tenant_id, + const int64_t remove_ts) { + int ret = OB_SUCCESS; + ObRecordHeader header; + int64_t header_length = header.get_serialize_size(); + char *dump_buf = NULL; + int64_t buf_length = header_length + map_.size() * ObTenantDataVersion::MAX_DUMP_BUF_SIZE; + PageArena<> pa; + + if (OB_ISNULL(dump_buf = pa.alloc(buf_length))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + COMMON_LOG(ERROR, "fail to alloc buf", K(ret), K(tenant_id), K(buf_length)); + } else { + int64_t pos = 0; + const int64_t data_pos = pos + header_length; + pos += header_length; + ObTenantDataVersionMap::const_iterator it = map_.begin(); + for (; it != map_.end() && OB_SUCC(ret); ++it) { + const uint64_t iter_tenant_id = it->first; + const ObTenantDataVersion *iter_version = it->second; + if (OB_ISNULL(iter_version)) { + ret = OB_ERR_UNEXPECTED; + COMMON_LOG(WARN, "iter_version is null", K(iter_tenant_id)); + } else if (iter_tenant_id == tenant_id) { + if (OB_FAIL(dump_data_version_(dump_buf, buf_length, pos, iter_tenant_id, + true /*removed*/, + remove_ts, + iter_version->get_version()))) { + COMMON_LOG(WARN, "fail to dump data_version", K(ret), + K(iter_tenant_id), K(remove_ts), K(*iter_version)); + } + } else { + if (OB_FAIL(dump_data_version_(dump_buf, buf_length, pos, + iter_tenant_id, + iter_version->is_removed(), + iter_version->get_remove_timestamp(), + iter_version->get_version()))) { + COMMON_LOG(WARN, "fail to dump data_version", K(ret), + K(iter_tenant_id), K(*iter_version)); + } + } + } + if (OB_FAIL(ret)) { + + } else if (OB_FAIL(write_to_file_(dump_buf, buf_length, pos - data_pos))) { + COMMON_LOG(WARN, "fail to write data_version file", K(ret), K(tenant_id)); + } + } + + return ret; +} + +int64_t ObTenantDataVersionMgr::get_max_dump_buf_size_() const +{ + ObRecordHeader header; + int64_t header_size = header.get_serialize_size(); + // we may need to insert a new entry to the map + int64_t data_size = (map_.size() + 1) * ObTenantDataVersion::MAX_DUMP_BUF_SIZE; + return header_size + data_size; +} + +int ObTenantDataVersionMgr::dump_data_version_(char *buf, int64_t buf_length, int64_t &pos, + const uint64_t tenant_id, + const bool removed, + const int64_t remove_ts, + const uint64_t data_version) { + int ret = OB_SUCCESS; + char tmp_buf[ObTenantDataVersion::MAX_DUMP_BUF_SIZE]{0}; + char version_str[OB_SERVER_VERSION_LENGTH]{0}; + int res = 0; + if (OB_INVALID_INDEX == + VersionUtil::print_version_str(version_str, OB_SERVER_VERSION_LENGTH, data_version)) { + ret = OB_INVALID_ARGUMENT; + COMMON_LOG(WARN, "fail to print data_version str", K(ret), K(data_version)); + } else if (OB_FAIL(databuff_printf( + buf, buf_length, pos, ObTenantDataVersion::DUMP_BUF_FORMAT, + tenant_id, version_str, data_version, removed, remove_ts))) { + COMMON_LOG(WARN, "fail to printf", K(ret), K(tenant_id), K(buf_length), K(pos)); + } else if (pos >= buf_length) { + ret = OB_SIZE_OVERFLOW; + COMMON_LOG(WARN, "buffer size overflow", K(ret), K(tenant_id), K(buf_length), K(pos)); + } else { + // we use '\n' as the separator of tenant, we'll use STRTOK to parse this + buf[pos] = '\n'; + pos += 1; + } + + return ret; +} + +int ObTenantDataVersionMgr::load_data_version_(char *buf, int64_t &pos) { + int ret = OB_SUCCESS; + ObTenantDataVersion *version = NULL; + uint64_t tenant_id = 0; + int removed = false; + uint64_t remove_timestamp = 0; + uint64_t version_val = 0; + char version_str[OB_SERVER_VERSION_LENGTH]{0}; + int res = 0; + const int expected_item_size = 5; + char *saveptr = NULL; + char *token = NULL; + + if (NULL == buf) { + ret = OB_INVALID_ARGUMENT; + COMMON_LOG(WARN, "buf is null", K(ret), K(pos)); + } else if (NULL == (token = STRTOK_R(buf + pos, "\n", &saveptr))) { + ret = OB_ITER_END; + } else { + res = sscanf(token, ObTenantDataVersion::DUMP_BUF_FORMAT, &tenant_id, + version_str, &version_val, &removed, &remove_timestamp); + if (res != expected_item_size) { + ret = OB_INVALID_DATA; + COMMON_LOG(ERROR, "fail to parse data_version", K(ret), K(res), K(pos), + K(token), K(tenant_id), K(version_val), K(version_str), + K(removed), K(remove_timestamp)); + } else { + COMMON_LOG(INFO, "[DATA_VERSION] successfully parse data_version", + K(tenant_id), K(version_val), K(version_str), K(removed), + K(remove_timestamp), K(pos)); + void *version_buf = NULL; + if (OB_ISNULL(version_buf = + allocator_.alloc(sizeof(ObTenantDataVersion)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + COMMON_LOG(ERROR, "fail to alloc buf", K(ret), K(sizeof(ObTenantDataVersion))); + } else if (FALSE_IT(version = new (version_buf) ObTenantDataVersion( + removed, remove_timestamp, version_val))) { + + } else if (OB_FAIL(map_.set_refactored(tenant_id, version))) { + COMMON_LOG(WARN, "fail to set data_version", K(ret), K(tenant_id), K(version)); + } else { + pos += (saveptr - token); + } + } + } + return ret; +} + +int ObTenantDataVersionMgr::write_to_file_(char *buf, int64_t buf_length, int64_t data_length) +{ + int ret = OB_SUCCESS; + int fd = 0; + ObRecordHeader header; + const int64_t header_length = header.get_serialize_size(); + const int64_t total_length = header_length + data_length; + const int64_t max_length = TENANT_DATA_VERSION_FILE_MAX_SIZE; + int64_t header_pos = 0; + + if (total_length > buf_length || total_length > max_length) { + ret = OB_INVALID_DATA; + COMMON_LOG(WARN, "dump buffer overflow", K(ret), K(total_length), + K(data_length), K(buf_length), K(max_length)); + } else { + header.magic_ = OB_CONFIG_MAGIC; + header.header_length_ = static_cast(header_length); + header.version_ = OB_CONFIG_VERSION; + header.data_length_ = static_cast(data_length); + header.data_zlength_ = header.data_length_; + header.data_checksum_ = ob_crc64(buf + header_length, data_length); + header.set_header_checksum(); + if (OB_FAIL(header.serialize(buf, buf_length, header_pos))) { + COMMON_LOG(WARN, "fail to serialize header", K(ret), K(header), K(buf_length), K(header_pos)); + } else { + const char *file_path = TENANT_DATA_VERSION_FILE_PATH; + char tmp_path[MAX_PATH_SIZE]{0}; + char hist_path[MAX_PATH_SIZE]{0}; + if (OB_FAIL(databuff_printf(tmp_path, MAX_PATH_SIZE, "%s.tmp", file_path))) { + COMMON_LOG(WARN, "fail to printf", K(ret)); + } else if (OB_FAIL(databuff_printf(hist_path, MAX_PATH_SIZE, "%s.history", file_path))) { + COMMON_LOG(WARN, "fail to printf", K(ret)); + } else if ((fd = ::open(tmp_path, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP)) < 0) { + ret = OB_IO_ERROR; + COMMON_LOG(WARN, "fail to open data_version file", K(ret), K(errno), + K(fd), K(total_length), K(tmp_path)); + } else if (total_length != ::write(fd, buf, total_length)) { + ret = OB_IO_ERROR; + COMMON_LOG(WARN, "fail to write data_version file", K(ret), K(errno), + K(fd), K(total_length)); + if (0 != ::close(fd)) { + COMMON_LOG(WARN, "fail to close data_version file fd", K(ret), K(errno), + K(fd), K(total_length)); + } + } else if (0 != ::fsync(fd)) { + ret = OB_IO_ERROR; + COMMON_LOG(WARN, "fail to sync data_version file", K(ret), K(errno), + K(fd), K(total_length)); + if (0 != ::close(fd)) { + COMMON_LOG(WARN, "fail to close data_version file fd", K(ret), K(errno), + K(fd), K(total_length)); + } + } else if (0 != ::close(fd)) { + ret = OB_IO_ERROR; + COMMON_LOG(WARN, "fail to close data_version file fd", K(ret), K(errno), + K(fd), K(total_length)); + } + if (OB_SUCC(ret)) { + if (0 != ::rename(file_path, hist_path) && errno != ENOENT) { + // it's OK to continue if we fail to backup history file, so we ignore the err ret here + COMMON_LOG(WARN, "fail to backup history config file", KERRMSG, K(ret)); + } + // 运行到这里的时候可能掉电,导致没有 conf 文件,需要 DBA 手工拷贝 tmp 文件到这里 + if (0 != ::rename(tmp_path, file_path)) { + ret = OB_ERR_SYS; + COMMON_LOG(WARN, "fail to move tmp config file", KERRMSG, K(ret)); + } + } + } + + COMMON_LOG(INFO, "[DATA_VERSION] write data_version file", K(ret), + K(header_length), K(data_length), K(total_length)); + } + + return ret; +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/common/ob_tenant_data_version_mgr.h b/deps/oblib/src/common/ob_tenant_data_version_mgr.h new file mode 100644 index 0000000000..d62ab5f6da --- /dev/null +++ b/deps/oblib/src/common/ob_tenant_data_version_mgr.h @@ -0,0 +1,154 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * 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 PubL v2 for more details. + */ + +#ifndef OCEANBASE_OBSERVER_OB_TENANT_DATA_VERSION_H_ +#define OCEANBASE_OBSERVER_OB_TENANT_DATA_VERSION_H_ + +#include "lib/ob_define.h" +#include "lib/hash/ob_hashmap.h" +#include "common/ob_version_def.h" + +namespace oceanbase +{ +namespace common +{ +/** + * ObTenantDataVersionMgr maintains the data_version of all tenants by a + * hashmap. + * + * The map is persisted in a disk file, and whenever + * the data_version of a tenant need to be updated, the disk file will be + * modified before the map updated in memory, so we can ensure the data_version + * will not go back in this machine. + * + * The path of the disk file is $observer_home/etc/observer.data_version.bin. + * This file is composed of a header part and a data part. + * | ---------------------HEADER (Not Readable)---------------------- | + * | ObRecordHeader(magic_number, length, checksum...) | + * | ------------------------DATA (Readable)------------------------- | + * | tenant_id: version_str version_val removed remove_timestamp\n | + * | 1001: 4.3.0.1 17180065793 0 0\n | + * | 1002: 4.3.0.1 17180065793 0 0\n | + * | ... | + * | ------------------------------------------------------------------ + + * The insert/update/remove operations will set a mgr-level write lock first, + * however the get operation can access the map directly without a lock, + * therefore the overhead of the get operation is relatively small. + * + */ +class ObTenantDataVersionMgr +{ +public: + ObTenantDataVersionMgr() + : is_inited_(false), allocator_(lib::ObLabel("TenantDVMgr")), + mock_data_version_(0), enable_compatible_monotonic_(false) {} + ~ObTenantDataVersionMgr() {} + static ObTenantDataVersionMgr& get_instance(); + int init(bool enable_compatible_monotonic); + int get(const uint64_t tenant_id, uint64_t &data_version) const; + /** + * update the tenant's data_version, if the tenant is not in the mgr yet, + * insert the entry instead. + */ + int set(const uint64_t tenant_id, const uint64_t data_version); + int remove(const uint64_t tenant_id); + int load_from_file(); + bool is_enable_compatible_monotonic() { + return ATOMIC_LOAD(&enable_compatible_monotonic_); + } + void set_enable_compatible_monotonic(bool enable) { + ATOMIC_STORE(&enable_compatible_monotonic_, enable); + } + // for unittest + void set_mock_data_version(const uint64_t data_version) { + ATOMIC_SET(&mock_data_version_, data_version); + } +private: + struct ObTenantDataVersion + { + ObTenantDataVersion(uint64_t version) + : removed_(false), remove_timestamp_(0), version_(version) {} + ObTenantDataVersion(bool removed, uint64_t remove_timestamp_, uint64_t version) + : removed_(removed), remove_timestamp_(remove_timestamp_), version_(version) {} + ~ObTenantDataVersion() {} + // tenant_id: version_str version_val removed remove_timestamp + // for removed field, 1 stands for tenant is removed, 0 stands for tenant is active + // e.g. 1001: 4.3.0.1 17180065793 0 0 + static constexpr const char *DUMP_BUF_FORMAT = "%lu: %s %lu %d %lu"; + // the max length of uint64 decimal format is 20, so: + // tenant_id(20) + version_str(OB_SERVER_VERSION_LENGTH) + version_val(20) + + // removed(1) + remove_timestamp(20) + spaces_and_others(10) + static constexpr int64_t MAX_DUMP_BUF_SIZE = 20 + OB_SERVER_VERSION_LENGTH + 20 + 1 + 20 + 10; + bool is_removed() const + { + return ATOMIC_LOAD(&removed_); + } + uint64_t get_remove_timestamp() const + { + return ATOMIC_LOAD(&remove_timestamp_); + } + void set_removed(bool removed, uint64_t remove_ts) + { + ATOMIC_STORE(&removed_, removed); + ATOMIC_STORE(&remove_timestamp_, remove_ts); + } + uint64_t get_version() const + { + return ATOMIC_LOAD(&version_); + } + void set_version(uint64_t version) + { + ATOMIC_STORE(&version_, version); + } + TO_STRING_KV(K_(removed), K_(remove_timestamp), K_(version)); + private: + bool removed_; + uint64_t remove_timestamp_; + uint64_t version_; + }; + int set_(const uint64_t tenant_id, const uint64_t data_version); + // for set: set data_version before dump + int set_and_dump_to_file_(const uint64_t tenant_id, const uint64_t data_version, const bool need_to_insert); + // for remove: remove `tenant_id`'s data_version before dump + int remove_and_dump_to_file_(const uint64_t tenant_id, const int64_t remove_ts); + int64_t get_max_dump_buf_size_() const; + int dump_data_version_(char *buf, int64_t buf_length, int64_t &pos, const uint64_t tenant_id, + const bool removed, const int64_t remove_ts, + const uint64_t data_version); + int load_data_version_(char *buf, int64_t &pos); + int write_to_file_(char *buf, int64_t buf_length, int64_t data_length); +private: + // we use NoPthreadDefendMode here, so the hashmap will not lock buckets before get/set. + // to ensure thread safety, we have several promises: + // 1. we only insert new entry into the hashmap, never delete or overwrite existing entry + // 2. before insert new entry, we acquire a global lock in ObTenantDataVersionMgr + typedef hash::ObHashMap ObTenantDataVersionMap; + static constexpr const char *TENANT_DATA_VERSION_FILE_PATH = "etc/observer.data_version.bin"; + static constexpr int64_t TENANT_DATA_VERSION_FILE_MAX_SIZE = 1 << 26; // 64MB + // The number of tenant won't be too large, so 1024 buckets should be enough + static constexpr int64_t TENANT_DATA_VERSION_BUCKET_NUM = 1024; + static constexpr int16_t OB_CONFIG_MAGIC = static_cast(0XBEDE); + static const int16_t OB_CONFIG_VERSION = 1; + bool is_inited_; + ObTenantDataVersionMap map_; + common::SpinRWLock lock_; + common::ObArenaAllocator allocator_; + // for unittest + uint64_t mock_data_version_; + bool enable_compatible_monotonic_; +}; + +} // namespace common +} // namespace oceanbase +#define ODV_MGR (::oceanbase::common::ObTenantDataVersionMgr::get_instance()) +#endif // OCEANBASE_OBSERVER_OB_TENANT_DATA_VERSION_H_ \ No newline at end of file diff --git a/deps/oblib/src/common/ob_version_def.cpp b/deps/oblib/src/common/ob_version_def.cpp new file mode 100644 index 0000000000..674d69e6a1 --- /dev/null +++ b/deps/oblib/src/common/ob_version_def.cpp @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * 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 PubL v2 for more details. + */ + +#include "common/ob_version_def.h" +#include "lib/utility/ob_print_utils.h" + +namespace oceanbase +{ +namespace common +{ + +bool VersionUtil::check_version_valid(const uint64_t version) +{ + bool bret = true; + const uint32_t major = OB_VSN_MAJOR(version); + const uint16_t minor = OB_VSN_MINOR(version); + const uint8_t major_patch = OB_VSN_MAJOR_PATCH(version); + const uint8_t minor_patch = OB_VSN_MINOR_PATCH(version); + if (major < 3 || (3 == major && minor < 2)) { + // cluster_version is less than "3.2": + // - should be "a.b.0.c"; + bret = (0 == major_patch); + } else if (3 == major && 2 == minor) { + // cluster_version's prefix is "3.2": + // - cluster_version == 3.2.0.0/1/2 + // - cluster_version >= 3.2.3.x + bret = (0 == major_patch && minor_patch <= 2) || (major_patch >= 3); + } else { + // cluster_version is greator than "3.2" + bret = true; + } + return bret; +} + +int64_t VersionUtil::print_version_str(char *buf, const int64_t buf_len, uint64_t version) +{ + int ret = OB_SUCCESS; + int64_t pos = 0; + const uint32_t major = OB_VSN_MAJOR(version); + const uint16_t minor = OB_VSN_MINOR(version); + const uint8_t major_patch = OB_VSN_MAJOR_PATCH(version); + const uint8_t minor_patch = OB_VSN_MINOR_PATCH(version); + if (OB_UNLIKELY(!check_version_valid(version))) { + ret = OB_INVALID_ARGUMENT; + COMMON_LOG(ERROR, "invalid cluster version", K(version), K(lbt())); + } else if (major < 3 + || (3 == major && minor < 2) + || (3 == major && 2 == minor && 0 == major_patch && minor_patch < 3)) { + if (OB_FAIL(databuff_printf(buf, buf_len, pos, "%u.%u.%u", + major, minor, minor_patch))) { + COMMON_LOG(WARN, "fail to print version str", K(ret), K(version)); + } + } else { + if (OB_FAIL(databuff_printf(buf, buf_len, pos, "%u.%u.%u.%u", + major, minor, major_patch, minor_patch))) { + COMMON_LOG(WARN, "fail to print version str", K(ret), K(version)); + } + } + if (OB_FAIL(ret)) { + pos = OB_INVALID_INDEX; + } + return pos; +} + +} // namespace common +} // namespace oceanbase \ No newline at end of file diff --git a/deps/oblib/src/common/ob_version_def.h b/deps/oblib/src/common/ob_version_def.h new file mode 100644 index 0000000000..aad96b98ae --- /dev/null +++ b/deps/oblib/src/common/ob_version_def.h @@ -0,0 +1,178 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * 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 PubL v2 for more details. + */ + +#ifndef OCEANBASE_OBSERVER_OB_VERSION_DEF_H_ +#define OCEANBASE_OBSERVER_OB_VERSION_DEF_H_ + +#include "lib/ob_define.h" +#include "lib/allocator/page_arena.h" + +namespace oceanbase +{ +namespace common +{ +#define OB_VSN_MAJOR_SHIFT 32 +#define OB_VSN_MINOR_SHIFT 16 +#define OB_VSN_MAJOR_PATCH_SHIFT 8 +#define OB_VSN_MINOR_PATCH_SHIFT 0 +#define OB_VSN_MAJOR_MASK 0xffffffff +#define OB_VSN_MINOR_MASK 0xffff +#define OB_VSN_MAJOR_PATCH_MASK 0xff +#define OB_VSN_MINOR_PATCH_MASK 0xff +#define OB_VSN_MAJOR(version) (static_cast((version >> OB_VSN_MAJOR_SHIFT) & OB_VSN_MAJOR_MASK)) +#define OB_VSN_MINOR(version) (static_cast((version >> OB_VSN_MINOR_SHIFT) & OB_VSN_MINOR_MASK)) +#define OB_VSN_MAJOR_PATCH(version) (static_cast((version >> OB_VSN_MAJOR_PATCH_SHIFT) & OB_VSN_MAJOR_PATCH_MASK)) +#define OB_VSN_MINOR_PATCH(version) (static_cast(version & OB_VSN_MINOR_PATCH_MASK)) + +#define CALC_VERSION(major, minor, major_patch, minor_patch) \ + (((major) << OB_VSN_MAJOR_SHIFT) + \ + ((minor) << OB_VSN_MINOR_SHIFT) + \ + ((major_patch) << OB_VSN_MAJOR_PATCH_SHIFT) + \ + ((minor_patch))) +constexpr static inline uint64_t +cal_version(const uint64_t major, const uint64_t minor, const uint64_t major_patch, const uint64_t minor_patch) +{ + return CALC_VERSION(major, minor, major_patch, minor_patch); +} + +#define DEF_MAJOR_VERSION 1 +#define DEF_MINOR_VERSION 4 +#define DEF_MAJOR_PATCH_VERSION 40 +#define DEF_MINOR_PATCH_VERSION 0 + +#define CLUSTER_VERSION_140 (oceanbase::common::cal_version(1, 4, 0, 0)) +#define CLUSTER_VERSION_141 (oceanbase::common::cal_version(1, 4, 0, 1)) +#define CLUSTER_VERSION_142 (oceanbase::common::cal_version(1, 4, 0, 2)) +#define CLUSTER_VERSION_143 (oceanbase::common::cal_version(1, 4, 0, 3)) +#define CLUSTER_VERSION_1431 (oceanbase::common::cal_version(1, 4, 0, 31)) +#define CLUSTER_VERSION_1432 (oceanbase::common::cal_version(1, 4, 0, 32)) +#define CLUSTER_VERSION_144 (oceanbase::common::cal_version(1, 4, 0, 4)) +#define CLUSTER_VERSION_1440 (oceanbase::common::cal_version(1, 4, 0, 40)) +#define CLUSTER_VERSION_1450 (oceanbase::common::cal_version(1, 4, 0, 50)) +#define CLUSTER_VERSION_1460 (oceanbase::common::cal_version(1, 4, 0, 60)) +#define CLUSTER_VERSION_1461 (oceanbase::common::cal_version(1, 4, 0, 61)) +#define CLUSTER_VERSION_1470 (oceanbase::common::cal_version(1, 4, 0, 70)) +#define CLUSTER_VERSION_1471 (oceanbase::common::cal_version(1, 4, 0, 71)) +#define CLUSTER_VERSION_1472 (oceanbase::common::cal_version(1, 4, 0, 72)) +#define CLUSTER_VERSION_1500 (oceanbase::common::cal_version(1, 5, 0, 0)) +#define CLUSTER_VERSION_2000 (oceanbase::common::cal_version(2, 0, 0, 0)) +#define CLUSTER_VERSION_2100 (oceanbase::common::cal_version(2, 1, 0, 0)) +#define CLUSTER_VERSION_2110 (oceanbase::common::cal_version(2, 1, 0, 1)) +#define CLUSTER_VERSION_2200 (oceanbase::common::cal_version(2, 2, 0, 0)) +#define CLUSTER_VERSION_2210 (oceanbase::common::cal_version(2, 2, 0, 1)) +/* + * FIXME: cluster_version目前最高是4位,此处定义要和CMakeLists.txt、tools/upgrade、src/share/parameter/ob_parameter_seed.ipp的定义保持一致 + * 当最后一位非0时,需要注意。比方说2.2.2版本实际上代表的是2.2.02版本,但实际我们想定义成2.2.20版本,和我们的意图不符。 + * 但2.2.1及之前的版本已经发版,为了避免引入兼容性问题,不改历史版本的cluster_version定义。 + */ +#define CLUSTER_VERSION_2220 (oceanbase::common::cal_version(2, 2, 0, 20)) +#define CLUSTER_VERSION_2230 (oceanbase::common::cal_version(2, 2, 0, 30)) +#define CLUSTER_VERSION_2240 (oceanbase::common::cal_version(2, 2, 0, 40)) +#define CLUSTER_VERSION_2250 (oceanbase::common::cal_version(2, 2, 0, 50)) +#define CLUSTER_VERSION_2260 (oceanbase::common::cal_version(2, 2, 0, 60)) +#define CLUSTER_VERSION_2270 (oceanbase::common::cal_version(2, 2, 0, 70)) +#define CLUSTER_VERSION_2271 (oceanbase::common::cal_version(2, 2, 0, 71)) +#define CLUSTER_VERSION_2272 (oceanbase::common::cal_version(2, 2, 0, 72)) +#define CLUSTER_VERSION_2273 (oceanbase::common::cal_version(2, 2, 0, 73)) +#define CLUSTER_VERSION_2274 (oceanbase::common::cal_version(2, 2, 0, 74)) +#define CLUSTER_VERSION_2275 (oceanbase::common::cal_version(2, 2, 0, 75)) +#define CLUSTER_VERSION_2276 (oceanbase::common::cal_version(2, 2, 0, 76)) +#define CLUSTER_VERSION_2277 (oceanbase::common::cal_version(2, 2, 0, 77)) +#define CLUSTER_VERSION_3000 (oceanbase::common::cal_version(3, 0, 0, 0)) +#define CLUSTER_VERSION_3100 (oceanbase::common::cal_version(3, 1, 0, 0)) +#define CLUSTER_VERSION_311 (oceanbase::common::cal_version(3, 1, 0, 1)) +#define CLUSTER_VERSION_312 (oceanbase::common::cal_version(3, 1, 0, 2)) +#define CLUSTER_VERSION_3200 (oceanbase::common::cal_version(3, 2, 0, 0)) +#define CLUSTER_VERSION_321 (oceanbase::common::cal_version(3, 2, 0, 1)) +#define CLUSTER_VERSION_322 (oceanbase::common::cal_version(3, 2, 0, 2)) +// ATTENSION!!!!!!!!!!!!!!!!! +// +// Cluster Version which is less than "3.2.3": +// - 1. It's composed by 3 parts(major、minor、minor_patch) +// - 2. String: cluster version will be format as "major.minor.minor_patch[.0]", and string like "major.minor.x.minor_patch" is invalid. +// - 3. Integer: for compatibility, cluster version will be encoded into "major|minor|x|minor_patch". "x" must be 0, otherwise, it's invalid. +// - 4. Print: cluster version str will be still printed as 3 parts. +// +// Cluster Version which is not less than "3.2.3": +// - 1. It's composed by 4 parts(major、minor、major_patch、minor_patch) +// - 2. String: cluster version will be format as "major.minor.major_patch.minor_patch". +// - 3. Integer: cluster version will be encoded into "major|minor|major_patch|minor_patch". +// - 4. Print: cluster version str will be printed as 4 parts. +#define CLUSTER_VERSION_3_2_3_0 (oceanbase::common::cal_version(3, 2, 3, 0)) +#define CLUSTER_VERSION_4_0_0_0 (oceanbase::common::cal_version(4, 0, 0, 0)) +#define CLUSTER_VERSION_4_1_0_0 (oceanbase::common::cal_version(4, 1, 0, 0)) +#define CLUSTER_VERSION_4_1_0_1 (oceanbase::common::cal_version(4, 1, 0, 1)) +#define CLUSTER_VERSION_4_1_0_2 (oceanbase::common::cal_version(4, 1, 0, 2)) +#define CLUSTER_VERSION_4_2_0_0 (oceanbase::common::cal_version(4, 2, 0, 0)) +#define CLUSTER_VERSION_4_2_1_0 (oceanbase::common::cal_version(4, 2, 1, 0)) +#define CLUSTER_VERSION_4_2_1_1 (oceanbase::common::cal_version(4, 2, 1, 1)) +#define CLUSTER_VERSION_4_2_1_2 (oceanbase::common::cal_version(4, 2, 1, 2)) +#define MOCK_CLUSTER_VERSION_4_2_1_3 (oceanbase::common::cal_version(4, 2, 1, 3)) +#define MOCK_CLUSTER_VERSION_4_2_1_4 (oceanbase::common::cal_version(4, 2, 1, 4)) +#define MOCK_CLUSTER_VERSION_4_2_1_6 (oceanbase::common::cal_version(4, 2, 1, 6)) +#define MOCK_CLUSTER_VERSION_4_2_1_7 (oceanbase::common::cal_version(4, 2, 1, 7)) +#define CLUSTER_VERSION_4_2_2_0 (oceanbase::common::cal_version(4, 2, 2, 0)) +#define MOCK_CLUSTER_VERSION_4_2_2_1 (oceanbase::common::cal_version(4, 2, 2, 1)) +#define MOCK_CLUSTER_VERSION_4_2_3_0 (oceanbase::common::cal_version(4, 2, 3, 0)) +#define MOCK_CLUSTER_VERSION_4_2_3_1 (oceanbase::common::cal_version(4, 2, 3, 1)) +#define MOCK_CLUSTER_VERSION_4_2_4_0 (oceanbase::common::cal_version(4, 2, 4, 0)) +// new data version before 4.3 cannot upgrade to master, must add "MOCK_" prefix +#define CLUSTER_VERSION_4_3_0_0 (oceanbase::common::cal_version(4, 3, 0, 0)) +#define CLUSTER_VERSION_4_3_0_1 (oceanbase::common::cal_version(4, 3, 0, 1)) +#define CLUSTER_VERSION_4_3_1_0 (oceanbase::common::cal_version(4, 3, 1, 0)) +#define CLUSTER_VERSION_4_3_2_0 (oceanbase::common::cal_version(4, 3, 2, 0)) +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +//TODO: If you update the above version, please update CLUSTER_CURRENT_VERSION. +#define CLUSTER_CURRENT_VERSION CLUSTER_VERSION_4_3_2_0 + +// ATTENSION !!!!!!!!!!!!!!!!!!!!!!!!!!! +// 1. After 4.0, each cluster_version is corresponed to a data version. +// 2. cluster_version and data_version is not compariable. +// 3. TODO: If you update data_version below, please update DATA_CURRENT_VERSION & ObUpgradeChecker too. +#define DEFAULT_MIN_DATA_VERSION (oceanbase::common::cal_version(0, 0, 0, 1)) +#define DATA_VERSION_4_0_0_0 (oceanbase::common::cal_version(4, 0, 0, 0)) +#define DATA_VERSION_4_1_0_0 (oceanbase::common::cal_version(4, 1, 0, 0)) +#define DATA_VERSION_4_1_0_1 (oceanbase::common::cal_version(4, 1, 0, 1)) +#define DATA_VERSION_4_1_0_2 (oceanbase::common::cal_version(4, 1, 0, 2)) +#define DATA_VERSION_4_2_0_0 (oceanbase::common::cal_version(4, 2, 0, 0)) +#define DATA_VERSION_4_2_1_0 (oceanbase::common::cal_version(4, 2, 1, 0)) +#define DATA_VERSION_4_2_1_1 (oceanbase::common::cal_version(4, 2, 1, 1)) +#define DATA_VERSION_4_2_1_2 (oceanbase::common::cal_version(4, 2, 1, 2)) +#define MOCK_DATA_VERSION_4_2_1_3 (oceanbase::common::cal_version(4, 2, 1, 3)) +#define MOCK_DATA_VERSION_4_2_1_4 (oceanbase::common::cal_version(4, 2, 1, 4)) +#define MOCK_DATA_VERSION_4_2_1_5 (oceanbase::common::cal_version(4, 2, 1, 5)) +#define DATA_VERSION_4_2_2_0 (oceanbase::common::cal_version(4, 2, 2, 0)) +#define MOCK_DATA_VERSION_4_2_2_1 (oceanbase::common::cal_version(4, 2, 2, 1)) +#define MOCK_DATA_VERSION_4_2_3_0 (oceanbase::common::cal_version(4, 2, 3, 0)) +#define MOCK_DATA_VERSION_4_2_3_1 (oceanbase::common::cal_version(4, 2, 3, 1)) +#define MOCK_DATA_VERSION_4_2_4_0 (oceanbase::common::cal_version(4, 2, 4, 0)) +// new data version before 4.3 cannot upgrade to master, must add "MOCK_" prefix +#define DATA_VERSION_4_3_0_0 (oceanbase::common::cal_version(4, 3, 0, 0)) +#define DATA_VERSION_4_3_0_1 (oceanbase::common::cal_version(4, 3, 0, 1)) +#define DATA_VERSION_4_3_1_0 (oceanbase::common::cal_version(4, 3, 1, 0)) +#define DATA_VERSION_4_3_2_0 (oceanbase::common::cal_version(4, 3, 2, 0)) +#define DATA_CURRENT_VERSION DATA_VERSION_4_3_2_0 +// ATTENSION !!!!!!!!!!!!!!!!!!!!!!!!!!! +// LAST_BARRIER_DATA_VERSION should be the latest barrier data version before DATA_CURRENT_VERSION +#define LAST_BARRIER_DATA_VERSION DATA_VERSION_4_2_1_0 + +class VersionUtil +{ +public: + static bool check_version_valid(const uint64_t version); + static int64_t print_version_str(char *buf, const int64_t buf_len, uint64_t version); +}; + +} // namespace common +} // namespace oceanbase + +#endif \ No newline at end of file diff --git a/deps/oblib/src/lib/ob_name_id_def.h b/deps/oblib/src/lib/ob_name_id_def.h index 8c2bbcb943..2759f61984 100644 --- a/deps/oblib/src/lib/ob_name_id_def.h +++ b/deps/oblib/src/lib/ob_name_id_def.h @@ -884,6 +884,9 @@ DEF_NAME(id, "id") DEF_NAME(sql_update_cost_time, "sql_update_cost_time") DEF_NAME(sql_update_times, "sql_update_times") DEF_NAME(last_sql_update_time, "last_sql_update_time") + DEF_NAME(is_data_version_crossed, "is_data_version_crossed") + DEF_NAME(finish_data_version, "finish_data_version") + DEF_NAME(data_version_barrier_scn, "data_version_barrier_scn") // << add pair events BEFORE this line DEF_NAME(NAME_COUNT, "invalid") diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_net_handler.h b/deps/oblib/src/rpc/obrpc/ob_rpc_net_handler.h index 9830695b91..a66c825c19 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_net_handler.h +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_net_handler.h @@ -50,6 +50,12 @@ public: public: static int64_t CLUSTER_ID; static uint64_t CLUSTER_NAME_HASH; + static bool is_self_cluster(int64_t cluster_id) + { + return ObRpcNetHandler::CLUSTER_ID == cluster_id && + ObRpcNetHandler::CLUSTER_ID != OB_INVALID_CLUSTER_ID && + cluster_id != OB_INVALID_CLUSTER_ID; + } protected: char *easy_alloc(easy_pool_t *pool, int64_t size) const; private: diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_packet.cpp b/deps/oblib/src/rpc/obrpc/ob_rpc_packet.cpp index 014e19b45b..eae1b8b229 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_packet.cpp +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_packet.cpp @@ -16,7 +16,9 @@ #include "lib/ob_define.h" #include "lib/coro/co_var.h" #include "common/storage/ob_sequence.h" +#include "common/ob_tenant_data_version_mgr.h" #include "rpc/obrpc/ob_rpc_net_handler.h" +#include "share/ob_cluster_version.h" using namespace oceanbase::common::serialization; using namespace oceanbase::common; @@ -34,7 +36,16 @@ int ObRpcPacketHeader::serialize(char* buf, const int64_t buf_len, int64_t& pos) int ret = OB_SUCCESS; if (buf_len - pos >= get_encoded_size()) { seq_no_ = ObSequence::get_max_seq_no(); - LOG_DEBUG("rpc send seq_no ", K_(seq_no)); + data_version_ = 0; + if (ObRpcNetHandler::is_self_cluster(dst_cluster_id_) && ODV_MGR.is_enable_compatible_monotonic()) { + int tmp_ret = OB_SUCCESS; + if (OB_TMP_FAIL(ODV_MGR.get(tenant_id_, data_version_))) { + data_version_ = LAST_BARRIER_DATA_VERSION; + LOG_WARN("fail to get data_version", K(tmp_ret), K(tenant_id_)); + } + } + LOG_TRACE("rpc send info", K_(tenant_id), K_(data_version), K_(seq_no), K_(dst_cluster_id), + K_(pcode), K(ObRpcNetHandler::CLUSTER_ID)); if (OB_FAIL(encode_i32(buf, buf_len, pos, pcode_))) { LOG_WARN("Encode error", K(ret), KP(buf), K(buf_len), K(pos)); } else if (OB_FAIL(encode_i8(buf, buf_len, pos, static_cast (get_encoded_size())))) { @@ -83,6 +94,8 @@ int ObRpcPacketHeader::serialize(char* buf, const int64_t buf_len, int64_t& pos) LOG_WARN("Encode error", K(ret), KP(buf), K(buf_len), K(pos)); } else if (OB_FAIL(encode_i64(buf, buf_len, pos, cluster_name_hash_))) { LOG_WARN("Encode error", K(ret), KP(buf), K(buf_len), K(pos)); + } else if (OB_FAIL(encode_i64(buf, buf_len, pos, data_version_))) { + LOG_WARN("Encode error", K(ret), KP(buf), K(buf_len), K(pos)); } else { //do nothing #ifdef ERRSIM @@ -169,6 +182,8 @@ int ObRpcPacketHeader::deserialize(const char* buf, const int64_t data_len, int6 LOG_WARN("Decode error", K(ret), KP(buf), K(hlen_), K(pos)); } else if (hlen_ > pos && OB_FAIL(decode_i64(buf, hlen_, pos, reinterpret_cast(&cluster_name_hash_)))) { LOG_WARN("Decode error", K(ret), KP(buf), K(hlen_), K(pos)); + } else if (hlen_ > pos && OB_FAIL(decode_i64(buf, data_len, pos, reinterpret_cast(&data_version_)))) { + LOG_WARN("Decode error", K(ret), KP(buf), K(data_len), K(pos)); } else { #ifdef ERRSIM int64_t type = 0; @@ -182,6 +197,21 @@ int ObRpcPacketHeader::deserialize(const char* buf, const int64_t data_len, int6 } ObSequence::update_max_seq_no(seq_no_); LOG_DEBUG("rpc receive seq_no ", K_(seq_no), K(ObSequence::get_max_seq_no())); + // for RPC response, if the src_cluster_id is the same as current cluster id, we set the + // data_version here. for RPC request, the failure of setting data_version may cause + // disconnection, to avoid it, we delay setting to the RPC process phase. + if (OB_SUCC(ret) && + flags_ & ObRpcPacketHeader::RESP_FLAG && + ObRpcNetHandler::is_self_cluster(src_cluster_id_) && data_version_ > 0) { + if (OB_FAIL(ODV_MGR.set(tenant_id_, data_version_))) { + LOG_WARN("fail to update data_version", K(ret), KP(tenant_id_), K(data_version_)); + } + LOG_TRACE("rpc receive data version", K_(tenant_id), K_(data_version), K_(pcode), + K_(src_cluster_id), K(ObRpcNetHandler::CLUSTER_ID)); + } + if (OB_ARB_GC_NOTIFY == pcode_ && REACH_TIME_INTERVAL(5000000)) { + LOG_TRACE("receive arb rpc", K_(src_cluster_id), K_(pcode)); + } } return ret; diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_packet.h b/deps/oblib/src/rpc/obrpc/ob_rpc_packet.h index 5ebf3ccc73..226cfd4db5 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_packet.h +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_packet.h @@ -180,6 +180,7 @@ public: int64_t seq_no_; int32_t group_id_; uint64_t cluster_name_hash_; + uint64_t data_version_; #ifdef ERRSIM ObErrsimModuleType module_type_; @@ -191,12 +192,13 @@ public: TO_STRING_KV(K(checksum_), K(pcode_), K(hlen_), K(priority_), K(flags_), K(tenant_id_), K(priv_tenant_id_), K(session_id_), K(trace_id_), K(timeout_), K_(timestamp), K_(dst_cluster_id), K_(cost_time), - K(compressor_type_), K(original_len_), K(src_cluster_id_), K(seq_no_)); + K(compressor_type_), K(original_len_), K(src_cluster_id_), K(seq_no_), + K(data_version_)); ObRpcPacketHeader() { memset(this, 0, sizeof(*this)); flags_ |= (OB_LOG_LEVEL_NONE & OB_LOG_LEVEL_MASK); } static inline int64_t get_encoded_size() { - return HEADER_SIZE + ObRpcCostTime::get_encoded_size() + 8 /* for seq no */; + return HEADER_SIZE + ObRpcCostTime::get_encoded_size() + 8 /* for seq no */ + 8 /* for data version*/; } }; @@ -339,6 +341,7 @@ public: inline int32_t get_request_level() const; inline void set_group_id(int32_t group_id); inline int32_t get_group_id() const; + inline uint64_t get_data_version() const; int encode_ez_header(char *buf, int64_t len, int64_t &pos); TO_STRING_KV(K(hdr_), K(chid_), K(clen_), K_(assemble), K_(msg_count), K_(payload)); @@ -837,6 +840,11 @@ int32_t ObRpcPacket::get_group_id() const return hdr_.group_id_; } +uint64_t ObRpcPacket::get_data_version() const +{ + return hdr_.data_version_; +} + RLOCAL_EXTERN(int, g_pcode); inline ObRpcPacketCode current_pcode() { diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.cpp b/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.cpp index a3eb81a5c6..c5c8c02997 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.cpp +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.cpp @@ -22,6 +22,7 @@ #include "lib/trace/ob_trace_event.h" #include "lib/trace/ob_trace.h" #include "common/data_buffer.h" +#include "common/ob_tenant_data_version_mgr.h" #include "rpc/obrpc/ob_rpc_req_context.h" #include "rpc/obrpc/ob_rpc_stream_cond.h" #include "rpc/obrpc/ob_rpc_result_code.h" @@ -76,6 +77,11 @@ int ObRpcProcessorBase::run() LOG_WARN("req timeout", K(ret)); } else if (OB_FAIL(check_cluster_id())) { LOG_WARN("checking cluster ID failed", K(ret)); + } else if (OB_FAIL(update_data_version())) { + // update_data_version could have been called in RPC deserialization process, however, the + // failure of setting data_version may cause disconnection, so for normal RPC request, we do it + // here + LOG_WARN("fail to update data_version", K(ret)); } else if (OB_FAIL(deserialize())) { deseri_succ = false; LOG_WARN("deserialize argument fail", K(ret)); @@ -137,6 +143,26 @@ int ObRpcProcessorBase::check_cluster_id() return ret; } +int ObRpcProcessorBase::update_data_version() +{ + int ret = OB_SUCCESS; + + if (OB_ISNULL(rpc_pkt_)) { + ret = OB_ERR_UNEXPECTED; + RPC_OBRPC_LOG(ERROR, "rpc_pkt_ should not be NULL", K(ret)); + } else { + int64_t src_cluster_id = rpc_pkt_->get_src_cluster_id(); + uint64_t data_version = rpc_pkt_->get_data_version(); + if (ObRpcNetHandler::is_self_cluster(src_cluster_id) && data_version > 0) { + if (OB_FAIL(ODV_MGR.set(tenant_id_, data_version))) { + LOG_WARN("fail to update data_version", K(ret), KP(tenant_id_), K(data_version)); + } + } + } + + return ret; +} + int ObRpcProcessorBase::deserialize() { int ret = OB_SUCCESS; @@ -299,6 +325,10 @@ int ObRpcProcessorBase::do_response(const Response &rsp) packet->set_resp(); // The cluster_id of the response must be the src_cluster_id of the request packet->set_dst_cluster_id(rpc_pkt_->get_src_cluster_id()); + // the tenant_id in response is only used to sync data_version, it has no meaning to the + // RPC framework + packet->set_tenant_id(rpc_pkt_->get_tenant_id()); + packet->set_src_cluster_id(ObRpcNetHandler::CLUSTER_ID); #ifdef ERRSIM packet->set_module_type(THIS_WORKER.get_module_type()); @@ -598,6 +628,11 @@ int ObRpcProcessorBase::flush(int64_t wait_timeout, const ObAddr *src_addr) req_ = NULL; is_stream_end_ = true; RPC_OBRPC_LOG(ERROR, "rpc packet is NULL in stream", K(ret)); + } else if (OB_FAIL(update_data_version())) { + // update_data_version could have been called in RPC deserialization process, however, the + // failure of setting data_version may cause disconnection, so for stream RPC request, we do + // it here + RPC_OBRPC_LOG(WARN, "fail to update data_version", K(ret)); } else if (rpc_pkt_->is_stream_last()) { ret = OB_ITER_END; } else { diff --git a/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.h b/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.h index 0f8a382b79..a8266807a5 100644 --- a/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.h +++ b/deps/oblib/src/rpc/obrpc/ob_rpc_processor_base.h @@ -71,7 +71,7 @@ public: protected: int check_timeout() { return common::OB_SUCCESS; } virtual int check_cluster_id(); - + int update_data_version(); virtual int before_process() { return common::OB_SUCCESS; } virtual int after_process(int error_code); diff --git a/src/observer/ob_server.cpp b/src/observer/ob_server.cpp index 92ed09b02f..08c102dec8 100644 --- a/src/observer/ob_server.cpp +++ b/src/observer/ob_server.cpp @@ -15,6 +15,7 @@ #include "observer/ob_server.h" #include #include "common/log/ob_log_constants.h" +#include "common/ob_tenant_data_version_mgr.h" #include "lib/allocator/ob_libeasy_mem_pool.h" #include "lib/alloc/memory_dump.h" #include "lib/thread/protected_stack_allocator.h" @@ -1892,14 +1893,20 @@ int ObServer::init_config() int ret = OB_SUCCESS; bool has_config_file = true; - // set dump path - const char *dump_path = "etc/observer.config.bin"; - config_mgr_.set_dump_path(dump_path); - if (OB_FILE_NOT_EXIST == (ret = config_mgr_.load_config())) { - has_config_file = false; - ret = OB_SUCCESS; - } else if (OB_FAIL(ret)) { - LOG_ERROR("load config from file failed", KR(ret)); + if (OB_FAIL(ODV_MGR.init(true /*enable_compatible_monotonic*/))) { + LOG_ERROR("fail to init data_version_mgr", KR(ret)); + } else if (OB_FAIL(ODV_MGR.load_from_file())) { + LOG_ERROR("failed to load data_version_mgr file", KR(ret)); + } else { + // set dump path + const char *dump_path = "etc/observer.config.bin"; + config_mgr_.set_dump_path(dump_path); + if (OB_FILE_NOT_EXIST == (ret = config_mgr_.load_config())) { + has_config_file = false; + ret = OB_SUCCESS; + } else if (OB_FAIL(ret)) { + LOG_ERROR("load config from file failed", KR(ret)); + } } if (OB_FAIL(ret)) { diff --git a/src/observer/ob_service.cpp b/src/observer/ob_service.cpp index 18c26600dc..c81f12da4a 100644 --- a/src/observer/ob_service.cpp +++ b/src/observer/ob_service.cpp @@ -3274,7 +3274,9 @@ int ObService::update_tenant_info_cache( if (OB_ISNULL(tenant_info_loader)) { ret = OB_ERR_UNEXPECTED; COMMON_LOG(ERROR, "tenant_info_loader should not be null", KR(ret)); - } else if (OB_FAIL(tenant_info_loader->update_tenant_info_cache(arg.get_ora_rowscn(), arg.get_tenant_info()))) { + } else if (OB_FAIL(tenant_info_loader->update_tenant_info_cache( + arg.get_ora_rowscn(), arg.get_tenant_info(), arg.get_finish_data_version(), + arg.get_data_version_barrier_scn()))) { COMMON_LOG(WARN, "update_tenant_info_cache failed", KR(ret), K(arg)); } else if (OB_FAIL(result.init(arg.get_tenant_id()))) { LOG_WARN("failed to init res", KR(ret), K(arg.get_tenant_id())); diff --git a/src/observer/omt/ob_tenant_config.cpp b/src/observer/omt/ob_tenant_config.cpp index e08b0e28b5..4c00e157cc 100644 --- a/src/observer/omt/ob_tenant_config.cpp +++ b/src/observer/omt/ob_tenant_config.cpp @@ -322,18 +322,35 @@ int ObTenantConfig::publish_special_config_after_dump() LOG_WARN("Invalid config string", K(tenant_id_), K(ret)); } else if (!(*pp_item)->dump_value_updated()) { LOG_INFO("config dump value is not set, no need read", K(tenant_id_), K((*pp_item)->spfile_str())); - } else if (!(*pp_item)->set_value((*pp_item)->spfile_str())) { - ret = OB_INVALID_CONFIG; - LOG_WARN("Invalid config value", K(tenant_id_), K((*pp_item)->spfile_str()), K(ret)); } else { - FLOG_INFO("[COMPATIBLE] read data_version after dump", - KR(ret), K_(tenant_id), - "version", (*pp_item)->version(), - "value", (*pp_item)->str(), - "value_updated", (*pp_item)->value_updated(), - "dump_version", (*pp_item)->dumped_version(), - "dump_value", (*pp_item)->spfile_str(), - "dump_value_updated", (*pp_item)->dump_value_updated()); + uint64_t new_data_version = 0; + uint64_t old_data_version = 0; + bool value_updated = (*pp_item)->value_updated(); + if (OB_FAIL(ObClusterVersion::get_version((*pp_item)->spfile_str(), new_data_version))) { + LOG_ERROR("parse data_version failed", KR(ret), K((*pp_item)->spfile_str())); + } else if (OB_FAIL(ObClusterVersion::get_version((*pp_item)->str(), old_data_version))) { + LOG_ERROR("parse data_version failed", KR(ret), K((*pp_item)->str())); + } else if (!value_updated && old_data_version != DATA_CURRENT_VERSION) { + ret = OB_ERR_UNEXPECTED; + SHARE_LOG(ERROR, "unexpected data_version", KR(ret), K(old_data_version)); + } else if (value_updated && new_data_version <= old_data_version) { + LOG_INFO("[COMPATIBLE] [DATA_VERSION] no need to update", K(tenant_id_), + K(old_data_version), K(new_data_version)); + // do nothing + } else { + if (!(*pp_item)->set_value((*pp_item)->spfile_str())) { + ret = OB_INVALID_CONFIG; + LOG_WARN("Invalid config value", K(tenant_id_), K((*pp_item)->spfile_str()), K(ret)); + } else { + FLOG_INFO("[COMPATIBLE] [DATA_VERSION] read data_version after dump", + KR(ret), K_(tenant_id), "version", (*pp_item)->version(), + "value", (*pp_item)->str(), "value_updated", + (*pp_item)->value_updated(), "dump_version", + (*pp_item)->dumped_version(), "dump_value", + (*pp_item)->spfile_str(), "dump_value_updated", + (*pp_item)->dump_value_updated()); + } + } } return ret; } @@ -362,6 +379,7 @@ int ObTenantConfig::add_extra_config(const char *config_str, buf[config_str_length] = '\0'; token = STRTOK_R(buf, ",\n", &saveptr); const ObString compatible_cfg(COMPATIBLE); + const ObString enable_compatible_monotonic_cfg(ENABLE_COMPATIBLE_MONOTONIC); while (OB_SUCC(ret) && OB_LIKELY(NULL != token)) { char *saveptr_one = NULL; char *name = NULL; @@ -404,21 +422,44 @@ int ObTenantConfig::add_extra_config(const char *config_str, LOG_WARN("Invalid config string, no such config item", K(name), K(value), K(ret)); } if (OB_FAIL(ret) || OB_ISNULL(pp_item)) { - } else if (compatible_cfg.case_compare(name) == 0) { - if (!(*pp_item)->set_dump_value(value)) { - ret = OB_INVALID_CONFIG; - LOG_WARN("Invalid config value", K(name), K(value), K(ret)); + } else if (0 == compatible_cfg.case_compare(name)) { + // init tenant and observer reload with -o will use this interface to update tenant's + // config. considering the -o situation, we need to ensure the new_data_version won't + // go back + uint64_t new_data_version = 0; + uint64_t old_data_version = 0; + if (OB_FAIL(ObClusterVersion::get_version(value, new_data_version))) { + LOG_ERROR("parse data_version failed", KR(ret), K(value)); + } else if (((*pp_item)->value_updated() || (*pp_item)->dump_value_updated()) && + OB_FAIL(ObClusterVersion::get_version( + (*pp_item)->spfile_str(), old_data_version))) { + LOG_ERROR("parse data_version failed", KR(ret), K((*pp_item)->spfile_str())); + } else if (new_data_version <= old_data_version) { + // do nothing + LOG_INFO("[COMPATIBLE] DATA_VERSION no need to update", + K(tenant_id_), K(old_data_version), + K(new_data_version)); } else { - (*pp_item)->set_dump_value_updated(); - (*pp_item)->set_version(version); - FLOG_INFO("[COMPATIBLE] init data_version before dump", - KR(ret), K_(tenant_id), - "version", (*pp_item)->version(), - "value", (*pp_item)->str(), - "value_updated", (*pp_item)->value_updated(), - "dump_version", (*pp_item)->dumped_version(), - "dump_value", (*pp_item)->spfile_str(), - "dump_value_updated", (*pp_item)->dump_value_updated()); + if (!(*pp_item)->set_dump_value(value)) { + ret = OB_INVALID_CONFIG; + LOG_WARN("Invalid config value", K(name), K(value), K(ret)); + } else { + (*pp_item)->set_dump_value_updated(); + (*pp_item)->set_version(version); + int tmp_ret = 0; + if (OB_TMP_FAIL(ODV_MGR.set(tenant_id_, new_data_version))) { + LOG_WARN("fail to set data_version", KR(tmp_ret), + K(tenant_id_), K(new_data_version)); + } + FLOG_INFO("[COMPATIBLE] [DATA_VERSION] init data_version before dump", + KR(ret), K_(tenant_id), "version", + (*pp_item)->version(), "value", (*pp_item)->str(), + "value_updated", (*pp_item)->value_updated(), + "dump_version", (*pp_item)->dumped_version(), + "dump_value", (*pp_item)->spfile_str(), + "dump_value_updated", (*pp_item)->dump_value_updated(), + K(old_data_version), K(new_data_version)); + } } } else if (!(*pp_item)->set_value(value)) { ret = OB_INVALID_CONFIG; @@ -434,6 +475,11 @@ int ObTenantConfig::add_extra_config(const char *config_str, } else { (*pp_item)->set_version(version); LOG_INFO("Load tenant config succ", K(name), K(value)); + if (0 == enable_compatible_monotonic_cfg.case_compare(name)) { + ObString v_str((*pp_item)->str()); + ODV_MGR.set_enable_compatible_monotonic(0 == v_str.case_compare("True") ? true + : false); + } } } } diff --git a/src/observer/omt/ob_tenant_config_mgr.cpp b/src/observer/omt/ob_tenant_config_mgr.cpp index 5f4054f52d..029f9bfadb 100644 --- a/src/observer/omt/ob_tenant_config_mgr.cpp +++ b/src/observer/omt/ob_tenant_config_mgr.cpp @@ -21,6 +21,7 @@ #include "share/ob_rpc_struct.h" #include "share/inner_table/ob_inner_table_schema_constants.h" #include "share/schema/ob_multi_version_schema_service.h" +#include "common/ob_tenant_data_version_mgr.h" using namespace oceanbase::common; using namespace oceanbase::share; @@ -199,6 +200,22 @@ int ObTenantConfigMgr::refresh_tenants(const ObIArray &tenants) if (OB_FAIL(new_tenants.push_back(tenant_id))) { LOG_WARN("fail add tenant config", K(tenant_id), K(ret)); } + } else if (OB_ISNULL((*config))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("tenant config is null", K(ret), K(tenant_id), K(config)); + } else { + // periodically(10s) check that ObTenantDataVersionMgr doesn't fall behind ObTenantConfigMgr + bool value_updated = (*config)->compatible.value_updated(); + if (value_updated) { + int tmp_ret = OB_SUCCESS; + const uint64_t data_version = (*config)->compatible; + if (OB_TMP_FAIL(ODV_MGR.set(tenant_id, data_version))) { + LOG_WARN("fail to set data_version in refresh_tenants", KR(tmp_ret), K(tenant_id), + K(data_version)); + } + LOG_INFO("[DATA_VERSION] periodically update data_version", KR(tmp_ret), K(tenant_id), + K(data_version)); + } } } } @@ -336,6 +353,10 @@ int ObTenantConfigMgr::del_tenant_config(uint64_t tenant_id) } else { ob_delete(config); LOG_INFO("tenant config deleted", K(tenant_id), K(ret)); + int tmp_ret = OB_SUCCESS; + if (OB_TMP_FAIL(ODV_MGR.remove(tenant_id))) { + LOG_WARN("fail to remove data_version", K(tmp_ret), K(tenant_id)); + } } } return ret; @@ -508,21 +529,38 @@ void ObTenantConfigMgr::get_lease_request(share::ObLeaseRequest &lease_request) } // for __all_virtual_tenant_parameter_info -int ObTenantConfigMgr::get_all_tenant_config_info(common::ObArray &all_config) +int ObTenantConfigMgr::get_all_tenant_config_info( + common::ObArray &all_config, + common::ObIAllocator *allocator) { int ret = OB_SUCCESS; DRWLock::RDLockGuard guard(rwlock_); TenantConfigMap::const_iterator it = config_map_.begin(); for (; OB_SUCC(ret) && it != config_map_.end(); ++it) { - uint64_t tenant_id = it->first.tenant_id_; + const uint64_t tenant_id = it->first.tenant_id_; ObTenantConfig *tenant_config = it->second; for (ObConfigContainer::const_iterator iter = tenant_config->get_container().begin(); iter != tenant_config->get_container().end(); iter++) { TenantConfigInfo config_info(tenant_id); - if (0 == ObString("compatible").case_compare(iter->first.str()) - && !iter->second->value_updated()) { - if (OB_FAIL(config_info.set_value("0.0.0.0"))) { - LOG_WARN("set value fail", K(iter->second->str()), K(ret)); + if (0 == ObString("compatible").case_compare(iter->first.str())) { + uint64_t data_version = 0; + char *dv_buf = NULL; + if (GET_MIN_DATA_VERSION(tenant_id, data_version) != OB_SUCCESS) { + if (OB_FAIL(config_info.set_value("0.0.0.0"))) { + LOG_WARN("set value fail", K(ret), K(tenant_id)); + } + } else if (OB_ISNULL(dv_buf = (char *)allocator->alloc(OB_SERVER_VERSION_LENGTH))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_ERROR("fail to alloc buf", K(ret), K(tenant_id), K(OB_SERVER_VERSION_LENGTH)); + } else if (OB_INVALID_INDEX == + VersionUtil::print_version_str( + dv_buf, OB_SERVER_VERSION_LENGTH, data_version)) { + ret = OB_INVALID_ARGUMENT; + LOG_ERROR("fail to print data_version", K(ret), K(tenant_id), K(data_version)); + } else { + if (OB_FAIL(config_info.set_value(dv_buf))) { + LOG_WARN("set value fail", K(ret), K(tenant_id), K(data_version), K(dv_buf)); + } } } else { if (OB_FAIL(config_info.set_value(iter->second->str()))) { @@ -628,6 +666,10 @@ int ObTenantConfigMgr::add_config_to_existing_tenant(const char *config_str) if (OB_FAIL(it->second->add_extra_config(config_str, version))) { LOG_WARN("add tenant extra config failed", "tenant_id", it->second->get_tenant_id(), "config_str", config_str, KR(ret)); + } else if (OB_FAIL(dump2file())) { + LOG_WARN("fail to dump config to file", KR(ret), K(config_str)); + } else if (OB_FAIL(it->second->publish_special_config_after_dump())) { + LOG_WARN("fail to publish config after dump", KR(ret), K(config_str)); } } } diff --git a/src/observer/omt/ob_tenant_config_mgr.h b/src/observer/omt/ob_tenant_config_mgr.h index e3cab436ed..4814f184ee 100644 --- a/src/observer/omt/ob_tenant_config_mgr.h +++ b/src/observer/omt/ob_tenant_config_mgr.h @@ -142,7 +142,8 @@ public: int64_t get_tenant_config_version(uint64_t tenant_id); void get_lease_request(share::ObLeaseRequest &lease_request); int get_lease_response(share::ObLeaseResponse &lease_response); - int get_all_tenant_config_info(common::ObArray &config_info); + int get_all_tenant_config_info(common::ObArray &config_info, + common::ObIAllocator *allocator); int got_versions(const common::ObIArray > &versions); int got_version(uint64_t tenant_id, int64_t version, const bool remove_repeat = true); int update_local(uint64_t tenant_id, int64_t expected_version); diff --git a/src/observer/virtual_table/ob_all_virtual_tenant_parameter_info.cpp b/src/observer/virtual_table/ob_all_virtual_tenant_parameter_info.cpp index a5a2f2a95f..f644369cd8 100644 --- a/src/observer/virtual_table/ob_all_virtual_tenant_parameter_info.cpp +++ b/src/observer/virtual_table/ob_all_virtual_tenant_parameter_info.cpp @@ -37,7 +37,7 @@ int ObAllVirtualTenantParameterInfo::inner_open() { int ret = OB_SUCCESS; const ObAddr &addr = GCTX.self_addr(); - if (OB_FAIL(OTC_MGR.get_all_tenant_config_info(all_config_))) { + if (OB_FAIL(OTC_MGR.get_all_tenant_config_info(all_config_, allocator_))) { SERVER_LOG(WARN, "fail to get all tenant config info", K(ret)); } else if (!addr.ip_to_string(ip_buf_, sizeof(ip_buf_))) { ret = OB_ERR_UNEXPECTED; @@ -50,6 +50,7 @@ int ObAllVirtualTenantParameterInfo::inner_open() void ObAllVirtualTenantParameterInfo::reset() { + ObVirtualTableIterator::reset(); config_iter_ = all_config_.begin(); } diff --git a/src/observer/virtual_table/ob_all_virtual_tenant_parameter_stat.cpp b/src/observer/virtual_table/ob_all_virtual_tenant_parameter_stat.cpp index b1baf7ddfe..ed30dd0a0c 100644 --- a/src/observer/virtual_table/ob_all_virtual_tenant_parameter_stat.cpp +++ b/src/observer/virtual_table/ob_all_virtual_tenant_parameter_stat.cpp @@ -16,6 +16,7 @@ #include "observer/omt/ob_multi_tenant.h" #include "observer/ob_sql_client_decorator.h" #include "share/inner_table/ob_inner_table_schema_constants.h" +#include "common/ob_tenant_data_version_mgr.h" namespace oceanbase { @@ -270,11 +271,28 @@ int ObAllVirtualTenantParameterStat::fill_row_(common::ObNewRow *&row, break; } case VALUE: { - if (0 == ObString("compatible").case_compare(iter->first.str()) - && !iter->second->value_updated()) { - // `compatible` is used for tenant compatibility, - // default value should not be used when `compatible` is not loaded yet. - cells[i].set_varchar("0.0.0.0"); + if (0 == ObString("compatible").case_compare(iter->first.str())) { + const uint64_t tenant_id = tenant_id_list_.at(cur_tenant_idx_); + uint64_t data_version = 0; + char *dv_buf = NULL; + if (GET_MIN_DATA_VERSION(tenant_id, data_version) != OB_SUCCESS) { + // `compatible` is used for tenant compatibility, + // default value should not be used when `compatible` is not + // loaded yet. + cells[i].set_varchar("0.0.0.0"); + } else if (OB_ISNULL(dv_buf = (char *)allocator_->alloc(OB_SERVER_VERSION_LENGTH))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + SERVER_LOG(ERROR, "fail to alloc buf", K(ret), K(tenant_id), + K(OB_SERVER_VERSION_LENGTH)); + } else if (OB_INVALID_INDEX == + VersionUtil::print_version_str( + dv_buf, OB_SERVER_VERSION_LENGTH, data_version)) { + ret = OB_INVALID_ARGUMENT; + SERVER_LOG(ERROR, "fail to print data_version", K(ret), + K(tenant_id), K(data_version)); + } else { + cells[i].set_varchar(dv_buf); + } } else { if (!is_sys_tenant(effective_tenant_id_) && (0 == ObString(SSL_EXTERNAL_KMS_INFO).case_compare(iter->first.str()) || diff --git a/src/rootserver/ob_common_ls_service.cpp b/src/rootserver/ob_common_ls_service.cpp index 1dc0df142f..3f0dfa5685 100755 --- a/src/rootserver/ob_common_ls_service.cpp +++ b/src/rootserver/ob_common_ls_service.cpp @@ -350,6 +350,7 @@ void ObCommonLSService::try_update_primary_ip_list() char passwd[OB_MAX_PASSWORD_LENGTH + 1] = { 0 }; //unencrypted password uint64_t user_tenant_id = gen_user_tenant_id(tenant_id_); bool log_restore_source_exist = true; + bool cluster_id_dup = false; if (OB_FAIL(restore_source_mgr.init(user_tenant_id, proxy_))) { LOG_WARN("fail to init restore_source_mgr", K(user_tenant_id)); @@ -398,6 +399,14 @@ void ObCommonLSService::try_update_primary_ip_list() } else if ((primary_cluster_id != service_attr.user_.cluster_id_) || (primary_tenant_id != service_attr.user_.tenant_id_)) { LOG_WARN("primary cluster_id or tenant_id has been changed", K(primary_cluster_id), K_(service_attr.user_.cluster_id), K(primary_tenant_id), K_(service_attr.user_.tenant_id), K(user_tenant_id)); + } else if (OB_FAIL(restore_proxy_.check_different_cluster_with_same_cluster_id( + service_attr.user_.cluster_id_, cluster_id_dup))) { + LOG_WARN("fail to check different cluster with same cluster id", KR(ret), + K(service_attr.user_.cluster_id_)); + } else if (cluster_id_dup) { + ret = OB_OP_NOT_ALLOW; + LOG_ERROR("different cluster with same cluster id is not allowed", KR(ret), + K(service_attr.user_.cluster_id_)); } else { // update primary state bool cur_primary_state = true; diff --git a/src/rootserver/ob_ddl_service.cpp b/src/rootserver/ob_ddl_service.cpp index aab43901df..d5a317df6c 100755 --- a/src/rootserver/ob_ddl_service.cpp +++ b/src/rootserver/ob_ddl_service.cpp @@ -26595,6 +26595,11 @@ int ObDDLService::init_tenant_schema( } else if (is_user_tenant(tenant_id) && OB_FAIL(OB_PRIMARY_STANDBY_SERVICE.write_upgrade_barrier_log( trans, tenant_id, data_version))) { LOG_WARN("fail to write_upgrade_barrier_log", KR(ret), K(tenant_id), K(data_version)); + } else if (is_user_tenant(tenant_id) && + OB_FAIL(OB_PRIMARY_STANDBY_SERVICE.write_upgrade_data_version_barrier_log( + trans, tenant_id, data_version))) { + LOG_WARN("fail to write_upgrade_data_version_barrier_log", KR(ret), + K(tenant_id), K(data_version)); } } if (trans.is_started()) { diff --git a/src/rootserver/ob_ls_recovery_reportor.cpp b/src/rootserver/ob_ls_recovery_reportor.cpp index 3a8fcefdc5..94e3fc7966 100755 --- a/src/rootserver/ob_ls_recovery_reportor.cpp +++ b/src/rootserver/ob_ls_recovery_reportor.cpp @@ -259,7 +259,7 @@ int ObLSRecoveryReportor::update_ls_recovery_stat_() LOG_ERROR("ls is null", KR(ret), KP(ls)); } else { share::SCN replayable_scn = SCN::base_scn(); - if (OB_TMP_FAIL(tenant_info_loader->get_replayable_scn(replayable_scn))) { + if (OB_TMP_FAIL(tenant_info_loader->get_local_replayable_scn(replayable_scn))) { LOG_WARN("failed to get replayable_scn", KR(ret), KPC(ls)); } else if (OB_TMP_FAIL(ls->update_ls_replayable_point(replayable_scn))) { LOG_WARN("failed to update_ls_replayable_point", KR(tmp_ret), KPC(ls), K(replayable_scn)); @@ -432,7 +432,7 @@ int ObLSRecoveryReportor::update_replayable_point_from_tenant_info_() if (OB_ISNULL(tenant_info_loader)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("mtl pointer is null", KR(ret), KP(tenant_info_loader)); - } else if (OB_FAIL(tenant_info_loader->get_replayable_scn(replayable_scn))) { + } else if (OB_FAIL(tenant_info_loader->get_local_replayable_scn(replayable_scn))) { LOG_WARN("failed to get replayable_scn", KR(ret), K_(tenant_id)); } else if (OB_FAIL(log_service->update_replayable_point(replayable_scn))) { LOG_WARN("logservice update_replayable_point failed", KR(ret), K(replayable_scn)); diff --git a/src/rootserver/ob_ls_recovery_stat_handler.cpp b/src/rootserver/ob_ls_recovery_stat_handler.cpp index bae3eb5f23..c9f87d0f52 100755 --- a/src/rootserver/ob_ls_recovery_stat_handler.cpp +++ b/src/rootserver/ob_ls_recovery_stat_handler.cpp @@ -196,7 +196,7 @@ int ObLSRecoveryStatHandler::increase_ls_replica_readable_scn_(SCN &readable_scn ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguments", KR(ret), K(readable_scn)); // scn get order: read_scn before replayable_scn before sync_scn - } else if (OB_FAIL(tenant_info_loader->get_replayable_scn(replayable_scn))) { + } else if (OB_FAIL(tenant_info_loader->get_global_replayable_scn(replayable_scn))) { LOG_WARN("failed to get replayable_scn", KR(ret)); } else if (OB_FAIL(ObLSServiceHelper::get_ls_replica_sync_scn(MTL_ID(), ls_->get_ls_id(), sync_scn))) { LOG_WARN("failed to get ls sync scn", KR(ret), "tenant_id", MTL_ID()); diff --git a/src/rootserver/ob_recovery_ls_service.cpp b/src/rootserver/ob_recovery_ls_service.cpp index 8d76eb47b5..f7467b33f0 100755 --- a/src/rootserver/ob_recovery_ls_service.cpp +++ b/src/rootserver/ob_recovery_ls_service.cpp @@ -483,8 +483,12 @@ int ObRecoveryLSService::process_ls_tx_log_(ObTxLogBlock &tx_log_block, const SC if (OB_FAIL(process_upgrade_log_(sync_scn, node))) { LOG_WARN("failed to process_upgrade_log_", KR(ret), K(node)); } - } else if (ObTxDataSourceType::LS_TABLE != node.get_data_source_type() - && ObTxDataSourceType::TRANSFER_TASK != node.get_data_source_type()) { + } else if (ObTxDataSourceType::STANDBY_UPGRADE_DATA_VERSION != + node.get_data_source_type() && + ObTxDataSourceType::LS_TABLE != + node.get_data_source_type() && + ObTxDataSourceType::TRANSFER_TASK != + node.get_data_source_type()) { // nothing } else if (! trans.is_started() && OB_FAIL(trans.start(proxy_, exec_tenant_id))) { LOG_WARN("failed to start trans", KR(ret), K(exec_tenant_id)); @@ -492,6 +496,11 @@ int ObRecoveryLSService::process_ls_tx_log_(ObTxLogBlock &tx_log_block, const SC //can not be there; } else if (OB_FAIL(check_valid_to_operator_ls_(sync_scn))) { LOG_WARN("failed to check valid to operator ls", KR(ret), K(sync_scn)); + } else if (ObTxDataSourceType::STANDBY_UPGRADE_DATA_VERSION == + node.get_data_source_type()) { + if (OB_FAIL(process_upgrade_data_version_log_(sync_scn, node, trans))) { + LOG_WARN("failed to process_upgrade_data_version_log_", KR(ret), K(node)); + } } else if (ObTxDataSourceType::TRANSFER_TASK == node.get_data_source_type()) { if (OB_FAIL(process_ls_transfer_task_in_trans_(node, sync_scn, trans))) { LOG_WARN("failed to process ls transfer task", KR(ret), K(node)); @@ -649,6 +658,47 @@ int ObRecoveryLSService::process_upgrade_log_( return ret; } +int ObRecoveryLSService::process_upgrade_data_version_log_( + const share::SCN &sync_scn, + const ObTxBufferNode &node, + common::ObMySQLTransaction &trans) +{ + int ret = OB_SUCCESS; + uint64_t standby_data_version = 0; + + if (!node.is_valid() || !sync_scn.is_valid() || !trans.is_started()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", KR(ret), K(node), K(sync_scn), "trans_started", + trans.is_started()); + } else { + ObStandbyUpgrade primary_data_version; + int64_t pos = 0; + if (OB_FAIL(primary_data_version.deserialize( + node.get_data_buf().ptr(), node.get_data_buf().length(), pos))) { + LOG_WARN("failed to deserialize", KR(ret), K(node), + KPHEX(node.get_data_buf().ptr(), node.get_data_buf().length())); + } else if (OB_UNLIKELY(pos > node.get_data_buf().length())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to get primary_data_version", KR(ret), K(pos), + K(node.get_data_buf().length())); + } else if (!primary_data_version.is_valid()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("primary_data_version not valid", KR(ret), K(primary_data_version)); + } else { + const uint64_t primary_data_version_value = primary_data_version.get_data_version(); + uint64_t exec_tenant_id = gen_meta_tenant_id(tenant_id_); + ObGlobalStatProxy stat_proxy(trans, exec_tenant_id); + if (OB_FAIL(stat_proxy.update_finish_data_version(primary_data_version_value, sync_scn))) { + LOG_WARN("fail to update finish_data_version", K(ret), K(tenant_id_), K(sync_scn), + K(primary_data_version_value)); + } + } + LOG_INFO("handle upgrade_data_version_log", KR(ret), K(tenant_id_), K(sync_scn), + K(primary_data_version)); + } + return ret; +} + int ObRecoveryLSService::get_min_data_version_(uint64_t &compatible) { int ret = OB_SUCCESS; diff --git a/src/rootserver/ob_recovery_ls_service.h b/src/rootserver/ob_recovery_ls_service.h index ac4a94247b..dac7f3cb4b 100755 --- a/src/rootserver/ob_recovery_ls_service.h +++ b/src/rootserver/ob_recovery_ls_service.h @@ -98,6 +98,9 @@ private: palf::PalfBufferIterator &iterator); int process_upgrade_log_(const share::SCN &sync_scn, const transaction::ObTxBufferNode &node); + int process_upgrade_data_version_log_(const share::SCN &sync_scn, + const transaction::ObTxBufferNode &node, + common::ObMySQLTransaction &trans); int process_gc_log_(logservice::ObGCLSLog &gc_log, const share::SCN &syn_scn); int process_ls_tx_log_(transaction::ObTxLogBlock &tx_log, diff --git a/src/rootserver/ob_system_admin_util.cpp b/src/rootserver/ob_system_admin_util.cpp index aff126ba1a..2d44a39374 100644 --- a/src/rootserver/ob_system_admin_util.cpp +++ b/src/rootserver/ob_system_admin_util.cpp @@ -1084,6 +1084,7 @@ int ObAdminSetConfig::update_config(obrpc::ObAdminSetConfigArg &arg, int64_t new ObConfigItem *ci = nullptr; // tenant not exist in RS, use SYS instead omt::ObTenantConfigGuard tenant_config(TENANT_CONF(OB_SYS_TENANT_ID)); + const ObString compatible_cfg(COMPATIBLE); if (!tenant_config.is_valid()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to get tenant config",K(tenant_id), KR(ret)); @@ -1100,6 +1101,12 @@ int ObAdminSetConfig::update_config(obrpc::ObAdminSetConfigArg &arg, int64_t new || OB_FAIL(dml.add_column("edit_level", ci->edit_level())) || OB_FAIL(dml.add_column("data_type", ci->data_type()))) { LOG_WARN("add column failed", KR(ret)); + } else if (0 == compatible_cfg.case_compare(item->name_.ptr())) { + if (OB_FAIL(update_config_for_compatible( + tenant_id, item, svr_ip, svr_port, table_name, dml, new_version))) { + LOG_WARN("fail to update compatible", KR(ret), K(tenant_id), + K(svr_ip), K(svr_port), K(table_name), K(new_version)); + } } else if (OB_FAIL(exec.exec_insert_update(table_name, dml, affected_rows))) { LOG_WARN("execute insert update failed", K(tenant_id), KR(ret), "item", *item); @@ -1190,6 +1197,110 @@ int ObAdminSetConfig::update_config(obrpc::ObAdminSetConfigArg &arg, int64_t new return ret; } +int ObAdminSetConfig::update_config_for_compatible(const uint64_t tenant_id, + const obrpc::ObAdminSetConfigItem *item, + const char *svr_ip, const int64_t svr_port, + const char *table_name, + share::ObDMLSqlSplicer &dml, + const int64_t new_version) +{ + int ret = OB_SUCCESS; + bool need_to_update = true; + const uint64_t exec_tenant_id = gen_meta_tenant_id(tenant_id); + ObMySQLTransaction trans; + if (OB_ISNULL(item) || OB_ISNULL(svr_ip) || OB_ISNULL(table_name)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid args", K(tenant_id), K(item), K(svr_ip), K(svr_port), + K(table_name), K(new_version)); + } else if (OB_FAIL(trans.start(ctx_.sql_proxy_, exec_tenant_id))) { + LOG_WARN("fail to start trans", KR(ret), K(exec_tenant_id)); + } else { + SMART_VAR(ObMySQLProxy::MySQLResult, res) { + ObSqlString sql_string; + sqlclient::ObMySQLResult *result = NULL; + if (OB_FAIL(sql_string.assign_fmt( + "SELECT value as compatible FROM %s WHERE tenant_id = %lu " + "and " + "zone = '%s' and svr_type = '%s' and svr_ip = '%s' " + "and " + "svr_port = %ld and name = '%s' FOR UPDATE", + table_name, tenant_id, item->zone_.ptr(), + print_server_role(OB_SERVER), svr_ip, svr_port, COMPATIBLE))) { + LOG_WARN("assign sql string failed", K(ret)); + } else if (OB_FAIL(trans.read(res, exec_tenant_id, sql_string.ptr()))) { + LOG_WARN("fail to execute sql", K(ret), K(exec_tenant_id), + K(sql_string)); + } else if (OB_ISNULL(result = res.get_result())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get sql result", K(ret), KP(result)); + } else { + if (OB_FAIL(result->next())) { + if (OB_ITER_END == ret) { + ret = OB_SUCCESS; + } else { + LOG_WARN("get result next failed", KR(ret), K(sql_string)); + } + } else { + ObString old_compatible_str; + uint64_t old_compatible_val = 0; + uint64_t new_compatible_val = 0; + EXTRACT_VARCHAR_FIELD_MYSQL(*result, "compatible", + old_compatible_str); + if (OB_FAIL(ret)) { + LOG_WARN("failed to get result", KR(ret), K(sql_string)); + } else if (OB_FAIL(ObClusterVersion::get_version( + old_compatible_str, old_compatible_val))) { + LOG_WARN("parse version failed", KR(ret), K(old_compatible_str)); + } else if (OB_FAIL(ObClusterVersion::get_version( + item->value_.ptr(), new_compatible_val))) { + LOG_WARN("parse version failed", KR(ret), K(item->value_.ptr())); + } else if (new_compatible_val <= old_compatible_val) { + need_to_update = false; + LOG_INFO("[COMPATIBLE] [DATA_VERSION] no need to update", + K(tenant_id), K(old_compatible_val), + K(new_compatible_val)); + } + } + } + } + } + if (OB_SUCC(ret) && need_to_update) { + int64_t affected_rows = 0; + ObDMLExecHelper exec(trans, exec_tenant_id); + if (OB_FAIL(exec.exec_insert_update(table_name, dml, affected_rows))) { + LOG_WARN("execute insert update failed", K(tenant_id), KR(ret), "item", + *item); + } else if (is_zero_row(affected_rows) || affected_rows > 2) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unexpected affected rows", K(tenant_id), K(affected_rows), + KR(ret)); + } else { + // set config_version to config_version_map and trigger parameter update + if (ObAdminSetConfig::OB_PARAMETER_SEED_ID == tenant_id) { + } else if (OB_FAIL(OTC_MGR.set_tenant_config_version(tenant_id, + new_version))) { + LOG_WARN("failed to set tenant config version", K(tenant_id), KR(ret), + "item", *item); + } else if (GCTX.omt_->has_tenant(tenant_id) && + OB_FAIL(OTC_MGR.got_version(tenant_id, new_version))) { + LOG_WARN("failed to got version", K(tenant_id), KR(ret), "item", *item); + } else { + LOG_INFO("got new tenant config version", K(new_version), K(tenant_id), + "item", *item); + } + } + } + if (trans.is_started()) { + int tmp_ret = OB_SUCCESS; + if (OB_TMP_FAIL(trans.end(OB_SUCC(ret)))) { + LOG_WARN("trans end failed", KR(tmp_ret), K(ret)); + ret = OB_SUCC(ret) ? tmp_ret : ret; + } + } + + return ret; +} + int ObAdminSetConfig::execute(obrpc::ObAdminSetConfigArg &arg) { LOG_INFO("execute set config request", K(arg)); diff --git a/src/rootserver/ob_system_admin_util.h b/src/rootserver/ob_system_admin_util.h index 2759355051..898e681d6e 100644 --- a/src/rootserver/ob_system_admin_util.h +++ b/src/rootserver/ob_system_admin_util.h @@ -349,6 +349,13 @@ private: private: int verify_config(obrpc::ObAdminSetConfigArg &arg); int update_config(obrpc::ObAdminSetConfigArg &arg, int64_t new_version); + int update_config_for_compatible(const uint64_t tenant_id, + const obrpc::ObAdminSetConfigItem *item, + const char *svr_ip, const int64_t svr_port, + const char *table_name, + share::ObDMLSqlSplicer &dml, + const int64_t new_version); + private: DISALLOW_COPY_AND_ASSIGN(ObAdminSetConfig); }; diff --git a/src/rootserver/ob_tenant_info_loader.cpp b/src/rootserver/ob_tenant_info_loader.cpp index 9bd38d0dbf..66cd627f5d 100644 --- a/src/rootserver/ob_tenant_info_loader.cpp +++ b/src/rootserver/ob_tenant_info_loader.cpp @@ -16,6 +16,7 @@ #include "share/rc/ob_tenant_base.h" // MTL_ID #include "share/scn.h"//SCN #include "share/ob_all_server_tracer.h" // ObAllServerTracer +#include "share/ob_global_stat_proxy.h" #include "observer/ob_server_struct.h" // GCTX #include "rootserver/ob_tenant_info_loader.h" #include "rootserver/ob_rs_async_rpc_proxy.h" @@ -312,6 +313,8 @@ void ObTenantInfoLoader::broadcast_tenant_info_content_() share::ObAllTenantInfo tenant_info; int64_t last_sql_update_time = OB_INVALID_TIMESTAMP; int64_t ora_rowscn = 0; + uint64_t finish_data_version = 0; + share::SCN data_version_barrier_scn; if (IS_NOT_INIT) { ret = OB_NOT_INIT; @@ -324,28 +327,53 @@ void ObTenantInfoLoader::broadcast_tenant_info_content_() *GCTX.srv_rpc_proxy_, &obrpc::ObSrvRpcProxy::update_tenant_info_cache); int64_t rpc_count = 0; - if (OB_FAIL(tenant_info_cache_.get_tenant_info(tenant_info, last_sql_update_time, ora_rowscn))) { + if (OB_FAIL(tenant_info_cache_.get_tenant_info(tenant_info, last_sql_update_time, ora_rowscn, finish_data_version, data_version_barrier_scn))) { LOG_WARN("failed to get tenant info", KR(ret)); - } else if (OB_FAIL(share::ObAllServerTracer::get_instance().for_each_server_info( - [&rpc_count, &tenant_info, &proxy, ora_rowscn](const share::ObServerInfoInTable &server_info) -> int { - int ret = OB_SUCCESS; - obrpc::ObUpdateTenantInfoCacheArg arg; - if (!server_info.is_valid()) { - LOG_WARN("skip invalid server_info", KR(ret), K(server_info)); - } else if (!server_info.is_alive()) { - //not send to alive - } else if (OB_FAIL(arg.init(tenant_info.get_tenant_id(), tenant_info, ora_rowscn))) { - LOG_WARN("failed to init arg", KR(ret), K(tenant_info), K(ora_rowscn)); - // use meta rpc process thread - } else if (OB_FAIL(proxy.call(server_info.get_server(), DEFAULT_TIMEOUT_US, gen_meta_tenant_id(tenant_info.get_tenant_id()), arg))) { - LOG_WARN("failed to send rpc", KR(ret), K(server_info), K(tenant_info), K(arg)); - } else { - rpc_count++; - } + } else { + struct UpdateTenantInfoCacheFunc { + int64_t &rpc_count; + share::ObAllTenantInfo &tenant_info; + ObUpdateTenantInfoCacheProxy &proxy; + int64_t ora_rowscn; + uint64_t finish_data_version; + share::SCN data_version_barrier_scn; - return ret; - }))) { - LOG_WARN("for each server_info failed", KR(ret)); + UpdateTenantInfoCacheFunc(int64_t &rpc_count, share::ObAllTenantInfo &tenant_info, + ObUpdateTenantInfoCacheProxy &proxy, int64_t ora_rowscn, + uint64_t finish_data_version, share::SCN data_version_barrier_scn) + : rpc_count(rpc_count), tenant_info(tenant_info), proxy(proxy), ora_rowscn(ora_rowscn), + finish_data_version(finish_data_version), + data_version_barrier_scn(data_version_barrier_scn) + { + } + + int operator()(const share::ObServerInfoInTable &server_info) + { + int ret = OB_SUCCESS; + obrpc::ObUpdateTenantInfoCacheArg arg; + if (!server_info.is_valid()) { + LOG_WARN("skip invalid server_info", KR(ret), K(server_info)); + } else if (!server_info.is_alive()) { + // not send to alive + } else if (OB_FAIL(arg.init(tenant_info.get_tenant_id(), tenant_info, ora_rowscn, + finish_data_version, data_version_barrier_scn))) { + LOG_WARN("failed to init arg", KR(ret), K(tenant_info), K(ora_rowscn)); + // use meta rpc process thread + } else if (OB_FAIL(proxy.call(server_info.get_server(), DEFAULT_TIMEOUT_US, + gen_meta_tenant_id(tenant_info.get_tenant_id()), arg))) { + LOG_WARN("failed to send rpc", KR(ret), K(server_info), K(tenant_info), K(arg)); + } else { + rpc_count++; + } + return ret; + } + }; + ObFunction functor( + UpdateTenantInfoCacheFunc(rpc_count, tenant_info, proxy, ora_rowscn, finish_data_version, + data_version_barrier_scn)); + if (OB_FAIL(share::ObAllServerTracer::get_instance().for_each_server_info(functor))) { + LOG_WARN("for each server_info failed", KR(ret)); + } } int tmp_ret = OB_SUCCESS; @@ -467,7 +495,7 @@ int ObTenantInfoLoader::check_is_primary_normal_status(bool &is_primary_normal_s return ret; } -int ObTenantInfoLoader::get_replayable_scn(share::SCN &replayable_scn) +int ObTenantInfoLoader::get_global_replayable_scn(share::SCN &replayable_scn) { int ret = OB_SUCCESS; replayable_scn.set_min(); @@ -488,6 +516,33 @@ int ObTenantInfoLoader::get_replayable_scn(share::SCN &replayable_scn) return ret; } +int ObTenantInfoLoader::get_local_replayable_scn(share::SCN &replayable_scn) +{ + int ret = OB_SUCCESS; + replayable_scn.set_min(); + share::ObTenantRole::Role tenant_role = MTL_GET_TENANT_ROLE_CACHE(); + + if (OB_FAIL(get_global_replayable_scn(replayable_scn))) { + LOG_WARN("failed to get replayable scn", KR(ret)); + } else if (!is_primary_tenant(tenant_role)) { + bool is_data_version_crossed = false; + share::SCN data_version_barrier_scn; + if (OB_FAIL(tenant_info_cache_.is_data_version_crossed(is_data_version_crossed, + data_version_barrier_scn))) { + LOG_WARN("failed to get is_data_version_crossed", KR(ret)); + } else if (is_data_version_crossed) { + + } else if (!data_version_barrier_scn.is_valid_and_not_min()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("data_version_barrier_scn is invalid", K(ret), K(data_version_barrier_scn)); + } else { + replayable_scn = data_version_barrier_scn; + } + } + + return ret; +} + int ObTenantInfoLoader::get_sync_scn(share::SCN &sync_scn) { int ret = OB_SUCCESS; @@ -546,14 +601,19 @@ int ObTenantInfoLoader::refresh_tenant_info() return ret; } -int ObTenantInfoLoader::update_tenant_info_cache(const int64_t new_ora_rowscn, const ObAllTenantInfo &new_tenant_info) +int ObTenantInfoLoader::update_tenant_info_cache(const int64_t new_ora_rowscn, + const ObAllTenantInfo &new_tenant_info, + const uint64_t new_finish_data_version, + const share::SCN &new_data_version_barrier_scn) { int ret = OB_SUCCESS; bool refreshed = false; if (IS_NOT_INIT) { ret = OB_NOT_INIT; LOG_WARN("not init", KR(ret)); - } else if (OB_FAIL(tenant_info_cache_.update_tenant_info_cache(new_ora_rowscn, new_tenant_info, refreshed))) { + } else if (OB_FAIL(tenant_info_cache_.update_tenant_info_cache( + new_ora_rowscn, new_tenant_info, new_finish_data_version, + new_data_version_barrier_scn, refreshed))) { LOG_WARN("failed to update_tenant_info_cache", KR(ret), K(new_ora_rowscn), K(new_tenant_info)); } else if (refreshed) { (void)ATOMIC_AAF(&rpc_update_times_, 1); @@ -565,7 +625,10 @@ int ObTenantInfoLoader::update_tenant_info_cache(const int64_t new_ora_rowscn, c DEFINE_TO_YSON_KV(ObAllTenantInfoCache, OB_ID(tenant_info), tenant_info_, OB_ID(last_sql_update_time), last_sql_update_time_, - OB_ID(ora_rowscn), ora_rowscn_); + OB_ID(ora_rowscn), ora_rowscn_, + OB_ID(is_data_version_crossed), is_data_version_crossed_, + OB_ID(finish_data_version), finish_data_version_, + OB_ID(data_version_barrier_scn), data_version_barrier_scn_); void ObAllTenantInfoCache::reset() { @@ -573,6 +636,11 @@ void ObAllTenantInfoCache::reset() tenant_info_.reset(); last_sql_update_time_ = OB_INVALID_TIMESTAMP; ora_rowscn_ = 0; + is_data_version_crossed_ = false; + // finish_data_version and data_version_barrier_scn_ may be 0 and min_value for a long time, + // until the data_version barrier log is iterated + finish_data_version_ = 0; + data_version_barrier_scn_.set_min(); } ERRSIM_POINT_DEF(ERRSIM_UPDATE_TENANT_INFO_CACHE_ERROR); @@ -583,6 +651,8 @@ int ObAllTenantInfoCache::refresh_tenant_info(const uint64_t tenant_id, int ret = OB_SUCCESS; ObAllTenantInfo new_tenant_info; int64_t ora_rowscn = 0; + uint64_t finish_data_version = 0; + share::SCN data_version_barrier_scn; const int64_t new_refresh_time_us = ObClockGenerator::getClock(); content_changed = false; if (OB_ISNULL(sql_proxy) || !is_user_tenant(tenant_id)) { @@ -594,6 +664,8 @@ int ObAllTenantInfoCache::refresh_tenant_info(const uint64_t tenant_id, } else if (INT64_MAX == ora_rowscn || 0 == ora_rowscn) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("invalid ora_rowscn", KR(ret), K(ora_rowscn), K(tenant_id), K(new_tenant_info), K(lbt())); + } else if (OB_FAIL(query_new_finish_data_version_(tenant_id, sql_proxy, finish_data_version, data_version_barrier_scn))) { + LOG_WARN("failed to query new finish data version", KR(ret), K(tenant_id)); } else { /** * Only need to refer to tenant role, no need to refer to switchover status. @@ -606,11 +678,10 @@ int ObAllTenantInfoCache::refresh_tenant_info(const uint64_t tenant_id, if (OB_UNLIKELY(ERRSIM_UPDATE_TENANT_INFO_CACHE_ERROR)) { ret = ERRSIM_UPDATE_TENANT_INFO_CACHE_ERROR; } else if (ora_rowscn >= ora_rowscn_) { - if (ora_rowscn > ora_rowscn_) { - MTL_SET_TENANT_ROLE_CACHE(new_tenant_info.get_tenant_role().value()); - (void)tenant_info_.assign(new_tenant_info); - ora_rowscn_ = ora_rowscn; - content_changed = true; + if (OB_FAIL(assign_new_tenant_info_(ora_rowscn, new_tenant_info, finish_data_version, + data_version_barrier_scn, content_changed))) { + LOG_WARN("failed to assign new tenant info", KR(ret), K(ora_rowscn), K(new_tenant_info), + K(finish_data_version), K(data_version_barrier_scn)); } // In order to provide sts an accurate time of tenant info refresh time, it is necessary to // update last_sql_update_time_ after sql refresh @@ -624,41 +695,171 @@ int ObAllTenantInfoCache::refresh_tenant_info(const uint64_t tenant_id, if (dump_tenant_info_interval_.reach()) { LOG_INFO("refresh tenant info", KR(ret), K(new_tenant_info), K(new_refresh_time_us), - K(tenant_id), K(tenant_info_), K(last_sql_update_time_), K(ora_rowscn_)); + K(tenant_id), K(tenant_info_), K(last_sql_update_time_), + K(ora_rowscn_), K(content_changed)); } return ret; } -int ObAllTenantInfoCache::update_tenant_info_cache( - const int64_t new_ora_rowscn, - const ObAllTenantInfo &new_tenant_info, - bool &refreshed) +int ObAllTenantInfoCache::update_tenant_info_cache(const int64_t new_ora_rowscn, + const ObAllTenantInfo &new_tenant_info, + const uint64_t new_finish_data_version, + const share::SCN &new_data_version_barrier_scn, + bool &refreshed) { int ret = OB_SUCCESS; refreshed = false; - if (!new_tenant_info.is_valid() || 0 == new_ora_rowscn || INT64_MAX == new_ora_rowscn) { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("invalid argument", KR(ret), K(new_tenant_info), K(new_ora_rowscn)); + SpinWLockGuard guard(lock_); + if (!is_tenant_info_valid_()) { + ret = OB_EAGAIN; + LOG_WARN("my tenant_info is invalid, don't refresh", KR(ret), K_(tenant_info), K_(ora_rowscn)); } else if (OB_UNLIKELY(ERRSIM_UPDATE_TENANT_INFO_CACHE_ERROR)) { ret = ERRSIM_UPDATE_TENANT_INFO_CACHE_ERROR; - } else { - SpinWLockGuard guard(lock_); - if (!tenant_info_.is_valid() || 0 == ora_rowscn_) { - ret = OB_EAGAIN; - LOG_WARN("my tenant_info is invalid, don't refresh", KR(ret), K_(tenant_info), K_(ora_rowscn)); - } else if (new_ora_rowscn > ora_rowscn_) { - MTL_SET_TENANT_ROLE_CACHE(new_tenant_info.get_tenant_role().value()); - (void)tenant_info_.assign(new_tenant_info); - ora_rowscn_ = new_ora_rowscn; - refreshed = true; - LOG_TRACE("refresh_tenant_info_content", K(new_tenant_info), K(new_ora_rowscn), K(tenant_info_), K(ora_rowscn_)); + } else if (OB_FAIL(assign_new_tenant_info_(new_ora_rowscn, new_tenant_info, + new_finish_data_version, new_data_version_barrier_scn, + refreshed))) { + LOG_WARN("failed to assign new tenant info", KR(ret), K(new_ora_rowscn), K(new_tenant_info), + K(new_finish_data_version), K(new_data_version_barrier_scn)); + } + + return ret; +} + +// caller should acquire lock before call this function +bool ObAllTenantInfoCache::is_tenant_info_valid_() +{ + return tenant_info_.is_valid() && OB_INVALID_TIMESTAMP != last_sql_update_time_ && + 0 != ora_rowscn_; +} + +// caller should acquire lock before call this function +int ObAllTenantInfoCache::assign_new_tenant_info_( + const int64_t new_ora_rowscn, + const ObAllTenantInfo &new_tenant_info, + const uint64_t new_finish_data_version, + const share::SCN &new_data_version_barrier_scn, + bool &assigned) +{ + int ret = OB_SUCCESS; + assigned = false; + + if (0 == new_ora_rowscn || INT64_MAX == new_ora_rowscn || !new_tenant_info.is_valid() || + !new_data_version_barrier_scn.is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", KR(ret), K(new_ora_rowscn), K(new_tenant_info), + K(new_finish_data_version), K(new_data_version_barrier_scn)); + } else if (new_ora_rowscn > ora_rowscn_) { + MTL_SET_TENANT_ROLE_CACHE(new_tenant_info.get_tenant_role().value()); + (void)tenant_info_.assign(new_tenant_info); + ora_rowscn_ = new_ora_rowscn; + assigned = true; + LOG_TRACE("assign new tenant info", K(new_tenant_info), K(new_ora_rowscn), K(tenant_info_), + K(ora_rowscn_)); + if (new_finish_data_version > finish_data_version_) { + finish_data_version_ = new_finish_data_version; + data_version_barrier_scn_ = new_data_version_barrier_scn; + is_data_version_crossed_ = false; + LOG_INFO("update finish data version cache", K(finish_data_version_), + K(data_version_barrier_scn_)); } } return ret; } +int ObAllTenantInfoCache::query_new_finish_data_version_(const uint64_t tenant_id, + common::ObMySQLProxy *sql_proxy, + uint64_t &finish_data_version, + share::SCN &data_version_barrier_scn) +{ + int ret = OB_SUCCESS; + uint64_t exec_tenant_id = gen_meta_tenant_id(tenant_id); + finish_data_version = 0; + data_version_barrier_scn.set_min(); + + if (OB_ISNULL(sql_proxy)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("sql proxy is null", KR(ret), K(tenant_id), K(sql_proxy)); + } else { + ObGlobalStatProxy proxy(*sql_proxy, exec_tenant_id); + if (OB_FAIL(proxy.get_finish_data_version(finish_data_version, data_version_barrier_scn))) { + if (OB_ERR_NULL_VALUE == ret) { + // have not iterated over the barrier log + finish_data_version = 0; + data_version_barrier_scn.set_min(); + ret = OB_SUCCESS; + } else { + LOG_WARN("fail to get finish data version", KR(ret), K(exec_tenant_id)); + } + } + } + + return ret; +} + +ERRSIM_POINT_DEF(ERRSIM_DATA_VERSION_BARRIER_ERROR); +int ObAllTenantInfoCache::is_data_version_crossed(bool &result, + share::SCN &data_version_barrier_scn) +{ + int ret = OB_SUCCESS; + uint64_t current_data_version = 0; + result = false; + data_version_barrier_scn.set_min(); + SpinRLockGuard guard(lock_); + + if (!is_tenant_info_valid_()) { + ret = OB_NEED_WAIT; + const int64_t PRINT_INTERVAL = 1 * 1000 * 1000L; + if (REACH_TIME_INTERVAL(PRINT_INTERVAL)) { + LOG_WARN("finish_data_version is invalid, need wait", KR(ret), K(*this)); + } + } else if (is_data_version_crossed_) { + result = true; + } else if (OB_FAIL(GET_MIN_DATA_VERSION(MTL_ID(), current_data_version))) { + LOG_WARN("failed to get min data version", KR(ret)); + } else if (current_data_version < finish_data_version_ || ERRSIM_DATA_VERSION_BARRIER_ERROR) { + result = false; + data_version_barrier_scn = data_version_barrier_scn_; + LOG_INFO("local data version has not crossed", KR(ret), K(data_version_barrier_scn), + "has_injected_error", ERRSIM_DATA_VERSION_BARRIER_ERROR); + } else { + result = true; + is_data_version_crossed_ = true; + } + + return ret; +} + +int ObAllTenantInfoCache::get_tenant_info(share::ObAllTenantInfo &tenant_info, + int64_t &last_sql_update_time, + int64_t &ora_rowscn, + uint64_t &finish_data_version, + share::SCN &data_version_barrier_scn) +{ + int ret = OB_SUCCESS; + tenant_info.reset(); + last_sql_update_time = OB_INVALID_TIMESTAMP; + ora_rowscn = 0; + SpinRLockGuard guard(lock_); + + if (!is_tenant_info_valid_()) { + ret = OB_NEED_WAIT; + const int64_t PRINT_INTERVAL = 1 * 1000 * 1000L; + if (REACH_TIME_INTERVAL(PRINT_INTERVAL)) { + LOG_WARN("tenant info is invalid, need wait", KR(ret), K(last_sql_update_time_), + K(tenant_info_), K(ora_rowscn_), K(data_version_barrier_scn_)); + } + } else { + (void)tenant_info.assign(tenant_info_); + last_sql_update_time = last_sql_update_time_; + ora_rowscn = ora_rowscn_; + finish_data_version = finish_data_version_; + data_version_barrier_scn = data_version_barrier_scn_; + } + return ret; +} + int ObAllTenantInfoCache::get_tenant_info( share::ObAllTenantInfo &tenant_info, int64_t &last_sql_update_time, @@ -668,18 +869,12 @@ int ObAllTenantInfoCache::get_tenant_info( tenant_info.reset(); last_sql_update_time = OB_INVALID_TIMESTAMP; ora_rowscn = 0; - SpinRLockGuard guard(lock_); + uint64_t finish_data_version = 0; + share::SCN data_version_barrier_scn; - if (!tenant_info_.is_valid() || OB_INVALID_TIMESTAMP == last_sql_update_time_ || 0 == ora_rowscn_) { - ret = OB_NEED_WAIT; - const int64_t PRINT_INTERVAL = 1 * 1000 * 1000L; - if (REACH_TIME_INTERVAL(PRINT_INTERVAL)) { - LOG_WARN("tenant info is invalid, need wait", KR(ret), K(last_sql_update_time_), K(tenant_info_), K(ora_rowscn_)); - } - } else { - (void)tenant_info.assign(tenant_info_); - last_sql_update_time = last_sql_update_time_; - ora_rowscn = ora_rowscn_; + if (OB_FAIL(get_tenant_info(tenant_info, last_sql_update_time, ora_rowscn, finish_data_version, + data_version_barrier_scn))) { + LOG_WARN("failed to get tenant info", KR(ret)); } return ret; } @@ -690,8 +885,11 @@ int ObAllTenantInfoCache::get_tenant_info(share::ObAllTenantInfo &tenant_info) tenant_info.reset(); int64_t last_sql_update_time = OB_INVALID_TIMESTAMP; int64_t ora_rowscn = 0; + uint64_t finish_data_version = 0; + share::SCN data_version_barrier_scn; - if (OB_FAIL(get_tenant_info(tenant_info, last_sql_update_time, ora_rowscn))) { + if (OB_FAIL(get_tenant_info(tenant_info, last_sql_update_time, ora_rowscn, finish_data_version, + data_version_barrier_scn))) { LOG_WARN("failed to get tenant info", KR(ret)); } return ret; diff --git a/src/rootserver/ob_tenant_info_loader.h b/src/rootserver/ob_tenant_info_loader.h index 3e9ada2d02..653c673afe 100644 --- a/src/rootserver/ob_tenant_info_loader.h +++ b/src/rootserver/ob_tenant_info_loader.h @@ -40,19 +40,39 @@ public: tenant_info_(), last_sql_update_time_(OB_INVALID_TIMESTAMP), dump_tenant_info_interval_(DUMP_TENANT_INFO_INTERVAL), - ora_rowscn_(0) {} + ora_rowscn_(0), + is_data_version_crossed_(false), + finish_data_version_(0) + { + data_version_barrier_scn_.set_min(); + } ~ObAllTenantInfoCache() {} int get_tenant_info(share::ObAllTenantInfo &tenant_info); int get_tenant_info(share::ObAllTenantInfo &tenant_info, int64_t &last_sql_update_time, int64_t &ora_rowscn); + int get_tenant_info(share::ObAllTenantInfo &tenant_info, + int64_t &last_sql_update_time, int64_t &ora_rowscn, + uint64_t &finish_data_version, share::SCN &data_version_barrier_scn); int refresh_tenant_info(const uint64_t tenant_id, common::ObMySQLProxy *sql_proxy, bool &content_changed); void reset(); void set_refresh_interval_for_sts(); - int update_tenant_info_cache(const int64_t new_ora_rowscn, const ObAllTenantInfo &new_tenant_info, bool &refreshed); + int update_tenant_info_cache(const int64_t new_ora_rowscn, const ObAllTenantInfo &new_tenant_info, + const uint64_t new_finish_data_version, + const share::SCN &new_data_version_barrier_scn, bool &refreshed); + int is_data_version_crossed(bool &is_data_version_crossed, share::SCN &data_version_barrier_scn); + private: + bool is_tenant_info_valid_(); + int assign_new_tenant_info_(const int64_t new_ora_rowscn, const ObAllTenantInfo &new_tenant_info, + const uint64_t new_finish_data_version, + const share::SCN &new_data_version_barrier_scn, bool &assigned); + int query_new_finish_data_version_(const uint64_t tenant_id, common::ObMySQLProxy *sql_proxy, + uint64_t &finish_data_version, + share::SCN &data_version_barrier_scn); const static int64_t DUMP_TENANT_INFO_INTERVAL = 3 * 1000 * 1000; // 3s public: - TO_STRING_KV(K_(last_sql_update_time), K_(tenant_info), K_(ora_rowscn)); + TO_STRING_KV(K_(last_sql_update_time), K_(tenant_info), K_(ora_rowscn), + K_(is_data_version_crossed), K_(finish_data_version), K_(data_version_barrier_scn)); DECLARE_TO_YSON_KV; private: @@ -61,6 +81,9 @@ private: int64_t last_sql_update_time_; common::ObTimeInterval dump_tenant_info_interval_; int64_t ora_rowscn_; + bool is_data_version_crossed_; + uint64_t finish_data_version_; + share::SCN data_version_barrier_scn_; DISALLOW_COPY_AND_ASSIGN(ObAllTenantInfoCache); }; @@ -114,13 +137,25 @@ public: /** * @description: - * get tenant replayable_scn. + * get tenant's global replayable_scn. * for SYS/META tenant: there isn't replayable_scn - * for user tenant: get replayable_scn from __all_tenant_info cache + * for user tenant: get replayable_scn for tenant, which is directly retrieved from + * __all_tenant_info cache * @param[out] replayable_scn */ - int get_replayable_scn(share::SCN &replayable_scn); + int get_global_replayable_scn(share::SCN &replayable_scn); + /** + * @description: + * get tenant's local replayable_scn. + * for SYS/META tenant: there isn't replayable_scn + * for user tenant: get replayable_scn for current machine, which may be smaller than the + * global replayable_scn if current machine's data version has been synced + * by using this interface, we can ensure the log stream will never replay new version log in + * old data version + * @param[out] replayable_scn + */ + int get_local_replayable_scn(share::SCN &replayable_scn); /** * @description: * get tenant sync_scn. @@ -158,7 +193,9 @@ public: int check_is_primary_normal_status(bool &is_primary_normal_status); int refresh_tenant_info(); - int update_tenant_info_cache(const int64_t new_ora_rowscn, const ObAllTenantInfo &new_tenant_info); + int update_tenant_info_cache(const int64_t new_ora_rowscn, const ObAllTenantInfo &new_tenant_info, + const uint64_t new_finish_data_version, + const share::SCN &new_data_version_barrier_scn); bool need_refresh(const int64_t refresh_time_interval_us); int get_max_ls_id(uint64_t &tenant_id, ObLSID &max_ls_id); diff --git a/src/rootserver/ob_upgrade_executor.cpp b/src/rootserver/ob_upgrade_executor.cpp index c55bef136b..12176f3ef2 100644 --- a/src/rootserver/ob_upgrade_executor.cpp +++ b/src/rootserver/ob_upgrade_executor.cpp @@ -1077,9 +1077,9 @@ int ObUpgradeExecutor::run_upgrade_all_post_action_( start_idx, end_idx))) { LOG_WARN("fail to get processor by version", KR(ret), K(current_data_version)); } + int64_t version = OB_INVALID_VERSION; for (int64_t i = start_idx + 1; OB_SUCC(ret) && i <= end_idx; i++) { ObBaseUpgradeProcessor *processor = NULL; - int64_t version = OB_INVALID_VERSION; if (OB_FAIL(check_stop())) { LOG_WARN("executor should stopped", KR(ret)); } else if (OB_FAIL(upgrade_processors_.get_processor_by_idx(i, processor))) { @@ -1092,14 +1092,49 @@ int ObUpgradeExecutor::run_upgrade_all_post_action_( LOG_WARN("run post upgrade by version failed", KR(ret), K(tenant_id), K(version)); } else if (OB_FAIL(check_schema_sync_(tenant_id))) { LOG_WARN("fail to check schema sync", KR(ret), K(tenant_id)); - } else if (OB_FAIL(proxy.update_current_data_version(version))) { - LOG_WARN("fail to update current data version", KR(ret), K(tenant_id), K(version)); + } else if (i < end_idx) { + if (OB_FAIL(proxy.update_current_data_version(version))) { + LOG_WARN("fail to update current data version", KR(ret), K(tenant_id), K(version)); + } + } else if (OB_FAIL(update_final_current_data_version_(tenant_id, version))) { + LOG_WARN("fail to update final current data version", KR(ret), K(tenant_id), K(version)); } } // end for } return ret; } +// for the final version, we need to write a data version barrier log when updating the +// current_data_version +int ObUpgradeExecutor::update_final_current_data_version_(const uint64_t tenant_id, + const int64_t version) +{ + int ret = OB_SUCCESS; + + ObMySQLTransaction trans; + if (OB_FAIL(trans.start(sql_proxy_, tenant_id))) { + LOG_WARN("fail to start trans", KR(ret), K(tenant_id)); + } else { + ObGlobalStatProxy end_proxy(trans, tenant_id); + if (OB_FAIL(end_proxy.update_current_data_version(version))) { + LOG_WARN("fail to update current data version", KR(ret), K(tenant_id), K(version)); + } else if (is_user_tenant(tenant_id) && + OB_FAIL(OB_PRIMARY_STANDBY_SERVICE.write_upgrade_data_version_barrier_log( + trans, tenant_id, version))) { + LOG_WARN("fail to write_upgrade_data_version_barrier_log", KR(ret), K(tenant_id), K(version)); + } + } + if (trans.is_started()) { + int tmp_ret = OB_SUCCESS; + if (OB_TMP_FAIL(trans.end(OB_SUCC(ret)))) { + LOG_WARN("trans end failed", KR(tmp_ret), K(ret)); + ret = OB_SUCC(ret) ? tmp_ret : ret; + } + } + + return ret; +} + int ObUpgradeExecutor::run_upgrade_inspection_job_( const common::ObIArray &tenant_ids) { diff --git a/src/rootserver/ob_upgrade_executor.h b/src/rootserver/ob_upgrade_executor.h index df95624e15..e457da8246 100644 --- a/src/rootserver/ob_upgrade_executor.h +++ b/src/rootserver/ob_upgrade_executor.h @@ -94,6 +94,7 @@ private: int upgrade_oracle_system_package_job_(); #endif int run_upgrade_all_post_action_(const uint64_t tenant_id); + int update_final_current_data_version_(const uint64_t tenant_id, const int64_t version); int run_upgrade_end_action_(const uint64_t tenant_id); int check_schema_sync_(const uint64_t tenant_id); diff --git a/src/share/backup/ob_log_restore_config.cpp b/src/share/backup/ob_log_restore_config.cpp index 1e49a56583..08b73f63b8 100644 --- a/src/share/backup/ob_log_restore_config.cpp +++ b/src/share/backup/ob_log_restore_config.cpp @@ -225,6 +225,7 @@ int ObLogRestoreSourceServiceConfigParser::check_before_update_inner_config( int ret = OB_SUCCESS; compat_mode = ObCompatibilityMode::OCEANBASE_MODE; bool source_is_self = false; + bool cluster_id_dup = false; SMART_VAR(ObLogRestoreProxyUtil, proxy) { if (is_empty_) { @@ -236,6 +237,14 @@ int ObLogRestoreSourceServiceConfigParser::check_before_update_inner_config( ret = OB_OP_NOT_ALLOW; LOG_WARN("set tenant itself as log restore source is not allowed"); LOG_USER_ERROR(OB_OP_NOT_ALLOW, "set tenant itself as log restore source is"); + } else if (!for_verify && OB_FAIL(proxy.check_different_cluster_with_same_cluster_id( + service_attr_.user_.cluster_id_, cluster_id_dup))) { + LOG_WARN("fail to check different cluster with same cluster id", KR(ret), + K(service_attr_.user_.cluster_id_)); + } else if (cluster_id_dup) { + ret = OB_OP_NOT_ALLOW; + LOG_WARN("different cluster with same cluster id is not allowed"); + LOG_USER_ERROR(OB_OP_NOT_ALLOW, "different cluster with same cluster id is"); } else if (OB_FAIL(proxy.get_compatibility_mode(service_attr_.user_.tenant_id_, service_attr_.user_.mode_))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("get primary compatibility mode failed", K(tenant_id_), K(service_attr_.user_.tenant_id_)); diff --git a/src/share/config/ob_common_config.cpp b/src/share/config/ob_common_config.cpp index bdee8f3e81..22392f0118 100644 --- a/src/share/config/ob_common_config.cpp +++ b/src/share/config/ob_common_config.cpp @@ -317,6 +317,7 @@ int ObCommonConfig::add_extra_config(const char *config_str, const ObString external_kms_info_cfg(EXTERNAL_KMS_INFO); const ObString ssl_external_kms_info_cfg(SSL_EXTERNAL_KMS_INFO); const ObString compatible_cfg(COMPATIBLE); + const ObString enable_compatible_monotonic_cfg(ENABLE_COMPATIBLE_MONOTONIC); auto func = [&]() { char *saveptr_one = NULL; const char *name = NULL; @@ -369,7 +370,15 @@ int ObCommonConfig::add_extra_config(const char *config_str, (*pp_item)->set_version(version); LOG_INFO("Load config succ", K(name), K(value)); if (0 == compatible_cfg.case_compare(name)) { - FLOG_INFO("[COMPATIBLE] load data_version from config file", + const uint64_t tenant_id = get_tenant_id(); + uint64_t data_version = 0; + int tmp_ret = 0; + if (OB_TMP_FAIL(ObClusterVersion::get_version(value, data_version))) { + LOG_ERROR("parse data_version failed", KR(tmp_ret), K(value)); + } else if (OB_TMP_FAIL(ODV_MGR.set(tenant_id, data_version))) { + LOG_WARN("fail to set data_version", KR(tmp_ret), K(tenant_id), K(data_version)); + } + FLOG_INFO("[COMPATIBLE] [DATA_VERSION] load data_version from config file", KR(ret), "tenant_id", get_tenant_id(), "version", (*pp_item)->version(), "value", (*pp_item)->str(), @@ -377,6 +386,9 @@ int ObCommonConfig::add_extra_config(const char *config_str, "dump_version", (*pp_item)->dumped_version(), "dump_value", (*pp_item)->spfile_str(), "dump_value_updated", (*pp_item)->dump_value_updated()); + } else if (0 == enable_compatible_monotonic_cfg.case_compare(name)) { + ObString v_str((*pp_item)->str()); + ODV_MGR.set_enable_compatible_monotonic(0 == v_str.case_compare("True") ? true : false); } } } @@ -445,7 +457,7 @@ OB_DEF_SERIALIZE(ObCommonConfig) it->first.str(), it->second->spfile_str()); } if (OB_SUCC(ret) && 0 == compatible_cfg.case_compare(it->first.str())) { - FLOG_INFO("[COMPATIBLE] dump data_version", + FLOG_INFO("[COMPATIBLE] [DATA_VERSION] dump data_version", KR(ret), "tenant_id", get_tenant_id(), "version", it->second->version(), "value", it->second->str(), diff --git a/src/share/config/ob_server_config.h b/src/share/config/ob_server_config.h index 67841dea84..010154f2f8 100644 --- a/src/share/config/ob_server_config.h +++ b/src/share/config/ob_server_config.h @@ -62,6 +62,7 @@ const char* const TENANT_MEMSTORE_LIMIT_PERCENTAGE = "_memstore_limit_percentage const char* const _TX_DATA_MEMORY_LIMIT_PERCENTAGE = "_tx_data_memory_limit_percentage"; const char* const _MDS_MEMORY_LIMIT_PERCENTAGE = "_mds_memory_limit_percentage"; const char* const COMPATIBLE = "compatible"; +const char* const ENABLE_COMPATIBLE_MONOTONIC = "_enable_compatible_monotonic"; const char* const WEAK_READ_VERSION_REFRESH_INTERVAL = "weak_read_version_refresh_interval"; const char* const PARTITION_BALANCE_SCHEDULE_INTERVAL = "partition_balance_schedule_interval"; const char* const BALANCER_IDLE_TIME = "balancer_idle_time"; diff --git a/src/share/config/ob_system_config.cpp b/src/share/config/ob_system_config.cpp index 6461fa59b8..0731ef897f 100644 --- a/src/share/config/ob_system_config.cpp +++ b/src/share/config/ob_system_config.cpp @@ -14,6 +14,8 @@ #include "share/config/ob_config.h" #include "share/config/ob_server_config.h" #include "share/ob_task_define.h" +#include "share/ob_cluster_version.h" +#include "common/ob_tenant_data_version_mgr.h" namespace oceanbase { @@ -346,25 +348,46 @@ int ObSystemConfig::read_config( item.set_version(version); } } - const ObString compatible_cfg(COMPATIBLE); - if (compatible_cfg.case_compare(key.name()) == 0) { - if (!item.set_dump_value(pvalue->value())) { + const ObString enable_compatible_monotonic_cfg(ENABLE_COMPATIBLE_MONOTONIC); + if (0 == compatible_cfg.case_compare(key.name())) { + uint64_t new_data_version = 0; + uint64_t old_data_version = 0; + bool value_updated = item.value_updated(); + if (OB_FAIL(ObClusterVersion::get_version(pvalue->value(), new_data_version))) { + SHARE_LOG(ERROR, "parse data_version failed", KR(ret), K(pvalue->value())); + } else if (OB_FAIL(ObClusterVersion::get_version(item.spfile_str(), old_data_version))) { + SHARE_LOG(ERROR, "parse data_version failed", KR(ret), K(item.spfile_str())); + } else if (!value_updated && old_data_version != DATA_CURRENT_VERSION) { ret = OB_ERR_UNEXPECTED; - SHARE_LOG(WARN, "set config item dump value failed", - K(ret), K(key.name()), K(pvalue->value()), K(version)); + SHARE_LOG(ERROR, "unexpected data_version", KR(ret), K(old_data_version)); + } else if (value_updated && new_data_version <= old_data_version) { + // do nothing + SHARE_LOG(INFO, "[COMPATIBLE] [DATA_VERSION] no need to update", K(tenant_id), + K(old_data_version), K(new_data_version)); } else { - item.set_dump_value_updated(); - item.set_version(version); - share::ObTaskController::get().allow_next_syslog(); - SHARE_LOG(INFO, "[COMPATIBLE] read data_version", - KR(ret), K(tenant_id), - "version", item.version(), - "value", item.str(), - "value_updated", item.value_updated(), - "dump_version", item.dumped_version(), - "dump_value", item.spfile_str(), - "dump_value_updated", item.dump_value_updated()); + if (!item.set_dump_value(pvalue->value())) { + ret = OB_ERR_UNEXPECTED; + SHARE_LOG(WARN, "set config item dump value failed", K(ret), + K(key.name()), K(pvalue->value()), K(version)); + } else { + item.set_dump_value_updated(); + item.set_version(version); + share::ObTaskController::get().allow_next_syslog(); + int tmp_ret = 0; + if (OB_TMP_FAIL(ODV_MGR.set(tenant_id, new_data_version))) { + SHARE_LOG(WARN, "fail to set data_version", KR(tmp_ret), + K(tenant_id), K(new_data_version)); + } + SHARE_LOG(INFO, "[COMPATIBLE] [DATA_VERSION] read data_version", + KR(ret), K(tenant_id), + "version", item.version(), + "value", item.str(), + "value_updated", item.value_updated(), + "dump_version", item.dumped_version(), + "dump_value", item.spfile_str(), + "dump_value_updated", item.dump_value_updated()); + } } } else if (item.reboot_effective()) { // 以 STATIC_EFFECTIVE 的 stack_size 举例说明: @@ -390,6 +413,10 @@ int ObSystemConfig::read_config( K(key.name()), K(pvalue->value()), K(version)); } else { item.set_value_updated(); + if (0 == enable_compatible_monotonic_cfg.case_compare(key.name())) { + ObString v_str(item.str()); + ODV_MGR.set_enable_compatible_monotonic(0 == v_str.case_compare("True") ? true : false); + } } } diff --git a/src/share/ob_cluster_version.cpp b/src/share/ob_cluster_version.cpp index 86ec1b7a43..f306005f74 100644 --- a/src/share/ob_cluster_version.cpp +++ b/src/share/ob_cluster_version.cpp @@ -192,32 +192,7 @@ int64_t ObClusterVersion::print_vsn(char *buf, const int64_t buf_len, uint64_t v int64_t ObClusterVersion::print_version_str(char *buf, const int64_t buf_len, uint64_t version) { - int ret = OB_SUCCESS; - int64_t pos = 0; - const uint32_t major = OB_VSN_MAJOR(version); - const uint16_t minor = OB_VSN_MINOR(version); - const uint8_t major_patch = OB_VSN_MAJOR_PATCH(version); - const uint8_t minor_patch = OB_VSN_MINOR_PATCH(version); - if (OB_UNLIKELY(!check_version_valid_(version))) { - ret = OB_INVALID_ARGUMENT; - COMMON_LOG(ERROR, "invalid cluster version", K(version), K(lbt())); - } else if (major < 3 - || (3 == major && minor < 2) - || (3 == major && 2 == minor && 0 == major_patch && minor_patch < 3)) { - if (OB_FAIL(databuff_printf(buf, buf_len, pos, "%u.%u.%u", - major, minor, minor_patch))) { - COMMON_LOG(WARN, "fail to print version str", KR(ret), K(version)); - } - } else { - if (OB_FAIL(databuff_printf(buf, buf_len, pos, "%u.%u.%u.%u", - major, minor, major_patch, minor_patch))) { - COMMON_LOG(WARN, "fail to print version str", KR(ret), K(version)); - } - } - if (OB_FAIL(ret)) { - pos = OB_INVALID_INDEX; - } - return pos; + return VersionUtil::print_version_str(buf, buf_len, version); } int ObClusterVersion::refresh_cluster_version(const char *verstr) @@ -262,6 +237,7 @@ void ObClusterVersion::update_cluster_version(const uint64_t cluster_version) void ObClusterVersion::update_data_version(const uint64_t data_version) { ATOMIC_SET(&data_version_, data_version); + ODV_MGR.set_mock_data_version(data_version); } int ObClusterVersion::get_tenant_data_version( @@ -273,57 +249,12 @@ int ObClusterVersion::get_tenant_data_version( if (OB_UNLIKELY(0 != data_version_)) { // only work for unittest data_version = ATOMIC_LOAD(&cluster_version_); - } else if (OB_ISNULL(tenant_config_mgr_)) { - ret = OB_NOT_INIT; - COMMON_LOG(WARN, "tenant_config is null", KR(ret), KP(tenant_config_mgr_)); } else { - // wont't fallback or retry - omt::ObTenantConfigGuard tenant_config(tenant_config_mgr_->get_tenant_config_with_lock(tenant_id)); - if (tenant_config.is_valid() && tenant_config->compatible.value_updated()) { - data_version = tenant_config->compatible; - } else if (is_sys_tenant(tenant_id) - || is_meta_tenant(tenant_id)) { - // For sys/meta tenant, circular dependency problem may exist when load tenant config from inner tables. - // For safety, data_version will fallback to last barrier data version until actual tenant config is loaded. - data_version = LAST_BARRIER_DATA_VERSION; - if (REACH_TIME_INTERVAL(60 * 1000 * 1000L)) { - share::ObTaskController::get().allow_next_syslog(); - COMMON_LOG(INFO, "tenant data version fallback to last barrier version", K(tenant_id), K(data_version)); - } - } else { - // For user tenant - ret = OB_ENTRY_NOT_EXIST; - if (tenant_config.is_valid()) { - COMMON_LOG(WARN, "[COMPATIBLE] data_version is not refreshed", - KR(ret), K(tenant_id), - "version", tenant_config->compatible.version(), - "value", tenant_config->compatible.str(), - "value_updated", tenant_config->compatible.value_updated(), - "dump_version", tenant_config->compatible.dumped_version(), - "dump_value", tenant_config->compatible.spfile_str(), - "dump_value_updated", tenant_config->compatible.dump_value_updated()); - } else { - COMMON_LOG(WARN, "[COMPATIBLE] data_version is not refreshed", - KR(ret), K(tenant_id), "valid", tenant_config.is_valid()); - } - } + ret = ODV_MGR.get(tenant_id, data_version); } return ret; } -int ObClusterVersion::tenant_need_upgrade( - const uint64_t tenant_id, - bool &need_upgrade) -{ - int ret = OB_SUCCESS; - uint64_t data_version = 0; - if (OB_FAIL(get_tenant_data_version(tenant_id, data_version))) { - COMMON_LOG(WARN, "fail to get tenant data version", KR(ret), K(tenant_id)); - } else { - need_upgrade = (data_version < DATA_CURRENT_VERSION); - } - return ret; -} int ObClusterVersion::is_valid(const char *verstr) { @@ -371,25 +302,7 @@ int ObClusterVersion::get_version(const char *verstr, uint64_t &version) bool ObClusterVersion::check_version_valid_(const uint64_t version) { - bool bret = true; - const uint32_t major = OB_VSN_MAJOR(version); - const uint16_t minor = OB_VSN_MINOR(version); - const uint8_t major_patch = OB_VSN_MAJOR_PATCH(version); - const uint8_t minor_patch = OB_VSN_MINOR_PATCH(version); - if (major < 3 || (3 == major && minor < 2)) { - // cluster_version is less than "3.2": - // - should be "a.b.0.c"; - bret = (0 == major_patch); - } else if (3 == major && 2 == minor) { - // cluster_version's prefix is "3.2": - // - cluster_version == 3.2.0.0/1/2 - // - cluster_version >= 3.2.3.x - bret = (0 == major_patch && minor_patch <= 2) || (major_patch >= 3); - } else { - // cluster_version is greator than "3.2" - bret = true; - } - return bret; + return VersionUtil::check_version_valid(version); } ObClusterVersion &ObClusterVersion::get_instance() diff --git a/src/share/ob_cluster_version.h b/src/share/ob_cluster_version.h index db65e3fb61..5c46028070 100644 --- a/src/share/ob_cluster_version.h +++ b/src/share/ob_cluster_version.h @@ -15,6 +15,7 @@ #include #include "lib/atomic/ob_atomic.h" +#include "common/ob_tenant_data_version_mgr.h" namespace oceanbase { @@ -49,7 +50,6 @@ public: /* data version related */ int get_tenant_data_version(const uint64_t tenant_id, uint64_t &data_version); - int tenant_need_upgrade(const uint64_t tenant_id, bool &need_upgrade); // ATTENTION!!! this interface only work for unittest void update_data_version(const uint64_t data_version); /*------------------------*/ @@ -76,160 +76,15 @@ private: uint64_t data_version_; }; -#define OB_VSN_MAJOR_SHIFT 32 -#define OB_VSN_MINOR_SHIFT 16 -#define OB_VSN_MAJOR_PATCH_SHIFT 8 -#define OB_VSN_MINOR_PATCH_SHIFT 0 -#define OB_VSN_MAJOR_MASK 0xffffffff -#define OB_VSN_MINOR_MASK 0xffff -#define OB_VSN_MAJOR_PATCH_MASK 0xff -#define OB_VSN_MINOR_PATCH_MASK 0xff -#define OB_VSN_MAJOR(version) (static_cast((version >> OB_VSN_MAJOR_SHIFT) & OB_VSN_MAJOR_MASK)) -#define OB_VSN_MINOR(version) (static_cast((version >> OB_VSN_MINOR_SHIFT) & OB_VSN_MINOR_MASK)) -#define OB_VSN_MAJOR_PATCH(version) (static_cast((version >> OB_VSN_MAJOR_PATCH_SHIFT) & OB_VSN_MAJOR_PATCH_MASK)) -#define OB_VSN_MINOR_PATCH(version) (static_cast(version & OB_VSN_MINOR_PATCH_MASK)) +// the version definition is moved to deps/oblib/src/common/ob_version_def.h -#define CALC_VERSION(major, minor, major_patch, minor_patch) \ - (((major) << OB_VSN_MAJOR_SHIFT) + \ - ((minor) << OB_VSN_MINOR_SHIFT) + \ - ((major_patch) << OB_VSN_MAJOR_PATCH_SHIFT) + \ - ((minor_patch))) -constexpr static inline uint64_t -cal_version(const uint64_t major, const uint64_t minor, const uint64_t major_patch, const uint64_t minor_patch) -{ - return CALC_VERSION(major, minor, major_patch, minor_patch); -} - -#define DEF_MAJOR_VERSION 1 -#define DEF_MINOR_VERSION 4 -#define DEF_MAJOR_PATCH_VERSION 40 -#define DEF_MINOR_PATCH_VERSION 0 - -#define CLUSTER_VERSION_140 (oceanbase::common::cal_version(1, 4, 0, 0)) -#define CLUSTER_VERSION_141 (oceanbase::common::cal_version(1, 4, 0, 1)) -#define CLUSTER_VERSION_142 (oceanbase::common::cal_version(1, 4, 0, 2)) -#define CLUSTER_VERSION_143 (oceanbase::common::cal_version(1, 4, 0, 3)) -#define CLUSTER_VERSION_1431 (oceanbase::common::cal_version(1, 4, 0, 31)) -#define CLUSTER_VERSION_1432 (oceanbase::common::cal_version(1, 4, 0, 32)) -#define CLUSTER_VERSION_144 (oceanbase::common::cal_version(1, 4, 0, 4)) -#define CLUSTER_VERSION_1440 (oceanbase::common::cal_version(1, 4, 0, 40)) -#define CLUSTER_VERSION_1450 (oceanbase::common::cal_version(1, 4, 0, 50)) -#define CLUSTER_VERSION_1460 (oceanbase::common::cal_version(1, 4, 0, 60)) -#define CLUSTER_VERSION_1461 (oceanbase::common::cal_version(1, 4, 0, 61)) -#define CLUSTER_VERSION_1470 (oceanbase::common::cal_version(1, 4, 0, 70)) -#define CLUSTER_VERSION_1471 (oceanbase::common::cal_version(1, 4, 0, 71)) -#define CLUSTER_VERSION_1472 (oceanbase::common::cal_version(1, 4, 0, 72)) -#define CLUSTER_VERSION_1500 (oceanbase::common::cal_version(1, 5, 0, 0)) -#define CLUSTER_VERSION_2000 (oceanbase::common::cal_version(2, 0, 0, 0)) -#define CLUSTER_VERSION_2100 (oceanbase::common::cal_version(2, 1, 0, 0)) -#define CLUSTER_VERSION_2110 (oceanbase::common::cal_version(2, 1, 0, 1)) -#define CLUSTER_VERSION_2200 (oceanbase::common::cal_version(2, 2, 0, 0)) -#define CLUSTER_VERSION_2210 (oceanbase::common::cal_version(2, 2, 0, 1)) -/* - * FIXME: cluster_version目前最高是4位,此处定义要和CMakeLists.txt、tools/upgrade、src/share/parameter/ob_parameter_seed.ipp的定义保持一致 - * 当最后一位非0时,需要注意。比方说2.2.2版本实际上代表的是2.2.02版本,但实际我们想定义成2.2.20版本,和我们的意图不符。 - * 但2.2.1及之前的版本已经发版,为了避免引入兼容性问题,不改历史版本的cluster_version定义。 - */ -#define CLUSTER_VERSION_2220 (oceanbase::common::cal_version(2, 2, 0, 20)) -#define CLUSTER_VERSION_2230 (oceanbase::common::cal_version(2, 2, 0, 30)) -#define CLUSTER_VERSION_2240 (oceanbase::common::cal_version(2, 2, 0, 40)) -#define CLUSTER_VERSION_2250 (oceanbase::common::cal_version(2, 2, 0, 50)) -#define CLUSTER_VERSION_2260 (oceanbase::common::cal_version(2, 2, 0, 60)) -#define CLUSTER_VERSION_2270 (oceanbase::common::cal_version(2, 2, 0, 70)) -#define CLUSTER_VERSION_2271 (oceanbase::common::cal_version(2, 2, 0, 71)) -#define CLUSTER_VERSION_2272 (oceanbase::common::cal_version(2, 2, 0, 72)) -#define CLUSTER_VERSION_2273 (oceanbase::common::cal_version(2, 2, 0, 73)) -#define CLUSTER_VERSION_2274 (oceanbase::common::cal_version(2, 2, 0, 74)) -#define CLUSTER_VERSION_2275 (oceanbase::common::cal_version(2, 2, 0, 75)) -#define CLUSTER_VERSION_2276 (oceanbase::common::cal_version(2, 2, 0, 76)) -#define CLUSTER_VERSION_2277 (oceanbase::common::cal_version(2, 2, 0, 77)) -#define CLUSTER_VERSION_3000 (oceanbase::common::cal_version(3, 0, 0, 0)) -#define CLUSTER_VERSION_3100 (oceanbase::common::cal_version(3, 1, 0, 0)) -#define CLUSTER_VERSION_311 (oceanbase::common::cal_version(3, 1, 0, 1)) -#define CLUSTER_VERSION_312 (oceanbase::common::cal_version(3, 1, 0, 2)) -#define CLUSTER_VERSION_3200 (oceanbase::common::cal_version(3, 2, 0, 0)) -#define CLUSTER_VERSION_321 (oceanbase::common::cal_version(3, 2, 0, 1)) -#define CLUSTER_VERSION_322 (oceanbase::common::cal_version(3, 2, 0, 2)) -// ATTENSION!!!!!!!!!!!!!!!!! -// -// Cluster Version which is less than "3.2.3": -// - 1. It's composed by 3 parts(major、minor、minor_patch) -// - 2. String: cluster version will be format as "major.minor.minor_patch[.0]", and string like "major.minor.x.minor_patch" is invalid. -// - 3. Integer: for compatibility, cluster version will be encoded into "major|minor|x|minor_patch". "x" must be 0, otherwise, it's invalid. -// - 4. Print: cluster version str will be still printed as 3 parts. -// -// Cluster Version which is not less than "3.2.3": -// - 1. It's composed by 4 parts(major、minor、major_patch、minor_patch) -// - 2. String: cluster version will be format as "major.minor.major_patch.minor_patch". -// - 3. Integer: cluster version will be encoded into "major|minor|major_patch|minor_patch". -// - 4. Print: cluster version str will be printed as 4 parts. -#define CLUSTER_VERSION_3_2_3_0 (oceanbase::common::cal_version(3, 2, 3, 0)) -#define CLUSTER_VERSION_4_0_0_0 (oceanbase::common::cal_version(4, 0, 0, 0)) -#define CLUSTER_VERSION_4_1_0_0 (oceanbase::common::cal_version(4, 1, 0, 0)) -#define CLUSTER_VERSION_4_1_0_1 (oceanbase::common::cal_version(4, 1, 0, 1)) -#define CLUSTER_VERSION_4_1_0_2 (oceanbase::common::cal_version(4, 1, 0, 2)) -#define CLUSTER_VERSION_4_2_0_0 (oceanbase::common::cal_version(4, 2, 0, 0)) -#define CLUSTER_VERSION_4_2_1_0 (oceanbase::common::cal_version(4, 2, 1, 0)) -#define CLUSTER_VERSION_4_2_1_1 (oceanbase::common::cal_version(4, 2, 1, 1)) -#define CLUSTER_VERSION_4_2_1_2 (oceanbase::common::cal_version(4, 2, 1, 2)) -#define MOCK_CLUSTER_VERSION_4_2_1_3 (oceanbase::common::cal_version(4, 2, 1, 3)) -#define MOCK_CLUSTER_VERSION_4_2_1_4 (oceanbase::common::cal_version(4, 2, 1, 4)) -#define MOCK_CLUSTER_VERSION_4_2_1_6 (oceanbase::common::cal_version(4, 2, 1, 6)) -#define MOCK_CLUSTER_VERSION_4_2_1_7 (oceanbase::common::cal_version(4, 2, 1, 7)) -#define CLUSTER_VERSION_4_2_2_0 (oceanbase::common::cal_version(4, 2, 2, 0)) -#define MOCK_CLUSTER_VERSION_4_2_2_1 (oceanbase::common::cal_version(4, 2, 2, 1)) -#define MOCK_CLUSTER_VERSION_4_2_3_0 (oceanbase::common::cal_version(4, 2, 3, 0)) -#define MOCK_CLUSTER_VERSION_4_2_3_1 (oceanbase::common::cal_version(4, 2, 3, 1)) -#define MOCK_CLUSTER_VERSION_4_2_4_0 (oceanbase::common::cal_version(4, 2, 4, 0)) -// new data version before 4.3 cannot upgrade to master, must add "MOCK_" prefix -#define CLUSTER_VERSION_4_3_0_0 (oceanbase::common::cal_version(4, 3, 0, 0)) -#define CLUSTER_VERSION_4_3_0_1 (oceanbase::common::cal_version(4, 3, 0, 1)) -#define CLUSTER_VERSION_4_3_1_0 (oceanbase::common::cal_version(4, 3, 1, 0)) -#define CLUSTER_VERSION_4_3_2_0 (oceanbase::common::cal_version(4, 3, 2, 0)) - -//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -//TODO: If you update the above version, please update CLUSTER_CURRENT_VERSION. -#define CLUSTER_CURRENT_VERSION CLUSTER_VERSION_4_3_2_0 #define GET_MIN_CLUSTER_VERSION() (oceanbase::common::ObClusterVersion::get_instance().get_cluster_version()) #define IS_CLUSTER_VERSION_BEFORE_4_1_0_0 (oceanbase::common::ObClusterVersion::get_instance().get_cluster_version() < CLUSTER_VERSION_4_1_0_0) - -// ATTENSION !!!!!!!!!!!!!!!!!!!!!!!!!!! -// 1. After 4.0, each cluster_version is corresponed to a data version. -// 2. cluster_version and data_version is not compariable. -// 3. TODO: If you update data_version below, please update DATA_CURRENT_VERSION & ObUpgradeChecker too. -#define DEFAULT_MIN_DATA_VERSION (oceanbase::common::cal_version(0, 0, 0, 1)) -#define DATA_VERSION_4_0_0_0 (oceanbase::common::cal_version(4, 0, 0, 0)) -#define DATA_VERSION_4_1_0_0 (oceanbase::common::cal_version(4, 1, 0, 0)) -#define DATA_VERSION_4_1_0_1 (oceanbase::common::cal_version(4, 1, 0, 1)) -#define DATA_VERSION_4_1_0_2 (oceanbase::common::cal_version(4, 1, 0, 2)) -#define DATA_VERSION_4_2_0_0 (oceanbase::common::cal_version(4, 2, 0, 0)) -#define DATA_VERSION_4_2_1_0 (oceanbase::common::cal_version(4, 2, 1, 0)) -#define DATA_VERSION_4_2_1_1 (oceanbase::common::cal_version(4, 2, 1, 1)) -#define DATA_VERSION_4_2_1_2 (oceanbase::common::cal_version(4, 2, 1, 2)) -#define MOCK_DATA_VERSION_4_2_1_3 (oceanbase::common::cal_version(4, 2, 1, 3)) -#define MOCK_DATA_VERSION_4_2_1_4 (oceanbase::common::cal_version(4, 2, 1, 4)) -#define MOCK_DATA_VERSION_4_2_1_5 (oceanbase::common::cal_version(4, 2, 1, 5)) -#define DATA_VERSION_4_2_2_0 (oceanbase::common::cal_version(4, 2, 2, 0)) -#define MOCK_DATA_VERSION_4_2_2_1 (oceanbase::common::cal_version(4, 2, 2, 1)) -#define MOCK_DATA_VERSION_4_2_3_0 (oceanbase::common::cal_version(4, 2, 3, 0)) -#define MOCK_DATA_VERSION_4_2_3_1 (oceanbase::common::cal_version(4, 2, 3, 1)) -#define MOCK_DATA_VERSION_4_2_4_0 (oceanbase::common::cal_version(4, 2, 4, 0)) -// new data version before 4.3 cannot upgrade to master, must add "MOCK_" prefix -#define DATA_VERSION_4_3_0_0 (oceanbase::common::cal_version(4, 3, 0, 0)) -#define DATA_VERSION_4_3_0_1 (oceanbase::common::cal_version(4, 3, 0, 1)) -#define DATA_VERSION_4_3_1_0 (oceanbase::common::cal_version(4, 3, 1, 0)) -#define DATA_VERSION_4_3_2_0 (oceanbase::common::cal_version(4, 3, 2, 0)) - #define IS_CLUSTER_VERSION_AFTER_4_3_1_0 (oceanbase::common::ObClusterVersion::get_instance().get_cluster_version() >= CLUSTER_VERSION_4_3_1_0) -#define DATA_CURRENT_VERSION DATA_VERSION_4_3_2_0 -// ATTENSION !!!!!!!!!!!!!!!!!!!!!!!!!!! -// LAST_BARRIER_DATA_VERSION should be the latest barrier data version before DATA_CURRENT_VERSION -#define LAST_BARRIER_DATA_VERSION DATA_VERSION_4_2_1_0 // should check returned ret #define GET_MIN_DATA_VERSION(tenant_id, data_version) (oceanbase::common::ObClusterVersion::get_instance().get_tenant_data_version((tenant_id), (data_version))) -#define TENANT_NEED_UPGRADE(tenant_id, need) (oceanbase::common::ObClusterVersion::get_instance().tenant_need_upgrade((tenant_id), (need))) // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! } // end of namespace common diff --git a/src/share/ob_global_stat_proxy.cpp b/src/share/ob_global_stat_proxy.cpp index 9b12aede0b..1fabc30a6c 100644 --- a/src/share/ob_global_stat_proxy.cpp +++ b/src/share/ob_global_stat_proxy.cpp @@ -265,6 +265,42 @@ int ObGlobalStatProxy::get_target_data_version( return ret; } +int ObGlobalStatProxy::update_finish_data_version(const uint64_t finish_data_version, + const share::SCN &barrier_scn) { + int ret = OB_SUCCESS; + ObGlobalStatItem::ItemList list; + ObGlobalStatItem version_item(list, "finish_data_version", finish_data_version); + ObGlobalStatItem scn_item(list, "data_version_barrier_scn", + barrier_scn.get_val_for_inner_table_field()); + bool is_incremental = true; + if (!is_valid() || !barrier_scn.is_valid() || finish_data_version <= 0) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid arg", KR(ret), "valid", is_valid(), K(barrier_scn), K(finish_data_version)); + } else if (OB_FAIL(update(list, is_incremental))) { + LOG_WARN("update failed", KR(ret), K(list)); + } + return ret; +} + +int ObGlobalStatProxy::get_finish_data_version(uint64_t &finish_data_version, + share::SCN &barrier_scn) { + int ret = OB_SUCCESS; + finish_data_version = 0; + ObGlobalStatItem::ItemList list; + ObGlobalStatItem version_item(list, "finish_data_version", OB_INVALID_VERSION); + ObGlobalStatItem scn_item(list, "data_version_barrier_scn", OB_INVALID_SCN_VAL); + if (!is_valid()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", KR(ret), "self valid", is_valid()); + } else if (OB_FAIL(get(list))) { + LOG_WARN("get failed", KR(ret)); + } else { + finish_data_version = static_cast(version_item.value_); + barrier_scn.convert_for_inner_table_field(static_cast(scn_item.value_)); + } + return ret; +} + int ObGlobalStatProxy::get_target_data_version_ora_rowscn( const uint64_t tenant_id, share::SCN &target_data_version_ora_rowscn) diff --git a/src/share/ob_global_stat_proxy.h b/src/share/ob_global_stat_proxy.h index 98806683b6..d6b26fa744 100644 --- a/src/share/ob_global_stat_proxy.h +++ b/src/share/ob_global_stat_proxy.h @@ -79,6 +79,8 @@ public: share::SCN &target_data_version_ora_rowscn); int update_target_data_version(const uint64_t target_data_version); int get_target_data_version(const bool for_update, uint64_t &target_data_version); + int update_finish_data_version(const uint64_t finish_data_version, const share::SCN &scn); + int get_finish_data_version(uint64_t &finish_data_version, share::SCN &scn); virtual int get_snapshot_info(int64_t &snapshot_gc_scn, int64_t &gc_schema_version); diff --git a/src/share/ob_log_restore_proxy.cpp b/src/share/ob_log_restore_proxy.cpp index 294ab1d5b5..2788044649 100644 --- a/src/share/ob_log_restore_proxy.cpp +++ b/src/share/ob_log_restore_proxy.cpp @@ -19,6 +19,7 @@ #include "lib/oblog/ob_log_module.h" #include "lib/net/ob_addr.h" #include "observer/ob_sql_client_decorator.h" //ObSQLClientRetryWeak +#include "observer/ob_server_struct.h" #include "common/ob_smart_var.h" #include "lib/mysqlclient/ob_mysql_connection_pool.h" #include "lib/mysqlclient/ob_mysql_result.h" @@ -27,6 +28,7 @@ #include "share/inner_table/ob_inner_table_schema_constants.h" #include "share/backup/ob_backup_struct.h" // COMPATIBILITY_MODE #include "share/ob_thread_mgr.h" +#include "share/config/ob_server_config.h" #include "logservice/palf/palf_options.h" #include "share/oracle_errno.h" #include @@ -411,6 +413,56 @@ int ObLogRestoreProxyUtil::get_cluster_id(uint64_t tenant_id, int64_t &cluster_i return ret; } +int ObLogRestoreProxyUtil::check_different_cluster_with_same_cluster_id( + const int64_t source_cluster_id, bool &res) +{ + int ret = OB_SUCCESS; + res = false; + + if (OB_UNLIKELY(!inited_)) { + ret = OB_NOT_INIT; + } else if (GCONF.cluster_id == source_cluster_id) { + // get one machine ip from the source cluster, then check if that machine is in current + // cluster's __all_server table + SMART_VAR(ObMySQLProxy::MySQLResult, result) { + ObSqlString sql; + char svr_ip_buf[common::OB_IP_STR_BUFF] = {0}; + common::ObAddr primary_server; + if (OB_FAIL(server_prover_.get_server(0, primary_server))) { + LOG_WARN("fail to get primary server", K(ret)); + } else if (!primary_server.ip_to_string(svr_ip_buf, common::OB_IP_STR_BUFF)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to convert ip to string", K(ret)); + } else if (OB_FAIL(sql.assign_fmt( + "SELECT COUNT(*) AS cnt FROM %s WHERE svr_ip='%s' AND inner_port=%d", + OB_ALL_SERVER_TNAME, svr_ip_buf, primary_server.get_port()))) { + LOG_WARN("fail to generate sql", K(ret)); + } else if (OB_ISNULL(GCTX.sql_proxy_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("sql proxy is null", K(ret)); + } else if (OB_FAIL(GCTX.sql_proxy_->read(result, sql.ptr()))) { + LOG_WARN("fail to get __all_server", K(ret), K(sql)); + } else if (OB_ISNULL(result.get_result())) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("query result is null", K(sql)); + } else if (OB_FAIL(result.get_result()->next())) { + LOG_WARN("get result next failed", K(sql)); + } else { + int64_t cnt = 0; + EXTRACT_INT_FIELD_MYSQL(*result.get_result(), "cnt", cnt, int64_t); + if (OB_FAIL(ret)) { + LOG_WARN("fail to get sql result", K(ret), K(sql)); + } else if (0 == cnt) { + res = true; + } + LOG_INFO("check if cluster_id duplicated", K(res), K(cnt), K(sql)); + } + } + } + + return ret; +} + int ObLogRestoreProxyUtil::get_compatibility_mode(const uint64_t tenant_id, ObCompatibilityMode &compat_mode) { int ret = OB_SUCCESS; diff --git a/src/share/ob_log_restore_proxy.h b/src/share/ob_log_restore_proxy.h index 12fb34fec4..702c8418be 100644 --- a/src/share/ob_log_restore_proxy.h +++ b/src/share/ob_log_restore_proxy.h @@ -150,6 +150,9 @@ public: int get_max_log_info(const ObLSID &id, palf::AccessMode &mode, SCN &scn); // get ls from dba_ob_ls int is_ls_existing(const ObLSID &id); + // check if the source cluster has the same cluster id as current cluster, but they are actually + // two different clusters, if so, out param `res` will be true, otherwise false + int check_different_cluster_with_same_cluster_id(const int64_t source_cluster_id, bool &res); private: // check if user or password changed bool is_user_changed_(const char *user_name, const char *user_password); diff --git a/src/share/ob_primary_standby_service.cpp b/src/share/ob_primary_standby_service.cpp index ca78fd5436..5de4368c91 100644 --- a/src/share/ob_primary_standby_service.cpp +++ b/src/share/ob_primary_standby_service.cpp @@ -32,6 +32,7 @@ #include "storage/tx/ob_trans_service.h" //ObTransService #include "storage/tx/ob_timestamp_service.h" // ObTimestampService #include "storage/high_availability/ob_transfer_lock_utils.h" // ObMemberListLockUtils +#include "common/ob_tenant_data_version_mgr.h" namespace oceanbase { @@ -669,8 +670,42 @@ int ObPrimaryStandbyService::write_upgrade_barrier_log( const uint64_t data_version) { int ret = OB_SUCCESS; + + if (OB_FAIL(write_barrier_log_(transaction::ObTxDataSourceType::STANDBY_UPGRADE, + trans, tenant_id, data_version))) { + LOG_WARN("fail to write upgrade barrier log", K(ret), K(tenant_id), K(data_version)); + } + + return ret; +} + +int ObPrimaryStandbyService::write_upgrade_data_version_barrier_log( + ObMySQLTransaction &trans, + const uint64_t tenant_id, + const uint64_t data_version) +{ + int ret = OB_SUCCESS; + + if (ODV_MGR.is_enable_compatible_monotonic() && + OB_FAIL(write_barrier_log_(transaction::ObTxDataSourceType::STANDBY_UPGRADE_DATA_VERSION, + trans, tenant_id, data_version))) { + LOG_WARN("fail to write upgrade data_version barrier log", K(ret), K(tenant_id), + K(data_version)); + } + + return ret; +} + +int ObPrimaryStandbyService::write_barrier_log_( + const transaction::ObTxDataSourceType type, + ObMySQLTransaction &trans, + const uint64_t tenant_id, + const uint64_t data_version) +{ + int ret = OB_SUCCESS; ObStandbyUpgrade primary_data_version(data_version); - observer::ObInnerSQLConnection *inner_conn = static_cast(trans.get_connection()); + observer::ObInnerSQLConnection *inner_conn = + static_cast(trans.get_connection()); if (OB_FAIL(check_inner_stat_())) { LOG_WARN("inner stat error", KR(ret), K_(inited)); } else if (OB_ISNULL(inner_conn)) { @@ -696,11 +731,11 @@ int ObPrimaryStandbyService::write_upgrade_barrier_log( ret = OB_SIZE_OVERFLOW; LOG_WARN("serialize error", KR(ret), K(pos), K(length), K(primary_data_version)); } else if (OB_FAIL(inner_conn->register_multi_data_source( - tenant_id, SYS_LS, transaction::ObTxDataSourceType::STANDBY_UPGRADE, - buf, length))) { + tenant_id, SYS_LS, type, buf, length))) { LOG_WARN("failed to register tx data", KR(ret), K(tenant_id)); } - LOG_INFO("write_upgrade_barrier_log finished", KR(ret), K(tenant_id), K(primary_data_version), K(length), KPHEX(buf, length)); + LOG_INFO("write_barrier_log finished", KR(ret), K(tenant_id), K(type), + K(primary_data_version), K(length), KPHEX(buf, length)); } return ret; } diff --git a/src/share/ob_primary_standby_service.h b/src/share/ob_primary_standby_service.h index cd116733db..0eecf792b3 100644 --- a/src/share/ob_primary_standby_service.h +++ b/src/share/ob_primary_standby_service.h @@ -65,6 +65,7 @@ public: int recover_tenant(const obrpc::ObRecoverTenantArg &arg); int write_upgrade_barrier_log(ObMySQLTransaction &trans, const uint64_t tenant_id, const uint64_t data_version); + int write_upgrade_data_version_barrier_log(ObMySQLTransaction &trans, const uint64_t tenant_id, const uint64_t data_version); /** * @description: @@ -211,6 +212,11 @@ private: * @return return code */ int check_ls_restore_status_(const uint64_t tenant_id); + int write_barrier_log_(const transaction::ObTxDataSourceType type, + ObMySQLTransaction &trans, + const uint64_t tenant_id, + const uint64_t data_version); + private: const static int64_t SEC_UNIT = 1000L * 1000L; const static int64_t PRINT_INTERVAL = 10 * 1000 * 1000L; diff --git a/src/share/ob_rpc_struct.cpp b/src/share/ob_rpc_struct.cpp index 6178cad39d..d172669080 100755 --- a/src/share/ob_rpc_struct.cpp +++ b/src/share/ob_rpc_struct.cpp @@ -6964,24 +6964,30 @@ bool ObUpdateTenantInfoCacheArg::is_valid() const { return OB_INVALID_TENANT_ID != tenant_id_ && tenant_info_.is_valid() - && 0 != ora_rowscn_; + && 0 != ora_rowscn_ + && data_version_barrier_scn_.is_valid(); } int ObUpdateTenantInfoCacheArg::init( const uint64_t tenant_id, const ObAllTenantInfo &tenant_info, - const int64_t ora_rowscn) + const int64_t ora_rowscn, + const uint64_t finish_data_version, + const share::SCN &data_version_barrier_scn) { int ret = OB_SUCCESS; if (OB_UNLIKELY(OB_INVALID_TENANT_ID == tenant_id || !tenant_info.is_valid() - || 0 == ora_rowscn)) { + || 0 == ora_rowscn + || !data_version_barrier_scn.is_valid())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", KR(ret), K(tenant_id), K(tenant_info), K(ora_rowscn)); } else { tenant_id_ = tenant_id; tenant_info_ = tenant_info; ora_rowscn_ = ora_rowscn; + finish_data_version_ = finish_data_version; + data_version_barrier_scn_ = data_version_barrier_scn; } return ret; } @@ -6993,6 +6999,8 @@ int ObUpdateTenantInfoCacheArg::assign(const ObUpdateTenantInfoCacheArg &other) tenant_id_ = other.tenant_id_; tenant_info_ = other.tenant_info_; ora_rowscn_ = other.ora_rowscn_; + finish_data_version_ = other.finish_data_version_; + data_version_barrier_scn_ = other.data_version_barrier_scn_; } return ret; } diff --git a/src/share/ob_rpc_struct.h b/src/share/ob_rpc_struct.h index 9d0debb232..9213d930a8 100755 --- a/src/share/ob_rpc_struct.h +++ b/src/share/ob_rpc_struct.h @@ -7737,12 +7737,17 @@ struct ObUpdateTenantInfoCacheArg { OB_UNIS_VERSION(1); public: - ObUpdateTenantInfoCacheArg(): tenant_id_(OB_INVALID_TENANT_ID), tenant_info_(), ora_rowscn_(0) {} + ObUpdateTenantInfoCacheArg(): tenant_id_(OB_INVALID_TENANT_ID), tenant_info_(), ora_rowscn_(0), finish_data_version_(0) { + data_version_barrier_scn_.set_min(); + } ~ObUpdateTenantInfoCacheArg() {} bool is_valid() const; - int init(const uint64_t tenant_id, const share::ObAllTenantInfo &tenant_info, const int64_t ora_rowscn); + int init(const uint64_t tenant_id, const share::ObAllTenantInfo &tenant_info, + const int64_t ora_rowscn, const uint64_t finish_data_version, + const share::SCN &data_version_barrier_scn); int assign(const ObUpdateTenantInfoCacheArg &other); - TO_STRING_KV(K_(tenant_id), K_(tenant_info), K_(ora_rowscn)); + TO_STRING_KV(K_(tenant_id), K_(tenant_info), K_(ora_rowscn), K_(finish_data_version), + K_(data_version_barrier_scn)); uint64_t get_tenant_id() const { @@ -7759,6 +7764,16 @@ public: return ora_rowscn_; } + uint64_t get_finish_data_version() const + { + return finish_data_version_; + } + + const share::SCN &get_data_version_barrier_scn() const + { + return data_version_barrier_scn_; + } + private: DISALLOW_COPY_AND_ASSIGN(ObUpdateTenantInfoCacheArg); private: diff --git a/src/share/ob_standby_upgrade.cpp b/src/share/ob_standby_upgrade.cpp index 7691c4a5ae..eea2f37d1c 100644 --- a/src/share/ob_standby_upgrade.cpp +++ b/src/share/ob_standby_upgrade.cpp @@ -23,5 +23,23 @@ namespace share OB_SERIALIZE_MEMBER(ObStandbyUpgrade, data_version_); +int ObUpgradeDataVersionMDSHelper::on_register( + const char* buf, + const int64_t len, + storage::mds::BufferCtx &ctx) +{ + UNUSEDx(buf, len, ctx); + return OB_SUCCESS; +} + +int ObUpgradeDataVersionMDSHelper::on_replay( + const char* buf, + const int64_t len, + const share::SCN &scn, + storage::mds::BufferCtx &ctx) +{ + UNUSEDx(buf, len, scn, ctx); + return OB_SUCCESS; +} } } diff --git a/src/share/ob_standby_upgrade.h b/src/share/ob_standby_upgrade.h index eb3aa0cde4..f77003de3f 100644 --- a/src/share/ob_standby_upgrade.h +++ b/src/share/ob_standby_upgrade.h @@ -16,6 +16,7 @@ #include "lib/utility/ob_print_utils.h" // Print* #include "lib/utility/ob_unify_serialize.h" // OB_UNIS_VERSION #include "share/ob_cluster_version.h" +#include "storage/multi_data_source/buffer_ctx.h" namespace oceanbase { @@ -44,6 +45,20 @@ private: uint64_t data_version_; }; +class ObUpgradeDataVersionMDSHelper +{ +public: + static int on_register( + const char* buf, + const int64_t len, + storage::mds::BufferCtx &ctx); + static int on_replay( + const char* buf, + const int64_t len, + const share::SCN &scn, + storage::mds::BufferCtx &ctx); +}; + } } diff --git a/src/share/parameter/ob_parameter_seed.ipp b/src/share/parameter/ob_parameter_seed.ipp index 9316586b38..54d8a9b0a3 100644 --- a/src/share/parameter/ob_parameter_seed.ipp +++ b/src/share/parameter/ob_parameter_seed.ipp @@ -2006,3 +2006,6 @@ DEF_CAP(lob_enable_block_cache_threshold, OB_TENANT_PARAMETER, "256K", "[0B, 512 DEF_INT(_ob_pl_compile_max_concurrency, OB_CLUSTER_PARAMETER, "4", "[0,)", "The maximum number of threads that an observer node can compile PL concurrently.", ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); +DEF_BOOL(_enable_compatible_monotonic, OB_CLUSTER_PARAMETER, "True", + "Control whether to enable cross-server monotonic compatible(data_version) mode", + ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); diff --git a/src/storage/multi_data_source/compile_utility/mds_register.h b/src/storage/multi_data_source/compile_utility/mds_register.h index 9fe3d32e5a..44246fa766 100644 --- a/src/storage/multi_data_source/compile_utility/mds_register.h +++ b/src/storage/multi_data_source/compile_utility/mds_register.h @@ -71,6 +71,7 @@ #include "src/storage/multi_data_source/ob_tablet_create_mds_ctx.h" #include "src/storage/multi_data_source/ob_start_transfer_in_mds_ctx.h" #include "src/storage/multi_data_source/ob_finish_transfer_in_mds_ctx.h" + #include "src/share/ob_standby_upgrade.h" #endif /**************************************************************************************************/ @@ -176,6 +177,10 @@ _GENERATE_MDS_FRAME_CODE_FOR_TRANSACTION_(HELPER_CLASS, BUFFER_CTX_TYPE, ID, ENU // 33,\ // STANDBY_UPGRADE_DATA_VERSION) // # 余留位置(此行之前占位) + GENERATE_MDS_FRAME_CODE_FOR_TRANSACTION(::oceanbase::share::ObUpgradeDataVersionMDSHelper, \ + ::oceanbase::storage::mds::MdsCtx, \ + 33,\ + STANDBY_UPGRADE_DATA_VERSION) #undef GENERATE_MDS_FRAME_CODE_FOR_TRANSACTION #endif /**************************************************************************************************/ diff --git a/src/storage/tx/ob_multi_data_source.h b/src/storage/tx/ob_multi_data_source.h index c5a8bd22be..2db87ada26 100644 --- a/src/storage/tx/ob_multi_data_source.h +++ b/src/storage/tx/ob_multi_data_source.h @@ -78,6 +78,7 @@ static const char * to_str_mds_type(const ObTxDataSourceType & mds_type ) TRX_ENUM_CASE_TO_STR(ObTxDataSourceType, DDL_BARRIER); TRX_ENUM_CASE_TO_STR(ObTxDataSourceType, DDL_TRANS); TRX_ENUM_CASE_TO_STR(ObTxDataSourceType, STANDBY_UPGRADE); + TRX_ENUM_CASE_TO_STR(ObTxDataSourceType, STANDBY_UPGRADE_DATA_VERSION); TRX_ENUM_CASE_TO_STR(ObTxDataSourceType, BEFORE_VERSION_4_1); TRX_ENUM_CASE_TO_STR(ObTxDataSourceType, TEST1); diff --git a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result index 0c69f7a815..10a250f72a 100644 --- a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result +++ b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result @@ -294,6 +294,7 @@ _enable_block_file_punch_hole _enable_choose_migration_source_policy _enable_column_store _enable_compaction_diagnose +_enable_compatible_monotonic _enable_convert_real_to_decimal _enable_dblink_reuse_connection _enable_dbms_job_package diff --git a/unittest/sql/test_sql_utils.cpp b/unittest/sql/test_sql_utils.cpp index 1f759f7271..23b4228241 100644 --- a/unittest/sql/test_sql_utils.cpp +++ b/unittest/sql/test_sql_utils.cpp @@ -181,6 +181,7 @@ TestSqlUtils::TestSqlUtils() cluster_version.init(&common::ObServerConfig::get_instance(), &oceanbase::omt::ObTenantConfigMgr::get_instance()); oceanbase::omt::ObTenantConfigMgr::get_instance().add_tenant_config(sys_tenant_id_); cluster_version.refresh_cluster_version("4.3.0.0"); + ODV_MGR.init(true); ObServer &observer = ObServer::get_instance(); int ret = OB_SUCCESS;