Coverage Report

Created: 2025-08-28 07:02

/src/leveldb/table/format.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file. See the AUTHORS file for names of contributors.
4
5
#include "table/format.h"
6
7
#include "leveldb/env.h"
8
#include "leveldb/options.h"
9
#include "port/port.h"
10
#include "table/block.h"
11
#include "util/coding.h"
12
#include "util/crc32c.h"
13
14
namespace leveldb {
15
16
263k
void BlockHandle::EncodeTo(std::string* dst) const {
17
  // Sanity check that all fields have been set
18
263k
  assert(offset_ != ~static_cast<uint64_t>(0));
19
263k
  assert(size_ != ~static_cast<uint64_t>(0));
20
263k
  PutVarint64(dst, offset_);
21
263k
  PutVarint64(dst, size_);
22
263k
}
23
24
2.05M
Status BlockHandle::DecodeFrom(Slice* input) {
25
2.05M
  if (GetVarint64(input, &offset_) && GetVarint64(input, &size_)) {
26
2.05M
    return Status::OK();
27
2.05M
  } else {
28
16
    return Status::Corruption("bad block handle");
29
16
  }
30
2.05M
}
31
32
80.2k
void Footer::EncodeTo(std::string* dst) const {
33
80.2k
  const size_t original_size = dst->size();
34
80.2k
  metaindex_handle_.EncodeTo(dst);
35
80.2k
  index_handle_.EncodeTo(dst);
36
80.2k
  dst->resize(2 * BlockHandle::kMaxEncodedLength);  // Padding
37
80.2k
  PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber & 0xffffffffu));
38
80.2k
  PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber >> 32));
39
80.2k
  assert(dst->size() == original_size + kEncodedLength);
40
80.2k
  (void)original_size;  // Disable unused variable warning.
41
80.2k
}
42
43
653k
Status Footer::DecodeFrom(Slice* input) {
44
653k
  if (input->size() < kEncodedLength) {
45
0
    return Status::Corruption("not an sstable (footer too short)");
46
0
  }
47
48
653k
  const char* magic_ptr = input->data() + kEncodedLength - 8;
49
653k
  const uint32_t magic_lo = DecodeFixed32(magic_ptr);
50
653k
  const uint32_t magic_hi = DecodeFixed32(magic_ptr + 4);
51
653k
  const uint64_t magic = ((static_cast<uint64_t>(magic_hi) << 32) |
52
653k
                          (static_cast<uint64_t>(magic_lo)));
53
653k
  if (magic != kTableMagicNumber) {
54
0
    return Status::Corruption("not an sstable (bad magic number)");
55
0
  }
56
57
653k
  Status result = metaindex_handle_.DecodeFrom(input);
58
653k
  if (result.ok()) {
59
653k
    result = index_handle_.DecodeFrom(input);
60
653k
  }
61
653k
  if (result.ok()) {
62
    // We skip over any leftover data (just padding for now) in "input"
63
653k
    const char* end = magic_ptr + 8;
64
653k
    *input = Slice(end, input->data() + input->size() - end);
65
653k
  }
66
653k
  return result;
67
653k
}
68
69
Status ReadBlock(RandomAccessFile* file, const ReadOptions& options,
70
1.40M
                 const BlockHandle& handle, BlockContents* result) {
71
1.40M
  result->data = Slice();
72
1.40M
  result->cachable = false;
73
1.40M
  result->heap_allocated = false;
74
75
  // Read the block contents as well as the type/crc footer.
76
  // See table_builder.cc for the code that built this structure.
77
1.40M
  size_t n = static_cast<size_t>(handle.size());
78
1.40M
  char* buf = new char[n + kBlockTrailerSize];
79
1.40M
  Slice contents;
80
1.40M
  Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf);
81
1.40M
  if (!s.ok()) {
82
0
    delete[] buf;
83
0
    return s;
84
0
  }
85
1.40M
  if (contents.size() != n + kBlockTrailerSize) {
86
0
    delete[] buf;
87
0
    return Status::Corruption("truncated block read");
88
0
  }
89
90
  // Check the crc of the type and the block contents
91
1.40M
  const char* data = contents.data();  // Pointer to where Read put the data
92
1.40M
  if (options.verify_checksums) {
93
0
    const uint32_t crc = crc32c::Unmask(DecodeFixed32(data + n + 1));
94
0
    const uint32_t actual = crc32c::Value(data, n + 1);
95
0
    if (actual != crc) {
96
0
      delete[] buf;
97
0
      s = Status::Corruption("block checksum mismatch");
98
0
      return s;
99
0
    }
100
0
  }
101
102
1.40M
  switch (data[n]) {
103
1.40M
    case kNoCompression:
104
1.40M
      if (data != buf) {
105
        // File implementation gave us pointer to some other data.
106
        // Use it directly under the assumption that it will be live
107
        // while the file is open.
108
1.40M
        delete[] buf;
109
1.40M
        result->data = Slice(data, n);
110
1.40M
        result->heap_allocated = false;
111
1.40M
        result->cachable = false;  // Do not double-cache
112
1.40M
      } else {
113
0
        result->data = Slice(buf, n);
114
0
        result->heap_allocated = true;
115
0
        result->cachable = true;
116
0
      }
117
118
      // Ok
119
1.40M
      break;
120
0
    case kSnappyCompression: {
121
0
      size_t ulength = 0;
122
0
      if (!port::Snappy_GetUncompressedLength(data, n, &ulength)) {
123
0
        delete[] buf;
124
0
        return Status::Corruption("corrupted snappy compressed block length");
125
0
      }
126
0
      char* ubuf = new char[ulength];
127
0
      if (!port::Snappy_Uncompress(data, n, ubuf)) {
128
0
        delete[] buf;
129
0
        delete[] ubuf;
130
0
        return Status::Corruption("corrupted snappy compressed block contents");
131
0
      }
132
0
      delete[] buf;
133
0
      result->data = Slice(ubuf, ulength);
134
0
      result->heap_allocated = true;
135
0
      result->cachable = true;
136
0
      break;
137
0
    }
138
0
    case kZstdCompression: {
139
0
      size_t ulength = 0;
140
0
      if (!port::Zstd_GetUncompressedLength(data, n, &ulength)) {
141
0
        delete[] buf;
142
0
        return Status::Corruption("corrupted zstd compressed block length");
143
0
      }
144
0
      char* ubuf = new char[ulength];
145
0
      if (!port::Zstd_Uncompress(data, n, ubuf)) {
146
0
        delete[] buf;
147
0
        delete[] ubuf;
148
0
        return Status::Corruption("corrupted zstd compressed block contents");
149
0
      }
150
0
      delete[] buf;
151
0
      result->data = Slice(ubuf, ulength);
152
0
      result->heap_allocated = true;
153
0
      result->cachable = true;
154
0
      break;
155
0
    }
156
0
    default:
157
0
      delete[] buf;
158
0
      return Status::Corruption("bad block type");
159
1.40M
  }
160
161
1.40M
  return Status::OK();
162
1.40M
}
163
164
}  // namespace leveldb