Coverage Report

Created: 2026-08-06 18:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/load/group_commit/wal/wal_writer.cpp
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#include "load/group_commit/wal/wal_writer.h"
19
20
#include <crc32c/crc32c.h>
21
#include <gen_cpp/AgentService_types.h>
22
#include <gen_cpp/FrontendService_types.h>
23
24
#include "common/config.h"
25
#include "common/status.h"
26
#include "io/fs/encrypted_fs_factory.h"
27
#include "io/fs/file_system.h"
28
#include "io/fs/file_writer.h"
29
#include "io/fs/local_file_system.h"
30
#include "io/fs/path.h"
31
#include "load/group_commit/wal/wal_manager.h"
32
#include "runtime/cluster_info.h"
33
#include "storage/storage_engine.h"
34
#include "util/thrift_rpc_helper.h"
35
36
namespace doris {
37
38
const char* k_wal_magic = "WAL1";
39
const uint32_t k_wal_magic_length = 4;
40
41
2
WalWriter::WalWriter(const std::string& file_name) : _file_name(file_name) {}
42
43
2
WalWriter::~WalWriter() {}
44
45
2
Status determine_wal_fs(int64_t db_id, int64_t tb_id, io::FileSystemSPtr& fs) {
46
2
    if (!config::enable_wal_tde) {
47
2
        fs = io::global_local_filesystem();
48
2
        return Status::OK();
49
2
    }
50
51
#ifndef BE_TEST
52
    TNetworkAddress master_addr = ExecEnv::GetInstance()->cluster_info()->master_fe_addr;
53
    TGetTableTDEInfoRequest req;
54
    req.__set_db_id(db_id);
55
    req.__set_table_id(tb_id);
56
    TGetTableTDEInfoResult ret;
57
    RETURN_IF_ERROR(ThriftRpcHelper::rpc<FrontendServiceClient>(
58
            master_addr.hostname, master_addr.port,
59
            [&req, &ret](FrontendServiceConnection& client) {
60
                client->getTableTDEInfo(ret, req);
61
            }));
62
    if (auto st = Status::create(ret.status); !st) {
63
        return st;
64
    }
65
    auto encrypt_algorithm = [&ret]() -> EncryptionAlgorithmPB {
66
        switch (ret.algorithm) {
67
        case doris::TEncryptionAlgorithm::AES256:
68
            return EncryptionAlgorithmPB::AES_256_CTR;
69
        case doris::TEncryptionAlgorithm::SM4:
70
            return EncryptionAlgorithmPB::SM4_128_CTR;
71
        default:
72
            return EncryptionAlgorithmPB::PLAINTEXT;
73
        }
74
    }();
75
76
    auto local_fs = io::global_local_filesystem();
77
    fs = io::make_file_system(local_fs, encrypt_algorithm);
78
#else
79
0
    fs = io::global_local_filesystem();
80
0
#endif
81
82
0
    return Status::OK();
83
2
}
84
85
2
Status WalWriter::init(const io::FileSystemSPtr& fs) {
86
2
    io::Path wal_path = _file_name;
87
2
    auto parent_path = wal_path.parent_path();
88
2
    bool exists = false;
89
2
    RETURN_IF_ERROR(fs->exists(parent_path, &exists));
90
2
    if (!exists) {
91
0
        RETURN_IF_ERROR(fs->create_directory(parent_path));
92
0
    }
93
2
    RETURN_IF_ERROR(fs->create_file(_file_name, &_file_writer));
94
2
    LOG(INFO) << "create wal " << _file_name;
95
2
    return Status::OK();
96
2
}
97
98
2
Status WalWriter::finalize() {
99
2
    if (!_file_writer) {
100
0
        return Status::InternalError("wal writer is null,fail to close file={}", _file_name);
101
0
    }
102
2
    auto st = _file_writer->close();
103
2
    if (!st.ok()) {
104
0
        LOG(WARNING) << "fail to close wal " << _file_name;
105
0
    }
106
2
    return Status::OK();
107
2
}
108
109
3
Status WalWriter::append_blocks(const PBlockArray& blocks) {
110
3
    if (!_file_writer) {
111
0
        return Status::InternalError("wal writer is null,fail to write file={}", _file_name);
112
0
    }
113
3
    size_t total_size = 0;
114
3
    size_t offset = 0;
115
4
    for (const auto& block : blocks) {
116
4
        uint8_t len_buf[sizeof(uint64_t)];
117
4
        uint64_t block_length = block->ByteSizeLong();
118
4
        total_size += LENGTH_SIZE + block_length + CHECKSUM_SIZE;
119
4
        encode_fixed64_le(len_buf, block_length);
120
4
        RETURN_IF_ERROR(_file_writer->append({len_buf, sizeof(uint64_t)}));
121
4
        offset += LENGTH_SIZE;
122
123
4
        std::string content = block->SerializeAsString();
124
4
        RETURN_IF_ERROR(_file_writer->append(content));
125
4
        offset += block_length;
126
127
4
        uint8_t checksum_buf[sizeof(uint32_t)];
128
4
        uint32_t checksum = crc32c::Crc32c(content.data(), block_length);
129
4
        encode_fixed32_le(checksum_buf, checksum);
130
4
        RETURN_IF_ERROR(_file_writer->append({checksum_buf, sizeof(uint32_t)}));
131
4
        offset += CHECKSUM_SIZE;
132
4
    }
133
3
    if (offset != total_size) {
134
0
        return Status::InternalError(
135
0
                "failed to write block to wal expected= " + std::to_string(total_size) +
136
0
                ",actually=" + std::to_string(offset));
137
0
    }
138
3
    return Status::OK();
139
3
}
140
141
1
Status WalWriter::append_header(std::string col_ids) {
142
1
    if (!_file_writer) {
143
0
        return Status::InternalError("wal writer is null,fail to write file={}", _file_name);
144
0
    }
145
1
    size_t total_size = 0;
146
1
    uint64_t length = col_ids.size();
147
1
    total_size += k_wal_magic_length;
148
1
    total_size += VERSION_SIZE;
149
1
    total_size += LENGTH_SIZE;
150
1
    total_size += length;
151
1
    size_t offset = 0;
152
1
    RETURN_IF_ERROR(_file_writer->append({k_wal_magic, k_wal_magic_length}));
153
1
    offset += k_wal_magic_length;
154
155
1
    uint8_t version_buf[sizeof(uint32_t)];
156
1
    encode_fixed32_le(version_buf, WAL_VERSION);
157
1
    RETURN_IF_ERROR(_file_writer->append({version_buf, sizeof(uint32_t)}));
158
1
    offset += VERSION_SIZE;
159
1
    uint8_t len_buf[sizeof(uint64_t)];
160
1
    encode_fixed64_le(len_buf, length);
161
1
    RETURN_IF_ERROR(_file_writer->append({len_buf, sizeof(uint64_t)}));
162
1
    offset += LENGTH_SIZE;
163
1
    RETURN_IF_ERROR(_file_writer->append(col_ids));
164
1
    offset += length;
165
1
    if (offset != total_size) {
166
0
        return Status::InternalError(
167
0
                "failed to write header to wal expected= " + std::to_string(total_size) +
168
0
                ",actually=" + std::to_string(offset));
169
0
    }
170
1
    return Status::OK();
171
1
}
172
173
} // namespace doris