• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

paticcaa / pain / 17713096990

14 Sep 2025 03:23PM UTC coverage: 55.184% (+0.9%) from 54.268%
17713096990

push

github

ivanallen
extract rsm to common

Signed-off-by: allen <1007729991@qq.com>

1660 of 4120 branches covered (40.29%)

Branch coverage included in aggregate %.

166 of 187 new or added lines in 13 files covered. (88.77%)

101 existing lines in 7 files now uncovered.

1938 of 2400 relevant lines covered (80.75%)

513.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

58.14
/src/deva/namespace.cc
1
#include "deva/namespace.h"
2
#include <pain/base/plog.h>
3
#include <pain/base/scope_exit.h>
4
#include "common/object_id_util.h"
5
#include "common/txn_manager.h"
6
#include "common/txn_store.h"
7

8
namespace pain::deva {
9

10
Namespace::Namespace(common::StorePtr store) : _store(store) {
28✔
11
    _root = ObjectId::from_str_or_die("00000000-00000000-0000-0000-0000-000000000000");
28!
12
}
28✔
13

14
Status Namespace::load() {
×
UNCOV
15
    return Status::OK();
×
16
}
17

18
Status Namespace::create(const ObjectId& parent, const std::string& name, FileType type, const ObjectId& inode) {
94✔
19
    auto in_txn = common::TxnManager::instance().in_txn();
94!
20
    auto this_txn = _store->begin_txn();
94!
21
    auto txn = in_txn ? common::TxnManager::instance().get_txn_store() : this_txn.get();
94!
22
    if (txn == nullptr) {
94!
UNCOV
23
        return Status(EIO, "Failed to begin transaction");
×
24
    }
25
    auto rollback = make_scope_exit([&txn]() {
188✔
26
        auto status = txn->rollback();
×
27
        if (!status.ok()) {
×
UNCOV
28
            PLOG_ERROR(("desc", "Failed to rollback")("status", status));
×
29
        }
30
    });
94✔
31
    if (in_txn) {
94✔
32
        rollback.release();
76✔
33
    }
34
    // find parent
35
    std::string dentries_str;
94✔
36
    proto::DirEntries dentries;
92!
37
    auto status = txn->hget(_dentry_key, parent.str(), &dentries_str);
93!
38
    if (status.ok()) {
92✔
39
        if (!dentries.ParseFromString(dentries_str)) {
69!
UNCOV
40
            return Status(EBADMSG, "Failed to parse dentries");
×
41
        }
42
    } else if (status.error_code() != ENOENT) {
24!
43
        // something wrong
UNCOV
44
        return status;
×
45
    }
46
    // check if name or inode already exists
47
    for (const auto& dentry : dentries.entries()) {
666!
48
        if (dentry.name() == name) {
572!
UNCOV
49
            return Status(EEXIST, "File name already exists");
×
50
        }
51
        if (dentry.file_id() == inode) {
572!
UNCOV
52
            return Status(EEXIST, "File inode already exists");
×
53
        }
54
    }
55
    // create dentry
56
    auto dentry = dentries.add_entries();
94!
57
    dentry->set_name(name);
58
    common::to_proto(inode, dentry->mutable_file_id());
94!
59
    common::to_proto(parent, dentry->mutable_parent_file_id());
94!
60
    dentry->set_type(static_cast<proto::FileType>(type));
94!
61
    dentries_str.clear();
94✔
62
    if (!dentries.SerializeToString(&dentries_str)) {
94!
UNCOV
63
        return Status(EBADMSG, "Failed to serialize dentries");
×
64
    }
65
    // create dentry
66
    txn->hset(_dentry_key, parent.str(), dentries_str);
94!
67

68
    // insert file info
69
    proto::FileInfo file_info;
93!
70
    common::to_proto(inode, file_info.mutable_file_id());
93!
71
    file_info.set_type(static_cast<proto::FileType>(type));
92!
72
    file_info.set_size(0);
92!
73
    file_info.set_ctime(0);
94!
74
    file_info.set_mtime(0);
94!
75
    file_info.set_atime(0);
94!
76
    file_info.set_uid(0);
92!
77
    file_info.set_gid(0);
92!
78
    std::string file_info_str;
92✔
79
    if (!file_info.SerializeToString(&file_info_str)) {
93!
UNCOV
80
        return Status(EBADMSG, "Failed to serialize file info");
×
81
    }
82
    status = txn->hset(_inode_key, inode.str(), file_info_str);
94!
83
    if (!status.ok()) {
94!
UNCOV
84
        return status;
×
85
    }
86

87
    if (in_txn) {
94✔
88
        return Status::OK();
76✔
89
    }
90

91
    status = txn->commit();
18!
92
    if (!status.ok()) {
18!
UNCOV
93
        return status;
×
94
    }
95
    rollback.release();
18✔
96
    return Status::OK();
18✔
97
}
94✔
98

99
Status Namespace::remove(const ObjectId& parent, const std::string& name) {
3✔
100
    auto in_txn = common::TxnManager::instance().in_txn();
3!
101
    auto this_txn = _store->begin_txn();
3!
102
    auto txn = in_txn ? common::TxnManager::instance().get_txn_store() : this_txn.get();
3!
103
    if (txn == nullptr) {
3!
UNCOV
104
        return Status(EIO, "Failed to begin transaction");
×
105
    }
106
    // find parent
107
    auto rollback = make_scope_exit([&txn]() {
6✔
UNCOV
108
        auto status = txn->rollback();
×
UNCOV
109
        if (!status.ok()) {
×
110
            PLOG_ERROR(("desc", "Failed to rollback")("status", status));
×
111
        }
112
    });
3✔
113
    if (in_txn) {
3!
UNCOV
114
        rollback.release();
×
115
    }
116
    // get dentries
117
    std::string dentries_str;
3✔
118
    auto status = txn->hget(_dentry_key, parent.str(), &dentries_str);
3!
119
    if (!status.ok()) {
3!
UNCOV
120
        return status;
×
121
    }
122
    proto::DirEntries dentries;
3!
123
    if (!dentries.ParseFromString(dentries_str)) {
3!
UNCOV
124
        return Status(EBADMSG, "Failed to parse dentries");
×
125
    }
126
    // remove dentry
127
    ObjectId file_id;
3✔
128
    auto entry =
3✔
129
        std::find_if(dentries.entries().begin(), dentries.entries().end(), [&name](const proto::DirEntry& dentry) {
3!
130
            return dentry.name() == name;
3✔
131
        });
132
    if (entry == dentries.entries().end()) {
3!
UNCOV
133
        return Status(ENOENT, "No such file or directory");
×
134
    }
135
    file_id = common::from_proto(entry->file_id());
3!
136
    dentries.mutable_entries()->erase(entry);
3!
137
    // set dentries
138
    if (!dentries.SerializeToString(&dentries_str)) {
3!
UNCOV
139
        return Status(EBADMSG, "Failed to serialize dentries");
×
140
    }
141
    status = txn->hset(_dentry_key, parent.str(), dentries_str);
3!
142
    if (!status.ok()) {
3!
UNCOV
143
        return status;
×
144
    }
145

146
    // remove file info
147
    status = txn->hdel(_inode_key, file_id.str());
3!
148
    if (!status.ok()) {
3!
UNCOV
149
        return status;
×
150
    }
151

152
    if (in_txn) {
3!
UNCOV
153
        return Status::OK();
×
154
    }
155

156
    status = txn->commit();
3!
157
    if (!status.ok()) {
3!
UNCOV
158
        return status;
×
159
    }
160
    rollback.release();
3✔
161
    return Status::OK();
3✔
162
}
3✔
163

164
void Namespace::list(const ObjectId& parent, std::list<DirEntry>* entries) const {
10✔
165
    entries->clear();
10✔
166
    std::string dentries_str;
10✔
167
    auto in_txn = common::TxnManager::instance().in_txn();
10!
168
    auto this_txn = _store->begin_txn();
10!
169
    auto txn = in_txn ? common::TxnManager::instance().get_txn_store() : this_txn.get();
10!
170
    if (txn == nullptr) {
10!
UNCOV
171
        return;
×
172
    }
173
    auto status = txn->hget(_dentry_key, parent.str(), &dentries_str);
10!
174
    if (!status.ok()) {
10!
UNCOV
175
        PLOG_ERROR(("desc", "Failed to get dentries")("status", status));
×
UNCOV
176
        return;
×
177
    }
178
    proto::DirEntries dentries;
10!
179
    if (!dentries.ParseFromString(dentries_str)) {
10!
UNCOV
180
        PLOG_ERROR(("desc", "Failed to parse dentries")("status", status));
×
UNCOV
181
        return;
×
182
    }
183
    for (const auto& dentry : dentries.entries()) {
49!
184
        entries->emplace_back(
78!
185
            common::from_proto(dentry.file_id()), dentry.name(), static_cast<FileType>(dentry.type()));
78!
186
    }
187
    if (in_txn) {
10!
UNCOV
188
        return;
×
189
    }
190

191
    status = txn->commit();
10!
192
    if (!status.ok()) {
10!
UNCOV
193
        PLOG_ERROR(("desc", "Failed to commit")("status", status));
×
194
    }
195
}
10!
196

197
// parse path such as /a/b/c to ["a", "b", "c"]
198
Status Namespace::parse_path(const char* path, std::list<std::string_view>* components) const {
93✔
199
    const char* p = path;
93✔
200
    if (*p != '/') {
93✔
201
        return Status(EINVAL, fmt::format("Invalid path:{}", path));
3!
202
    }
203

204
    while (*p != '\0') {
316✔
205
        if (*p == '/') {
224✔
206
            p++;
121✔
207
            continue;
121✔
208
        }
209
        const char* q = p;
103✔
210
        while (*q != '\0' && *q != '/') {
415✔
211
            q++;
312✔
212
        }
213
        components->emplace_back(p, q - p);
103!
214
        p = q;
103✔
215
    }
216
    return Status::OK();
92✔
217
}
218

219
Status Namespace::lookup(const char* path, ObjectId* inode, FileType* file_type) const {
86✔
220
    std::list<std::string_view> components;
86✔
221
    auto status = parse_path(path, &components);
86!
222
    if (!status.ok()) {
85!
UNCOV
223
        return status;
×
224
    }
225

226
    ObjectId parent = _root;
86✔
227
    *file_type = FileType::kDirectory;
85✔
228

229
    auto in_txn = common::TxnManager::instance().in_txn();
85!
230
    auto this_txn = _store->begin_txn();
85!
231
    auto txn = in_txn ? common::TxnManager::instance().get_txn_store() : this_txn.get();
85!
232
    if (txn == nullptr) {
84!
UNCOV
233
        return Status(EIO, "Failed to begin transaction");
×
234
    }
235

236
    for (const auto& component : components) {
163✔
237
        std::string dentries_str;
79✔
238
        auto status = txn->hget(_dentry_key, parent.str(), &dentries_str);
80!
239
        if (!status.ok()) {
81!
UNCOV
240
            return status;
×
241
        }
242
        proto::DirEntries dentries;
81!
243
        if (!dentries.ParseFromString(dentries_str)) {
81!
UNCOV
244
            return Status(EBADMSG, fmt::format("Failed to parse dentries: {}", component));
×
245
        }
246
        auto entry = std::find_if(
162!
247
            dentries.entries().begin(), dentries.entries().end(), [&component](const proto::DirEntry& dentry) {
81!
248
                return dentry.name() == component;
91✔
249
            });
250
        if (entry == dentries.entries().end()) {
81!
251
            return Status(ENOENT, fmt::format("No such file or directory: {}", component));
3!
252
        }
253
        if (entry->type() == static_cast<proto::FileType>(FileType::kFile) && component != components.back()) {
80!
254
            return Status(ENOENT, fmt::format("Not a directory: {}", component));
3!
255
        }
256
        parent = common::from_proto(entry->file_id());
79!
257
        *file_type = static_cast<FileType>(entry->type());
79!
258
    }
85✔
259
    *inode = parent;
84✔
260
    if (in_txn) {
84✔
261
        return Status::OK();
73✔
262
    }
263

264
    status = txn->commit();
11!
265
    if (!status.ok()) {
11!
UNCOV
266
        PLOG_ERROR(("desc", "Failed to commit")("status", status));
×
267
    }
268
    return status;
11!
269
}
86✔
270

271
} // namespace pain::deva
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc