500 lines
15 KiB
C++
500 lines
15 KiB
C++
/**
|
|
* 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_COMMON_OB_ROWKEY_H_
|
|
#define OCEANBASE_COMMON_OB_ROWKEY_H_
|
|
|
|
#include <stdint.h>
|
|
#include "lib/oblog/ob_log.h"
|
|
#include "lib/ob_define.h"
|
|
#include "lib/utility/utility.h"
|
|
#include "lib/checksum/ob_crc64.h"
|
|
#include "lib/json/ob_yson.h"
|
|
#include "common/ob_common_utility.h"
|
|
#include "common/object/ob_object.h"
|
|
|
|
namespace oceanbase
|
|
{
|
|
namespace common
|
|
{
|
|
class ObStoreRowkey;
|
|
|
|
class ObRowkey
|
|
{
|
|
public:
|
|
ObRowkey() : obj_ptr_(NULL), obj_cnt_(0) {}
|
|
ObRowkey(ObObj *ptr, const int64_t cnt) : obj_ptr_(ptr), obj_cnt_(cnt) {}
|
|
~ObRowkey() {}
|
|
public:
|
|
int to_store_rowkey(ObStoreRowkey &store_rowkey) const;
|
|
void reset() {obj_ptr_ = NULL; obj_cnt_ = 0; }
|
|
void destroy(ObIAllocator &allocator);
|
|
inline int64_t get_obj_cnt() const { return obj_cnt_; }
|
|
inline const ObObj *get_obj_ptr() const { return obj_ptr_; }
|
|
inline ObObj *get_obj_ptr() { return obj_ptr_; }
|
|
// for convenience compactible with ObString
|
|
inline int64_t length() const { return obj_cnt_; }
|
|
inline const ObObj *ptr() const { return obj_ptr_; }
|
|
inline bool is_legal() const { return !(NULL == obj_ptr_ && obj_cnt_ > 0); }
|
|
inline bool is_valid() const { return NULL != obj_ptr_ && obj_cnt_ > 0; }
|
|
// is min rowkey or max rowkey
|
|
inline bool is_min_row(void) const
|
|
{
|
|
bool bret = false;
|
|
int64_t i = 0;
|
|
for (i = 0; i < obj_cnt_; i++) {
|
|
if (!obj_ptr_[i].is_min_value()) {
|
|
break;
|
|
}
|
|
}
|
|
if (obj_cnt_ > 0 && i >= obj_cnt_) {
|
|
bret = true;
|
|
}
|
|
return bret;
|
|
}
|
|
|
|
inline bool is_max_row(void) const
|
|
{
|
|
bool bret = false;
|
|
int64_t i = 0;
|
|
for (i = 0; i < obj_cnt_; i++) {
|
|
if (!obj_ptr_[i].is_max_value()) {
|
|
break;
|
|
}
|
|
}
|
|
if (obj_cnt_ > 0 && i >= obj_cnt_) {
|
|
bret = true;
|
|
}
|
|
return bret;
|
|
}
|
|
|
|
inline void set_min_row(void) { *this = ObRowkey::MIN_ROWKEY; }
|
|
inline void set_max_row(void) { *this = ObRowkey::MAX_ROWKEY; }
|
|
inline void set_length(const int64_t cnt) { obj_cnt_ = cnt; }
|
|
inline void assign(ObObj *ptr, const int64_t cnt)
|
|
{
|
|
obj_ptr_ = ptr;
|
|
obj_cnt_ = cnt;
|
|
}
|
|
inline int obj_copy(ObRowkey &rowkey, ObObj *obj_buf, const int64_t cnt) const;
|
|
|
|
int64_t get_deep_copy_size() const;
|
|
|
|
template <typename Allocator>
|
|
int deep_copy(ObRowkey &rhs, Allocator &allocator) const;
|
|
|
|
OB_INLINE int deep_copy(char *buffer, int64_t size) const;
|
|
OB_INLINE int deep_copy(ObRowkey &out, char *buffer, int64_t size) const;
|
|
OB_INLINE int deep_copy(const ObRowkey &src, char *ptr, int64_t size, int64_t &pos);
|
|
|
|
template <typename Allocator>
|
|
int deserialize(Allocator &allocator, const char *buf, const int64_t data_len, int64_t &pos);
|
|
|
|
int serialize(char *buf, const int64_t buf_len, int64_t &pos) const;
|
|
int64_t get_serialize_size(void) const;
|
|
int deserialize(const char *buf, const int64_t buf_len, int64_t &pos, bool check_zero = false);
|
|
|
|
int serialize_objs(char *buf, const int64_t buf_len, int64_t &pos) const;
|
|
int64_t get_serialize_objs_size(void) const;
|
|
int deserialize_objs(const char *buf, const int64_t buf_len, int64_t &pos);
|
|
|
|
TO_YSON_KV(OB_ID(rowkey), to_cstring(*this));
|
|
int64_t to_string(char *buffer, const int64_t length) const;
|
|
//to_smart_string and to_format_string are for log_tool use
|
|
int64_t to_smart_string(char *buffer, const int64_t length) const;
|
|
int64_t to_format_string(char *buffer, const int64_t length) const;
|
|
|
|
int64_t to_plain_string(char *buffer, const int64_t length) const;
|
|
int need_transform_to_collation_free(bool &need_transform) const;
|
|
template <typename Allocator>
|
|
int to_collation_free_rowkey(common::ObRowkey &collation_free_rowkey, Allocator &allocator) const;
|
|
template <typename Allocator>
|
|
int to_collation_free_rowkey_on_demand(common::ObRowkey &collation_free_rowkey, Allocator &allocator) const;
|
|
|
|
int checksum(ObBatchChecksum &bc) const;
|
|
uint64_t murmurhash(const uint64_t hash) const;
|
|
inline uint64_t hash() const
|
|
{
|
|
return murmurhash(0);
|
|
}
|
|
inline int hash(uint64_t &hash_val) const
|
|
{
|
|
hash_val = hash();
|
|
return OB_SUCCESS;
|
|
}
|
|
static int get_common_prefix_length(const ObRowkey &lhs, const ObRowkey &rhs, int64_t &prefix_len);
|
|
|
|
public:
|
|
int equal(const ObRowkey &rhs, bool &is_equal) const;
|
|
bool simple_equal(const ObRowkey &rhs) const;
|
|
//FIXME temporarily, rowkey compare with column order use seperate func
|
|
OB_INLINE int compare(const ObRowkey &rhs, int &cmp) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
cmp = 0;
|
|
if (obj_ptr_ == rhs.obj_ptr_) {
|
|
cmp = static_cast<int32_t>(obj_cnt_ - rhs.obj_cnt_);
|
|
} else {
|
|
ret = compare_prefix(rhs, cmp);
|
|
if (0 == cmp) {
|
|
cmp = static_cast<int32_t>(obj_cnt_ - rhs.obj_cnt_);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
// TODO by fengshuo.fs: remove this function
|
|
OB_INLINE int compare(const ObRowkey &rhs) const
|
|
{
|
|
int cmp = 0;
|
|
if (obj_ptr_ == rhs.obj_ptr_) {
|
|
cmp = static_cast<int32_t>(obj_cnt_ - rhs.obj_cnt_);
|
|
} else {
|
|
cmp = compare_prefix(rhs);
|
|
if (0 == cmp) {
|
|
cmp = static_cast<int32_t>(obj_cnt_ - rhs.obj_cnt_);
|
|
}
|
|
}
|
|
return cmp;
|
|
}
|
|
|
|
OB_INLINE int compare_prefix(const ObRowkey &rhs, int &cmp) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int lv = 0;
|
|
int rv = 0;
|
|
cmp = 0;
|
|
//TODO remove disgusting loop, useless max min judge
|
|
if (is_min_row()) { lv = -1; }
|
|
else if (is_max_row()) { lv = 1; }
|
|
if (rhs.is_min_row()) { rv = -1; }
|
|
else if (rhs.is_max_row()) { rv = 1; }
|
|
if (0 == lv && 0 == rv) {
|
|
int64_t i = 0;
|
|
int64_t cmp_cnt = std::min(obj_cnt_, rhs.obj_cnt_);
|
|
for (; i < cmp_cnt && 0 == cmp && OB_SUCC(ret); ++i) {
|
|
//TODO remove collation free check
|
|
ret = obj_ptr_[i].check_collation_free_and_compare(rhs.obj_ptr_[i], cmp);
|
|
}
|
|
} else {
|
|
cmp = lv - rv;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// TODO by fengshuo.fs: remove this function
|
|
OB_INLINE int compare_prefix(const ObRowkey &rhs) const
|
|
{
|
|
int cmp = 0;
|
|
int lv = 0;
|
|
int rv = 0;
|
|
//TODO remove disgusting loop, useless max min judge
|
|
if (is_min_row()) { lv = -1; }
|
|
else if (is_max_row()) { lv = 1; }
|
|
if (rhs.is_min_row()) { rv = -1; }
|
|
else if (rhs.is_max_row()) { rv = 1; }
|
|
if (0 == lv && 0 == rv) {
|
|
int64_t i = 0;
|
|
int64_t cmp_cnt = std::min(obj_cnt_, rhs.obj_cnt_);
|
|
for (; i < cmp_cnt && 0 == cmp; ++i) {
|
|
//TODO remove collation free check
|
|
cmp = obj_ptr_[i].check_collation_free_and_compare(rhs.obj_ptr_[i]);
|
|
}
|
|
} else {
|
|
cmp = lv - rv;
|
|
}
|
|
return cmp;
|
|
}
|
|
|
|
inline bool operator<(const ObRowkey &rhs) const
|
|
{
|
|
return compare(rhs) < 0;
|
|
}
|
|
|
|
inline bool operator<=(const ObRowkey &rhs) const
|
|
{
|
|
return compare(rhs) <= 0;
|
|
}
|
|
|
|
inline bool operator>(const ObRowkey &rhs) const
|
|
{
|
|
return compare(rhs) > 0;
|
|
}
|
|
|
|
inline bool operator>=(const ObRowkey &rhs) const
|
|
{
|
|
return compare(rhs) >= 0;
|
|
}
|
|
|
|
inline bool operator==(const ObRowkey &rhs) const
|
|
{
|
|
return compare(rhs) == 0;
|
|
}
|
|
inline bool operator!=(const ObRowkey &rhs) const
|
|
{
|
|
return compare(rhs) != 0;
|
|
}
|
|
private:
|
|
ObObj *obj_ptr_;
|
|
int64_t obj_cnt_;
|
|
public:
|
|
static ObObj MIN_OBJECT;
|
|
static ObObj MAX_OBJECT;
|
|
static ObRowkey MIN_ROWKEY;
|
|
static ObRowkey MAX_ROWKEY;
|
|
};
|
|
|
|
inline int64_t ObRowkey::get_deep_copy_size() const
|
|
{
|
|
int tmp_ret = OB_SUCCESS;
|
|
int64_t obj_arr_len = obj_cnt_ * sizeof(common::ObObj);
|
|
int64_t total_len = obj_arr_len;
|
|
|
|
if (OB_UNLIKELY(!is_legal())) {
|
|
tmp_ret = OB_INVALID_DATA;
|
|
COMMON_LOG_RET(ERROR, common::OB_ERR_UNEXPECTED, "illegal rowkey.",
|
|
KP_(obj_ptr), K_(obj_cnt), K(tmp_ret));
|
|
} else {
|
|
for (int64_t i = 0; i < obj_cnt_; ++i) {
|
|
total_len += obj_ptr_[i].get_deep_copy_size();
|
|
}
|
|
}
|
|
|
|
return total_len;
|
|
}
|
|
|
|
template <typename Allocator>
|
|
int ObRowkey::deserialize(Allocator &allocator, const char *buf, const int64_t data_len,
|
|
int64_t &pos)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObObj array[OB_MAX_ROWKEY_COLUMN_NUMBER];
|
|
ObRowkey copy_rowkey;
|
|
copy_rowkey.assign(array, OB_MAX_ROWKEY_COLUMN_NUMBER);
|
|
|
|
if (NULL == buf || data_len <= 0) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
COMMON_LOG(WARN, "invalid arguments.",
|
|
KP(buf), K(data_len), K(ret));
|
|
} else if (OB_FAIL(copy_rowkey.deserialize(buf, data_len, pos))) {
|
|
COMMON_LOG(WARN, "deserialize to shallow copy key failed.",
|
|
KP(buf), K(data_len), K(pos), K(ret));
|
|
} else if (OB_FAIL(copy_rowkey.deep_copy(*this, allocator))) {
|
|
COMMON_LOG(WARN, "deep copy to self failed.",
|
|
KP(buf), K(data_len), K(pos), K(ret));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
OB_INLINE int ObRowkey::deep_copy(char *ptr, int64_t size) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
int64_t obj_arr_len = obj_cnt_ * sizeof(ObObj);
|
|
if (OB_UNLIKELY(NULL == ptr) || OB_UNLIKELY(size < obj_arr_len)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
COMMON_LOG(WARN, "invalid arguments.",
|
|
KP(ptr), K(size), KP_(obj_cnt), K(ret));
|
|
} else if (obj_cnt_ > 0 && NULL != obj_ptr_) {
|
|
ObObj *obj_ptr = NULL;
|
|
int64_t pos = 0;
|
|
|
|
obj_ptr = reinterpret_cast<ObObj *>(ptr);
|
|
pos += obj_arr_len;
|
|
|
|
for (int64_t i = 0; i < obj_cnt_ && OB_SUCCESS == ret; ++i) {
|
|
if (OB_FAIL(obj_ptr[i].deep_copy(obj_ptr_[i], ptr, size, pos))) {
|
|
COMMON_LOG(WARN, "deep copy object failed.",
|
|
K(i), K(obj_ptr_[i]), K(size), K(pos), K(ret));
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
OB_INLINE int ObRowkey::deep_copy(const ObRowkey &src, char *ptr, int64_t size, int64_t &pos)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_UNLIKELY(!src.is_legal())) {
|
|
ret = OB_INVALID_DATA;
|
|
COMMON_LOG(WARN, "illegal src rowkey.", KP(src.obj_ptr_), K(src.obj_cnt_), K(ret));
|
|
} else {
|
|
int64_t total_len = src.get_deep_copy_size();
|
|
if (size < total_len + pos || OB_UNLIKELY(NULL == ptr)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
COMMON_LOG(WARN, "invalid arguments.", KP(ptr), K(size), K(total_len), K(pos), K(ret));
|
|
} else if (src.obj_cnt_ > 0 && NULL != src.obj_ptr_) {
|
|
ObObj *obj_ptr = NULL;
|
|
obj_ptr = reinterpret_cast<ObObj *>(ptr + pos);
|
|
pos += (src.obj_cnt_ * sizeof(ObObj));
|
|
|
|
for (int64_t i = 0; i < src.obj_cnt_ && OB_SUCC(ret); ++i) {
|
|
if (OB_FAIL(obj_ptr[i].deep_copy(src.obj_ptr_[i], ptr, size, pos))) {
|
|
COMMON_LOG(WARN, "deep copy object failed.", K(i), K(src.obj_ptr_[i]), K(size), K(pos), K(ret));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
obj_ptr_ = obj_ptr;
|
|
obj_cnt_ = src.obj_cnt_;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
OB_INLINE int ObRowkey::deep_copy(ObRowkey &rhs, char *ptr, int64_t total_len) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
rhs.reset();
|
|
|
|
if (OB_UNLIKELY(!is_legal())) {
|
|
ret = OB_INVALID_DATA;
|
|
COMMON_LOG(WARN, "illegal rowkey.",
|
|
KP_(obj_ptr), K_(obj_cnt), K(ret));
|
|
} else if (obj_cnt_ > 0 && NULL != obj_ptr_) {
|
|
if (OB_FAIL(deep_copy(ptr, total_len))) {
|
|
COMMON_LOG(WARN, "deep copy rowkey failed.",
|
|
KP_(obj_ptr), KP_(obj_cnt), K(ret));
|
|
} else {
|
|
rhs.assign(reinterpret_cast<ObObj *>(ptr), obj_cnt_);
|
|
}
|
|
} else {
|
|
rhs.assign(NULL, 0);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
template <typename Allocator>
|
|
int ObRowkey::deep_copy(ObRowkey &rhs, Allocator &allocator) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
int64_t total_len = get_deep_copy_size();
|
|
char *ptr = NULL;
|
|
if (0 == total_len) {
|
|
rhs.obj_ptr_ = NULL;
|
|
rhs.obj_cnt_ = 0;
|
|
} else if (OB_ISNULL(ptr = (char *)allocator.alloc(total_len))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
COMMON_LOG(WARN, "allocate mem for obj array failed.",
|
|
K(total_len), K(ret));
|
|
} else if (OB_FAIL(deep_copy(rhs, ptr, total_len))) {
|
|
COMMON_LOG(WARN, "failed to deep copy", K(ret));
|
|
}
|
|
|
|
if (OB_FAIL(ret) && NULL != ptr) {
|
|
allocator.free(ptr);
|
|
ptr = NULL;
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
template<typename Allocator>
|
|
int ObRowkey::to_collation_free_rowkey(ObRowkey &collation_free_rowkey, Allocator &allocator) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (obj_cnt_ <= 0 || NULL == obj_ptr_) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
STORAGE_LOG(WARN, "invalid argument", K(ret), K(obj_cnt_), K(obj_ptr_));
|
|
} else {
|
|
ObObj *endkey = NULL;
|
|
if (NULL == (endkey = reinterpret_cast<ObObj*>(allocator.alloc(
|
|
sizeof(ObObj) * obj_cnt_)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
STORAGE_LOG(WARN, "failed to alloc endkey", K(ret));
|
|
} else {
|
|
const bool is_copy_all = true;
|
|
bool is_obj_collation_free_valid = false;
|
|
collation_free_rowkey.assign(endkey, obj_cnt_);
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < obj_cnt_; ++i) {
|
|
if (obj_ptr_[i].is_character_type()) {
|
|
if (OB_FAIL(obj_ptr_[i].to_collation_free_obj(collation_free_rowkey.obj_ptr_[i], is_obj_collation_free_valid, allocator))) {
|
|
COMMON_LOG(WARN, "fail to convert obj to collation free obj", K(ret), K(obj_ptr_[i]));
|
|
} else if (!is_obj_collation_free_valid) {
|
|
collation_free_rowkey.assign(NULL, 0);
|
|
break;
|
|
}
|
|
} else {
|
|
obj_ptr_[i].copy_value_or_obj(collation_free_rowkey.obj_ptr_[i], is_copy_all);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
collation_free_rowkey.assign(NULL, 0);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
template<typename Allocator>
|
|
int ObRowkey::to_collation_free_rowkey_on_demand(ObRowkey &collation_free_rowkey, Allocator &allocator) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool need_transform = false;
|
|
if (obj_cnt_ <= 0 || NULL == obj_ptr_) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
STORAGE_LOG(WARN, "invalid argument", K(ret), K(obj_cnt_), K(obj_ptr_));
|
|
} else if (OB_FAIL(need_transform_to_collation_free(need_transform))) {
|
|
STORAGE_LOG(WARN, "fail to get if need to transform to collation free rowkey", K(ret));
|
|
} else if (need_transform && OB_FAIL(to_collation_free_rowkey(collation_free_rowkey, allocator))) {
|
|
STORAGE_LOG(WARN, "fail to get collation free rowkey", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
inline std::ostream &operator<<(std::ostream &os, const ObRowkey &key) // for google test
|
|
{
|
|
os << " len=" << key.get_obj_cnt();
|
|
return os;
|
|
}
|
|
|
|
template <typename AllocatorT>
|
|
int ob_write_rowkey(AllocatorT &allocator, const ObRowkey &src, ObRowkey &dst)
|
|
{
|
|
return src.deep_copy(dst, allocator);
|
|
}
|
|
|
|
// only shallow copy obj, varchar is not copied
|
|
inline int ObRowkey::obj_copy(ObRowkey &dest_rowkey, ObObj *obj_buf, const int64_t cnt) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_UNLIKELY(NULL == obj_buf)
|
|
|| OB_UNLIKELY(cnt < obj_cnt_)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
COMMON_LOG(WARN, "invalid argument.",
|
|
KP(obj_buf), K(cnt), K_(obj_cnt), K(ret));
|
|
} else if (OB_UNLIKELY(!is_legal())) {
|
|
ret = OB_INVALID_DATA;
|
|
COMMON_LOG(WARN, "illegal rowkey.",
|
|
KP_(obj_ptr), K_(obj_cnt), K(ret));
|
|
} else {
|
|
for (int64_t i = 0; i < obj_cnt_; ++i) {
|
|
obj_buf[i] = obj_ptr_[i];
|
|
}
|
|
dest_rowkey.assign(obj_buf, obj_cnt_);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#endif //OCEANBASE_COMMON_OB_ROWKEY_H_
|