text: /**
   * Copyright (c) 2021 OceanBase
   * OceanBase Database Proxy(ODP) 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_ROW_CHECKSUM_H_
  #define OCEANBASE_COMMON_OB_ROW_CHECKSUM_H_
  
  #include <utility>
  #include "lib/ob_define.h"
  #include "lib/utility/utility.h"
  #include "lib/allocator/page_arena.h"
  
  namespace oceanbase
  {
  namespace common
  {
  
  class ObRow;
  struct ObRowChecksumValue
  {
    typedef std::pair<uint64_t, uint64_t> ObColumnIdChecksum;
  
  
    ObRowChecksumValue() { reset(); }
  
    NEED_SERIALIZE_AND_DESERIALIZE;
  
    template <typename Allocator>
    int deep_copy(const ObRowChecksumValue &src, Allocator &allocator);
  
    void reset();
    void reset_checksum();
  
    void sort();
  
    int64_t to_string(char *buf, const int64_t buf_len) const;
  
    int column_checksum2string(char *buf, const int64_t buf_len, int64_t &pos) const;
    template <typename Allocator>
    int string2column_checksum(Allocator &allocator, const char *str);
  
    uint64_t checksum_;
    // we do not store detail column checksum if %column_count_ is zero
    int64_t column_count_;
    ObColumnIdChecksum *column_checksum_array_;
  };
  
  template <int I>
  const char *column_checksum2string(const ObRowChecksumValue &v)
  {
    const static int BUFFER_SIZE = 16 * 1024;
    static __thread char buf[BUFFER_SIZE];
    int64_t pos = 0;
    const char *result = buf;
    int ret = v.column_checksum2string(buf, BUFFER_SIZE, pos);
    if (OB_FAIL(ret)) {
      COMMON_LOG(WARN, "column checksum to string failed", K(ret),
          "column_count",  v.column_count_);
      result = NULL;
    }
    return result;
  }
  
  template <typename Allocator>
  int ObRowChecksumValue::deep_copy(const ObRowChecksumValue &src, Allocator &allocator)
  {
    int ret = OB_SUCCESS;
  
    checksum_ = src.checksum_;
    column_count_ = src.column_count_;
    if (0 == column_count_) {
      column_checksum_array_ = NULL;
    } else {
      if (NULL == (column_checksum_array_ = reinterpret_cast<ObColumnIdChecksum *>(
          allocator.alloc(sizeof(ObColumnIdChecksum) * column_count_)))) {
        ret = OB_ALLOCATE_MEMORY_FAILED;
        COMMON_LOG(WARN, "allocate memory failed", K(ret),
            "size", sizeof(ObColumnIdChecksum) * column_count_);
      } else {
        MEMCPY(column_checksum_array_, src.column_checksum_array_,
               sizeof(ObColumnIdChecksum) * column_count_);
      }
    }
  
    return ret;
  }
  
  template <typename Allocator>
  int ObRowChecksumValue::string2column_checksum(Allocator &allocator, const char *str)
  {
    // %str can be NULL
    int64_t count = (NULL != str && strlen(str) > 0) ? 1 : 0;
    const char *p = str;
    int ret = OB_SUCCESS;
    while (NULL != p && NULL != (p = strchr(p, ','))) {
      p++;
      count++;
    }
    column_count_ = count;
    if (count == 0) {
      column_checksum_array_ = NULL;
    } else if (NULL == (column_checksum_array_ = reinterpret_cast<ObColumnIdChecksum *>(
        allocator.alloc(sizeof(*column_checksum_array_) * count)))) {
      ret = OB_ALLOCATE_MEMORY_FAILED;
      COMMON_LOG(WARN, "allocate memory failed", K(ret),
          "size", sizeof(*column_checksum_array_) * count);
    } else {
      p = str;
      char *end = NULL;
      for (int64_t i = 0; i < count; i++) {
        column_checksum_array_[i].first = strtoul(p, &end, 10);
        if (*end != ':') {
          ret = OB_INVALID_DATE_FORMAT;
          COMMON_LOG(WARN, "invalid column check string format", K(ret), K(str));
          break;
        }
        end++;
        p = end;
        column_checksum_array_[i].second = strtoul(p, &end, 10);
        if (*end != ',' && *end != '\0') {
          ret = OB_INVALID_DATE_FORMAT;
          COMMON_LOG(WARN, "invalid column check string format", K(ret), K(str));
          break;
        }
        end++;
        p = end;
      }
  
      if (OB_FAIL(ret)) {
        allocator.free(column_checksum_array_);
        column_checksum_array_ = NULL;
      }
    }
  
    return ret;
  }
  
  } // end namespace common
  } // end namespace oceanbase
  
  #endif // OCEANBASE_COMMON_OB_ROW_CHECKSUM_H_
  