Coverage Report

Created: 2026-06-01 18:35

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