Skip to content

Commit 59ec2a7

Browse files
rock-gitchuandew
authored andcommitted
[feat][mdsv2] Adjust fsstat web page.
1 parent e48f5c3 commit 59ec2a7

File tree

10 files changed

+586
-80
lines changed

10 files changed

+586
-80
lines changed

dev-scripts/test.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import os
2+
import shutil
3+
import stat
4+
import random
5+
import string
6+
import time
7+
import threading
8+
from concurrent.futures import ThreadPoolExecutor
9+
import queue
10+
import argparse
11+
12+
def generate_random_string(length=10):
13+
"""生成随机字符串"""
14+
return ''.join(random.choices(string.ascii_letters + string.digits, k=length))
15+
16+
17+
def create_blank_file(file_path):
18+
"""创建一个空白文件"""
19+
with open(file_path, 'w', encoding='utf-8') as f:
20+
pass
21+
return file_path
22+
23+
def create_directory(dir_path):
24+
"""创建一个目录"""
25+
os.makedirs(dir_path, exist_ok=True)
26+
return dir_path
27+
28+
29+
30+
# 递归创建目录和文件,每层创建10个子目录和1000个文件
31+
def create_nested_structure(base_path, depth, num_dirs=10, num_files=1000):
32+
"""递归创建目录和文件结构"""
33+
if depth == 0:
34+
return
35+
36+
for i in range(num_dirs):
37+
dir_name = f"dir_{i:05d}"
38+
dir_path = os.path.join(base_path, dir_name)
39+
create_directory(dir_path)
40+
41+
# 在当前目录下创建文件
42+
for j in range(num_files):
43+
44+
file_name = f"file_{j:010d}"
45+
file_path = os.path.join(dir_path, file_name)
46+
create_blank_file(file_path)
47+
48+
# 递归创建更深层的目录结构
49+
create_nested_structure(dir_path, depth - 1, num_dirs, num_files)
50+
51+
return base_path
52+
53+
# 递归删除目录和文件
54+
def delete_nested_structure(base_path):
55+
"""递归删除目录和文件结构"""
56+
if not os.path.exists(base_path):
57+
return
58+
59+
for item in os.listdir(base_path):
60+
item_path = os.path.join(base_path, item)
61+
if os.path.isdir(item_path):
62+
delete_nested_structure(item_path)
63+
else:
64+
os.remove(item_path)
65+
66+
os.rmdir(base_path)
67+
68+
# 多个线程同时调用create_nested_structure函数去创建目录和文件
69+
def threaded_create_structure(base_path, depth, num_threads=5, num_dirs=10, num_files=1000):
70+
"""使用多线程创建目录和文件结构"""
71+
with ThreadPoolExecutor(max_workers=num_threads) as executor:
72+
futures = []
73+
for i in range(num_threads):
74+
thread_base_path = f"{base_path}_thread_{i}"
75+
futures.append(executor.submit(create_nested_structure, thread_base_path, depth, num_dirs, num_files))
76+
77+
for future in futures:
78+
future.result() # 等待所有线程完成
79+
80+
def main():
81+
print("start test......")
82+
83+
# 解析命令行参数
84+
parser = argparse.ArgumentParser(description="Test script for creating and deleting nested directory structures.")
85+
parser.add_argument('--path', type=str, default='test_structure', help='Base path for the nested structure')
86+
parser.add_argument('--depth', type=int, default=3, help='Depth of the nested structure')
87+
parser.add_argument('--threads', type=int, default=5, help='Number of threads to use for creating structure')
88+
args = parser.parse_args()
89+
90+
91+
try:
92+
# 运行各种测试
93+
base_path = args.path
94+
depth = args.depth
95+
print(f"Creating nested structure at {base_path} with depth {depth}...")
96+
97+
create_nested_structure(base_path, depth, num_dirs=5, num_files=1000)
98+
99+
print("\ntest finish!")
100+
101+
finally:
102+
# delete_nested_structure(base_path)
103+
# print("\ncleanup completed!")
104+
pass
105+
106+
if __name__ == "__main__":
107+
main()

src/client/vfs/meta/v2/rpc.h

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <glog/logging.h>
2222
#include <json/config.h>
2323

24+
#include <cstdint>
2425
#include <map>
2526
#include <memory>
2627
#include <string>
@@ -31,6 +32,7 @@
3132
#include "dingofs/error.pb.h"
3233
#include "dingofs/mdsv2.pb.h"
3334
#include "fmt/core.h"
35+
#include "mdsv2/common/helper.h"
3436
#include "utils/concurrent/concurrent.h"
3537

3638
namespace dingofs {
@@ -152,30 +154,33 @@ Status RPC::SendRequest(const EndPoint& endpoint,
152154
cntl.set_timeout_ms(FLAGS_rpc_timeout_ms);
153155
cntl.set_log_id(butil::fast_rand());
154156

157+
uint64_t start_us = mdsv2::Helper::TimestampUs();
155158
channel->CallMethod(method, &cntl, &request, &response, nullptr);
159+
uint64_t elapsed_us = mdsv2::Helper::TimestampUs() - start_us;
156160
if (cntl.Failed()) {
157-
LOG(ERROR) << fmt::format("[rpc][{}][{}] fail, {} {} {} request({}).",
158-
EndPointToStr(endpoint), api_name,
159-
cntl.log_id(), cntl.ErrorCode(),
160-
cntl.ErrorText(), request.ShortDebugString());
161+
LOG(ERROR) << fmt::format(
162+
"[rpc][{}][{}][{}us] fail, {} {} {} request({}).",
163+
EndPointToStr(endpoint), api_name, elapsed_us, cntl.log_id(),
164+
cntl.ErrorCode(), cntl.ErrorText(), request.ShortDebugString());
161165
DeleteChannel(endpoint);
162166
return Status::NetError(cntl.ErrorCode(), cntl.ErrorText());
163167
}
164168

165169
if (response.error().errcode() == pb::error::OK) {
166170
LOG(INFO) << fmt::format(
167-
"[rpc][{}][{}] success, request({}) response({}).",
168-
EndPointToStr(endpoint), api_name, request.ShortDebugString(),
169-
response.ShortDebugString());
171+
"[rpc][{}][{}][{}us] success, request({}) response({}).",
172+
EndPointToStr(endpoint), api_name, elapsed_us,
173+
request.ShortDebugString(), response.ShortDebugString());
170174
return Status();
171175
}
172176

173177
++retry_count;
174178

175179
LOG(ERROR) << fmt::format(
176-
"[rpc][{}][{}] fail, request({}) retry_count({}) error({} {}).",
177-
EndPointToStr(endpoint), api_name, request.ShortDebugString(),
178-
retry_count, pb::error::Errno_Name(response.error().errcode()),
180+
"[rpc][{}][{}][{}us] fail, request({}) retry_count({}) error({} {}).",
181+
EndPointToStr(endpoint), api_name, elapsed_us,
182+
request.ShortDebugString(), retry_count,
183+
pb::error::Errno_Name(response.error().errcode()),
179184
response.error().errmsg());
180185

181186
// the errno of need retry

src/mdsv2/common/constant.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ const uint32_t kSetAttrNlink = 1 << 7;
3131

3232
const int kEmptyDirMinLinkNum = 2;
3333

34+
const uint64_t kRootIno = 1;
35+
const uint64_t kRootParentIno = 0;
36+
3437
} // namespace mdsv2
3538
} // namespace dingofs
3639

src/mdsv2/filesystem/filesystem.cc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,6 @@ static const int64_t kInoTableId = 1001;
5555
static const int64_t kInoBatchSize = 32;
5656
static const int64_t kInoStartId = 100000;
5757

58-
static const uint64_t kRootIno = 1;
59-
static const uint64_t kRootParentIno = 0;
60-
6158
static const std::string kFsTableName = "dingofs";
6259

6360
static const std::string kStatsName = ".stats";

src/mdsv2/filesystem/fs_utils.cc

Lines changed: 142 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,29 @@
1414

1515
#include "mdsv2/filesystem/fs_utils.h"
1616

17-
#include <fmt/format.h>
18-
#include <glog/logging.h>
19-
2017
#include <cstdint>
2118
#include <map>
19+
#include <string>
20+
#include <vector>
2221

2322
#include "dingofs/mdsv2.pb.h"
24-
#include "fmt/core.h"
23+
#include "fmt/format.h"
24+
#include "glog/logging.h"
2525
#include "mdsv2/common/codec.h"
26+
#include "mdsv2/common/constant.h"
2627
#include "mdsv2/common/helper.h"
2728
#include "mdsv2/common/logging.h"
2829
#include "mdsv2/common/status.h"
30+
#include "mdsv2/common/type.h"
2931
#include "nlohmann/json.hpp"
3032

3133
namespace dingofs {
3234
namespace mdsv2 {
3335

3436
DEFINE_int32(fs_scan_batch_size, 10000, "fs scan batch size");
3537

38+
static const uint32_t kBatchGetSize = 1000;
39+
3640
void FreeFsTree(FsTreeNode* root) {
3741
if (root == nullptr) {
3842
return;
@@ -237,5 +241,139 @@ std::string FsUtils::GenFsTreeJsonString() {
237241
return doc.dump();
238242
}
239243

244+
Status FsUtils::GenRootDirJsonString(std::string& result) {
245+
const uint32_t fs_id = fs_info_.fs_id();
246+
247+
auto txn = kv_storage_->NewTxn();
248+
249+
std::string value;
250+
auto status = txn->Get(MetaCodec::EncodeInodeKey(fs_id, kRootIno), value);
251+
if (!status.ok()) {
252+
DINGO_LOG(ERROR) << fmt::format("[fsutils] get root inode fail, {}.", status.error_str());
253+
return status;
254+
}
255+
256+
auto attr = MetaCodec::DecodeInodeValue(value);
257+
258+
nlohmann::json doc = nlohmann::json::array();
259+
260+
nlohmann::json item;
261+
item["ino"] = attr.ino();
262+
item["name"] = "/";
263+
item["type"] = "directory";
264+
if (fs_info_.partition_policy().type() == pb::mdsv2::PartitionType::MONOLITHIC_PARTITION) {
265+
item["node"] = fs_info_.partition_policy().mono().mds_id();
266+
} else {
267+
item["node"] = hash_router_->GetMDS(attr.ino());
268+
}
269+
270+
// mode,nlink,uid,gid,size,ctime,mtime,atime
271+
item["description"] =
272+
fmt::format("{},{}/{},{},{},{},{},{},{},{}", attr.version(), attr.mode(), Helper::FsModeToString(attr.mode()),
273+
attr.nlink(), attr.uid(), attr.gid(), attr.length(), FormatTime(attr.ctime()),
274+
FormatTime(attr.mtime()), FormatTime(attr.atime()));
275+
276+
doc.push_back(item);
277+
278+
result = doc.dump();
279+
return Status::OK();
280+
}
281+
282+
Status FsUtils::GenDirJsonString(Ino parent, std::string& result) {
283+
if (parent == kRootParentIno) {
284+
return GenRootDirJsonString(result);
285+
}
286+
287+
const uint32_t fs_id = fs_info_.fs_id();
288+
Range range;
289+
MetaCodec::EncodeDentryRange(fs_id, parent, range.start_key, range.end_key);
290+
291+
auto txn = kv_storage_->NewTxn();
292+
293+
std::vector<KeyValue> kvs;
294+
auto status = txn->Scan(range, 100000, kvs);
295+
if (!status.ok()) {
296+
DINGO_LOG(ERROR) << fmt::format("[fsutils] scan dentry table fail, {}.", status.error_str());
297+
return status;
298+
}
299+
300+
if (kvs.empty()) {
301+
return Status(pb::error::ENOT_FOUND, "not found kv");
302+
}
303+
304+
// add child dentry
305+
std::map<Ino, DentryType> dentries;
306+
for (size_t i = 1; i < kvs.size(); ++i) {
307+
const auto& kv = kvs.at(i);
308+
auto dentry = MetaCodec::DecodeDentryValue(kv.value);
309+
dentries.insert(std::make_pair(dentry.ino(), dentry));
310+
}
311+
312+
// batch get inode attrs
313+
std::map<Ino, AttrType> attrs;
314+
uint32_t count = 0;
315+
std::vector<std::string> keys;
316+
keys.reserve(kBatchGetSize);
317+
for (auto& [ino, dentry] : dentries) {
318+
keys.push_back(MetaCodec::EncodeInodeKey(fs_id, ino));
319+
320+
if (++count == dentries.size() || keys.size() == kBatchGetSize) {
321+
std::vector<KeyValue> inode_kvs;
322+
status = txn->BatchGet(keys, inode_kvs);
323+
if (!status.ok()) {
324+
DINGO_LOG(ERROR) << fmt::format("[fsutils] batch get inode attrs fail, {}.", status.error_str());
325+
return status;
326+
}
327+
328+
if (inode_kvs.size() != keys.size()) {
329+
DINGO_LOG(WARNING) << fmt::format("[fsutils] batch get inode attrs size({}) not match keys size({}).",
330+
inode_kvs.size(), keys.size());
331+
}
332+
333+
for (const auto& kv : inode_kvs) {
334+
auto attr = MetaCodec::DecodeInodeValue(kv.value);
335+
attrs.insert(std::make_pair(attr.ino(), attr));
336+
}
337+
338+
keys.clear();
339+
}
340+
}
341+
342+
// gen json
343+
nlohmann::json doc = nlohmann::json::array();
344+
for (auto& [ino, dentry] : dentries) {
345+
auto it = attrs.find(ino);
346+
if (it == attrs.end()) {
347+
DINGO_LOG(ERROR) << fmt::format("[fsutils] not found attr for dentry({}/{})", dentry.ino(), dentry.name());
348+
continue;
349+
}
350+
351+
const auto& attr = it->second;
352+
353+
nlohmann::json item;
354+
item["ino"] = dentry.ino();
355+
item["name"] = dentry.name();
356+
item["type"] = dentry.type() == pb::mdsv2::FileType::DIRECTORY ? "directory" : "file";
357+
if (fs_info_.partition_policy().type() == pb::mdsv2::PartitionType::MONOLITHIC_PARTITION) {
358+
item["node"] = fs_info_.partition_policy().mono().mds_id();
359+
} else {
360+
item["node"] = (dentry.type() == pb::mdsv2::FileType::DIRECTORY) ? hash_router_->GetMDS(dentry.ino())
361+
: hash_router_->GetMDS(dentry.parent());
362+
}
363+
364+
// mode,nlink,uid,gid,size,ctime,mtime,atime
365+
item["description"] =
366+
fmt::format("{},{}/{},{},{},{},{},{},{},{}", attr.version(), attr.mode(), Helper::FsModeToString(attr.mode()),
367+
attr.nlink(), attr.uid(), attr.gid(), attr.length(), FormatTime(attr.ctime()),
368+
FormatTime(attr.mtime()), FormatTime(attr.atime()));
369+
370+
doc.push_back(item);
371+
}
372+
373+
result = doc.dump();
374+
375+
return Status::OK();
376+
}
377+
240378
} // namespace mdsv2
241379
} // namespace dingofs

src/mdsv2/filesystem/fs_utils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,11 @@ class FsUtils {
7474

7575
FsTreeNode* GenFsTree(uint32_t fs_id);
7676
std::string GenFsTreeJsonString();
77+
Status GenDirJsonString(Ino parent, std::string& result);
7778

7879
private:
7980
void GenFsTreeJson(FsTreeNode* node, nlohmann::json& doc);
81+
Status GenRootDirJsonString(std::string& result);
8082

8183
FsInfoType fs_info_;
8284
KVStorageSPtr kv_storage_;

0 commit comments

Comments
 (0)