Coverage Report

Created: 2025-06-10 13:21

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
697
void BlockHandle::EncodeTo(std::string* dst) const {
16
  // Sanity check that all fields have been set
17
697
  assert(offset_ != ~static_cast<uint64_t>(0));
  Branch (17:3): [True: 697, False: 0]
18
697
  assert(size_ != ~static_cast<uint64_t>(0));
  Branch (18:3): [True: 697, False: 0]
19
697
  PutVarint64(dst, offset_);
20
697
  PutVarint64(dst, size_);
21
697
}
22
23
89
Status BlockHandle::DecodeFrom(Slice* input) {
24
89
  if (GetVarint64(input, &offset_) && GetVarint64(input, &size_)) {
  Branch (24:7): [True: 89, False: 0]
  Branch (24:39): [True: 89, False: 0]
25
89
    return Status::OK();
26
89
  } else {
27
0
    return Status::Corruption("bad block handle");
28
0
  }
29
89
}
30
31
24
void Footer::EncodeTo(std::string* dst) const {
32
24
  const size_t original_size = dst->size();
33
24
  metaindex_handle_.EncodeTo(dst);
34
24
  index_handle_.EncodeTo(dst);
35
24
  dst->resize(2 * BlockHandle::kMaxEncodedLength);  // Padding
36
24
  PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber & 0xffffffffu));
37
24
  PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber >> 32));
38
24
  assert(dst->size() == original_size + kEncodedLength);
  Branch (38:3): [True: 24, False: 0]
39
24
  (void)original_size;  // Disable unused variable warning.
40
24
}
41
42
24
Status Footer::DecodeFrom(Slice* input) {
43
24
  const char* magic_ptr = input->data() + kEncodedLength - 8;
44
24
  const uint32_t magic_lo = DecodeFixed32(magic_ptr);
45
24
  const uint32_t magic_hi = DecodeFixed32(magic_ptr + 4);
46
24
  const uint64_t magic = ((static_cast<uint64_t>(magic_hi) << 32) |
47
24
                          (static_cast<uint64_t>(magic_lo)));
48
24
  if (magic != kTableMagicNumber) {
  Branch (48:7): [True: 0, False: 24]
49
0
    return Status::Corruption("not an sstable (bad magic number)");
50
0
  }
51
52
24
  Status result = metaindex_handle_.DecodeFrom(input);
53
24
  if (result.ok()) {
  Branch (53:7): [True: 24, False: 0]
54
24
    result = index_handle_.DecodeFrom(input);
55
24
  }
56
24
  if (result.ok()) {
  Branch (56:7): [True: 24, False: 0]
57
    // We skip over any leftover data (just padding for now) in "input"
58
24
    const char* end = magic_ptr + 8;
59
24
    *input = Slice(end, input->data() + input->size() - end);
60
24
  }
61
24
  return result;
62
24
}
63
64
Status ReadBlock(RandomAccessFile* file, const ReadOptions& options,
65
84
                 const BlockHandle& handle, BlockContents* result) {
66
84
  result->data = Slice();
67
84
  result->cachable = false;
68
84
  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
84
  size_t n = static_cast<size_t>(handle.size());
73
84
  char* buf = new char[n + kBlockTrailerSize];
74
84
  Slice contents;
75
84
  Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf);
76
84
  if (!s.ok()) {
  Branch (76:7): [True: 0, False: 84]
77
0
    delete[] buf;
78
0
    return s;
79
0
  }
80
84
  if (contents.size() != n + kBlockTrailerSize) {
  Branch (80:7): [True: 0, False: 84]
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
84
  const char* data = contents.data();  // Pointer to where Read put the data
87
84
  if (options.verify_checksums) {
  Branch (87:7): [True: 84, False: 0]
88
84
    const uint32_t crc = crc32c::Unmask(DecodeFixed32(data + n + 1));
89
84
    const uint32_t actual = crc32c::Value(data, n + 1);
90
84
    if (actual != crc) {
  Branch (90:9): [True: 0, False: 84]
91
0
      delete[] buf;
92
0
      s = Status::Corruption("block checksum mismatch", file->GetName());
93
0
      return s;
94
0
    }
95
84
  }
96
97
84
  switch (data[n]) {
98
84
    case kNoCompression:
  Branch (98:5): [True: 84, False: 0]
99
84
      if (data != buf) {
  Branch (99:11): [True: 84, 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
84
        delete[] buf;
104
84
        result->data = Slice(data, n);
105
84
        result->heap_allocated = false;
106
84
        result->cachable = false;  // Do not double-cache
107
84
      } 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
84
      break;
115
0
    case kSnappyCompression: {
  Branch (115:5): [True: 0, False: 84]
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: 84]
134
0
      delete[] buf;
135
0
      return Status::Corruption("bad block type", file->GetName());
136
84
  }
137
138
84
  return Status::OK();
139
84
}
140
141
}  // namespace leveldb