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

paticcaa / pain / 17367121930

01 Sep 2025 03:54AM UTC coverage: 43.591% (-0.04%) from 43.635%
17367121930

push

github

ivanallen
refactor store

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

1011 of 3023 branches covered (33.44%)

Branch coverage included in aggregate %.

116 of 199 new or added lines in 10 files covered. (58.29%)

1 existing line in 1 file now uncovered.

1152 of 1939 relevant lines covered (59.41%)

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

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

80
    status = txn->commit();
18!
81
    if (!status.ok()) {
18!
NEW
82
        return status;
×
83
    }
84
    rollback.release();
18✔
85
    return Status::OK();
18✔
86
}
18✔
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!
NEW
92
        return Status(EIO, "Failed to begin transaction");
×
93
    }
94
    auto rollback = make_scope_exit([&txn]() {
6✔
NEW
95
        auto status = txn->rollback();
×
NEW
96
        if (!status.ok()) {
×
NEW
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!
NEW
104
        return status;
×
105
    }
106
    proto::DirEntries dentries;
3!
107
    if (!dentries.ParseFromString(dentries_str)) {
3!
NEW
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!
NEW
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!
NEW
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!
NEW
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 {
7✔
139
    entries->clear();
7✔
140
    std::string dentries_str;
7✔
141
    auto status = _store->hget(_dentry_key, parent.str(), &dentries_str);
7!
142
    if (!status.ok()) {
7!
UNCOV
143
        return;
×
144
    }
145
    proto::DirEntries dentries;
7!
146
    if (!dentries.ParseFromString(dentries_str)) {
7!
NEW
147
        return;
×
148
    }
149
    for (const auto& dentry : dentries.entries()) {
22!
150
        entries->emplace_back(
30!
151
            UUID(dentry.file_id().high(), dentry.file_id().low()), dentry.name(), static_cast<FileType>(dentry.type()));
30!
152
    }
153
}
7!
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 {
17✔
157
    const char* p = path;
17✔
158
    if (*p != '/') {
17✔
159
        return Status(EINVAL, "Invalid path");
1!
160
    }
161

162
    while (*p != '\0') {
96✔
163
        if (*p == '/') {
80✔
164
            p++;
44✔
165
            continue;
44✔
166
        }
167
        const char* q = p;
36✔
168
        while (*q != '\0' && *q != '/') {
76✔
169
            q++;
40✔
170
        }
171
        components->emplace_back(p, q - p);
36!
172
        p = q;
36✔
173
    }
174
    return Status::OK();
16✔
175
}
176

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

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

187
    for (const auto& component : components) {
22✔
188
        std::string dentries_str;
14✔
189
        auto status = _store->hget(_dentry_key, parent.str(), &dentries_str);
14!
190
        if (!status.ok()) {
14!
NEW
191
            return status;
×
192
        }
193
        proto::DirEntries dentries;
14!
194
        if (!dentries.ParseFromString(dentries_str)) {
14!
NEW
195
            return Status(EBADMSG, fmt::format("Failed to parse dentries: {}", component));
×
196
        }
197
        auto entry = std::find_if(
28!
198
            dentries.entries().begin(), dentries.entries().end(), [&component](const proto::DirEntry& dentry) {
14!
199
                return dentry.name() == component;
24✔
200
            });
201
        if (entry == dentries.entries().end()) {
14!
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()) {
13!
205
            return Status(ENOENT, fmt::format("Not a directory: {}", component));
3!
206
        }
207
        parent = UUID(entry->file_id().high(), entry->file_id().low());
12!
208
        *file_type = static_cast<FileType>(entry->type());
12!
209
    }
18✔
210
    *inode = parent;
8✔
211
    return Status::OK();
8✔
212
}
10✔
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