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

paticcaa / pain / 17455596282

04 Sep 2025 06:40AM UTC coverage: 56.572% (+0.4%) from 56.202%
17455596282

push

github

ivanallen
add snapshot

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

1424 of 3382 branches covered (42.11%)

Branch coverage included in aggregate %.

53 of 79 new or added lines in 9 files covered. (67.09%)

5 existing lines in 3 files now uncovered.

1688 of 2119 relevant lines covered (79.66%)

439.4 hits per line

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

57.79
/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/txn_store.h"
5

6
namespace pain::deva {
7

8
Namespace::Namespace(common::StorePtr store) : _store(store) {
24✔
9
    _root = UUID::from_str_or_die("00000000-0000-0000-0000-000000000000");
72!
10
}
24✔
11

12
Status Namespace::load() {
×
13
    return Status::OK();
×
14
}
15

16
Status Namespace::create(const UUID& parent, const std::string& name, FileType type, const UUID& inode) {
92✔
17
    auto txn = _store->begin_txn();
92!
18
    if (!txn) {
92!
19
        return Status(EIO, "Failed to begin transaction");
×
20
    }
21
    auto rollback = make_scope_exit([&txn]() {
184✔
22
        auto status = txn->rollback();
×
23
        if (!status.ok()) {
×
24
            PLOG_ERROR(("desc", "Failed to rollback")("status", status));
×
25
        }
26
    });
92✔
27
    // find parent
28
    std::string dentries_str;
92✔
29
    proto::DirEntries dentries;
92!
30
    auto status = txn->hget(_dentry_key, parent.str(), &dentries_str);
90!
31
    if (status.ok()) {
92✔
32
        if (!dentries.ParseFromString(dentries_str)) {
67!
33
            return Status(EBADMSG, "Failed to parse dentries");
×
34
        }
35
    } else if (status.error_code() != ENOENT) {
25!
36
        // something wrong
37
        return status;
×
38
    }
39
    // check if name or inode already exists
40
    for (const auto& dentry : dentries.entries()) {
642!
41
        if (dentry.name() == name) {
550!
42
            return Status(EEXIST, "File name already exists");
×
43
        }
44
        if (dentry.file_id().high() == inode.high() && dentry.file_id().low() == inode.low()) {
550!
45
            return Status(EEXIST, "File inode already exists");
×
46
        }
47
    }
48
    // create dentry
49
    auto dentry = dentries.add_entries();
92!
50
    dentry->set_name(name);
51
    dentry->mutable_file_id()->set_high(inode.high());
92!
52
    dentry->mutable_file_id()->set_low(inode.low());
92!
53
    dentry->mutable_parent_file_id()->set_high(parent.high());
92!
54
    dentry->mutable_parent_file_id()->set_low(parent.low());
92!
55
    dentry->set_type(static_cast<proto::FileType>(type));
92!
56
    dentries_str.clear();
92✔
57
    if (!dentries.SerializeToString(&dentries_str)) {
92!
58
        return Status(EBADMSG, "Failed to serialize dentries");
×
59
    }
60
    // create dentry
61
    txn->hset(_dentry_key, parent.str(), dentries_str);
92!
62

63
    // insert file info
64
    proto::FileInfo file_info;
92!
65
    file_info.mutable_file_id()->set_high(inode.high());
92!
66
    file_info.mutable_file_id()->set_low(inode.low());
92!
67
    file_info.set_type(static_cast<proto::FileType>(type));
92!
68
    file_info.set_size(0);
92!
69
    file_info.set_ctime(0);
92!
70
    file_info.set_mtime(0);
92!
71
    file_info.set_atime(0);
92!
72
    file_info.set_uid(0);
92!
73
    file_info.set_gid(0);
92!
74
    std::string file_info_str;
92✔
75
    if (!file_info.SerializeToString(&file_info_str)) {
92!
76
        return Status(EBADMSG, "Failed to serialize file info");
×
77
    }
78
    txn->hset(_inode_key, inode.str(), file_info_str);
91!
79

80
    status = txn->commit();
92!
81
    if (!status.ok()) {
92!
82
        return status;
×
83
    }
84
    rollback.release();
92✔
85
    return Status::OK();
91✔
86
}
91✔
87

88
Status Namespace::remove(const UUID& parent, const std::string& name) {
3✔
89
    // find parent
90
    auto txn = _store->begin_txn();
3!
91
    if (!txn) {
3!
92
        return Status(EIO, "Failed to begin transaction");
×
93
    }
94
    auto rollback = make_scope_exit([&txn]() {
6✔
95
        auto status = txn->rollback();
×
96
        if (!status.ok()) {
×
97
            PLOG_ERROR(("desc", "Failed to rollback")("status", status));
×
98
        }
99
    });
3✔
100
    // get dentries
101
    std::string dentries_str;
3✔
102
    auto status = txn->hget(_dentry_key, parent.str(), &dentries_str);
3!
103
    if (!status.ok()) {
3!
104
        return status;
×
105
    }
106
    proto::DirEntries dentries;
3!
107
    if (!dentries.ParseFromString(dentries_str)) {
3!
108
        return Status(EBADMSG, "Failed to parse dentries");
×
109
    }
110
    // remove dentry
111
    UUID file_id;
3✔
112
    auto entry =
3✔
113
        std::find_if(dentries.entries().begin(), dentries.entries().end(), [&name](const proto::DirEntry& dentry) {
3!
114
            return dentry.name() == name;
3✔
115
        });
116
    if (entry == dentries.entries().end()) {
3!
117
        return Status(ENOENT, "No such file or directory");
×
118
    }
119
    file_id = UUID(entry->file_id().high(), entry->file_id().low());
3!
120
    dentries.mutable_entries()->erase(entry);
3!
121
    // set dentries
122
    if (!dentries.SerializeToString(&dentries_str)) {
3!
123
        return Status(EBADMSG, "Failed to serialize dentries");
×
124
    }
125
    txn->hset(_dentry_key, parent.str(), dentries_str);
3!
126

127
    // remove file info
128
    txn->hdel(_inode_key, file_id.str());
3!
129

130
    status = txn->commit();
3!
131
    if (!status.ok()) {
3!
132
        return status;
×
133
    }
134
    rollback.release();
3✔
135
    return Status::OK();
3✔
136
}
3✔
137

138
void Namespace::list(const UUID& parent, std::list<DirEntry>* entries) const {
9✔
139
    entries->clear();
9✔
140
    std::string dentries_str;
9✔
141
    auto status = _store->hget(_dentry_key, parent.str(), &dentries_str);
9!
142
    if (!status.ok()) {
9!
143
        return;
×
144
    }
145
    proto::DirEntries dentries;
9!
146
    if (!dentries.ParseFromString(dentries_str)) {
9!
147
        return;
×
148
    }
149
    for (const auto& dentry : dentries.entries()) {
45!
150
        entries->emplace_back(
72!
151
            UUID(dentry.file_id().high(), dentry.file_id().low()), dentry.name(), static_cast<FileType>(dentry.type()));
72!
152
    }
153
}
9!
154

155
// parse path such as /a/b/c to ["a", "b", "c"]
156
Status Namespace::parse_path(const char* path, std::list<std::string_view>* components) const {
93✔
157
    const char* p = path;
93✔
158
    if (*p != '/') {
93✔
159
        return Status(EINVAL, fmt::format("Invalid path:{}", path));
3!
160
    }
161

162
    while (*p != '\0') {
314✔
163
        if (*p == '/') {
222✔
164
            p++;
120✔
165
            continue;
120✔
166
        }
167
        const char* q = p;
102✔
168
        while (*q != '\0' && *q != '/') {
406✔
169
            q++;
304✔
170
        }
171
        components->emplace_back(p, q - p);
102!
172
        p = q;
102✔
173
    }
174
    return Status::OK();
92✔
175
}
176

177
Status Namespace::lookup(const char* path, UUID* inode, FileType* file_type) const {
86✔
178
    std::list<std::string_view> components;
86✔
179
    auto status = parse_path(path, &components);
86!
180
    if (!status.ok()) {
86!
UNCOV
181
        return status;
×
182
    }
183

184
    UUID parent = _root;
86✔
185
    *file_type = FileType::kDirectory;
86✔
186

187
    for (const auto& component : components) {
164✔
188
        std::string dentries_str;
80✔
189
        auto status = _store->hget(_dentry_key, parent.str(), &dentries_str);
80!
190
        if (!status.ok()) {
80!
191
            return status;
×
192
        }
193
        proto::DirEntries dentries;
79!
194
        if (!dentries.ParseFromString(dentries_str)) {
79!
195
            return Status(EBADMSG, fmt::format("Failed to parse dentries: {}", component));
×
196
        }
197
        auto entry = std::find_if(
160!
198
            dentries.entries().begin(), dentries.entries().end(), [&component](const proto::DirEntry& dentry) {
80!
199
                return dentry.name() == component;
90✔
200
            });
201
        if (entry == dentries.entries().end()) {
80!
202
            return Status(ENOENT, fmt::format("No such file or directory: {}", component));
3!
203
        }
204
        if (entry->type() == static_cast<proto::FileType>(FileType::kFile) && component != components.back()) {
78!
205
            return Status(ENOENT, fmt::format("Not a directory: {}", component));
3!
206
        }
207
        parent = UUID(entry->file_id().high(), entry->file_id().low());
78!
208
        *file_type = static_cast<FileType>(entry->type());
78!
209
    }
84✔
210
    *inode = parent;
83✔
211
    return Status::OK();
83✔
212
}
85✔
213

214
} // 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