github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/c-deps/libroach/encoding.cc (about)

     1  // Copyright 2014 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  #include "encoding.h"
    12  #include <rocksdb/slice.h>
    13  #include "db.h"
    14  #include "keys.h"
    15  
    16  namespace cockroach {
    17  
    18  void EncodeUint32(std::string* buf, uint32_t v) {
    19    const uint8_t tmp[sizeof(v)] = {
    20        uint8_t(v >> 24),
    21        uint8_t(v >> 16),
    22        uint8_t(v >> 8),
    23        uint8_t(v),
    24    };
    25    buf->append(reinterpret_cast<const char*>(tmp), sizeof(tmp));
    26  }
    27  
    28  void EncodeUint64(std::string* buf, uint64_t v) {
    29    const uint8_t tmp[sizeof(v)] = {
    30        uint8_t(v >> 56), uint8_t(v >> 48), uint8_t(v >> 40), uint8_t(v >> 32),
    31        uint8_t(v >> 24), uint8_t(v >> 16), uint8_t(v >> 8),  uint8_t(v),
    32    };
    33    buf->append(reinterpret_cast<const char*>(tmp), sizeof(tmp));
    34  }
    35  
    36  void EncodeUvarint64(std::string* buf, uint64_t v) {
    37    if (v <= kIntSmall) {
    38      const uint8_t tmp[1] = {
    39          uint8_t(v + kIntZero),
    40      };
    41      buf->append(reinterpret_cast<const char*>(tmp), sizeof(tmp));
    42    } else if (v <= 0xff) {
    43      const uint8_t tmp[2] = {
    44          uint8_t(kIntMax - 7),
    45          uint8_t(v),
    46      };
    47      buf->append(reinterpret_cast<const char*>(tmp), sizeof(tmp));
    48    } else if (v <= 0xffff) {
    49      const uint8_t tmp[3] = {
    50          uint8_t(kIntMax - 6),
    51          uint8_t(v >> 8),
    52          uint8_t(v),
    53      };
    54      buf->append(reinterpret_cast<const char*>(tmp), sizeof(tmp));
    55    } else if (v <= 0xffffff) {
    56      const uint8_t tmp[4] = {
    57          uint8_t(kIntMax - 5),
    58          uint8_t(v >> 16),
    59          uint8_t(v >> 8),
    60          uint8_t(v),
    61      };
    62      buf->append(reinterpret_cast<const char*>(tmp), sizeof(tmp));
    63    } else if (v <= 0xffffffff) {
    64      const uint8_t tmp[5] = {
    65          uint8_t(kIntMax - 4), uint8_t(v >> 24), uint8_t(v >> 16), uint8_t(v >> 8), uint8_t(v),
    66      };
    67      buf->append(reinterpret_cast<const char*>(tmp), sizeof(tmp));
    68    } else if (v <= 0xffffffffff) {
    69      const uint8_t tmp[6] = {
    70          uint8_t(kIntMax - 3), uint8_t(v >> 32), uint8_t(v >> 24),
    71          uint8_t(v >> 16),     uint8_t(v >> 8),  uint8_t(v),
    72      };
    73      buf->append(reinterpret_cast<const char*>(tmp), sizeof(tmp));
    74    } else if (v <= 0xffffffffffff) {
    75      const uint8_t tmp[7] = {
    76          uint8_t(kIntMax - 2), uint8_t(v >> 40), uint8_t(v >> 32), uint8_t(v >> 24),
    77          uint8_t(v >> 16),     uint8_t(v >> 8),  uint8_t(v),
    78      };
    79      buf->append(reinterpret_cast<const char*>(tmp), sizeof(tmp));
    80    } else if (v <= 0xffffffffffffff) {
    81      const uint8_t tmp[8] = {
    82          uint8_t(kIntMax - 1), uint8_t(v >> 48), uint8_t(v >> 40), uint8_t(v >> 32),
    83          uint8_t(v >> 24),     uint8_t(v >> 16), uint8_t(v >> 8),  uint8_t(v),
    84      };
    85      buf->append(reinterpret_cast<const char*>(tmp), sizeof(tmp));
    86    } else {
    87      const uint8_t tmp[9] = {
    88          uint8_t(kIntMax), uint8_t(v >> 56), uint8_t(v >> 48), uint8_t(v >> 40), uint8_t(v >> 32),
    89          uint8_t(v >> 24), uint8_t(v >> 16), uint8_t(v >> 8),  uint8_t(v),
    90      };
    91      buf->append(reinterpret_cast<const char*>(tmp), sizeof(tmp));
    92    }
    93  }
    94  
    95  bool DecodeUint32(rocksdb::Slice* buf, uint32_t* value) {
    96    const int N = sizeof(*value);
    97    if (buf->size() < N) {
    98      return false;
    99    }
   100    const uint8_t* b = reinterpret_cast<const uint8_t*>(buf->data());
   101    *value = (uint32_t(b[0]) << 24) | (uint32_t(b[1]) << 16) | (uint32_t(b[2]) << 8) | uint32_t(b[3]);
   102    buf->remove_prefix(N);
   103    return true;
   104  }
   105  
   106  bool DecodeUint64(rocksdb::Slice* buf, uint64_t* value) {
   107    const int N = sizeof(*value);
   108    if (buf->size() < N) {
   109      return false;
   110    }
   111    const uint8_t* b = reinterpret_cast<const uint8_t*>(buf->data());
   112    *value = (uint64_t(b[0]) << 56) | (uint64_t(b[1]) << 48) | (uint64_t(b[2]) << 40) |
   113             (uint64_t(b[3]) << 32) | (uint64_t(b[4]) << 24) | (uint64_t(b[5]) << 16) |
   114             (uint64_t(b[6]) << 8) | uint64_t(b[7]);
   115    buf->remove_prefix(N);
   116    return true;
   117  }
   118  
   119  bool DecodeUvarint64(rocksdb::Slice* buf, uint64_t* value) {
   120    if (buf->size() == 0) {
   121      return false;
   122    }
   123    int length = uint8_t((*buf)[0]) - kIntZero;
   124    buf->remove_prefix(1);  // skip length byte
   125    if (length <= kIntSmall) {
   126      *value = uint64_t(length);
   127      return true;
   128    }
   129    length -= kIntSmall;
   130    if (length < 0 || length > 8) {
   131      return false;
   132    } else if (buf->size() < length) {
   133      return false;
   134    }
   135    *value = 0;
   136    for (int i = 0; i < length; i++) {
   137      *value = (*value << 8) | uint8_t((*buf)[i]);
   138    }
   139    buf->remove_prefix(length);
   140    return true;
   141  }
   142  
   143  void EncodeTimestamp(std::string& s, int64_t wall_time, int32_t logical) {
   144    EncodeUint64(&s, uint64_t(wall_time));
   145    if (logical != 0) {
   146      EncodeUint32(&s, uint32_t(logical));
   147    }
   148  }
   149  
   150  std::string EncodeTimestamp(DBTimestamp ts) {
   151    std::string s;
   152    s.reserve(kMVCCVersionTimestampSize);
   153    EncodeTimestamp(s, ts.wall_time, ts.logical);
   154    return s;
   155  }
   156  
   157  bool EmptyTimestamp(DBTimestamp ts) { return ts.wall_time == 0 && ts.logical == 0; }
   158  
   159  // MVCC keys are encoded as <key>\x00[<wall_time>[<logical>]]<#timestamp-bytes>. A
   160  // custom RocksDB comparator (DBComparator) is used to maintain the desired
   161  // ordering as these keys do not sort lexicographically correctly.
   162  std::string EncodeKey(const rocksdb::Slice& key, int64_t wall_time, int32_t logical) {
   163    std::string s;
   164    const bool ts = wall_time != 0 || logical != 0;
   165    s.reserve(key.size() + 1 + (ts ? 1 + kMVCCVersionTimestampSize : 0));
   166    s.append(key.data(), key.size());
   167    if (ts) {
   168      // Add a NUL prefix to the timestamp data. See DBPrefixExtractor.Transform
   169      // for more details.
   170      s.push_back(0);
   171      EncodeTimestamp(s, wall_time, logical);
   172    }
   173    s.push_back(char(s.size() - key.size()));
   174    return s;
   175  }
   176  
   177  // MVCC keys are encoded as <key>\x00[<wall_time>[<logical>]]<#timestamp-bytes>. A
   178  // custom RocksDB comparator (DBComparator) is used to maintain the desired
   179  // ordering as these keys do not sort lexicographically correctly.
   180  std::string EncodeKey(DBKey k) { return EncodeKey(ToSlice(k.key), k.wall_time, k.logical); }
   181  
   182  WARN_UNUSED_RESULT bool DecodeTimestamp(rocksdb::Slice* timestamp, int64_t* wall_time,
   183                                          int32_t* logical) {
   184    uint64_t w;
   185    if (!DecodeUint64(timestamp, &w)) {
   186      return false;
   187    }
   188    *wall_time = int64_t(w);
   189    *logical = 0;
   190    if (timestamp->size() > 0) {
   191      // TODO(peter): Use varint decoding here.
   192      uint32_t l;
   193      if (!DecodeUint32(timestamp, &l)) {
   194        return false;
   195      }
   196      *logical = int32_t(l);
   197    }
   198    return true;
   199  }
   200  
   201  WARN_UNUSED_RESULT bool DecodeTimestamp(rocksdb::Slice buf,
   202                                          cockroach::util::hlc::Timestamp* timestamp) {
   203    int64_t wall_time;
   204    int32_t logical;
   205    if (!DecodeTimestamp(&buf, &wall_time, &logical)) {
   206      return false;
   207    }
   208    timestamp->set_wall_time(wall_time);
   209    timestamp->set_logical(logical);
   210    return true;
   211  }
   212  
   213  WARN_UNUSED_RESULT bool DecodeKey(rocksdb::Slice buf, rocksdb::Slice* key, int64_t* wall_time,
   214                                    int32_t* logical) {
   215    key->clear();
   216  
   217    rocksdb::Slice timestamp;
   218    if (!SplitKey(buf, key, &timestamp)) {
   219      return false;
   220    }
   221    if (timestamp.size() > 0) {
   222      timestamp.remove_prefix(1);  // The NUL prefix.
   223      if (!DecodeTimestamp(&timestamp, wall_time, logical)) {
   224        return false;
   225      }
   226    }
   227    return timestamp.empty();
   228  }
   229  
   230  WARN_UNUSED_RESULT bool DecodeRangeIDKey(rocksdb::Slice buf, int64_t* range_id,
   231                                           rocksdb::Slice* infix, rocksdb::Slice* suffix,
   232                                           rocksdb::Slice* detail) {
   233    if (!buf.starts_with(kLocalRangeIDPrefix)) {
   234      return false;
   235    }
   236    // Cut the prefix, the Range ID, and the infix specifier.
   237    buf.remove_prefix(kLocalRangeIDPrefix.size());
   238    uint64_t range_id_uint;
   239    if (!DecodeUvarint64(&buf, &range_id_uint)) {
   240      return false;
   241    }
   242    *range_id = int64_t(range_id_uint);
   243    if (buf.size() < kLocalSuffixLength + 1) {
   244      return false;
   245    }
   246    *infix = rocksdb::Slice(buf.data(), 1);
   247    buf.remove_prefix(1);
   248    *suffix = rocksdb::Slice(buf.data(), kLocalSuffixLength);
   249    buf.remove_prefix(kLocalSuffixLength);
   250    *detail = buf;
   251    return true;
   252  }
   253  
   254  rocksdb::Slice KeyPrefix(const rocksdb::Slice& src) {
   255    rocksdb::Slice key;
   256    rocksdb::Slice ts;
   257    if (!SplitKey(src, &key, &ts)) {
   258      return src;
   259    }
   260    // RocksDB requires that keys generated via Transform be comparable with
   261    // normal encoded MVCC keys. Encoded MVCC keys have a suffix indicating the
   262    // number of bytes of timestamp data. MVCC keys without a timestamp have a
   263    // suffix of 0. We're careful in EncodeKey to make sure that the user-key
   264    // always has a trailing 0. If there is no timestamp this falls out
   265    // naturally. If there is a timestamp we prepend a 0 to the encoded
   266    // timestamp data.
   267    assert(src.size() > key.size() && src[key.size()] == 0);
   268    return rocksdb::Slice(key.data(), key.size() + 1);
   269  }
   270  
   271  WARN_UNUSED_RESULT bool IsInt(rocksdb::Slice* buf) {
   272    if (buf->size() > 0) {
   273      return uint8_t((*buf)[0]) >= kIntMin && uint8_t((*buf)[0]) <= kIntMax;
   274    }
   275  
   276    return false;
   277  }
   278  
   279  WARN_UNUSED_RESULT bool StripTenantPrefix(rocksdb::Slice* buf) {
   280    if (buf->size() == 0) {
   281      return true;
   282    }
   283    // kTenantPrefix is guaranteed to be a single byte.
   284    if ((*buf)[0] != kTenantPrefix[0]) {
   285      return true;
   286    }
   287    buf->remove_prefix(1);
   288    uint64_t tid;
   289    return DecodeUvarint64(buf, &tid);
   290  }
   291  
   292  WARN_UNUSED_RESULT bool DecodeTenantAndTablePrefix(rocksdb::Slice* buf, uint64_t* tbl) {
   293    if (!StripTenantPrefix(buf)) {
   294      return false;
   295    }
   296    if (!IsInt(buf) || !DecodeUvarint64(buf, tbl)) {
   297      return false;
   298    }
   299    return true;
   300  }
   301  }  // namespace cockroach