Compare commits

..

41 Commits

Author SHA1 Message Date
montaguelhz c4174c5510 [feat] tools-v2: add snapshot copyset --all
Signed-off-by: montaguelhz <1443171175@qq.com>
2023-07-16 15:59:18 +08:00
ilixiaocui 26824d62f4 curvefs/fix: addition of the objectPrefix field in the message S3Info has caused compatibility issues
Signed-off-by: ilixiaocui <ilixiaocui@163.com>
2023-07-10 16:21:14 +08:00
Hanqing Wu 09bccf3d8d curvebs/chunkserver: enable odsync by default
Signed-off-by: Hanqing Wu <wuhanqing@corp.netease.com>
2023-07-07 14:33:18 +08:00
Cyber-SiKu ace571a80e [fix]tools-v2: create file
Since the default value creates a striped volume by default when
creating the volume

Signed-off-by: Cyber-SiKu <Cyber-SiKu@outlook.com>
2023-07-05 16:00:15 +08:00
Cyber-SiKu 4caa027859 [fix] rm apt cmd in bs
debian9 eol. rm apt cmd
It will cause the execution of modprobe nbd to fail when the bs client
container restarts.

Signed-off-by: Cyber-SiKu <Cyber-SiKu@outlook.com>
2023-07-04 15:24:21 +08:00
Hanqing Wu 73defb0fe3 curvebs: support 512 aligned IO
Signed-off-by: Hanqing Wu <wuhanqing@corp.netease.com>
2023-07-03 10:54:09 +08:00
Hanqing Wu 3686938a20 Revert "client/chunkserver/curve-nbd: support 512 aligned IO requests"
This reverts commit de2a121967.

Signed-off-by: Hanqing Wu <wuhanqing@corp.netease.com>
2023-07-03 10:54:09 +08:00
caoxianfei1 8db694299e client supports mounting volumes in different clusters
Signed-off-by: caoxianfei1 <caoxianfei@corp.netease.com>
2023-06-30 10:01:04 +08:00
hzwuhongsong 7e8bc18194 curvefs/client: fix s3 object will not be removed 2023-06-30 09:53:39 +08:00
Hanqing Wu 37055e9eb7 unittest: fix filepool test invalid memory access
Signed-off-by: Hanqing Wu <wuhanqing@corp.netease.com>
2023-06-28 09:46:20 +08:00
swj 44949da50b mds/metaserver: Add idle_timeout_sec option
Signed-off-by: swj <1186093704@qq.com>
2023-06-27 09:58:52 +08:00
Cyber-SiKu 597e5bc502 [fix] warmup to mem error
It turns out that mem and disk are not separated, the storage of mem is
asynchronous, and the storage of disk is synchronous, so when it is
deleted later, it is generally written. Later, after the separation of
the two, an exception occurred in the asynchronous save of mem.

Signed-off-by: Cyber-SiKu <Cyber-SiKu@outlook.com>
2023-06-27 09:57:23 +08:00
Hanqing Wu d436082a0f upgrade googletest to v1.12.1
Signed-off-by: Hanqing Wu <wuhanqing@corp.netease.com>
2023-06-26 17:09:15 +08:00
XR-stb 6e00652be0 [refactor]tools-v2: refactor all *map to map~
Signed-off-by: XR-stb <2322882096@qq.com>
2023-06-26 14:56:42 +08:00
caoxianfei1 746f2c17ec add bs status cluster
Signed-off-by: caoxianfei1 <caoxianfei@corp.netease.com>
2023-06-26 10:00:47 +08:00
Cyber-SiKu f75db7e83c [fix][skipci] relace harbor with opencurve
Signed-off-by: Cyber-SiKu <Cyber-SiKu@outlook.com>
2023-06-26 10:00:39 +08:00
montaguelhz cb8d72f664 [feat] tools-v2: add update leader-schedule
Signed-off-by: montaguelhz <1443171175@qq.com>
2023-06-25 20:37:26 +08:00
dependabot[bot] e770d4aae4 build(deps): bump github.com/cilium/cilium in /tools-v2
Bumps [github.com/cilium/cilium](https://github.com/cilium/cilium) from 1.13.3 to 1.13.4.
- [Release notes](https://github.com/cilium/cilium/releases)
- [Changelog](https://github.com/cilium/cilium/blob/1.13.4/CHANGELOG.md)
- [Commits](https://github.com/cilium/cilium/compare/1.13.3...1.13.4)

---
updated-dependencies:
- dependency-name: github.com/cilium/cilium
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-21 10:43:24 +08:00
baiyongtian 771f8c183a [refactor]tools-v2: optimize duplicate code
Signed-off-by: baytan0720 <baytan2@hotmail.com>
2023-06-19 14:59:42 +08:00
baytan0720 83ee153726 [feat]tools-v2: add bs list may-broken-vol
Signed-off-by: baytan0720 <baytan2@hotmail.com>
2023-06-14 10:51:25 +08:00
Cyber-SiKu 6fa82a12ba [fix]get copysset in clusetr
The judgment condition is wrong. If it is the old way, as long as
filterScanning is set, the filter will be started regardless of the
value, which is inconsistent with expectations.

Signed-off-by: Cyber-SiKu <Cyber-SiKu@outlook.com>
2023-06-13 14:41:27 +08:00
Cyber-SiKu f76ed2d5f2 [fix]fs list copysetinfo err
when run `curve fs status copyset`, while get error:
```bahs
rpc error: code = ResourceExhausted desc = stream terminated by
RST_STREAM with error code: FLOW_CONTROL_ERROR
```

Refer to [issue](https://github.com/apache/brpc/issues/1087).

Signed-off-by: Cyber-SiKu <Cyber-SiKu@outlook.com>
2023-06-12 15:07:54 +08:00
Wine93 75acc364ee curvefs/client: fixed some minor bugs.
Signed-off-by: Wine93 <wine93.info@gmail.com>
2023-06-12 13:46:15 +08:00
Cyber-SiKu 1279ee95d2 [feat] add bs status copyset
Signed-off-by: Cyber-SiKu <Cyber-SiKu@outlook.com>
2023-06-09 10:47:24 +08:00
Hanqing Wu 191a001f9c curvebs/mds: add poolset rules to support assigning poolset based on directories
Signed-off-by: Hanqing Wu <wuhanqing@corp.netease.com>
2023-06-08 19:17:58 +08:00
jolly-sy ada6a181f2 curvebs: support poolset
Co-authored-by: jolly-sy <757050468@qq.com>
Co-authored-by: Hanqing Wu <wuhanqing@corp.netease.com>

Signed-off-by: jolly-sy <757050468@qq.com>
Signed-off-by: Hanqing Wu <wuhanqing@corp.netease.com>
2023-06-08 19:17:58 +08:00
Hanqing Wu d9d74a0a09 curvebs/client: mds address should not be empty
Signed-off-by: Hanqing Wu <wuhanqing@corp.netease.com>
2023-06-08 19:17:58 +08:00
Hanqing Wu 1822d49abc curvebs: fix segfault when enable O_DSYNC
Signed-off-by: Hanqing Wu <wuhanqing@corp.netease.com>
2023-06-08 19:17:58 +08:00
lzb-dell 4762448bbb [curve/toos-v2]: add bs scan-status
Signed-off-by: lianzhanbiao <lzbcs@outlook.com>
2023-06-06 15:46:44 +08:00
SiKu 586a736a7b Update README.md
Signed-off-by: SiKu <Cyber-SiKu@outlook.com>
2023-06-06 14:23:13 +08:00
swj d9e0310c78 fix buildfs.sh failed an debian11
Signed-off-by: swj <1186093704@qq.com>
2023-06-06 09:43:13 +08:00
baytan0720 26a51f0d4b [feat]tools-v2: add update copyset availflag
Signed-off-by: baytan0720 <baytan2@hotmail.com>
2023-06-05 15:44:28 +08:00
Xinlong-Chen f1286c2912 [feat] curvefs: add concurrent apply queue
Signed-off-by: Xinlong-Chen <xl_chen@zju.edu.cn>
2023-06-01 16:02:25 +08:00
Wine93 4ae45e5dd0 curvefs/client: improve metadata performance.
Signed-off-by: Wine93 <wine93.info@gmail.com>
2023-06-01 15:19:00 +08:00
h0hmj 8b12205642 fix python3 cbdclient binding, use bytes instead of str
Signed-off-by: h0hmj <h0hmjcn@gmail.com>
2023-06-01 10:05:42 +08:00
jbk 5a9772b4fe fix_enableSumInDir
Signed-off-by: jbk <2634358021@qq.com>

add_atomic

Signed-off-by: jbk <2634358021@qq.com>
2023-05-30 11:39:40 +08:00
UniverseParticle 4bb0b5267a add qos for curve-fuse, then we can limits the bandwidth and iops
Signed-off-by: UniverseParticle <daidonghuachn@163.com>
2023-05-25 13:59:36 +08:00
Ziy1-Tan cf31a8ba8d curvefs/client: fuse client exit when cache size less than 8MB
Signed-off-by: Ziy1-Tan <ajb459684460@gmail.com>
2023-05-24 16:47:04 +08:00
Ziy1-Tan f07a85e9b2 curvefs/client: remove unused setting fuseMaxSize
Signed-off-by: Ziy1-Tan <ajb459684460@gmail.com>
2023-05-24 14:23:03 +08:00
Sindweller 6f533ae401 feat: add list chunkserver
Signed-off-by: Sindweller <sindweller5530@gmail.com>
2023-05-19 16:32:39 +08:00
Cyber-SiKu cb8244d172 [fix] list space error
Signed-off-by: Cyber-SiKu <Cyber-SiKu@outlook.com>
2023-05-19 10:21:35 +08:00
567 changed files with 20074 additions and 13206 deletions

View File

@ -1,7 +1,10 @@
build --verbose_failures
build --define=with_glog=true --define=libunwind=true
build --copt -DHAVE_ZLIB=1 --copt -DGFLAGS_NS=google --copt -DUSE_BTHREAD_MUTEX
build --cxxopt -Wno-error=format-security
build:gcc7-later --cxxopt -faligned-new
build --incompatible_blacklisted_protos_requires_proto_info=false
build --copt=-fdiagnostics-color=always
run --copt=-fdiagnostics-color=always
run --copt=-fdiagnostics-color=always

19
.gitignore vendored
View File

@ -147,3 +147,22 @@ tools-v2/proto/curvefs/*
tools-v2/*/*.test
tools-v2/__debug_bin
tools-v2/vendor/
.test
.note
.playground
.dumpfile
metastore_test.dat
GPATH
GRTAGS
GTAGS
core.*
test/integration/*.conf
test/integration/client/config/client.conf*
test/integration/snapshotcloneserver/config/*.conf
.pre-commit-config.yaml
*.deb
*.whl

2
.obm.cfg Normal file
View File

@ -0,0 +1,2 @@
container_name: curve-build-playground-master
container_image: opencurvedocker/curve-base:build-debian9

View File

@ -1,6 +1,6 @@
# Copyright (C) 2021 Jingli Chen (Wine93), NetEase Inc.
.PHONY: list build dep install image
.PHONY: list build dep install image playground check test
stor?=""
prefix?= "$(PWD)/projects"
@ -70,3 +70,12 @@ install:
image:
@bash util/image.sh $(stor) $(tag) $(os)
playground:
@bash util/playground.sh
check:
@bash util/check.sh $(stor)
test:
@bash util/test.sh $(stor) $(only)

View File

@ -75,11 +75,14 @@ bind(
)
#import the gtest files.
new_git_repository(
http_archive(
name = "com_google_googletest",
build_file = "//:thirdparties/gmock.BUILD",
remote = "https://github.com/google/googletest",
tag = "release-1.8.0",
urls = [
"https://curve-build.nos-eastchina1.126.net/googletest-release-1.12.1.tar.gz",
"https://github.com/google/googletest/archive/refs/tags/release-1.12.1.tar.gz",
],
sha256 = "81964fe578e9bd7c94dfdb09c8e4d6e6759e19967e397dbea48d1c10e45d0df2",
strip_prefix = "googletest-release-1.12.1",
)
bind(
@ -228,6 +231,24 @@ http_archive(
sha256 = "59b862f50e710277f8ede96f083a5bb8d7c9595376146838b9580be90374ee1f",
)
# fmt
http_archive(
name = "fmt",
url = "https://github.com/fmtlib/fmt/archive/9.1.0.tar.gz",
sha256 = "5dea48d1fcddc3ec571ce2058e13910a0d4a6bab4cc09a809d8b1dd1c88ae6f2",
strip_prefix = "fmt-9.1.0",
build_file = "//:thirdparties/fmt.BUILD",
)
# spdlog
http_archive(
name = "spdlog",
urls = ["https://github.com/gabime/spdlog/archive/refs/tags/v1.11.0.tar.gz"],
strip_prefix = "spdlog-1.11.0",
sha256 = "ca5cae8d6cac15dae0ec63b21d6ad3530070650f68076f3a4a862ca293a858bb",
build_file = "//:thirdparties/spdlog.BUILD",
)
# Bazel platform rules.
http_archive(
name = "platforms",
@ -248,14 +269,14 @@ new_local_repository(
http_archive(
name = "hedron_compile_commands",
# Replace the commit hash in both places (below) with the latest, rather than using the stale one here.
# Replace the commit hash in both places (below) with the latest, rather than using the stale one here.
# Even better, set up Renovate and let it do the work for you (see "Suggestion: Updates" in the README).
urls = [
"https://curve-build.nos-eastchina1.126.net/bazel-compile-commands-extractor-af9af15f7bc16fc3e407e2231abfcb62907d258f.tar.gz",
"https://github.com/hedronvision/bazel-compile-commands-extractor/archive/af9af15f7bc16fc3e407e2231abfcb62907d258f.tar.gz",
],
strip_prefix = "bazel-compile-commands-extractor-af9af15f7bc16fc3e407e2231abfcb62907d258f",
# When you first run this tool, it'll recommend a sha256 hash to put here with a message like: "DEBUG: Rule 'hedron_compile_commands' indicated that a canonical reproducible form can be obtained by modifying arguments sha256 = ..."
# When you first run this tool, it'll recommend a sha256 hash to put here with a message like: "DEBUG: Rule 'hedron_compile_commands' indicated that a canonical reproducible form can be obtained by modifying arguments sha256 = ..."
)
load("@hedron_compile_commands//:workspace_setup.bzl", "hedron_compile_commands_setup")
hedron_compile_commands_setup()

View File

@ -7,12 +7,22 @@ then
exit
fi
if [ `gcc -dumpversion | awk -F'.' '{print $1}'` -le 6 ]
then
bazelflags=''
else
bazelflags='--copt -faligned-new'
fi
if [ "$1" = "debug" ]
then
DEBUG_FLAG="--compilation_mode=dbg"
fi
bazel build curvefs/... --copt -DHAVE_ZLIB=1 ${DEBUG_FLAG} -s --define=with_glog=true --define=libunwind=true --copt -DGFLAGS_NS=google --copt -Wno-error=format-security --copt -DUSE_BTHREAD_MUTEX --copt -DCURVEVERSION=${curve_version} --linkopt -L/usr/local/lib
bazel build curvefs/... --copt -DHAVE_ZLIB=1 ${DEBUG_FLAG} -s \
--define=with_glog=true --define=libunwind=true --copt -DGFLAGS_NS=google --copt -Wno-error=format-security --copt \
-DUSE_BTHREAD_MUTEX --copt -DCURVEVERSION=${curve_version} --linkopt -L/usr/local/lib ${bazelflags}
if [ $? -ne 0 ]
then
echo "build curvefs failed"
@ -34,4 +44,5 @@ then
echo "mds_test failed"
exit
fi
fi
fi
echo "end compile"

View File

@ -9,13 +9,20 @@ global.enable_external_server=true
global.external_ip=127.0.0.1 # __CURVEADM_TEMPLATE__ ${service_external_addr} __CURVEADM_TEMPLATE__
global.external_subnet=127.0.0.0/24
# chunk大小一般16MB
# it will be overwritten from chunkfilepool.meta if `chunkfilepool.enable_get_chunk_from_pool` is true
global.chunk_size=16777216
# chunk 元数据页大小一般4KB
# it will be overwritten from chunkfilepool.meta if `chunkfilepool.enable_get_chunk_from_pool` is true
global.meta_page_size=4096
# chunk's block size, IO requests must align with it, supported value is |512| and |4096|
# it should consist with `block_size` in chunkfilepool.meta_path and `mds.volume.blockSize` in MDS's configurations
# for clone chunk and snapshot chunk, it's also the minimum granularity that each bit represents
# if set to |512|, we need 4096 bytes bitmap for each chunk, so meta_page_size should be 8192 or larger.
# it will be overwritten from chunkfilepool.meta if `chunkfilepool.enable_get_chunk_from_pool` is true
global.block_size=4096
# clone chunk允许的最长location长度
global.location_limit=3000
# minimum alignment for io request
global.min_io_alignment=512
#
# MDS settings
@ -108,7 +115,7 @@ copyset.scan_rpc_retry_times=3
# the follower send scanmap to leader rpc retry interval
copyset.scan_rpc_retry_interval_us=100000
# enable O_DSYNC when open chunkfile
copyset.enable_odsync_when_open_chunkfile=false
copyset.enable_odsync_when_open_chunkfile=true
# sync trigger seconds
copyset.sync_trigger_seconds=25
# sync chunk limit default = 2MB

View File

@ -13,9 +13,12 @@ global.chunk_size=16777216
# chunk 元数据页大小一般4KB
global.meta_page_size=4096
# clone chunk允许的最长location长度
# chunk's block size, IO requests must align with it, supported value is |512| and |4096|
# it should consist with `block_size` in chunkfilepool.meta_path and `mds.volume.blockSize` in MDS's configurations
# for clone chunk and snapshot chunk, it's also the minimum granularity that each bit represents
# if set to |512|, we need 4096 bytes bitmap for each chunk, so meta_page_size should be 8192 or larger.
global.block_size=4096
global.location_limit=3000
# minimum alignment for io request
global.min_io_alignment=512
#
# MDS settings
@ -108,7 +111,7 @@ copyset.scan_rpc_retry_times=3
# the follower send scanmap to leader rpc retry interval
copyset.scan_rpc_retry_interval_us=100000
# enable O_DSYNC when open chunkfile
copyset.enable_odsync_when_open_chunkfile=false
copyset.enable_odsync_when_open_chunkfile=true
# sync trigger seconds
copyset.sync_trigger_seconds=25
# sync chunk limit default = 2MB

View File

@ -168,13 +168,6 @@ discard.granularity=4096
# discard cleanup task delay times in millisecond
discard.taskDelayMs=60000
##### alignment #####
# default alignment
global.alignment.commonVolume=512
# alignment for clone volume
# default is 4096, because lazy clone chunk bitmap granularity is 4096
global.alignment.cloneVolume=4096
##### chunkserver client option #####
# chunkserver client rpc timeout time
csClientOpt.rpcTimeoutMs=500
@ -188,4 +181,3 @@ csClientOpt.rpcMaxTimeoutMs=8000
##### chunkserver broadcaster option #####
# broad cast max machine num
csBroadCasterOpt.broadCastMaxNum=200

View File

@ -159,10 +159,3 @@ discard.enable=false
discard.granularity=4096
# discard cleanup task delay times in millisecond
discard.taskDelayMs=60000
##### alignment #####
# default alignment
global.alignment.commonVolume=512
# alignment for clone volume
# default is 4096, because lazy clone chunk bitmap granularity is 4096
global.alignment.cloneVolume=4096

View File

@ -197,6 +197,8 @@ mds.curvefs.defaultSegmentSize=1073741824
mds.curvefs.minFileLength=10737418240
# curvefs的默认最大文件大小20TB = 20*1024*1024*1024*1024 = 21990232555520
mds.curvefs.maxFileLength=21990232555520
# smallest read/write unit for volume, support |512| and |4096|
mds.curvefs.blockSize=4096
#
# chunkseverclient config
@ -237,3 +239,16 @@ mds.throttle.iopsPerGB=30
mds.throttle.bpsMinInMB=120
mds.throttle.bpsMaxInMB=260
mds.throttle.bpsPerGBInMB=0.3
#
## poolset rules
#
# for backward compatibility, rules are applied for select poolset when creating file
#
# for example
# mds.poolset.rules=/dir1/:poolset1;/dir2/:poolset2;/dir1/sub/:sub
#
# when creating file reqeust doesn't have poolset, above rules are used to select poolset
# - if filename is /dir1/file, then poolset1 is select
# - if filename is /dir1/sub/file, then sub is select
mds.poolset.rules=

View File

@ -153,10 +153,3 @@ discard.enable=false
discard.granularity=4096
# discard cleanup task delay times in millisecond
discard.taskDelayMs=60000
##### alignment #####
# default alignment
global.alignment.commonVolume=512
# alignment for clone volume
# default is 4096, because lazy clone chunk bitmap granularity is 4096
global.alignment.cloneVolume=4096

View File

@ -159,10 +159,3 @@ discard.enable=false
discard.granularity=4096
# discard cleanup task delay times in millisecond
discard.taskDelayMs=60000
##### alignment #####
# default alignment
global.alignment.commonVolume=512
# alignment for clone volume
# default is 4096, because lazy clone chunk bitmap granularity is 4096
global.alignment.cloneVolume=4096

View File

@ -164,7 +164,6 @@ chunkserver_walfilepool_retry_times: 5
chunkserver_trash_expire_after_sec: 300
chunkserver_trash_scan_period_sec: 120
chunkserver_common_log_dir: ./runlog/
chunkserver_min_io_alignment: 512
# 快照克隆配置默认值
snap_client_config_path: /etc/curve/snap_client.conf
@ -244,8 +243,6 @@ client_throttle_enable: false
client_discard_enable: true
client_discard_granularity: 4096
client_discard_task_delay_ms: 60000
client_alignment_common: 512
client_alignment_clone: 4096
# nebd默认配置
client_config_path: /etc/curve/client.conf

View File

@ -14,8 +14,6 @@ global.chunk_size={{ chunk_size }}
global.meta_page_size={{ chunkserver_meta_page_size }}
# clone chunk允许的最长location长度
global.location_limit={{ chunkserver_location_limit }}
# minimum alignment for io request
global.min_io_alignment={{ chunkserver_min_io_alignment }}
#
# MDS settings

View File

@ -175,10 +175,3 @@ discard.enable={{ client_discard_enable }}
discard.granularity={{ client_discard_granularity }}
# discard cleanup task delay times in millisecond
discard.taskDelayMs={{ client_discard_task_delay_ms }}
##### alignment #####
# default alignment
global.alignment.commonVolume={{ client_alignment_common }}
# alignment for clone volume
# default is 4096, because lazy clone chunk bitmap granularity is 4096
global.alignment.cloneVolume={{ client_alignment_clone }}

View File

@ -58,6 +58,10 @@ executorOpt.maxRetryTimesBeforeConsiderSuspend=20
# batch limit of get inode attr and xattr
executorOpt.batchInodeAttrLimit=10000
#### spaceserver
spaceServer.spaceAddr=127.0.0.1:19999 # __ANSIBLE_TEMPLATE__ {{ groups.space | join_peer(hostvars, "space_listen_port") }} __ANSIBLE_TEMPLATE__
spaceServer.rpcTimeoutMs=1000
#### bdev
# curve client's config file
bdev.confPath=/etc/curve/client.conf
@ -73,17 +77,7 @@ rpc.healthCheckIntervalSec=0
#### fuseClient
# TODO(xuchaojie): add unit
fuseClient.attrTimeOut=1.0
fuseClient.entryTimeOut=1.0
fuseClient.listDentryLimit=65536
fuseClient.flushPeriodSec=5
fuseClient.maxNameLength=255
fuseClient.iCacheLruSize=65536
fuseClient.dCacheLruSize=1000000
fuseClient.enableICacheMetrics=true
fuseClient.enableDCacheMetrics=true
fuseClient.lruTimeOutSec=60
fuseClient.cto=true
fuseClient.downloadMaxRetryTimes=3
### kvcache opt
@ -110,6 +104,61 @@ fuseClient.maxDataSize=1024
fuseClient.refreshDataIntervalSec=30
fuseClient.warmupThreadsNum=10
# the write throttle bps of fuseClient, default no limit
fuseClient.throttle.avgWriteBytes=0
# the write burst bps of fuseClient, default no limit
fuseClient.throttle.burstWriteBytes=0
# the times that write burst bps can continue, default 180s
fuseClient.throttle.burstWriteBytesSecs=180
# the write throttle iops of fuseClient, default no limit
fuseClient.throttle.avgWriteIops=0
# the write burst iops of fuseClient, default no limit
fuseClient.throttle.burstWriteIops=0
# the times that write burst Iops can continue, default 180s
fuseClient.throttle.burstWriteIopsSecs=180
# the read throttle bps of fuseClient, default no limit
fuseClient.throttle.avgReadBytes=0
# the read burst bps of fuseClient, default no limit
fuseClient.throttle.burstReadBytes=0
# the times that read burst bps can continue, default 180s
fuseClient.throttle.burstReadBytesSecs=180
# the read throttle iops of fuseClient, default no limit
fuseClient.throttle.avgReadIops=0
# the read burst Iops of fuseClient, default no limit
fuseClient.throttle.burstReadIops=0
# the times that read burst Iops can continue, default 180s
fuseClient.throttle.burstReadIopsSecs=180
#### filesystem metadata
# {
# fs.disableXattr:
# if you want to get better metadata performance,
# you can mount fs with |fs.disableXattr| is true
#
# fs.lookupCache.negativeTimeoutSec:
# entry which not found will be cached if |timeout| > 0
fs.cto=true
fs.maxNameLength=255
fs.disableXattr=false
fs.accessLogging=true
fs.kernelCache.attrTimeoutSec=3600
fs.kernelCache.dirAttrTimeoutSec=3600
fs.kernelCache.entryTimeoutSec=3600
fs.kernelCache.dirEntryTimeoutSec=3600
fs.lookupCache.negativeTimeoutSec=0
fs.lookupCache.minUses=1
fs.lookupCache.lruSize=100000
fs.dirCache.lruSize=5000000
fs.openFile.lruSize=65536
fs.attrWatcher.lruSize=5000000
fs.rpc.listDentryLimit=65536
fs.deferSync.delay=3
fs.deferSync.deferDirMtime=false
# }
#### volume
volume.bigFileSize=1048576
volume.volBlockSize=4096
@ -128,20 +177,9 @@ volume.bitmapAllocator.smallAllocProportion=0.2
# number of block groups that allocated once
volume.blockGroup.allocateOnce=4
## spaceserver
# the space used by the blockgroup exceeds this percentage and can
# be returned to mds [0.8-1]
volume.space.useThreshold=0.95
# the background thread calculates the time interval for returning
# the blockgroup to mds
volume.space.releaseInterSec=300
#### s3
# this is for test. if s3.fakeS3=true, all data will be discarded
s3.fakeS3=false
# the max size that fuse send
s3.fuseMaxSize=131072
s3.pageSize=65536
# prefetch blocks that disk cache use
s3.prefetchBlocks=1
@ -156,6 +194,7 @@ s3.baseSleepUs=500
s3.threadScheduleInterval=3
# data cache flush wait time
s3.cacheFlushIntervalSec=5
# write cache < 8,388,608 (8MB) is not allowed
s3.writeCacheMaxByte=838860800
s3.readCacheMaxByte=209715200
# file cache read thread num

View File

@ -6,6 +6,9 @@ mds.listen.addr=127.0.0.1:6700 #__CURVEADM_TEMPLATE__ ${service_addr}:${service
mds.dummy.port=7700 # __CURVEADM_TEMPLATE__ ${service_dummy_port} __CURVEADM_TEMPLATE__ __ANSIBLE_TEMPLATE__ {{ curvefs_mds_listen_dummy_port }} __ANSIBLE_TEMPLATE__
mds.common.logDir=/tmp/curvefs/mds # __CURVEADM_TEMPLATE__ ${prefix}/logs __CURVEADM_TEMPLATE__ __ANSIBLE_TEMPLATE__ /tmp/{{ inventory_hostname }}/curvefs/mds __ANSIBLE_TEMPLATE__
mds.loglevel=0
# If a connection does not read or write,it's treated as "idle" and will be closed by server soon.
# Default value is -1 which disables the feature.
mds.server.idleTimeoutSec=-1
#
# space options
@ -159,6 +162,3 @@ bs.mds.maxFailedTimesBeforeChangeMDS=2
bs.mds.normalRetryTimesBeforeTriggerWait=3
# sleep interval in ms for wait
bs.mds.waitSleepMs=1000
#### Options for volume space deallcatable setting
mds.space.calIntervalSec=60

View File

@ -128,16 +128,25 @@ copyset.trash.scan_periodsec=120
# this config item should be tuned according cpu/memory/disk
service.max_inflight_request=5000
### apply queue options for each copyset
### apply queue is used to isolate raft threads, each worker has its own queue
### when a task can be applied it's been pushed into a corresponding worker queue by certain rules
# number of apply queue workers for each, each worker will start a indepent thread
applyqueue.worker_count=3
#
# Concurrent apply queue
### concurrent apply queue options for each copyset
### concurrent apply queue is used to isolate raft threads, each worker has its own queue
### when a task can be applied it's been pushed into a corresponding read/write worker queue by certain rules
# apply queue depth for each copyset
# worker_count: number of apply queue workers for each, each worker will start a indepent thread
# queue_depth: apply queue depth for each copyset
# all tasks in queue must be done when do raft snapshot, and raft apply and raft snapshot are executed in same thread
# so, if queue depth is too large, it will cause other tasks to wait too long for apply
applyqueue.queue_depth=1
# write apply queue workers count
applyqueue.write_worker_count=3
# write apply queue depth
applyqueue.write_queue_depth=1
# read apply queue workers count
applyqueue.read_worker_count=2
# read apply queue depth
applyqueue.read_queue_depth=1
# number of worker threads that created by brpc::Server
# if set to |auto|, threads create by brpc::Server is equal to `getconf _NPROCESSORS_ONLN` + 1
@ -145,6 +154,10 @@ applyqueue.queue_depth=1
# it is recommended to set it to |auto| unless there is a significant performance improvement
bthread.worker_count=auto
# If a connection does not read or write, it's treated as "idle" and will be closed by server soon.
# Default value is -1 which disables the feature.
server.idleTimeoutSec=-1
### Braft related flags
### These configurations are ignored if the command line startup options are set
# Call fsync when need
@ -307,9 +320,3 @@ metaCacheOpt.metacacheGetLeaderRetry=3
metaCacheOpt.metacacheRPCRetryIntervalUS=100000
# RPC timeout of get leader
metaCacheOpt.metacacheGetLeaderRPCTimeOutMS=1000
#### volume deallocate
volume.deallocate.enable=true
volume.deallocate.workerNum=5
volume.deallocate.batchClean=10
volume.sdk.confPath=/etc/curvefs/curvebs_client.conf

View File

@ -113,7 +113,6 @@ proto_library(
name = "curvefs_heartbeat_proto",
srcs = ["heartbeat.proto"],
deps = [":curvefs_common_proto",
":metaserver_proto",
"//proto:heartbeat_proto"],
)

View File

@ -31,13 +31,6 @@ enum BitmapLocation {
AtEnd = 2;
}
message EmptyMsg {}
message BlockGroupID {
required uint64 fsId = 1;
required uint64 offset = 2;
}
// When creating fs, `volumeSize` and `extendAlignment` are fetched from the bs cluster
message Volume {
optional uint64 volumeSize = 1;

View File

@ -16,7 +16,6 @@
syntax = "proto2";
import "curvefs/proto/common.proto";
import "curvefs/proto/metaserver.proto";
import "proto/heartbeat.proto";
package curvefs.mds.heartbeat;
option cc_generic_services = true;
@ -28,17 +27,6 @@ option go_package = "curvefs/proto/heartbeat";
// required uint64 diskUsedByte = 2; // the disk this copyset used
// };
enum BlockGroupDeallcateStatusCode {
BGDP_PROCESSING = 0;
BGDP_DONE = 1;
}
message BlockGroupStatInfo {
required uint32 fsId = 1;
repeated metaserver.DeallocatableBlockGroup deallocatableBlockGroups = 2;
map<uint64, BlockGroupDeallcateStatusCode> blockGroupDeallocateStatus = 3;
}
message CopySetInfo {
required uint32 poolId = 1;
required uint32 copysetId = 2;
@ -93,7 +81,6 @@ message MetaServerHeartbeatRequest {
required uint32 leaderCount = 7;
required uint32 copysetCount = 8;
required MetaServerSpaceStatus spaceStatus = 9;
repeated BlockGroupStatInfo blockGroupStatInfos = 10;
};
message CopySetConf {
@ -120,14 +107,11 @@ enum HeartbeatStatusCode {
hbMetaServerIpPortNotMatch = 2;
hbMetaServerTokenNotMatch = 3;
hbAnalyseCopysetError = 4;
hbMetaServerFSUnkown = 5;
}
message MetaServerHeartbeatResponse {
required HeartbeatStatusCode statusCode = 1;
repeated CopySetConf needUpdateCopysets = 2;
// key is fsid, value is blockgroup offset
map<uint64, uint64> issuedBlockGroups = 3;
};
service HeartbeatService {

View File

@ -191,6 +191,7 @@ message RefreshSessionRequest {
message RefreshSessionResponse {
required FSStatusCode statusCode = 1;
repeated topology.PartitionTxId latestTxIdList = 2;
optional bool enableSumInDir = 3;
}
message DLockValue {

View File

@ -167,46 +167,6 @@ enum FsFileType {
TYPE_S3 = 4;
};
message DeallocatableBlockGroup {
required uint64 blockGroupOffset = 1;
optional uint64 deallocatableSize = 2;
repeated uint64 inodeIdlist = 3;
repeated uint64 inodeIdUnderDeallocate = 4;
oneof type {
IncreaseDeallocatableBlockGroup increase = 5;
DecreaseDeallocatableBlockGroup decrease = 6;
MarkDeallocatableBlockGroup mark = 7;
}
}
message IncreaseDeallocatableBlockGroup {
required uint64 increaseDeallocatableSize = 1;
repeated uint64 inodeIdlistAdd = 2;
}
message DecreaseDeallocatableBlockGroup {
required uint64 decreaseDeallocatableSize = 1;
repeated uint64 inodedDeallocated = 2;
}
message MarkDeallocatableBlockGroup {
repeated uint64 inodeIdUnderDeallocate = 2;
}
message UpdateDeallocatableBlockGroupRequest {
required uint32 poolId = 1;
required uint32 copysetId = 2;
required uint32 partitionId = 3;
required uint64 fsId = 4;
repeated DeallocatableBlockGroup update = 5;
}
message UpdateDeallocatableBlockGroupResponse {
required MetaStatusCode statusCode = 1;
optional uint64 appliedIndex = 2;
}
message VolumeExtent {
required uint64 fsOffset = 1;
required uint64 volumeOffset = 2;
@ -219,7 +179,7 @@ message VolumeExtentSlice {
repeated VolumeExtent extents = 2;
}
message VolumeExtentSliceList {
message VolumeExtentList {
repeated VolumeExtentSlice slices = 1;
}
@ -357,7 +317,7 @@ message UpdateInodeRequest {
map<string, bytes> xattr = 20;
repeated uint64 parent = 21;
map<uint64, S3ChunkInfoList> s3ChunkInfoAdd = 22;
optional VolumeExtentSliceList volumeExtents = 23;
optional VolumeExtentList volumeExtents = 23;
}
message UpdateInodeResponse {
@ -504,7 +464,7 @@ message GetVolumeExtentRequest {
message GetVolumeExtentResponse {
required MetaStatusCode statusCode = 1;
optional uint64 appliedIndex = 2;
optional VolumeExtentSliceList slices = 3;
optional VolumeExtentList slices = 3;
}
message UpdateVolumeExtentRequest {
@ -513,7 +473,7 @@ message UpdateVolumeExtentRequest {
required uint32 partitionId = 3;
required uint32 fsId = 4;
required uint64 inodeId = 5;
required VolumeExtentSliceList extents = 6;
required VolumeExtentList extents = 6;
}
message UpdateVolumeExtentResponse {
@ -548,7 +508,4 @@ service MetaServerService {
// volume extent interface
rpc GetVolumeExtent(GetVolumeExtentRequest) returns (GetVolumeExtentResponse);
rpc UpdateVolumeExtent(UpdateVolumeExtentRequest) returns (UpdateVolumeExtentResponse);
// block group with deallocatable inode list interface
rpc UpdateDeallocatableBlockGroup(UpdateDeallocatableBlockGroupRequest) returns (UpdateDeallocatableBlockGroupResponse);
}

View File

@ -48,10 +48,6 @@ message BlockGroup {
required common.BitmapLocation bitmaplocation = 4;
// owner, who owns this block group
optional string owner = 5;
// deallocating, metaserver who is deallocate this block group
repeated uint32 deallocating = 6;
// deallocated, metaserver who finish deallocate this block group
repeated uint32 deallocated = 7;
}
message AllocateBlockGroupRequest {

View File

@ -43,6 +43,8 @@ cc_library(
"s3/*.h",
"volume/*.cpp",
"volume/*.h",
"filesystem/*.cpp",
"filesystem/*.h",
"warmup/*.h",
"warmup/*.cpp",
],
@ -71,11 +73,14 @@ cc_library(
"//curvefs/src/volume",
"//curvefs/src/common:metric_utils",
"//curvefs/src/common:dynamic_vlog",
"//curvefs/src/common:threading",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/synchronization",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/meta:type_traits",
"@com_google_absl//absl/types:optional",
"@com_google_googletest//:gtest_prod",
"@spdlog//:spdlog",
],
)

View File

@ -28,7 +28,7 @@
#include <mutex>
#include "curvefs/proto/metaserver.pb.h"
#include "curvefs/src/client/error_code.h"
#include "curvefs/src/client/filesystem/error.h"
#include "curvefs/src/client/inode_wrapper.h"
namespace curvefs {
@ -63,26 +63,19 @@ CURVEFS_ERROR UpdateVolumeExtentClosure::Wait() {
cond_.wait(lk);
}
return MetaStatusCodeToCurvefsErrCode(GetStatusCode());
return ToFSError(GetStatusCode());
}
void UpdateVolumeExtentClosure::Run() {
auto st = GetStatusCode();
if (!IsOK(st)) {
if (inode_ != nullptr) {
inode_->MarkInodeError();
LOG(ERROR) << "UpdateVolumeExtent failed, error: "
<< MetaStatusCode_Name(st)
<< ", inodeid: " << inode_->GetInodeId();
} else {
LOG(ERROR) << "UpdateVolumeExtent failed, error: "
<< MetaStatusCode_Name(st);
}
LOG(ERROR) << "UpdateVolumeExtent failed, error: "
<< MetaStatusCode_Name(st)
<< ", inodeid: " << inode_->GetInodeId();
inode_->MarkInodeError();
}
if (inode_ != nullptr) {
inode_->syncingVolumeExtentsMtx_.unlock();
}
inode_->syncingVolumeExtentsMtx_.unlock();
if (sync_) {
std::lock_guard<bthread::Mutex> lk(mtx_);

View File

@ -28,12 +28,15 @@
#include <memory>
#include "curvefs/src/client/error_code.h"
#include "curvefs/src/client/rpcclient/task_excutor.h"
#include "curvefs/src/client/filesystem/error.h"
namespace curvefs {
namespace client {
using ::curvefs::client::filesystem::CURVEFS_ERROR;
using ::curvefs::client::filesystem::ToFSError;
class InodeWrapper;
namespace internal {

View File

@ -24,13 +24,14 @@
#include "src/common/uuid.h"
#include "curvefs/src/client/client_operator.h"
#include "curvefs/src/client/filesystem/error.h"
namespace curvefs {
namespace client {
using ::curve::common::UUIDGenerator;
using ::curvefs::metaserver::DentryFlag;
using ::curvefs::mds::topology::PartitionTxId;
using ::curvefs::client::filesystem::ToFSError;
#define LOG_ERROR(action, rc) \
LOG(ERROR) << action << " failed, retCode = " << rc \
@ -95,7 +96,7 @@ CURVEFS_ERROR RenameOperator::GetTxId(uint32_t fsId,
if (rc != MetaStatusCode::OK) {
LOG_ERROR("GetTxId", rc);
}
return MetaStatusCodeToCurvefsErrCode(rc);
return ToFSError(rc);
}
CURVEFS_ERROR RenameOperator::GetLatestTxIdWithLock() {
@ -204,7 +205,7 @@ CURVEFS_ERROR RenameOperator::PrepareRenameTx(
LOG_ERROR("PrepareRenameTx", rc);
}
return MetaStatusCodeToCurvefsErrCode(rc);
return ToFSError(rc);
}
CURVEFS_ERROR RenameOperator::PrepareTx() {
@ -418,8 +419,6 @@ CURVEFS_ERROR RenameOperator::UpdateInodeCtime() {
}
void RenameOperator::UpdateCache() {
dentryManager_->DeleteCache(parentId_, name_);
dentryManager_->InsertOrReplaceCache(newDentry_);
SetTxId(srcPartitionId_, srcTxId_ + 1);
SetTxId(dstPartitionId_, dstTxId_ + 1);
}

View File

@ -60,7 +60,6 @@ enum class MetaServerOpType {
GetVolumeExtent,
UpdateVolumeExtent,
CreateManageInode,
UpdateDeallocatableBlockGroup,
};
std::ostream &operator<<(std::ostream &os, MetaServerOpType optype);

View File

@ -50,6 +50,56 @@ DEFINE_bool(enableCto, true, "acheieve cto consistency");
DEFINE_bool(useFakeS3, false,
"Use fake s3 to inject more metadata for testing metaserver");
DEFINE_bool(supportKVcache, false, "use kvcache to speed up sharing");
DEFINE_bool(access_logging, true, "enable access log");
/**
* use curl -L fuseclient:port/flags/fuseClientAvgWriteBytes?setvalue=true
* for dynamic parameter configuration
*/
static bool pass_uint64(const char *, uint64_t) { return true; }
DEFINE_uint64(fuseClientAvgWriteBytes, 0,
"the write throttle bps of fuse client");
DEFINE_validator(fuseClientAvgWriteBytes, &pass_uint64);
DEFINE_uint64(fuseClientBurstWriteBytes, 0,
"the write burst bps of fuse client");
DEFINE_validator(fuseClientBurstWriteBytes, &pass_uint64);
DEFINE_uint64(fuseClientBurstWriteBytesSecs, 180,
"the times that write burst bps can continue");
DEFINE_validator(fuseClientBurstWriteBytesSecs, &pass_uint64);
DEFINE_uint64(fuseClientAvgWriteIops, 0,
"the write throttle iops of fuse client");
DEFINE_validator(fuseClientAvgWriteIops, &pass_uint64);
DEFINE_uint64(fuseClientBurstWriteIops, 0,
"the write burst iops of fuse client");
DEFINE_validator(fuseClientBurstWriteIops, &pass_uint64);
DEFINE_uint64(fuseClientBurstWriteIopsSecs, 180,
"the times that write burst iops can continue");
DEFINE_validator(fuseClientBurstWriteIopsSecs, &pass_uint64);
DEFINE_uint64(fuseClientAvgReadBytes, 0,
"the Read throttle bps of fuse client");
DEFINE_validator(fuseClientAvgReadBytes, &pass_uint64);
DEFINE_uint64(fuseClientBurstReadBytes, 0,
"the Read burst bps of fuse client");
DEFINE_validator(fuseClientBurstReadBytes, &pass_uint64);
DEFINE_uint64(fuseClientBurstReadBytesSecs, 180,
"the times that Read burst bps can continue");
DEFINE_validator(fuseClientBurstReadBytesSecs, &pass_uint64);
DEFINE_uint64(fuseClientAvgReadIops, 0,
"the Read throttle iops of fuse client");
DEFINE_validator(fuseClientAvgReadIops, &pass_uint64);
DEFINE_uint64(fuseClientBurstReadIops, 0,
"the Read burst iops of fuse client");
DEFINE_validator(fuseClientBurstReadIops, &pass_uint64);
DEFINE_uint64(fuseClientBurstReadIopsSecs, 180,
"the times that Read burst iops can continue");
DEFINE_validator(fuseClientBurstReadIopsSecs, &pass_uint64);
void InitMdsOption(Configuration *conf, MdsOption *mdsOpt) {
conf->GetValueFatalIfFail("mdsOpt.mdsMaxRetryMS", &mdsOpt->mdsMaxRetryMS);
@ -157,8 +207,6 @@ void InitDiskCacheOption(Configuration *conf,
void InitS3Option(Configuration *conf, S3Option *s3Opt) {
conf->GetValueFatalIfFail("s3.fakeS3", &FLAGS_useFakeS3);
conf->GetValueFatalIfFail("s3.fuseMaxSize",
&s3Opt->s3ClientAdaptorOpt.fuseMaxSize);
conf->GetValueFatalIfFail("s3.pageSize",
&s3Opt->s3ClientAdaptorOpt.pageSize);
conf->GetValueFatalIfFail("s3.prefetchBlocks",
@ -197,10 +245,6 @@ void InitVolumeOption(Configuration *conf, VolumeOption *volumeOpt) {
conf->GetValueFatalIfFail("volume.fsBlockSize", &volumeOpt->fsBlockSize);
conf->GetValueFatalIfFail("volume.allocator.type",
&volumeOpt->allocatorOption.type);
conf->GetValueFatalIfFail("volume.space.useThreshold",
&volumeOpt->threshold);
conf->GetValueFatalIfFail("volume.space.releaseInterSec",
&volumeOpt->releaseInterSec);
conf->GetValueFatalIfFail(
"volume.blockGroup.allocateOnce",
@ -249,6 +293,55 @@ void InitKVClientManagerOpt(Configuration *conf,
&config->getThreadPooln);
}
void InitFileSystemOption(Configuration* c, FileSystemOption* option) {
c->GetValueFatalIfFail("fs.cto", &option->cto);
c->GetValueFatalIfFail("fs.cto", &FLAGS_enableCto);
c->GetValueFatalIfFail("fs.disableXattr", &option->disableXattr);
c->GetValueFatalIfFail("fs.maxNameLength", &option->maxNameLength);
c->GetValueFatalIfFail("fs.accessLogging", &FLAGS_access_logging);
{ // kernel cache option
auto o = &option->kernelCacheOption;
c->GetValueFatalIfFail("fs.kernelCache.attrTimeoutSec",
&o->attrTimeoutSec);
c->GetValueFatalIfFail("fs.kernelCache.dirAttrTimeoutSec",
&o->dirAttrTimeoutSec);
c->GetValueFatalIfFail("fs.kernelCache.entryTimeoutSec",
&o->entryTimeoutSec);
c->GetValueFatalIfFail("fs.kernelCache.dirEntryTimeoutSec",
&o->dirEntryTimeoutSec);
}
{ // lookup cache option
auto o = &option->lookupCacheOption;
c->GetValueFatalIfFail("fs.lookupCache.lruSize",
&o->lruSize);
c->GetValueFatalIfFail("fs.lookupCache.negativeTimeoutSec",
&o->negativeTimeoutSec);
c->GetValueFatalIfFail("fs.lookupCache.minUses",
&o->minUses);
}
{ // dir cache option
auto o = &option->dirCacheOption;
c->GetValueFatalIfFail("fs.dirCache.lruSize", &o->lruSize);
}
{ // open file option
auto o = &option->openFilesOption;
c->GetValueFatalIfFail("fs.openFile.lruSize", &o->lruSize);
}
{ // attr watcher option
auto o = &option->attrWatcherOption;
c->GetValueFatalIfFail("fs.attrWatcher.lruSize", &o->lruSize);
}
{ // rpc option
auto o = &option->rpcOption;
c->GetValueFatalIfFail("fs.rpc.listDentryLimit", &o->listDentryLimit);
}
{ // defer sync option
auto o = &option->deferSyncOption;
c->GetValueFatalIfFail("fs.deferSync.delay", &o->delay);
c->GetValueFatalIfFail("fs.deferSync.deferDirMtime", &o->deferDirMtime);
}
}
void SetBrpcOpt(Configuration *conf) {
curve::common::GflagsLoadValueFromConfIfCmdNotSet dummy;
dummy.Load(conf, "defer_close_second", "rpc.defer.close.second",
@ -269,36 +362,16 @@ void InitFuseClientOption(Configuration *conf, FuseClientOption *clientOption) {
InitLeaseOpt(conf, &clientOption->leaseOpt);
InitRefreshDataOpt(conf, &clientOption->refreshDataOption);
InitKVClientManagerOpt(conf, &clientOption->kvClientManagerOpt);
InitFileSystemOption(conf, &clientOption->fileSystemOption);
conf->GetValueFatalIfFail("fuseClient.attrTimeOut",
&clientOption->attrTimeOut);
conf->GetValueFatalIfFail("fuseClient.entryTimeOut",
&clientOption->entryTimeOut);
conf->GetValueFatalIfFail("fuseClient.listDentryLimit",
&clientOption->listDentryLimit);
conf->GetValueFatalIfFail("fuseClient.listDentryThreads",
&clientOption->listDentryThreads);
conf->GetValueFatalIfFail("fuseClient.flushPeriodSec",
&clientOption->flushPeriodSec);
conf->GetValueFatalIfFail("fuseClient.maxNameLength",
&clientOption->maxNameLength);
conf->GetValueFatalIfFail("fuseClient.iCacheLruSize",
&clientOption->iCacheLruSize);
conf->GetValueFatalIfFail("fuseClient.dCacheLruSize",
&clientOption->dCacheLruSize);
conf->GetValueFatalIfFail("fuseClient.enableICacheMetrics",
&clientOption->enableICacheMetrics);
conf->GetValueFatalIfFail("fuseClient.enableDCacheMetrics",
&clientOption->enableDCacheMetrics);
conf->GetValueFatalIfFail("fuseClient.lruTimeOutSec",
&clientOption->lruTimeOutSec);
conf->GetValueFatalIfFail("client.dummyServer.startPort",
&clientOption->dummyServerStartPort);
conf->GetValueFatalIfFail("fuseClient.enableMultiMountPointRename",
&clientOption->enableMultiMountPointRename);
conf->GetValueFatalIfFail("fuseClient.disableXattr",
&clientOption->disableXattr);
conf->GetValueFatalIfFail("fuseClient.cto", &FLAGS_enableCto);
conf->GetValueFatalIfFail("fuseClient.downloadMaxRetryTimes",
&clientOption->downloadMaxRetryTimes);
conf->GetValueFatalIfFail("fuseClient.warmupThreadsNum",
@ -308,12 +381,33 @@ void InitFuseClientOption(Configuration *conf, FuseClientOption *clientOption) {
<< "Not found `fuseClient.enableSplice` in conf, use default value `"
<< std::boolalpha << clientOption->enableFuseSplice << '`';
// if enableCto, attr and entry cache must invalid
if (FLAGS_enableCto) {
clientOption->attrTimeOut = 0;
clientOption->entryTimeOut = 0;
}
conf->GetValueFatalIfFail("fuseClient.throttle.avgWriteBytes",
&FLAGS_fuseClientAvgWriteBytes);
conf->GetValueFatalIfFail("fuseClient.throttle.burstWriteBytes",
&FLAGS_fuseClientBurstWriteBytes);
conf->GetValueFatalIfFail("fuseClient.throttle.burstWriteBytesSecs",
&FLAGS_fuseClientBurstWriteBytesSecs);
conf->GetValueFatalIfFail("fuseClient.throttle.avgWriteIops",
&FLAGS_fuseClientAvgWriteIops);
conf->GetValueFatalIfFail("fuseClient.throttle.burstWriteIops",
&FLAGS_fuseClientBurstWriteIops);
conf->GetValueFatalIfFail("fuseClient.throttle.burstWriteIopsSecs",
&FLAGS_fuseClientBurstWriteIopsSecs);
conf->GetValueFatalIfFail("fuseClient.throttle.avgReadBytes",
&FLAGS_fuseClientAvgReadBytes);
conf->GetValueFatalIfFail("fuseClient.throttle.burstReadBytes",
&FLAGS_fuseClientBurstReadBytes);
conf->GetValueFatalIfFail("fuseClient.throttle.burstReadBytesSecs",
&FLAGS_fuseClientBurstReadBytesSecs);
conf->GetValueFatalIfFail("fuseClient.throttle.avgReadIops",
&FLAGS_fuseClientAvgReadIops);
conf->GetValueFatalIfFail("fuseClient.throttle.burstReadIops",
&FLAGS_fuseClientBurstReadIops);
conf->GetValueFatalIfFail("fuseClient.throttle.burstReadIopsSecs",
&FLAGS_fuseClientBurstReadIopsSecs);
SetBrpcOpt(conf);
}

View File

@ -73,6 +73,11 @@ struct LeaseOpt {
uint32_t leaseTimeUs = 20000000;
};
struct SpaceAllocServerOption {
std::string spaceaddr;
uint64_t rpcTimeoutMs;
};
struct KVClientManagerOpt {
int setThreadPooln = 4;
int getThreadPooln = 4;
@ -117,7 +122,6 @@ struct DiskCacheOption {
struct S3ClientAdaptorOption {
uint64_t blockSize;
uint64_t chunkSize;
uint32_t fuseMaxSize;
uint64_t pageSize;
uint32_t prefetchBlocks;
uint32_t prefetchExecQueueNum;
@ -160,9 +164,6 @@ struct VolumeOption {
uint64_t volBlockSize;
uint64_t fsBlockSize;
VolumeAllocatorOption allocatorOption;
double threshold{1.0};
uint64_t releaseInterSec{300};
};
struct ExtentManagerOption {
@ -173,11 +174,65 @@ struct RefreshDataOption {
uint64_t maxDataSize = 1024;
uint32_t refreshDataIntervalSec = 30;
};
// { filesystem option
struct KernelCacheOption {
uint32_t entryTimeoutSec;
uint32_t dirEntryTimeoutSec;
uint32_t attrTimeoutSec;
uint32_t dirAttrTimeoutSec;
};
struct LookupCacheOption {
uint64_t lruSize;
uint32_t negativeTimeoutSec;
uint32_t minUses;
};
struct DirCacheOption {
uint64_t lruSize;
uint32_t timeoutSec;
};
struct AttrWatcherOption {
uint64_t lruSize;
};
struct OpenFilesOption {
uint64_t lruSize;
uint32_t deferSyncSecond;
};
struct RPCOption {
uint32_t listDentryLimit;
};
struct DeferSyncOption {
uint32_t delay;
bool deferDirMtime;
};
struct FileSystemOption {
bool cto;
bool disableXattr;
uint32_t maxNameLength;
uint32_t blockSize = 0x10000u;
KernelCacheOption kernelCacheOption;
LookupCacheOption lookupCacheOption;
DirCacheOption dirCacheOption;
OpenFilesOption openFilesOption;
AttrWatcherOption attrWatcherOption;
RPCOption rpcOption;
DeferSyncOption deferSyncOption;
};
// }
struct FuseClientOption {
MdsOption mdsOpt;
MetaCacheOpt metaCacheOpt;
ExcutorOpt excutorOpt;
ExcutorOpt excutorInternalOpt;
SpaceAllocServerOption spaceOpt;
BlockDeviceClientOptions bdevOpt;
S3Option s3Opt;
ExtentManagerOption extentManagerOpt;
@ -185,22 +240,13 @@ struct FuseClientOption {
LeaseOpt leaseOpt;
RefreshDataOption refreshDataOption;
KVClientManagerOpt kvClientManagerOpt;
FileSystemOption fileSystemOption;
double attrTimeOut;
double entryTimeOut;
uint32_t listDentryLimit;
uint32_t listDentryThreads;
uint32_t flushPeriodSec;
uint32_t maxNameLength;
uint64_t iCacheLruSize;
uint64_t dCacheLruSize;
bool enableICacheMetrics;
bool enableDCacheMetrics;
uint32_t lruTimeOutSec;
uint32_t dummyServerStartPort;
bool enableMultiMountPointRename = false;
bool enableFuseSplice = false;
bool disableXattr = false;
uint32_t downloadMaxRetryTimes;
uint32_t warmupThreadsNum = 10;
};

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,7 @@
extern "C" {
#endif
int InitGlog(const char *confPath, const char *argv0);
int InitLog(const char *confPath, const char *argv0);
int InitFuseClient(const struct MountOption *mountOption);

View File

@ -44,31 +44,13 @@ namespace client {
using curve::common::WriteLockGuard;
using NameLockGuard = ::curve::common::GenericNameLockGuard<Mutex>;
void DentryCacheManagerImpl::InsertOrReplaceCache(const Dentry &dentry) {
std::string key = GetDentryCacheKey(dentry.parentinodeid(), dentry.name());
if (!curvefs::client::common::FLAGS_enableCto) {
NameLockGuard lock(nameLock_, key);
dCache_->Put(key, dentry);
}
}
void DentryCacheManagerImpl::DeleteCache(uint64_t parentId,
const std::string &name) {
std::string key = GetDentryCacheKey(parentId, name);
NameLockGuard lock(nameLock_, key);
dCache_->Remove(key);
}
using ::curvefs::client::filesystem::ToFSError;
CURVEFS_ERROR DentryCacheManagerImpl::GetDentry(uint64_t parent,
const std::string &name,
Dentry *out) {
std::string key = GetDentryCacheKey(parent, name);
NameLockGuard lock(nameLock_, key);
bool ok = dCache_->Get(key, out);
if (ok) {
return CURVEFS_ERROR::OK;
}
MetaStatusCode ret = metaClient_->GetDentry(fsId_, parent, name, out);
if (ret != MetaStatusCode::OK) {
@ -76,10 +58,7 @@ CURVEFS_ERROR DentryCacheManagerImpl::GetDentry(uint64_t parent,
<< "metaClient_ GetDentry failed, MetaStatusCode = " << ret
<< ", MetaStatusCode_Name = " << MetaStatusCode_Name(ret)
<< ", parent = " << parent << ", name = " << name;
return MetaStatusCodeToCurvefsErrCode(ret);
}
if (!curvefs::client::common::FLAGS_enableCto) {
dCache_->Put(key, *out);
return ToFSError(ret);
}
return CURVEFS_ERROR::OK;
}
@ -94,12 +73,9 @@ CURVEFS_ERROR DentryCacheManagerImpl::CreateDentry(const Dentry &dentry) {
<< ", MetaStatusCode_Name = " << MetaStatusCode_Name(ret)
<< ", parent = " << dentry.parentinodeid()
<< ", name = " << dentry.name();
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
if (!curvefs::client::common::FLAGS_enableCto) {
dCache_->Put(key, dentry);
}
return CURVEFS_ERROR::OK;
}
@ -108,14 +84,13 @@ CURVEFS_ERROR DentryCacheManagerImpl::DeleteDentry(uint64_t parent,
FsFileType type) {
std::string key = GetDentryCacheKey(parent, name);
NameLockGuard lock(nameLock_, key);
dCache_->Remove(key);
MetaStatusCode ret = metaClient_->DeleteDentry(fsId_, parent, name, type);
if (ret != MetaStatusCode::OK && ret != MetaStatusCode::NOT_FOUND) {
LOG(ERROR) << "metaClient_ DeleteInode failed, MetaStatusCode = " << ret
<< ", MetaStatusCode_Name = " << MetaStatusCode_Name(ret)
<< ", parent = " << parent << ", name = " << name;
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
return CURVEFS_ERROR::OK;
}
@ -149,7 +124,7 @@ CURVEFS_ERROR DentryCacheManagerImpl::ListDentry(uint64_t parent,
<< ", MetaStatusCode_Name = " << MetaStatusCode_Name(ret)
<< ", parent = " << parent << ", last = " << last
<< ", count = " << limit << ", onlyDir = " << onlyDir;
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
if (!onlyDir) {

View File

@ -33,20 +33,18 @@
#include <utility>
#include "curvefs/src/client/rpcclient/metaserver_client.h"
#include "curvefs/src/client/error_code.h"
#include "src/common/concurrent/concurrent.h"
#include "src/common/lru_cache.h"
#include "src/common/concurrent/name_lock.h"
#include "curvefs/src/client/filesystem/error.h"
using ::curvefs::metaserver::Dentry;
using ::curve::common::TimedLRUCache;
using ::curve::common::CacheMetrics;
namespace curvefs {
namespace client {
using rpcclient::MetaServerClient;
using rpcclient::MetaServerClientImpl;
using ::curvefs::client::filesystem::CURVEFS_ERROR;
static const char* kDentryKeyDelimiter = ":";
@ -59,13 +57,6 @@ class DentryCacheManager {
fsId_ = fsId;
}
virtual CURVEFS_ERROR Init(uint64_t cacheSize, bool enableCacheMetrics,
uint32_t cacheTimeOutSec) = 0;
virtual void InsertOrReplaceCache(const Dentry& dentry) = 0;
virtual void DeleteCache(uint64_t parentId, const std::string& name) = 0;
virtual CURVEFS_ERROR GetDentry(uint64_t parent,
const std::string &name, Dentry *out) = 0;
@ -86,30 +77,11 @@ class DentryCacheManager {
class DentryCacheManagerImpl : public DentryCacheManager {
public:
DentryCacheManagerImpl()
: metaClient_(std::make_shared<MetaServerClientImpl>()),
dCache_(nullptr) {}
: metaClient_(std::make_shared<MetaServerClientImpl>()) {}
explicit DentryCacheManagerImpl(
const std::shared_ptr<MetaServerClient> &metaClient)
: metaClient_(metaClient),
dCache_(nullptr) {}
CURVEFS_ERROR Init(uint64_t cacheSize, bool enableCacheMetrics,
uint32_t cacheTimeOutSec) override {
if (enableCacheMetrics) {
dCache_ = std::make_shared<
TimedLRUCache<std::string, Dentry>>(cacheTimeOutSec, cacheSize,
std::make_shared<CacheMetrics>("dcache"));
} else {
dCache_ = std::make_shared<
TimedLRUCache<std::string, Dentry>>(cacheTimeOutSec, cacheSize);
}
return CURVEFS_ERROR::OK;
}
void InsertOrReplaceCache(const Dentry& dentry) override;
void DeleteCache(uint64_t parentId, const std::string& name) override;
: metaClient_(metaClient) {}
CURVEFS_ERROR GetDentry(uint64_t parent,
const std::string &name, Dentry *out) override;
@ -130,8 +102,6 @@ class DentryCacheManagerImpl : public DentryCacheManager {
private:
std::shared_ptr<MetaServerClient> metaClient_;
// key is parentId + name
std::shared_ptr<TimedLRUCache<std::string, Dentry>> dCache_;
curve::common::GenericNameLock<Mutex> nameLock_;
};

View File

@ -1,98 +0,0 @@
/*
* Copyright (c) 2021 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: curve
* Created Date: Thur May 27 2021
* Author: xuchaojie
*/
#include "curvefs/src/client/error_code.h"
#include <map>
#include <string>
namespace curvefs {
namespace client {
using ::curvefs::metaserver::MetaStatusCode;
static const std::map<CURVEFS_ERROR, std::string> err2Msg = {
{CURVEFS_ERROR::OK, "OK"},
{CURVEFS_ERROR::INTERNAL, "internal error"},
{CURVEFS_ERROR::UNKNOWN, "unknown"},
{CURVEFS_ERROR::EXISTS, "inode or dentry already exist"},
{CURVEFS_ERROR::NOTEXIST, "inode or dentry not exist"},
{CURVEFS_ERROR::NO_SPACE, "no space to alloc"},
{CURVEFS_ERROR::BAD_FD, "bad fd"},
{CURVEFS_ERROR::INVALIDPARAM, "invalid param"},
{CURVEFS_ERROR::NOPERMISSION, "no permission"},
{CURVEFS_ERROR::NOTEMPTY, "dir not empty"},
{CURVEFS_ERROR::NOFLUSH, "no flush"},
{CURVEFS_ERROR::NOTSUPPORT, "not support"},
{CURVEFS_ERROR::NAMETOOLONG, "name too long"},
{CURVEFS_ERROR::MOUNT_POINT_EXIST, "mount point already exist"},
{CURVEFS_ERROR::MOUNT_FAILED, "mount failed"},
};
std::ostream &operator<<(std::ostream &os, CURVEFS_ERROR code) {
os << static_cast<int>(code) << "[" << [code]() {
auto it = err2Msg.find(code);
if (it != err2Msg.end()) {
return it->second;
}
return std::string{"Unknown"};
}() << "]";
return os;
}
CURVEFS_ERROR MetaStatusCodeToCurvefsErrCode(
MetaStatusCode code) {
CURVEFS_ERROR ret = CURVEFS_ERROR::UNKNOWN;
switch (code) {
case MetaStatusCode::OK:
ret = CURVEFS_ERROR::OK;
break;
case MetaStatusCode::NOT_FOUND:
ret = CURVEFS_ERROR::NOTEXIST;
break;
case MetaStatusCode::PARAM_ERROR:
ret = CURVEFS_ERROR::INVALIDPARAM;
break;
case MetaStatusCode::INODE_EXIST:
case MetaStatusCode::DENTRY_EXIST:
ret = CURVEFS_ERROR::EXISTS;
break;
case MetaStatusCode::SYM_LINK_EMPTY:
case MetaStatusCode::RPC_ERROR:
ret = CURVEFS_ERROR::INTERNAL;
break;
default:
ret = CURVEFS_ERROR::UNKNOWN;
}
return ret;
}
} // namespace client
} // namespace curvefs

View File

@ -0,0 +1,78 @@
CurveFS Client Metadata Cache Design
===
```
+----------------+
+ Kernel Cache |
+----------------+
| ^
(1) | | (4)
v |
+----------------+
+ CurveFS Fuse |
+----------------+
| ^
(2) | | (3)
v |
+----------------+
+ MetaServer |
+----------------+
```
(1) kernel cache timeout
---
* requests are always sent to fuse layer, except `lookup` and `getattr` request which affected by caching.
* if entry or attribute cache timeout, vfs layer will launch request to fuse layer.
(2) revalidate cache
---
* for `open` and `opendir` request, fuse layer should revalidate cache by comparing mtime, if modified, fuse layer should:
* `open`: return **ESTALE** to trigger vfs layer to invoke the `open` again with ignoring cache.
* `opendir`: drop all directory cache.
* others, proxy request to metaserver directly.
(3) retrive fresh metadata
---
* for `readdir` request, fuse layer should cache direcoty entries and their attributes.
* others, no caching.
(4) reply with timeout
---
* reply entry or attribute to vfs layer with corresponding cache timeout.
* four type timeouts provided: `entryTimeout`, `dirEntryTimeout`, `attrTimeout`, `dirAtttTimeout`.
* fuse layer should remeber the `mtime` of attribute while reply it to vfs layer.
Cache Layer Level
===
```
+-------------------------------------------------------+
| Kernel Cache | (L1 Cache)
+-------------------------------------------------------+
^ (update length)
|
+--------------------------------------------------------+
| Open File Cache | (L2 Cache)
| (only length and chunk) |
+--------------------------------------------------------+
^ ^
| (reply entry/attr) | (reply entry/attr)
+-----------------+ |
| Directory Cache | (L3 Cache) |
+-----------------+ |
^ |
| |
+-----------------+ +------------------------------------+
| readdir | | lookup、getattr、setattr、create... |
+-----------------+ +------------------------------------+
^ ^
| |
+--------------------------------------------------------+
| MetaServer |
+--------------------------------------------------------+
```

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-17
* Author: Jingli Chen (Wine93)
*/
#include <unistd.h>
#include <butil/time.h>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/daily_file_sink.h>
#include <string>
#include <memory>
#include "absl/strings/str_format.h"
#include "curvefs/src/client/common/config.h"
#ifndef CURVEFS_SRC_CLIENT_FILESYSTEM_ACCESS_LOG_H_
#define CURVEFS_SRC_CLIENT_FILESYSTEM_ACCESS_LOG_H_
namespace curvefs {
namespace client {
namespace common {
DECLARE_bool(access_logging);
}
namespace filesystem {
using ::absl::StrFormat;
using ::curvefs::client::common::FLAGS_access_logging;
using MessageHandler = std::function<std::string()>;
static std::shared_ptr<spdlog::logger> Logger;
bool InitAccessLog(const std::string& prefix) {
std::string filename = StrFormat("%s/access.%d.log", prefix, getpid());
Logger = spdlog::daily_logger_mt("fuse_access", filename, 0, 0);
spdlog::flush_every(std::chrono::seconds(1));
return true;
}
struct AccessLogGuard {
explicit AccessLogGuard(MessageHandler handler)
: enable(FLAGS_access_logging),
handler(handler) {
if (!enable) {
return;
}
timer.start();
}
~AccessLogGuard() {
if (!enable) {
return;
}
timer.stop();
Logger->info("{0} <{1:.6f}>", handler(), timer.u_elapsed() / 1e6);
}
bool enable;
MessageHandler handler;
butil::Timer timer;
};
} // namespace filesystem
} // namespace client
} // namespace curvefs
#endif // CURVEFS_SRC_CLIENT_FILESYSTEM_ACCESS_LOG_H_

View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-09
* Author: Jingli Chen (Wine93)
*/
#include "curvefs/src/client/filesystem/utils.h"
#include "curvefs/src/client/filesystem/attr_watcher.h"
namespace curvefs {
namespace client {
namespace filesystem {
AttrWatcher::AttrWatcher(AttrWatcherOption option,
std::shared_ptr<OpenFiles> openFiles,
std::shared_ptr<DirCache> dirCache)
: modifiedAt_(std::make_shared<LRUType>(option.lruSize)),
openFiles_(openFiles),
dirCache_(dirCache) {}
void AttrWatcher::RemeberMtime(const InodeAttr& attr) {
WriteLockGuard lk(rwlock_);
modifiedAt_->Put(attr.inodeid(), AttrMtime(attr));
}
bool AttrWatcher::GetMtime(Ino ino, TimeSpec* time) {
ReadLockGuard lk(rwlock_);
return modifiedAt_->Get(ino, time);
}
void AttrWatcher::UpdateDirEntryAttr(Ino ino, const InodeAttr& attr) {
std::shared_ptr<DirEntryList> entries;
for (const auto parent : attr.parent()) {
bool yes = dirCache_->Get(parent, &entries);
if (!yes) {
continue;
}
entries->UpdateAttr(ino, attr);
VLOG(1) << "Write back attribute to dir entry cache: ino = " << ino
<< ", attr = " << attr.ShortDebugString();
}
}
void AttrWatcher::UpdateDirEntryLength(Ino ino, const InodeAttr& open) {
std::shared_ptr<DirEntryList> entries;
for (const auto parent : open.parent()) {
bool yes = dirCache_->Get(parent, &entries);
if (!yes) {
continue;
}
entries->UpdateLength(ino, open);
VLOG(1) << "Write back file length to dir entry cache: ino = " << ino
<< ", attr = " << open.ShortDebugString();
}
}
AttrWatcherGuard::AttrWatcherGuard(std::shared_ptr<AttrWatcher> watcher,
InodeAttr* attr,
ReplyType type,
bool writeBack)
: watcher(watcher), attr(attr), type(type), writeBack(writeBack) {
InodeAttr open;
Ino ino = attr->inodeid();
bool yes = watcher->openFiles_->GetFileAttr(ino, &open);
if (!yes) {
return;
}
attr->set_length(open.length());
attr->set_mtime(open.mtime());
attr->set_mtime_ns(open.mtime_ns());
if (AttrCtime(open) > AttrCtime(*attr)) {
attr->set_ctime(open.ctime());
attr->set_ctime_ns(open.ctime_ns());
}
}
AttrWatcherGuard::~AttrWatcherGuard() {
switch (type) {
case ReplyType::ATTR:
watcher->RemeberMtime(*attr);
if (writeBack) {
watcher->UpdateDirEntryAttr(attr->inodeid(), *attr);
}
break;
case ReplyType::ONLY_LENGTH:
if (writeBack) {
watcher->UpdateDirEntryLength(attr->inodeid(), *attr);
}
break;
}
}
} // namespace filesystem
} // namespace client
} // namespace curvefs

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-09
* Author: Jingli Chen (Wine93)
*/
#ifndef CURVEFS_SRC_CLIENT_FILESYSTEM_ATTR_WATCHER_H_
#define CURVEFS_SRC_CLIENT_FILESYSTEM_ATTR_WATCHER_H_
#include <memory>
#include "src/common/lru_cache.h"
#include "curvefs/src/client/common/config.h"
#include "curvefs/src/client/filesystem/meta.h"
#include "curvefs/src/client/filesystem/openfile.h"
namespace curvefs {
namespace client {
namespace filesystem {
using ::curve::common::LRUCache;
using ::curve::common::RWLock;
using ::curve::common::ReadLockGuard;
using ::curve::common::WriteLockGuard;
using ::curvefs::client::common::AttrWatcherOption;
class AttrWatcher {
public:
using LRUType = LRUCache<Ino, struct TimeSpec>;
public:
AttrWatcher(AttrWatcherOption option,
std::shared_ptr<OpenFiles> openFiles,
std::shared_ptr<DirCache> dirCache);
void RemeberMtime(const InodeAttr& attr);
bool GetMtime(Ino ino, TimeSpec* time);
void UpdateDirEntryAttr(Ino ino, const InodeAttr& attr);
void UpdateDirEntryLength(Ino ino, const InodeAttr& open);
private:
friend class AttrWatcherGuard;
private:
RWLock rwlock_;
std::shared_ptr<LRUType> modifiedAt_;
std::shared_ptr<OpenFiles> openFiles_;
std::shared_ptr<DirCache> dirCache_;
};
enum class ReplyType {
ATTR,
ONLY_LENGTH
};
/*
* each attribute reply to kernel, the watcher will:
* before reply:
* 1) set attibute length if the corresponding file is opened
* after reply:
* 1) remeber attribute modified time.
* 2) write back attribute to dir entry cache if |writeBack| is true,
* because the dir-entry attribute maybe stale.
*/
struct AttrWatcherGuard {
public:
AttrWatcherGuard(std::shared_ptr<AttrWatcher> watcher,
InodeAttr* attr,
ReplyType type,
bool writeBack);
~AttrWatcherGuard();
private:
std::shared_ptr<AttrWatcher> watcher;
InodeAttr* attr;
ReplyType type;
bool writeBack;
};
} // namespace filesystem
} // namespace client
} // namespace curvefs
#endif // CURVEFS_SRC_CLIENT_FILESYSTEM_ATTR_WATCHER_H_

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-06
* Author: Jingli Chen (Wine93)
*/
#include <vector>
#include <memory>
#include "curvefs/src/client/filesystem/defer_sync.h"
#include "curvefs/src/client/filesystem/utils.h"
namespace curvefs {
namespace client {
namespace filesystem {
DeferSync::DeferSync(DeferSyncOption option)
: option_(option),
mutex_(),
running_(false),
thread_(),
sleeper_(),
inodes_() {
}
void DeferSync::Start() {
if (!running_.exchange(true)) {
thread_ = std::thread(&DeferSync::SyncTask, this);
LOG(INFO) << "Defer sync thread start success";
}
}
void DeferSync::Stop() {
if (running_.exchange(false)) {
LOG(INFO) << "Stop defer sync thread...";
sleeper_.interrupt();
thread_.join();
LOG(INFO) << "Defer sync thread stopped";
}
}
void DeferSync::SyncTask() {
std::vector<std::shared_ptr<InodeWrapper>> inodes;
for ( ;; ) {
bool running = sleeper_.wait_for(std::chrono::seconds(option_.delay));
{
LockGuard lk(mutex_);
inodes.swap(inodes_);
}
for (const auto& inode : inodes) {
UniqueLock lk(inode->GetUniqueLock());
inode->Async(nullptr, true);
}
inodes.clear();
if (!running) {
break;
}
}
}
void DeferSync::Push(const std::shared_ptr<InodeWrapper>& inode) {
LockGuard lk(mutex_);
inodes_.emplace_back(inode);
}
} // namespace filesystem
} // namespace client
} // namespace curvefs

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-06
* Author: Jingli Chen (Wine93)
*/
#ifndef CURVEFS_SRC_CLIENT_FILESYSTEM_DEFER_SYNC_H_
#define CURVEFS_SRC_CLIENT_FILESYSTEM_DEFER_SYNC_H_
#include <atomic>
#include <vector>
#include <memory>
#include "src/common/interruptible_sleeper.h"
#include "curvefs/src/client/common/config.h"
#include "curvefs/src/client/filesystem/meta.h"
namespace curvefs {
namespace client {
namespace filesystem {
using ::curvefs::client::common::DeferSyncOption;
using ::curve::common::Mutex;
using ::curve::common::LockGuard;
using ::curve::common::InterruptibleSleeper;
class DeferSync {
public:
explicit DeferSync(DeferSyncOption option);
void Start();
void Stop();
void Push(const std::shared_ptr<InodeWrapper>& inode);
private:
void SyncTask();
private:
DeferSyncOption option_;
Mutex mutex_;
std::atomic<bool> running_;
std::thread thread_;
InterruptibleSleeper sleeper_;
std::vector<std::shared_ptr<InodeWrapper>> inodes_;
};
} // namespace filesystem
} // namespace client
} // namespace curvefs
#endif // CURVEFS_SRC_CLIENT_FILESYSTEM_DEFER_SYNC_H_

View File

@ -0,0 +1,189 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-07
* Author: Jingli Chen (Wine93)
*/
#include <utility>
#include "curvefs/src/client/filesystem/dir_cache.h"
#include "curvefs/src/client/filesystem/utils.h"
namespace curvefs {
namespace client {
namespace filesystem {
DirEntryList::DirEntryList()
: rwlock_(),
mtime_(),
entries_(),
attrs_() {}
size_t DirEntryList::Size() {
ReadLockGuard lk(rwlock_);
return entries_.size();
}
void DirEntryList::Add(const DirEntry& dirEntry) {
WriteLockGuard lk(rwlock_);
entries_.push_back(std::move(dirEntry));
attrs_[dirEntry.ino] = &entries_.back();
}
bool DirEntryList::Get(Ino ino, DirEntry* dirEntry) {
ReadLockGuard lk(rwlock_);
auto iter = attrs_.find(ino);
if (iter == attrs_.end()) {
return false;
}
*dirEntry = *iter->second;
return true;
}
bool DirEntryList::UpdateAttr(Ino ino, const InodeAttr& attr) {
WriteLockGuard lk(rwlock_);
auto iter = attrs_.find(ino);
if (iter == attrs_.end()) {
return false;
}
DirEntry* dirEntry = iter->second;
dirEntry->attr = std::move(attr);
return true;
}
bool DirEntryList::UpdateLength(Ino ino, const InodeAttr& open) {
WriteLockGuard lk(rwlock_);
auto iter = attrs_.find(ino);
if (iter == attrs_.end()) {
return false;
}
InodeAttr* attr = &iter->second->attr;
attr->set_length(open.length());
attr->set_mtime(open.mtime());
attr->set_mtime_ns(open.mtime_ns());
if (AttrCtime(open) > AttrCtime(*attr)) {
attr->set_ctime(open.ctime());
attr->set_ctime_ns(open.ctime_ns());
}
return true;
}
void DirEntryList::Iterate(IterateHandler handler) {
ReadLockGuard lk(rwlock_);
for (auto iter = entries_.begin(); iter != entries_.end(); iter++) {
handler(&(*iter));
}
}
void DirEntryList::Clear() {
WriteLockGuard lk(rwlock_);
entries_.clear();
attrs_.clear();
}
void DirEntryList::SetMtime(TimeSpec mtime) {
WriteLockGuard lk(rwlock_);
mtime_ = mtime;
}
TimeSpec DirEntryList::GetMtime() {
ReadLockGuard lk(rwlock_);
return mtime_;
}
DirCache::DirCache(DirCacheOption option)
: rwlock_(),
nentries_(0),
option_(option) {
lru_ = std::make_shared<LRUType>(0); // control size by ourself
mq_ = std::make_shared<MessageQueueType>("dircache", 10000);
mq_->Subscribe([&](const std::shared_ptr<DirEntryList>& entries){
entries->Clear();
});
LOG(INFO) << "Using directory lru cache, capacity = " << option_.lruSize;
}
void DirCache::Start() {
mq_->Start();
}
void DirCache::Stop() {
WriteLockGuard lk(rwlock_);
Evit(option_.lruSize);
mq_->Stop();
}
void DirCache::Delete(Ino parent,
std::shared_ptr<DirEntryList> entries,
bool evit) {
nentries_ -= entries->Size();
mq_->Publish(entries); // clear entries in background
lru_->Remove(parent);
VLOG(1) << "Delete directory cache (evit=" << evit << "): "
<< "parent = " << parent
<< ", mtime = " << entries->GetMtime()
<< ", size = " << entries->Size()
<< ", nentries = " << nentries_;
}
void DirCache::Evit(size_t size) {
Ino parent;
std::shared_ptr<DirEntryList> entries;
while (nentries_ + size >= option_.lruSize) {
bool yes = lru_->GetLast(&parent, &entries);
if (!yes) {
break;
}
Delete(parent, entries, true);
}
}
void DirCache::Put(Ino parent, std::shared_ptr<DirEntryList> entries) {
WriteLockGuard lk(rwlock_);
Evit(entries->Size()); // it guarantee put entries success
lru_->Put(parent, entries);
nentries_ += entries->Size();
VLOG(1) << "Insert directory cache: parent = " << parent
<< ", mtime = " << entries->GetMtime()
<< ", size = " << entries->Size()
<< ", nentries = " << nentries_;
}
bool DirCache::Get(Ino parent, std::shared_ptr<DirEntryList>* entries) {
ReadLockGuard lk(rwlock_);
return lru_->Get(parent, entries);
}
void DirCache::Drop(Ino parent) {
WriteLockGuard lk(rwlock_);
std::shared_ptr<DirEntryList> entries;
bool yes = lru_->Get(parent, &entries);
if (yes) {
Delete(parent, entries, false);
}
}
} // namespace filesystem
} // namespace client
} // namespace curvefs

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-07
* Author: Jingli Chen (Wine93)
*/
#ifndef CURVEFS_SRC_CLIENT_FILESYSTEM_DIR_CACHE_H_
#define CURVEFS_SRC_CLIENT_FILESYSTEM_DIR_CACHE_H_
#include <map>
#include <list>
#include <memory>
#include "src/common/lru_cache.h"
#include "src/common/concurrent/concurrent.h"
#include "curvefs/src/client/common/config.h"
#include "curvefs/src/client/filesystem/meta.h"
#include "curvefs/src/client/filesystem/message_queue.h"
namespace curvefs {
namespace client {
namespace filesystem {
using ::curve::common::LRUCache;
using ::curve::common::RWLock;
using ::curve::common::ReadLockGuard;
using ::curve::common::WriteLockGuard;
using ::curvefs::client::common::DirCacheOption;
class DirEntryList {
public:
using IterateHandler = std::function<void(DirEntry* dirEntry)>;
public:
DirEntryList();
size_t Size();
void Add(const DirEntry& dirEntry);
void Iterate(IterateHandler handler);
bool Get(Ino ino, DirEntry* dirEntry);
bool UpdateAttr(Ino ino, const InodeAttr& attr);
bool UpdateLength(Ino ino, const InodeAttr& open);
void Clear();
void SetMtime(TimeSpec mtime);
TimeSpec GetMtime();
private:
RWLock rwlock_;
TimeSpec mtime_;
std::list<DirEntry> entries_;
std::map<Ino, DirEntry*> attrs_;
};
class DirCache {
public:
using LRUType = LRUCache<Ino, std::shared_ptr<DirEntryList>>;
using MessageType = std::shared_ptr<DirEntryList>;
using MessageQueueType = MessageQueue<MessageType>;
public:
explicit DirCache(DirCacheOption option);
void Start();
void Stop();
void Put(Ino parent, std::shared_ptr<DirEntryList> entries);
bool Get(Ino parent, std::shared_ptr<DirEntryList>* entries);
void Drop(Ino parent);
private:
void Delete(Ino parent, std::shared_ptr<DirEntryList> entries, bool evit);
void Evit(size_t size);
private:
RWLock rwlock_;
size_t nentries_;
DirCacheOption option_;
std::shared_ptr<LRUType> lru_;
std::shared_ptr<MessageQueueType> mq_;
};
} // namespace filesystem
} // namespace client
} // namespace curvefs
#endif // CURVEFS_SRC_CLIENT_FILESYSTEM_DIR_CACHE_H_

View File

@ -0,0 +1,106 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-06
* Author: Jingli Chen (Wine93)
*/
#include <map>
#include <utility>
#include <ostream>
#include "curvefs/src/client/filesystem/error.h"
namespace curvefs {
namespace client {
namespace filesystem {
static const std::map<CURVEFS_ERROR, std::pair<int, std::string>> errors = {
{ CURVEFS_ERROR::OK, { 0, "OK"} },
{ CURVEFS_ERROR::INTERNAL, { EIO, "internal error" } },
{ CURVEFS_ERROR::UNKNOWN, { -1, "unknown" } },
{ CURVEFS_ERROR::EXISTS, { EEXIST, "inode or dentry already exist" } },
{ CURVEFS_ERROR::NOTEXIST, { ENOENT, "inode or dentry not exist" } },
{ CURVEFS_ERROR::NO_SPACE, { ENOSPC, "no space to alloc" } },
{ CURVEFS_ERROR::BAD_FD, { EBADF, "bad file number" } },
{ CURVEFS_ERROR::INVALIDPARAM , { EINVAL , "invalid argument" } },
{ CURVEFS_ERROR::NOPERMISSION, { EACCES, "permission denied" } },
{ CURVEFS_ERROR::NOTEMPTY, { ENOTEMPTY, "directory not empty" } },
{ CURVEFS_ERROR::NOFLUSH, { -1, "no flush" } },
{ CURVEFS_ERROR::NOTSUPPORT, { EOPNOTSUPP, "operation not supported" } },
{ CURVEFS_ERROR::NAMETOOLONG, { ENAMETOOLONG, "file name too long" } },
{ CURVEFS_ERROR::MOUNT_POINT_EXIST, { -1, "mount point already exist" } },
{ CURVEFS_ERROR::MOUNT_FAILED, { -1, "mount failed" } },
{ CURVEFS_ERROR::OUT_OF_RANGE, { ERANGE, "out of range" } },
{ CURVEFS_ERROR::NODATA, { ENODATA, "no data available" } },
{ CURVEFS_ERROR::IO_ERROR, { EIO, "I/O error" } },
{ CURVEFS_ERROR::STALE, { ESTALE, "stale file handler" } },
{ CURVEFS_ERROR::NOSYS, { ENOSYS, "invalid system call" } },
};
std::string StrErr(CURVEFS_ERROR code) {
auto it = errors.find(code);
if (it != errors.end()) {
return it->second.second;
}
return "unknown";
}
int SysErr(CURVEFS_ERROR code) {
int syscode = -1;
auto it = errors.find(code);
if (it != errors.end()) {
syscode = it->second.first;
}
return (syscode == -1) ? EIO : syscode;
}
std::ostream &operator<<(std::ostream &os, CURVEFS_ERROR code) {
os << static_cast<int>(code) << "[" << [code]() {
auto it = errors.find(code);
if (it != errors.end()) {
return it->second.second;
}
return std::string{"Unknown"};
}() << "]";
return os;
}
CURVEFS_ERROR ToFSError(MetaStatusCode code) {
static std::map<MetaStatusCode, CURVEFS_ERROR> errs = {
{ MetaStatusCode::OK, CURVEFS_ERROR::OK },
{ MetaStatusCode::NOT_FOUND, CURVEFS_ERROR::NOTEXIST },
{ MetaStatusCode::PARAM_ERROR, CURVEFS_ERROR::INVALIDPARAM },
{ MetaStatusCode::INODE_EXIST, CURVEFS_ERROR::EXISTS },
{ MetaStatusCode::DENTRY_EXIST, CURVEFS_ERROR::EXISTS },
{ MetaStatusCode::SYM_LINK_EMPTY, CURVEFS_ERROR::INTERNAL },
{ MetaStatusCode::RPC_ERROR, CURVEFS_ERROR::INTERNAL },
};
auto it = errs.find(code);
if (it != errs.end()) {
return it->second;
}
return CURVEFS_ERROR::UNKNOWN;
}
} // namespace filesystem
} // namespace client
} // namespace curvefs

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 NetEase Inc.
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,22 +14,27 @@
* limitations under the License.
*/
/*
* Project: curve
* Created Date: Thur May 27 2021
* Author: xuchaojie
* Project: Curve
* Created Date: 2023-03-06
* Author: Jingli Chen (Wine93)
*/
#ifndef CURVEFS_SRC_CLIENT_ERROR_CODE_H_
#define CURVEFS_SRC_CLIENT_ERROR_CODE_H_
#include <map>
#include <string>
#include <iostream>
#include "curvefs/proto/metaserver.pb.h"
#ifndef CURVEFS_SRC_CLIENT_FILESYSTEM_ERROR_H_
#define CURVEFS_SRC_CLIENT_FILESYSTEM_ERROR_H_
namespace curvefs {
namespace client {
namespace filesystem {
using ::curvefs::metaserver::MetaStatusCode;
// notice : the error code should be negative.
enum class CURVEFS_ERROR {
OK = 0,
INTERNAL = -1,
@ -49,15 +54,21 @@ enum class CURVEFS_ERROR {
OUT_OF_RANGE = -15,
NODATA = -16,
IO_ERROR = -17,
CACHETOOSMALL = -18,
STALE = -19,
NOSYS = -20,
};
std::string StrErr(CURVEFS_ERROR code);
int SysErr(CURVEFS_ERROR code);
std::ostream &operator<<(std::ostream &os, CURVEFS_ERROR code);
CURVEFS_ERROR MetaStatusCodeToCurvefsErrCode(
::curvefs::metaserver::MetaStatusCode code);
CURVEFS_ERROR ToFSError(MetaStatusCode code);
} // namespace filesystem
} // namespace client
} // namespace curvefs
#endif // CURVEFS_SRC_CLIENT_ERROR_CODE_H_
#endif // CURVEFS_SRC_CLIENT_FILESYSTEM_ERROR_H_

View File

@ -0,0 +1,353 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-08
* Author: Jingli Chen (Wine93)
*/
#include <map>
#include "curvefs/src/client/filesystem/filesystem.h"
#include "curvefs/src/client/filesystem/utils.h"
namespace curvefs {
namespace client {
namespace filesystem {
FileSystem::FileSystem(FileSystemOption option, ExternalMember member)
: option_(option), member(member) {
deferSync_ = std::make_shared<DeferSync>(option.deferSyncOption);
negative_ = std::make_shared<LookupCache>(option.lookupCacheOption);
dirCache_ = std::make_shared<DirCache>(option.dirCacheOption);
openFiles_ = std::make_shared<OpenFiles>(option_.openFilesOption,
deferSync_);
attrWatcher_ = std::make_shared<AttrWatcher>(option_.attrWatcherOption,
openFiles_, dirCache_);
handlerManager_ = std::make_shared<HandlerManager>();
rpc_ = std::make_shared<RPCClient>(option.rpcOption, member);
}
void FileSystem::Run() {
deferSync_->Start();
dirCache_->Start();
}
void FileSystem::Destory() {
openFiles_->CloseAll();
deferSync_->Stop();
dirCache_->Stop();
}
void FileSystem::Attr2Stat(InodeAttr* attr, struct stat* stat) {
std::memset(stat, 0, sizeof(struct stat));
stat->st_ino = attr->inodeid(); // inode number
stat->st_mode = attr->mode(); // permission mode
stat->st_nlink = attr->nlink(); // number of links
stat->st_uid = attr->uid(); // user ID of owner
stat->st_gid = attr->gid(); // group ID of owner
stat->st_size = attr->length(); // total size, in bytes
stat->st_rdev = attr->rdev(); // device ID (if special file)
stat->st_atim.tv_sec = attr->atime(); // time of last access
stat->st_atim.tv_nsec = attr->atime_ns();
stat->st_mtim.tv_sec = attr->mtime(); // time of last modification
stat->st_mtim.tv_nsec = attr->mtime_ns();
stat->st_ctim.tv_sec = attr->ctime(); // time of last status change
stat->st_ctim.tv_nsec = attr->ctime_ns();
stat->st_blksize = option_.blockSize; // blocksize for file system I/O
stat->st_blocks = 0; // number of 512B blocks allocated
if (IsS3File(*attr)) {
stat->st_blocks = (attr->length() + 511) / 512;
}
}
void FileSystem::Entry2Param(EntryOut* entryOut,
fuse_entry_param* e) {
std::memset(e, 0, sizeof(fuse_entry_param));
e->ino = entryOut->attr.inodeid();
e->generation = 0;
Attr2Stat(&entryOut->attr, &e->attr);
e->entry_timeout = entryOut->entryTimeout;
e->attr_timeout = entryOut->attrTimeout;
}
void FileSystem::SetEntryTimeout(EntryOut* entryOut) {
auto option = option_.kernelCacheOption;
if (IsDir(entryOut->attr)) {
entryOut->entryTimeout = option.dirEntryTimeoutSec;
entryOut->attrTimeout = option.dirAttrTimeoutSec;
} else {
entryOut->entryTimeout = option.entryTimeoutSec;
entryOut->attrTimeout = option.attrTimeoutSec;
}
}
void FileSystem::SetAttrTimeout(AttrOut* attrOut) {
auto option = option_.kernelCacheOption;
if (IsDir(attrOut->attr)) {
attrOut->attrTimeout = option.dirAttrTimeoutSec;
} else {
attrOut->attrTimeout = option.attrTimeoutSec;
}
}
// fuse reply*
void FileSystem::ReplyError(Request req, CURVEFS_ERROR code) {
fuse_reply_err(req, SysErr(code));
}
void FileSystem::ReplyEntry(Request req,
EntryOut* entryOut) {
AttrWatcherGuard watcher(attrWatcher_, &entryOut->attr,
ReplyType::ATTR, true);
fuse_entry_param e;
SetEntryTimeout(entryOut);
Entry2Param(entryOut, &e);
fuse_reply_entry(req, &e);
}
void FileSystem::ReplyAttr(Request req,
AttrOut* attrOut) {
AttrWatcherGuard watcher(attrWatcher_, &attrOut->attr,
ReplyType::ATTR, true);
struct stat stat;
SetAttrTimeout(attrOut);
Attr2Stat(&attrOut->attr, &stat);
fuse_reply_attr(req, &stat, attrOut->attrTimeout);
}
void FileSystem::ReplyReadlink(Request req, const std::string& link) {
fuse_reply_readlink(req, link.c_str());
}
void FileSystem::ReplyOpen(Request req, FileInfo* fi) {
fuse_reply_open(req, fi);
}
void FileSystem::ReplyOpen(Request req, FileOut* fileOut) {
AttrWatcherGuard watcher(attrWatcher_, &fileOut->attr,
ReplyType::ONLY_LENGTH, true);
fuse_reply_open(req, fileOut->fi);
}
void FileSystem::ReplyData(Request req,
struct fuse_bufvec *bufv,
enum fuse_buf_copy_flags flags) {
fuse_reply_data(req, bufv, flags);
}
void FileSystem::ReplyWrite(Request req, FileOut* fileOut) {
AttrWatcherGuard watcher(attrWatcher_, &fileOut->attr,
ReplyType::ONLY_LENGTH, true);
fuse_reply_write(req, fileOut->nwritten);
}
void FileSystem::ReplyBuffer(Request req, const char *buf, size_t size) {
fuse_reply_buf(req, buf, size);
}
void FileSystem::ReplyStatfs(Request req, const struct statvfs *stbuf) {
fuse_reply_statfs(req, stbuf);
}
void FileSystem::ReplyXattr(Request req, size_t size) {
fuse_reply_xattr(req, size);
}
void FileSystem::ReplyCreate(Request req, EntryOut* entryOut, FileInfo* fi) {
AttrWatcherGuard watcher(attrWatcher_, &entryOut->attr,
ReplyType::ATTR, true);
fuse_entry_param e;
SetEntryTimeout(entryOut);
Entry2Param(entryOut, &e);
fuse_reply_create(req, &e, fi);
}
void FileSystem::AddDirEntry(Request req,
DirBufferHead* buffer,
DirEntry* dirEntry) {
struct stat stat;
std::memset(&stat, 0, sizeof(stat));
stat.st_ino = dirEntry->ino;
// add a directory entry to the buffer
size_t oldsize = buffer->size;
const char* name = dirEntry->name.c_str();
buffer->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
buffer->p = static_cast<char *>(realloc(buffer->p, buffer->size));
fuse_add_direntry(req,
buffer->p + oldsize, // char* buf
buffer->size - oldsize, // size_t bufisze
name, &stat, buffer->size);
}
void FileSystem::AddDirEntryPlus(Request req,
DirBufferHead* buffer,
DirEntry* dirEntry) {
AttrWatcherGuard watcher(attrWatcher_, &dirEntry->attr,
ReplyType::ATTR, false);
struct fuse_entry_param e;
EntryOut entryOut(dirEntry->attr);
SetEntryTimeout(&entryOut);
Entry2Param(&entryOut, &e);
// add a directory entry to the buffer with the attributes
size_t oldsize = buffer->size;
const char* name = dirEntry->name.c_str();
buffer->size += fuse_add_direntry_plus(req, NULL, 0, name, NULL, 0);
buffer->p = static_cast<char *>(realloc(buffer->p, buffer->size));
fuse_add_direntry_plus(req,
buffer->p + oldsize, // char* buf
buffer->size - oldsize, // size_t bufisze
name, &e, buffer->size);
}
// handler*
std::shared_ptr<FileHandler> FileSystem::NewHandler() {
return handlerManager_->NewHandler();
}
std::shared_ptr<FileHandler> FileSystem::FindHandler(uint64_t fh) {
return handlerManager_->FindHandler(fh);
}
void FileSystem::ReleaseHandler(uint64_t fh) {
return handlerManager_->ReleaseHandler(fh);
}
FileSystemMember FileSystem::BorrowMember() {
return FileSystemMember(deferSync_, openFiles_, attrWatcher_);
}
// fuse request*
CURVEFS_ERROR FileSystem::Lookup(Request req,
Ino parent,
const std::string& name,
EntryOut* entryOut) {
if (name.size() > option_.maxNameLength) {
return CURVEFS_ERROR::NAMETOOLONG;
}
bool yes = negative_->Get(parent, name);
if (yes) {
return CURVEFS_ERROR::NOTEXIST;
}
auto rc = rpc_->Lookup(parent, name, entryOut);
if (rc == CURVEFS_ERROR::OK) {
negative_->Delete(parent, name);
} else if (rc == CURVEFS_ERROR::NOTEXIST) {
negative_->Put(parent, name);
}
return rc;
}
CURVEFS_ERROR FileSystem::GetAttr(Request req, Ino ino, AttrOut* attrOut) {
InodeAttr attr;
auto rc = rpc_->GetAttr(ino, &attr);
if (rc == CURVEFS_ERROR::OK) {
*attrOut = AttrOut(attr);
}
return rc;
}
CURVEFS_ERROR FileSystem::OpenDir(Request req, Ino ino, FileInfo* fi) {
InodeAttr attr;
CURVEFS_ERROR rc = rpc_->GetAttr(ino, &attr);
if (rc != CURVEFS_ERROR::OK) {
return rc;
}
// revalidate directory cache
std::shared_ptr<DirEntryList> entries;
bool yes = dirCache_->Get(ino, &entries);
if (yes) {
if (entries->GetMtime() != AttrMtime(attr)) {
dirCache_->Drop(ino);
}
}
auto handler = NewHandler();
handler->mtime = AttrMtime(attr);
fi->fh = handler->fh;
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR FileSystem::ReadDir(Request req,
Ino ino,
FileInfo* fi,
std::shared_ptr<DirEntryList>* entries) {
bool yes = dirCache_->Get(ino, entries);
if (yes) {
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR rc = rpc_->ReadDir(ino, entries);
if (rc != CURVEFS_ERROR::OK) {
return rc;
}
(*entries)->SetMtime(FindHandler(fi->fh)->mtime);
dirCache_->Put(ino, *entries);
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR FileSystem::ReleaseDir(Request req, Ino ino, FileInfo* fi) {
ReleaseHandler(fi->fh);
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR FileSystem::Open(Request req, Ino ino, FileInfo* fi) {
std::shared_ptr<InodeWrapper> inode;
bool yes = openFiles_->IsOpened(ino, &inode);
if (yes) {
openFiles_->Open(ino, inode);
// fi->keep_cache = 1;
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR rc = rpc_->Open(ino, &inode);
if (rc != CURVEFS_ERROR::OK) {
return rc;
}
TimeSpec mtime;
yes = attrWatcher_->GetMtime(ino, &mtime);
if (!yes) {
// It is rare which only arise when attribute evited for attr-watcher.
LOG(WARNING) << "open(" << ino << "): stale file handler"
<< ": attribute not found in wacther";
return CURVEFS_ERROR::STALE;
} else if (mtime != InodeMtime(inode)) {
LOG(WARNING) << "open(" << ino << "): stale file handler"
<< ", cache(" << mtime << ") vs remote("
<< InodeMtime(inode) << ")";
return CURVEFS_ERROR::STALE;
}
openFiles_->Open(ino, inode);
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR FileSystem::Release(Request req, Ino ino) {
openFiles_->Close(ino);
return CURVEFS_ERROR::OK;
}
} // namespace filesystem
} // namespace client
} // namespace curvefs

View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-08
* Author: Jingli Chen (Wine93)
*/
#ifndef CURVEFS_SRC_CLIENT_FILESYSTEM_FILESYSTEM_H_
#define CURVEFS_SRC_CLIENT_FILESYSTEM_FILESYSTEM_H_
#include <gtest/gtest_prod.h>
#include <memory>
#include <string>
#include "curvefs/src/client/filesystem/error.h"
#include "curvefs/src/client/common/config.h"
#include "curvefs/src/client/filesystem/package.h"
#include "curvefs/src/client/filesystem/meta.h"
#include "curvefs/src/client/filesystem/lookup_cache.h"
#include "curvefs/src/client/filesystem/dir_cache.h"
#include "curvefs/src/client/filesystem/openfile.h"
#include "curvefs/src/client/filesystem/attr_watcher.h"
#include "curvefs/src/client/filesystem/rpc_client.h"
#include "curvefs/src/client/filesystem/defer_sync.h"
namespace curvefs {
namespace client {
namespace filesystem {
using ::curvefs::client::common::FileSystemOption;
struct FileSystemMember {
FileSystemMember(std::shared_ptr<DeferSync> deferSync,
std::shared_ptr<OpenFiles> openFiles,
std::shared_ptr<AttrWatcher> attrWatcher)
: deferSync(deferSync),
openFiles(openFiles),
attrWatcher(attrWatcher) {}
std::shared_ptr<DeferSync> deferSync;
std::shared_ptr<OpenFiles> openFiles;
std::shared_ptr<AttrWatcher> attrWatcher;
};
class FileSystem {
public:
FileSystem(struct FileSystemOption option, ExternalMember member);
void Run();
void Destory();
// fuse request
CURVEFS_ERROR Lookup(Request req,
Ino parent,
const std::string& name,
EntryOut* entryOut);
CURVEFS_ERROR GetAttr(Request req, Ino ino, AttrOut* attrOut);
CURVEFS_ERROR OpenDir(Request req, Ino ino, FileInfo* fi);
CURVEFS_ERROR ReadDir(Request req,
Ino ino,
FileInfo* fi,
std::shared_ptr<DirEntryList>* entries);
CURVEFS_ERROR ReleaseDir(Request req, Ino ino, FileInfo* fi);
CURVEFS_ERROR Open(Request req, Ino ino, FileInfo* fi);
CURVEFS_ERROR Release(Request req, Ino ino);
// fuse reply: we control all replies to vfs layer in same entrance.
void ReplyError(Request req, CURVEFS_ERROR code);
void ReplyEntry(Request req, EntryOut* entryOut);
void ReplyAttr(Request req, AttrOut* attrOut);
void ReplyReadlink(Request req, const std::string& link);
void ReplyOpen(Request req, FileInfo *fi);
void ReplyOpen(Request req, FileOut* fileOut);
void ReplyData(Request req,
struct fuse_bufvec *bufv,
enum fuse_buf_copy_flags flags);
void ReplyWrite(Request req, FileOut* fileOut);
void ReplyBuffer(Request req, const char *buf, size_t size);
void ReplyStatfs(Request req, const struct statvfs *stbuf);
void ReplyXattr(Request req, size_t size);
void ReplyCreate(Request req, EntryOut* entryOut, FileInfo* fi);
void AddDirEntry(Request req,
DirBufferHead* buffer,
DirEntry* dirEntry);
void AddDirEntryPlus(Request req,
DirBufferHead* buffer,
DirEntry* dirEntry);
// utility: file handler
std::shared_ptr<FileHandler> NewHandler();
std::shared_ptr<FileHandler> FindHandler(uint64_t fh);
void ReleaseHandler(uint64_t fh);
// utility: others
FileSystemMember BorrowMember();
private:
FRIEND_TEST(FileSystemTest, Attr2Stat);
FRIEND_TEST(FileSystemTest, Entry2Param);
FRIEND_TEST(FileSystemTest, SetEntryTimeout);
FRIEND_TEST(FileSystemTest, SetAttrTimeout);
// utility: convert to system type.
void Attr2Stat(InodeAttr* attr, struct stat* stat);
void Entry2Param(EntryOut* entryOut, fuse_entry_param* e);
// utility: set entry/attribute timeout
void SetEntryTimeout(EntryOut* entryOut);
void SetAttrTimeout(AttrOut* attrOut);
private:
FileSystemOption option_;
ExternalMember member;
std::shared_ptr<DeferSync> deferSync_;
std::shared_ptr<LookupCache> negative_;
std::shared_ptr<DirCache> dirCache_;
std::shared_ptr<OpenFiles> openFiles_;
std::shared_ptr<AttrWatcher> attrWatcher_;
std::shared_ptr<HandlerManager> handlerManager_;
std::shared_ptr<RPCClient> rpc_;
};
} // namespace filesystem
} // namespace client
} // namespace curvefs
#endif // CURVEFS_SRC_CLIENT_FILESYSTEM_FILESYSTEM_H_

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-31
* Author: Jingli Chen (Wine93)
*/
#include <glog/logging.h>
#include <ctime>
#include "absl/strings/str_format.h"
#include "curvefs/src/client/filesystem/utils.h"
#include "curvefs/src/client/filesystem/lookup_cache.h"
namespace curvefs {
namespace client {
namespace filesystem {
#define RETURN_FALSE_IF_DISABLED() \
do { \
if (!enable_) { \
return false; \
} \
} while (0)
LookupCache::LookupCache(LookupCacheOption option)
: enable_(option.negativeTimeoutSec > 0),
rwlock_(),
option_(option) {
lru_ = std::make_shared<LRUType>(option.lruSize);
if (enable_) {
LOG(INFO) << "Using lookup negative lru cache"
<< ", timeout = " << option.negativeTimeoutSec
<< ", capacity = " << option.lruSize;
}
}
std::string LookupCache::CacheKey(Ino parent, const std::string& name) {
return absl::StrFormat("%d:%s", parent, name);
}
bool LookupCache::Get(Ino parent, const std::string& name) {
RETURN_FALSE_IF_DISABLED();
ReadLockGuard lk(rwlock_);
CacheEntry entry;
auto key = CacheKey(parent, name);
bool yes = lru_->Get(key, &entry);
if (!yes) {
VLOG(1) << absl::StrFormat("Lookup cache not found: key(%d,%s)",
parent, name);
return false;
} else if (entry.uses < option_.minUses) {
return false;
} else if (entry.expireTime < Now()) {
return false;
}
return true;
}
bool LookupCache::Put(Ino parent, const std::string& name) {
RETURN_FALSE_IF_DISABLED();
WriteLockGuard lk(rwlock_);
CacheEntry entry;
auto key = CacheKey(parent, name);
bool yes = lru_->Get(key, &entry);
if (yes) {
entry.uses++;
} else {
entry.uses = 0;
}
entry.expireTime = Now() + TimeSpec(option_.negativeTimeoutSec, 0);
lru_->Put(key, entry);
return true;
}
bool LookupCache::Delete(Ino parent, const std::string& name) {
RETURN_FALSE_IF_DISABLED();
WriteLockGuard lk(rwlock_);
auto key = CacheKey(parent, name);
lru_->Remove(key);
return true;
}
} // namespace filesystem
} // namespace client
} // namespace curvefs

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-31
* Author: Jingli Chen (Wine93)
*/
#ifndef CURVEFS_SRC_CLIENT_FILESYSTEM_LOOKUP_CACHE_H_
#define CURVEFS_SRC_CLIENT_FILESYSTEM_LOOKUP_CACHE_H_
#include <memory>
#include <string>
#include "src/common/lru_cache.h"
#include "curvefs/src/client/common/config.h"
#include "curvefs/src/client/filesystem/meta.h"
namespace curvefs {
namespace client {
namespace filesystem {
using ::curve::common::LRUCache;
using ::curve::common::RWLock;
using ::curve::common::ReadLockGuard;
using ::curve::common::WriteLockGuard;
using ::curvefs::client::common::LookupCacheOption;
// memory cache for lookup result, now we only support cache negative result,
// and other positive entry will be cached in kernel.
class LookupCache {
public:
struct CacheEntry {
uint32_t uses;
TimeSpec expireTime;
};
using LRUType = LRUCache<std::string, CacheEntry>;
public:
explicit LookupCache(LookupCacheOption option);
bool Get(Ino parent, const std::string& name);
bool Put(Ino parent, const std::string& name);
bool Delete(Ino parent, const std::string& name);
private:
std::string CacheKey(Ino parent, const std::string& name);
private:
bool enable_;
RWLock rwlock_;
LookupCacheOption option_;
std::shared_ptr<LRUType> lru_;
};
} // namespace filesystem
} // namespace client
} // namespace curvefs
#endif // CURVEFS_SRC_CLIENT_FILESYSTEM_LOOKUP_CACHE_H_

View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-09
* Author: Jingli Chen (Wine93)
*/
#ifndef CURVEFS_SRC_CLIENT_FILESYSTEM_MESSAGE_QUEUE_H_
#define CURVEFS_SRC_CLIENT_FILESYSTEM_MESSAGE_QUEUE_H_
#include <glog/logging.h>
#include <string>
#include <atomic>
#include <thread>
#include "src/common/concurrent/task_queue.h"
#include "curvefs/src/common/threading.h"
namespace curvefs {
namespace client {
namespace filesystem {
using ::curve::common::TaskQueue;
using ::curvefs::common::SetThreadName;
template <typename MessageT>
class MessageQueue {
public:
using MessageHandler = std::function<void(const MessageT& message)>;
public:
MessageQueue(const std::string& name, size_t bufferSize)
: name_(name),
running_(false),
thread_(),
handler_(),
queue_(bufferSize) {}
void Start() {
if (running_.exchange(true)) {
return;
}
thread_ = std::thread(&MessageQueue::Consumer, this);
LOG(INFO) << "MessageQueue [ " << name_ << " ] "
<< "consumer thread start success";
}
void Stop() {
if (!running_.exchange(false)) {
return;
}
auto wakeup = []() {};
queue_.Push(wakeup);
LOG(INFO) << "MessageQueue [ " << name_ << " ] "
<< "consumer thread stoping...";
thread_.join();
LOG(INFO) << "MessageQueue [ " << name_ << " ] "
<< "consumer thread stopped";
}
void Publish(MessageT message) {
if (handler_ != nullptr) {
queue_.Push([this, message](){
this->handler_(message);
});
}
}
void Subscribe(MessageHandler handler) {
handler_ = handler;
}
private:
void Consumer() {
SetThreadName(name_.c_str());
while (running_.load(std::memory_order_relaxed)) {
queue_.Pop()();
}
while (queue_.Size() > 0) {
queue_.Pop()();
}
}
private:
std::string name_;
std::atomic<bool> running_;
std::thread thread_;
MessageHandler handler_;
TaskQueue queue_;
};
} // namespace filesystem
} // namespace client
} // namespace curvefs
#endif // CURVEFS_SRC_CLIENT_FILESYSTEM_MESSAGE_QUEUE_H_

View File

@ -0,0 +1,129 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-06
* Author: Jingli Chen (Wine93)
*/
#include <sys/stat.h>
#include "absl/strings/str_format.h"
#include "curvefs/src/client/filesystem/meta.h"
namespace curvefs {
namespace client {
namespace filesystem {
HandlerManager::HandlerManager()
: mutex_(),
dirBuffer_(std::make_shared<DirBuffer>()),
handlers_() {}
HandlerManager::~HandlerManager() {
dirBuffer_->DirBufferFreeAll();
}
std::shared_ptr<FileHandler> HandlerManager::NewHandler() {
UniqueLock lk(mutex_);
auto handler = std::make_shared<FileHandler>();
handler->fh = dirBuffer_->DirBufferNew();
handler->buffer = dirBuffer_->DirBufferGet(handler->fh);
handler->padding = false;
handlers_.emplace(handler->fh, handler);
return handler;
}
std::shared_ptr<FileHandler> HandlerManager::FindHandler(uint64_t fh) {
UniqueLock lk(mutex_);
auto iter = handlers_.find(fh);
if (iter == handlers_.end()) {
return nullptr;
}
return iter->second;
}
void HandlerManager::ReleaseHandler(uint64_t fh) {
UniqueLock lk(mutex_);
dirBuffer_->DirBufferRelease(fh);
handlers_.erase(fh);
}
std::string StrMode(uint16_t mode) {
static std::map<uint16_t, char> type2char = {
{ S_IFSOCK, 's' },
{ S_IFLNK, 'l' },
{ S_IFREG, '-' },
{ S_IFBLK, 'b' },
{ S_IFDIR, 'd' },
{ S_IFCHR, 'c' },
{ S_IFIFO, 'f' },
{ 0, '?' },
};
std::string s("?rwxrwxrwx");
s[0] = type2char[mode & (S_IFMT & 0xffff)];
if (mode & S_ISUID) {
s[3] = 's';
}
if (mode & S_ISGID) {
s[6] = 's';
}
if (mode & S_ISVTX) {
s[9] = 't';
}
for (auto i = 0; i < 9; i++) {
if ((mode & (1 << i)) == 0) {
if ((s[9-i] == 's') || (s[9-i] == 't')) {
s[9-i] &= 0xDF;
} else {
s[9-i] = '-';
}
}
}
return s;
}
namespace {
std::string Attr2Str(const InodeAttr& attr) {
if (!attr.IsInitialized()) {
return "";
}
std::string smode;
return absl::StrFormat(" (%d,[%s:0%06o,%d,%d,%d,%d,%d,%d,%d])",
attr.inodeid(), StrMode(attr.mode()).c_str(), attr.mode(), attr.nlink(),
attr.uid(), attr.gid(),
attr.atime(), attr.mtime(), attr.ctime(),
attr.length());
}
} // namespace
std::string StrEntry(EntryOut entryOut) {
return Attr2Str(entryOut.attr);
}
std::string StrAttr(AttrOut attrOut) {
return Attr2Str(attrOut.attr);
}
} // namespace filesystem
} // namespace client
} // namespace curvefs

View File

@ -0,0 +1,178 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-06
* Author: Jingli Chen (Wine93)
*/
#ifndef CURVEFS_SRC_CLIENT_FILESYSTEM_META_H_
#define CURVEFS_SRC_CLIENT_FILESYSTEM_META_H_
#include <map>
#include <memory>
#include <string>
#include <iostream>
#include "src/common/concurrent/concurrent.h"
#include "curvefs/proto/metaserver.pb.h"
#include "curvefs/src/client/fuse_common.h"
#include "curvefs/src/client/dir_buffer.h"
#include "curvefs/src/client/inode_wrapper.h"
namespace curvefs {
namespace client {
namespace filesystem {
using ::curve::common::Mutex;
using ::curve::common::RWLock;
using ::curve::common::UniqueLock;
using ::curve::common::ReadLockGuard;
using ::curve::common::WriteLockGuard;
using ::curvefs::metaserver::XAttr;
using ::curvefs::metaserver::Dentry;
using ::curvefs::metaserver::InodeAttr;
using ::curvefs::metaserver::FsFileType;
using ::curvefs::client::DirBufferHead;
using ::curvefs::client::InodeWrapper;
using Ino = fuse_ino_t;
using Request = fuse_req_t;
using FileInfo = struct fuse_file_info;
struct EntryOut {
EntryOut() = default;
explicit EntryOut(InodeAttr attr) : attr(attr) {}
InodeAttr attr;
double entryTimeout;
double attrTimeout;
};
struct AttrOut {
AttrOut() = default;
explicit AttrOut(InodeAttr attr) : attr(attr) {}
InodeAttr attr;
double attrTimeout;
};
struct DirEntry {
DirEntry() = default;
DirEntry(Ino ino, const std::string& name, InodeAttr attr)
: ino(ino), name(name), attr(attr) {}
Ino ino;
std::string name;
InodeAttr attr;
};
struct FileOut {
FileOut() = default;
FileOut(FileInfo* fi, InodeAttr attr)
: fi(fi), attr(attr), nwritten(0) {}
FileOut(InodeAttr attr, size_t nwritten)
: fi(nullptr), attr(attr), nwritten(nwritten) {}
FileInfo* fi;
InodeAttr attr;
size_t nwritten;
};
struct TimeSpec {
TimeSpec() : seconds(0), nanoSeconds(0) {}
TimeSpec(uint64_t seconds, uint32_t nanoSeconds)
: seconds(seconds), nanoSeconds(nanoSeconds) {}
TimeSpec(const TimeSpec& time)
: seconds(time.seconds), nanoSeconds(time.nanoSeconds) {}
TimeSpec& operator=(const TimeSpec& time) = default;
TimeSpec operator+(const TimeSpec& time) const {
return TimeSpec(seconds + time.seconds, nanoSeconds + time.nanoSeconds);
}
uint64_t seconds;
uint32_t nanoSeconds;
};
struct FileHandler {
uint64_t fh;
DirBufferHead* buffer;
TimeSpec mtime;
bool padding; // padding buffer
};
class HandlerManager {
public:
HandlerManager();
~HandlerManager();
std::shared_ptr<FileHandler> NewHandler();
std::shared_ptr<FileHandler> FindHandler(uint64_t id);
void ReleaseHandler(uint64_t id);
private:
Mutex mutex_;
std::shared_ptr<DirBuffer> dirBuffer_;
std::map<uint64_t, std::shared_ptr<FileHandler>> handlers_;
};
inline bool operator==(const TimeSpec& lhs, const TimeSpec& rhs) {
return (lhs.seconds == rhs.seconds) &&
(lhs.nanoSeconds == rhs.nanoSeconds);
}
inline bool operator!=(const TimeSpec& lhs, const TimeSpec& rhs) {
return !(lhs == rhs);
}
inline bool operator<(const TimeSpec& lhs, const TimeSpec& rhs) {
return (lhs.seconds < rhs.seconds) ||
(lhs.seconds == rhs.seconds && lhs.nanoSeconds < rhs.nanoSeconds);
}
inline bool operator>(const TimeSpec& lhs, const TimeSpec& rhs) {
return (lhs.seconds > rhs.seconds) ||
(lhs.seconds == rhs.seconds && lhs.nanoSeconds > rhs.nanoSeconds);
}
inline std::ostream &operator<<(std::ostream &os, const TimeSpec& time) {
return os << time.seconds << "." << time.nanoSeconds;
}
std::string StrMode(uint16_t mode);
std::string StrEntry(EntryOut entryOut);
std::string StrAttr(AttrOut attrOut);
} // namespace filesystem
} // namespace client
} // namespace curvefs
#endif // CURVEFS_SRC_CLIENT_FILESYSTEM_META_H_

View File

@ -0,0 +1,141 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-09
* Author: Jingli Chen (Wine93)
*/
#include "curvefs/src/client/filesystem/openfile.h"
#include "curvefs/src/client/filesystem/utils.h"
namespace curvefs {
namespace client {
namespace filesystem {
OpenFiles::OpenFiles(OpenFilesOption option,
std::shared_ptr<DeferSync> deferSync)
: rwlock_(),
option_(option),
deferSync_(deferSync),
files_(std::make_shared<LRUType>(option.lruSize)) {
LOG(INFO) << "Using openfile lru cache, capacity " << option.lruSize;
}
/*
* Delete(...) does:
* 1) publish to message queue which will flush file to server with async
* 2) delete file from lru cache
*/
void OpenFiles::Delete(Ino ino,
const std::shared_ptr<OpenFile>& file,
bool flush) {
if (flush) {
deferSync_->Push(file->inode);
}
files_->Remove(ino);
VLOG(1) << "Delete open file cache: ino = " << ino
<< ", refs = " << file->refs
<< ", mtime = " << InodeMtime(file->inode);
}
void OpenFiles::Evit(size_t size) {
Ino ino;
std::shared_ptr<OpenFile> file;
while (files_->Size() + size >= option_.lruSize) {
bool yes = files_->GetLast(&ino, &file);
if (!yes) {
break;
}
Delete(ino, file, true);
}
}
void OpenFiles::Open(Ino ino, std::shared_ptr<InodeWrapper> inode) {
WriteLockGuard lk(rwlock_);
Evit(1);
std::shared_ptr<OpenFile> file;
bool yes = files_->Get(ino, &file);
if (yes) {
file->refs++;
return;
}
file = std::make_shared<OpenFile>(inode);
file->refs++;
files_->Put(ino, file);
VLOG(1) << "Insert open file cache: ino = " << ino
<< ", refs = " << file->refs
<< ", mtime = " << InodeMtime(file->inode);
}
bool OpenFiles::IsOpened(Ino ino, std::shared_ptr<InodeWrapper>* inode) {
ReadLockGuard lk(rwlock_);
std::shared_ptr<OpenFile> file;
bool yes = files_->Get(ino, &file);
if (!yes) {
return false;
}
*inode = file->inode;
return true;
}
void OpenFiles::Close(Ino ino) {
WriteLockGuard lk(rwlock_);
std::shared_ptr<OpenFile> file;
bool yes = files_->Get(ino, &file);
if (!yes) {
return;
}
if (file->refs > 0) {
file->refs--;
}
if (file->refs == 0) {
Delete(ino, file, false); // file already flushed before close
}
}
/*
* CloseAll() does:
* flush all file to server and delete from LRU cache
*/
void OpenFiles::CloseAll() {
WriteLockGuard lk(rwlock_);
Evit(option_.lruSize);
}
bool OpenFiles::GetFileAttr(Ino ino, InodeAttr* attr) {
ReadLockGuard lk(rwlock_);
std::shared_ptr<OpenFile> file;
bool yes = files_->Get(ino, &file);
if (!yes) {
return false;
}
file->inode->GetInodeAttr(attr);
return true;
}
} // namespace filesystem
} // namespace client
} // namespace curvefs

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-09
* Author: Jingli Chen (Wine93)
*/
#ifndef CURVEFS_SRC_CLIENT_FILESYSTEM_OPENFILE_H_
#define CURVEFS_SRC_CLIENT_FILESYSTEM_OPENFILE_H_
#include <memory>
#include "src/common/lru_cache.h"
#include "curvefs/src/client/inode_wrapper.h"
#include "curvefs/src/client/filesystem/meta.h"
#include "curvefs/src/client/filesystem/defer_sync.h"
#include "curvefs/src/client/filesystem/dir_cache.h"
namespace curvefs {
namespace client {
namespace filesystem {
using ::curve::common::LRUCache;
using ::curve::common::ReadLockGuard;
using ::curve::common::WriteLockGuard;
using ::curvefs::client::InodeWrapper;
using ::curvefs::client::common::OpenFilesOption;
struct OpenFile {
explicit OpenFile(std::shared_ptr<InodeWrapper> inode)
: inode(inode), refs(0) {}
std::shared_ptr<InodeWrapper> inode;
uint64_t refs;
};
class OpenFiles {
public:
using LRUType = LRUCache<Ino, std::shared_ptr<OpenFile>>;
public:
explicit OpenFiles(OpenFilesOption option,
std::shared_ptr<DeferSync> deferSync);
void Open(Ino ino, std::shared_ptr<InodeWrapper> inode);
bool IsOpened(Ino ino, std::shared_ptr<InodeWrapper>* inode);
void Close(Ino ino);
void CloseAll();
bool GetFileAttr(Ino ino, InodeAttr* inode);
private:
void Delete(Ino ino, const std::shared_ptr<OpenFile>& file, bool flush);
void Evit(size_t size);
private:
RWLock rwlock_;
OpenFilesOption option_;
std::shared_ptr<DeferSync> deferSync_;
std::shared_ptr<LRUType> files_;
};
} // namespace filesystem
} // namespace client
} // namespace curvefs
#endif // CURVEFS_SRC_CLIENT_FILESYSTEM_OPENFILE_H_

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-06
* Author: Jingli Chen (Wine93)
*/
#ifndef CURVEFS_SRC_CLIENT_FILESYSTEM_PACKAGE_H_
#define CURVEFS_SRC_CLIENT_FILESYSTEM_PACKAGE_H_
#include <memory>
#include "curvefs/src/client/dentry_cache_manager.h"
#include "curvefs/src/client/inode_cache_manager.h"
#include "curvefs/src/client/xattr_manager.h"
namespace curvefs {
namespace client {
namespace filesystem {
struct ExternalMember { // external member depended by FileSystem
ExternalMember() = delete;
ExternalMember(std::shared_ptr<DentryCacheManager> dentryManager,
std::shared_ptr<InodeCacheManager> inodeManager)
: dentryManager(dentryManager),
inodeManager(inodeManager) {}
std::shared_ptr<DentryCacheManager> dentryManager;
std::shared_ptr<InodeCacheManager> inodeManager;
};
} // namespace filesystem
} // namespace client
} // namespace curvefs
#endif // CURVEFS_SRC_CLIENT_FILESYSTEM_PACKAGE_H_

View File

@ -0,0 +1,128 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-07
* Author: Jingli Chen (Wine93)
*/
#include <map>
#include <set>
#include <list>
#include <string>
#include <memory>
#include <utility>
#include "curvefs/src/client/filesystem/rpc_client.h"
namespace curvefs {
namespace client {
namespace filesystem {
RPCClient::RPCClient(RPCOption option,
ExternalMember member)
: option_(option),
inodeManager_(member.inodeManager),
dentryManager_(member.dentryManager) {}
CURVEFS_ERROR RPCClient::GetAttr(Ino ino, InodeAttr* attr) {
CURVEFS_ERROR rc = inodeManager_->GetInodeAttr(ino, attr);
if (rc != CURVEFS_ERROR::OK) {
LOG(ERROR) << "rpc(getattr::GetInodeAttr) failed, retCode = " << rc
<< ", ino = " << ino;
}
return rc;
}
CURVEFS_ERROR RPCClient::Lookup(Ino parent,
const std::string& name,
EntryOut* entryOut) {
Dentry dentry;
CURVEFS_ERROR rc = dentryManager_->GetDentry(parent, name, &dentry);
if (rc != CURVEFS_ERROR::OK) {
if (rc != CURVEFS_ERROR::NOTEXIST) {
LOG(ERROR) << "rpc(lookup::GetDentry) failed, retCode = " << rc
<< ", parent = " << parent << ", name = " << name;
}
return rc;
}
Ino ino = dentry.inodeid();
rc = inodeManager_->GetInodeAttr(ino, &entryOut->attr);
if (rc != CURVEFS_ERROR::OK) {
LOG(ERROR) << "rpc(lookup::GetInodeAttr) failed, retCode = " << rc
<< ", ino = " << ino;
}
return rc;
}
CURVEFS_ERROR RPCClient::ReadDir(Ino ino,
std::shared_ptr<DirEntryList>* entries) {
uint32_t limit = option_.listDentryLimit;
std::list<Dentry> dentries;
CURVEFS_ERROR rc = dentryManager_->ListDentry(ino, &dentries, limit);
if (rc != CURVEFS_ERROR::OK) {
LOG(ERROR) << "rpc(readdir::ListDentry) failed, retCode = " << rc
<< ", ino = " << ino;
return rc;
}
std::set<uint64_t> inos;
std::map<uint64_t, InodeAttr> attrs;
std::for_each(dentries.begin(), dentries.end(), [&](Dentry& dentry){
inos.emplace(dentry.inodeid());
});
rc = inodeManager_->BatchGetInodeAttrAsync(ino, &inos, &attrs);
if (rc != CURVEFS_ERROR::OK) {
LOG(ERROR) << "rpc(readdir::BatchGetInodeAttrAsync) failed"
<< ", retCode = " << rc << ", ino = " << ino;
return rc;
}
DirEntry dirEntry;
for (const auto& dentry : dentries) {
Ino ino = dentry.inodeid();
auto iter = attrs.find(ino);
if (iter == attrs.end()) {
LOG(WARNING) << "rpc(readdir::BatchGetInodeAttrAsync) "
<< "missing attribute, ino = " << ino;
continue;
}
// NOTE: we can't use std::move() for attribute for hard link
// which will sharing inode attribute.
dirEntry.ino = ino;
dirEntry.name = std::move(dentry.name());
dirEntry.attr = iter->second;
(*entries)->Add(dirEntry);
}
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR RPCClient::Open(Ino ino, std::shared_ptr<InodeWrapper>* inode) {
CURVEFS_ERROR rc = inodeManager_->GetInode(ino, *inode);
if (rc != CURVEFS_ERROR::OK) {
LOG(ERROR) << "rpc(open/GetInode) failed" << ", retCode = " << rc
<< ", ino = " << ino;
}
return rc;
}
} // namespace filesystem
} // namespace client
} // namespace curvefs

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-07
* Author: Jingli Chen (Wine93)
*/
#ifndef CURVEFS_SRC_CLIENT_FILESYSTEM_RPC_CLIENT_H_
#define CURVEFS_SRC_CLIENT_FILESYSTEM_RPC_CLIENT_H_
#include <memory>
#include <string>
#include "curvefs/src/client/common/config.h"
#include "curvefs/src/client/filesystem/meta.h"
#include "curvefs/src/client/filesystem/package.h"
#include "curvefs/src/client/filesystem/dir_cache.h"
namespace curvefs {
namespace client {
namespace filesystem {
using ::curvefs::client::common::RPCOption;
class RPCClient {
public:
RPCClient(RPCOption option,
ExternalMember member);
CURVEFS_ERROR GetAttr(Ino ino, InodeAttr* attr);
CURVEFS_ERROR Lookup(Ino parent,
const std::string& name,
EntryOut* entryOut);
CURVEFS_ERROR ReadDir(Ino ino, std::shared_ptr<DirEntryList>* entries);
CURVEFS_ERROR Open(Ino ino, std::shared_ptr<InodeWrapper>* inode);
private:
RPCOption option_;
std::shared_ptr<InodeCacheManager> inodeManager_;
std::shared_ptr<DentryCacheManager> dentryManager_;
};
} // namespace filesystem
} // namespace client
} // namespace curvefs
#endif // CURVEFS_SRC_CLIENT_FILESYSTEM_RPC_CLIENT_H_

View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-06
* Author: Jingli Chen (Wine93)
*/
#include <glog/logging.h>
#include "curvefs/src/client/filesystem/utils.h"
namespace curvefs {
namespace client {
namespace filesystem {
bool IsDir(const InodeAttr& attr) {
return attr.type() == FsFileType::TYPE_DIRECTORY;
}
bool IsS3File(const InodeAttr& attr) {
return attr.type() == FsFileType::TYPE_S3;
}
bool IsVolmeFile(const InodeAttr& attr) {
return attr.type() == FsFileType::TYPE_FILE;
}
bool IsSymLink(const InodeAttr& attr) {
return attr.type() == FsFileType::TYPE_SYM_LINK;
}
TimeSpec AttrMtime(const InodeAttr& attr) {
return TimeSpec(attr.mtime(), attr.mtime_ns());
}
TimeSpec AttrCtime(const InodeAttr& attr) {
return TimeSpec(attr.ctime(), attr.ctime_ns());
}
TimeSpec InodeMtime(const std::shared_ptr<InodeWrapper> inode) {
InodeAttr attr;
inode->GetInodeAttr(&attr);
return AttrMtime(attr);
}
TimeSpec Now() {
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
return TimeSpec(now.tv_sec, now.tv_nsec);
}
} // namespace filesystem
} // namespace client
} // namespace curvefs

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2023 NetEase Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Project: Curve
* Created Date: 2023-03-06
* Author: Jingli Chen (Wine93)
*/
#ifndef CURVEFS_SRC_CLIENT_FILESYSTEM_UTILS_H_
#define CURVEFS_SRC_CLIENT_FILESYSTEM_UTILS_H_
#include <memory>
#include "curvefs/src/client/filesystem/meta.h"
#include "curvefs/src/client/filesystem/package.h"
namespace curvefs {
namespace client {
namespace filesystem {
// directory
bool IsDir(const InodeAttr& attr);
// file which data is stored in s3
bool IsS3File(const InodeAttr& attr);
// file which data is stored in volume
bool IsVolmeFile(const InodeAttr& attr);
// symbol link
bool IsSymLink(const InodeAttr& attr);
struct TimeSpec AttrMtime(const InodeAttr& attr);
struct TimeSpec AttrCtime(const InodeAttr& attr);
struct TimeSpec InodeMtime(const std::shared_ptr<InodeWrapper> inode);
struct TimeSpec Now();
} // namespace filesystem
} // namespace client
} // namespace curvefs
#endif // CURVEFS_SRC_CLIENT_FILESYSTEM_UTILS_H_

View File

@ -35,7 +35,7 @@
#include "curvefs/proto/mds.pb.h"
#include "curvefs/src/client/common/common.h"
#include "curvefs/src/client/error_code.h"
#include "curvefs/src/client/filesystem/error.h"
#include "curvefs/src/client/fuse_common.h"
#include "curvefs/src/client/client_operator.h"
#include "curvefs/src/client/inode_wrapper.h"
@ -55,7 +55,10 @@ using ::curvefs::mds::topology::PartitionTxId;
using ::curvefs::mds::FSStatusCode_Name;
using ::curvefs::client::common::MAX_XATTR_NAME_LENGTH;
using ::curvefs::client::common::MAX_XATTR_VALUE_LENGTH;
using ::curvefs::client::common::FileHandle;
using ::curvefs::client::filesystem::ExternalMember;
using ::curvefs::client::filesystem::DirEntry;
using ::curvefs::client::filesystem::DirEntryList;
using ::curvefs::client::filesystem::FileOut;
#define RETURN_IF_UNSUCCESS(action) \
do { \
@ -70,6 +73,21 @@ namespace curvefs {
namespace client {
namespace common {
DECLARE_bool(enableCto);
DECLARE_uint64(fuseClientAvgWriteIops);
DECLARE_uint64(fuseClientBurstWriteIops);
DECLARE_uint64(fuseClientBurstWriteIopsSecs);
DECLARE_uint64(fuseClientAvgWriteBytes);
DECLARE_uint64(fuseClientBurstWriteBytes);
DECLARE_uint64(fuseClientBurstWriteBytesSecs);
DECLARE_uint64(fuseClientAvgReadIops);
DECLARE_uint64(fuseClientBurstReadIops);
DECLARE_uint64(fuseClientBurstReadIopsSecs);
DECLARE_uint64(fuseClientAvgReadBytes);
DECLARE_uint64(fuseClientBurstReadBytes);
DECLARE_uint64(fuseClientBurstReadBytesSecs);
} // namespace common
} // namespace client
} // namespace curvefs
@ -83,6 +101,27 @@ using rpcclient::Cli2ClientImpl;
using rpcclient::MetaCache;
using common::FLAGS_enableCto;
using common::FLAGS_fuseClientAvgWriteIops;
using common::FLAGS_fuseClientBurstWriteIops;
using common::FLAGS_fuseClientBurstWriteIopsSecs;
using common::FLAGS_fuseClientAvgWriteBytes;
using common::FLAGS_fuseClientBurstWriteBytes;
using common::FLAGS_fuseClientBurstWriteBytesSecs;
using common::FLAGS_fuseClientAvgReadIops;
using common::FLAGS_fuseClientBurstReadIops;
using common::FLAGS_fuseClientBurstReadIopsSecs;
using common::FLAGS_fuseClientAvgReadBytes;
using common::FLAGS_fuseClientBurstReadBytes;
using common::FLAGS_fuseClientBurstReadBytesSecs;
static void on_throttle_timer(void *arg) {
FuseClient *fuseClient = reinterpret_cast<FuseClient *>(arg);
fuseClient->InitQosParam();
}
CURVEFS_ERROR FuseClient::Init(const FuseClientOption &option) {
option_ = option;
@ -98,7 +137,8 @@ CURVEFS_ERROR FuseClient::Init(const FuseClientOption &option) {
auto channelManager = std::make_shared<ChannelManager<MetaserverID>>();
leaseExecutor_ = absl::make_unique<LeaseExecutor>(option.leaseOpt,
metaCache, mdsClient_);
metaCache, mdsClient_,
&enableSumInDir_);
xattrManager_ = std::make_shared<XattrManager>(inodeManager_,
dentryManager_, option_.listDentryLimit, option_.listDentryThreads);
@ -117,6 +157,11 @@ CURVEFS_ERROR FuseClient::Init(const FuseClientOption &option) {
curve::client::ClientDummyServerInfo::GetInstance().SetPort(listenPort);
curve::client::ClientDummyServerInfo::GetInstance().SetIP(localIp);
{
ExternalMember member(dentryManager_, inodeManager_);
fs_ = std::make_shared<FileSystem>(option_.fileSystemOption, member);
}
MetaStatusCode ret2 =
metaClient_->Init(option.excutorOpt, option.excutorInternalOpt,
metaCache, channelManager);
@ -124,18 +169,14 @@ CURVEFS_ERROR FuseClient::Init(const FuseClientOption &option) {
return CURVEFS_ERROR::INTERNAL;
}
CURVEFS_ERROR ret3 =
inodeManager_->Init(option.iCacheLruSize, option.enableICacheMetrics,
option.flushPeriodSec, option.refreshDataOption,
option.lruTimeOutSec);
if (ret3 != CURVEFS_ERROR::OK) {
return ret3;
}
ret3 =
dentryManager_->Init(option.dCacheLruSize, option.enableDCacheMetrics,
option.lruTimeOutSec);
if (ret3 != CURVEFS_ERROR::OK) {
return ret3;
{ // init inode manager
auto member = fs_->BorrowMember();
CURVEFS_ERROR rc = inodeManager_->Init(option.refreshDataOption,
member.openFiles,
member.deferSync);
if (rc != CURVEFS_ERROR::OK) {
return rc;
}
}
if (warmupManager_ != nullptr) {
@ -143,7 +184,9 @@ CURVEFS_ERROR FuseClient::Init(const FuseClientOption &option) {
warmupManager_->SetFsInfo(fsInfo_);
}
return ret3;
InitQosParam();
return CURVEFS_ERROR::OK;
}
void FuseClient::UnInit() {
@ -153,11 +196,14 @@ void FuseClient::UnInit() {
delete mdsBase_;
mdsBase_ = nullptr;
while (bthread_timer_del(throttleTimer_) == 1) {
bthread_usleep(1000);
}
}
CURVEFS_ERROR FuseClient::Run() {
if (isStop_.exchange(false)) {
inodeManager_->Run();
return CURVEFS_ERROR::OK;
}
return CURVEFS_ERROR::INTERNAL;
@ -165,7 +211,6 @@ CURVEFS_ERROR FuseClient::Run() {
void FuseClient::Fini() {
if (!isStop_.exchange(true)) {
inodeManager_->Stop();
xattrManager_->Stop();
}
}
@ -174,6 +219,7 @@ CURVEFS_ERROR FuseClient::FuseOpInit(void *userdata,
struct fuse_conn_info *conn) {
(void)userdata;
(void)conn;
fs_->Run();
return CURVEFS_ERROR::OK;
}
@ -183,7 +229,7 @@ void FuseClient::FuseOpDestroy(void *userdata) {
}
FlushAll();
dirBuf_->DirBufferFreeAll();
fs_->Destory();
// stop lease before umount fs, otherwise, lease request after umount fs
// will add a mountpoint entry.
@ -215,91 +261,38 @@ void FuseClient::FuseOpDestroy(void *userdata) {
<< " success!";
}
void InodeAttr2ParamAttr(const InodeAttr &inodeAttr, struct stat *attr) {
attr->st_ino = inodeAttr.inodeid();
attr->st_mode = inodeAttr.mode();
attr->st_nlink = inodeAttr.nlink();
attr->st_uid = inodeAttr.uid();
attr->st_gid = inodeAttr.gid();
attr->st_size = inodeAttr.length();
attr->st_rdev = inodeAttr.rdev();
attr->st_atim.tv_sec = inodeAttr.atime();
attr->st_atim.tv_nsec = inodeAttr.atime_ns();
attr->st_mtim.tv_sec = inodeAttr.mtime();
attr->st_mtim.tv_nsec = inodeAttr.mtime_ns();
attr->st_ctim.tv_sec = inodeAttr.ctime();
attr->st_ctim.tv_nsec = inodeAttr.ctime_ns();
attr->st_blksize = kOptimalIOBlockSize;
switch (inodeAttr.type()) {
case metaserver::TYPE_S3:
attr->st_blocks = (inodeAttr.length() + 511) / 512;
break;
default:
attr->st_blocks = 0;
break;
CURVEFS_ERROR FuseClient::FuseOpLookup(fuse_req_t req,
fuse_ino_t parent,
const char* name,
EntryOut* entryOut) {
CURVEFS_ERROR rc = fs_->Lookup(req, parent, name, entryOut);
if (rc != CURVEFS_ERROR::OK && rc != CURVEFS_ERROR::NOTEXIST) {
LOG(ERROR) << "Lookup() failed, retCode = " << rc
<< ", parent = " << parent << ", name = " << name;
}
return rc;
}
void GetDentryParamFromInodeAttr(
const FuseClientOption &option,
const InodeAttr &inodeAttr,
fuse_entry_param *param) {
memset(param, 0, sizeof(fuse_entry_param));
param->ino = inodeAttr.inodeid();
param->generation = 0;
InodeAttr2ParamAttr(inodeAttr, &param->attr);
param->attr_timeout = option.attrTimeOut;
param->entry_timeout = option.entryTimeOut;
}
CURVEFS_ERROR FuseClient::FuseOpLookup(fuse_req_t req, fuse_ino_t parent,
const char *name, fuse_entry_param *e) {
(void)req;
VLOG(1) << "FuseOpLookup parent: " << parent
<< ", name: " << name;
if (strlen(name) > option_.maxNameLength) {
return CURVEFS_ERROR::NAMETOOLONG;
}
Dentry dentry;
CURVEFS_ERROR ret = dentryManager_->GetDentry(parent, name, &dentry);
if (ret != CURVEFS_ERROR::OK) {
if (ret != CURVEFS_ERROR::NOTEXIST) {
LOG(WARNING) << "dentryManager_ get dentry fail, ret = " << ret
<< ", parent inodeid = " << parent
<< ", name = " << name;
}
return ret;
}
fuse_ino_t ino = dentry.inodeid();
InodeAttr attr;
ret = inodeManager_->GetInodeAttr(ino, &attr);
if (ret != CURVEFS_ERROR::OK) {
LOG(ERROR) << "inodeManager get inodeAttr fail, ret = " << ret
<< ", inodeid = " << ino;
return ret;
}
GetDentryParamFromInodeAttr(option_, attr, e);
return ret;
}
CURVEFS_ERROR FuseClient::FuseOpOpen(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi) {
(void)req;
VLOG(1) << "FuseOpOpen, ino: " << ino;
CURVEFS_ERROR FuseClient::HandleOpenFlags(fuse_req_t req,
fuse_ino_t ino,
struct fuse_file_info* fi,
FileOut* fileOut) {
std::shared_ptr<InodeWrapper> inodeWrapper;
// alredy opened
CURVEFS_ERROR ret = inodeManager_->GetInode(ino, inodeWrapper);
if (ret != CURVEFS_ERROR::OK) {
LOG(ERROR) << "inodeManager get inode fail, ret = " << ret
<< ", inodeid = " << ino;
return ret;
}
::curve::common::UniqueLock lgGuard = inodeWrapper->GetUniqueLock();
fileOut->fi = fi;
inodeWrapper->GetInodeAttr(&fileOut->attr);
if (fi->flags & O_TRUNC) {
if (fi->flags & O_WRONLY || fi->flags & O_RDWR) {
::curve::common::UniqueLock lgGuard =
inodeWrapper->GetUniqueLock();
uint64_t length = inodeWrapper->GetLengthLocked();
CURVEFS_ERROR tRet = Truncate(inodeWrapper.get(), 0);
if (tRet != CURVEFS_ERROR::OK) {
@ -318,7 +311,7 @@ CURVEFS_ERROR FuseClient::FuseOpOpen(fuse_req_t req, fuse_ino_t ino,
inodeWrapper->MarkDirty();
}
if (enableSumInDir_ && length != 0) {
if (enableSumInDir_.load() && length != 0) {
// update parent summary info
const Inode *inode = inodeWrapper->GetInodeLocked();
XAttr xattr;
@ -334,18 +327,29 @@ CURVEFS_ERROR FuseClient::FuseOpOpen(fuse_req_t req, fuse_ino_t ino,
}
}
}
inodeWrapper->GetInodeAttrLocked(&fileOut->attr);
} else {
return CURVEFS_ERROR::NOPERMISSION;
}
}
if (FLAGS_enableCto) {
inodeManager_->AddOpenedInode(ino);
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR FuseClient::FuseOpOpen(fuse_req_t req,
fuse_ino_t ino,
struct fuse_file_info* fi,
FileOut* fileOut) {
CURVEFS_ERROR rc = fs_->Open(req, ino, fi);
if (rc != CURVEFS_ERROR::OK) {
LOG(ERROR) << "open(" << ino << ") failed, retCode = " << rc;
return rc;
}
return ret;
return HandleOpenFlags(req, ino, fi, fileOut);
}
CURVEFS_ERROR FuseClient::UpdateParentMCTimeAndNlink(
fuse_ino_t parent, FsFileType type, NlinkChange nlink) {
std::shared_ptr<InodeWrapper> parentInodeWrapper;
auto ret = inodeManager_->GetInode(parent, parentInodeWrapper);
if (ret != CURVEFS_ERROR::OK) {
@ -361,16 +365,27 @@ CURVEFS_ERROR FuseClient::UpdateParentMCTimeAndNlink(
if (FsFileType::TYPE_DIRECTORY == type) {
parentInodeWrapper->UpdateNlinkLocked(nlink);
}
if (option_.fileSystemOption.deferSyncOption.deferDirMtime) {
inodeManager_->ShipToFlush(parentInodeWrapper);
} else {
return parentInodeWrapper->SyncAttr();
}
}
inodeManager_->ShipToFlush(parentInodeWrapper);
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR FuseClient::MakeNode(fuse_req_t req, fuse_ino_t parent,
const char *name, mode_t mode,
FsFileType type, dev_t rdev, bool internal,
fuse_entry_param *e) {
if (strlen(name) > option_.maxNameLength) {
CURVEFS_ERROR FuseClient::MakeNode(
fuse_req_t req,
fuse_ino_t parent,
const char* name,
mode_t mode,
FsFileType type,
dev_t rdev,
bool internal,
std::shared_ptr<InodeWrapper>& inodeWrapper) {
if (strlen(name) > option_.fileSystemOption.maxNameLength) {
return CURVEFS_ERROR::NAMETOOLONG;
}
@ -401,7 +416,6 @@ CURVEFS_ERROR FuseClient::MakeNode(fuse_req_t req, fuse_ino_t parent,
param.rdev = rdev;
param.parent = parent;
std::shared_ptr<InodeWrapper> inodeWrapper;
CURVEFS_ERROR ret = inodeManager_->CreateInode(param, inodeWrapper);
if (ret != CURVEFS_ERROR::OK) {
LOG(ERROR) << "inodeManager CreateInode fail, ret = " << ret
@ -453,7 +467,7 @@ CURVEFS_ERROR FuseClient::MakeNode(fuse_req_t req, fuse_ino_t parent,
<< ", parent = " << parent << ", name = " << name
<< ", mode = " << mode;
if (enableSumInDir_) {
if (enableSumInDir_.load()) {
// update parent summary info
XAttr xattr;
xattr.mutable_xattrinfos()->insert({XATTRENTRIES, "1"});
@ -472,20 +486,26 @@ CURVEFS_ERROR FuseClient::MakeNode(fuse_req_t req, fuse_ino_t parent,
}
}
InodeAttr attr;
inodeWrapper->GetInodeAttr(&attr);
GetDentryParamFromInodeAttr(option_, attr, e);
return ret;
}
CURVEFS_ERROR FuseClient::FuseOpMkDir(fuse_req_t req, fuse_ino_t parent,
const char *name, mode_t mode,
fuse_entry_param *e) {
CURVEFS_ERROR FuseClient::FuseOpMkDir(fuse_req_t req,
fuse_ino_t parent,
const char *name,
mode_t mode,
EntryOut* entryOut) {
VLOG(1) << "FuseOpMkDir, parent: " << parent << ", name: " << name
<< ", mode: " << mode;
bool internal = false;
return MakeNode(req, parent, name, S_IFDIR | mode,
FsFileType::TYPE_DIRECTORY, 0, internal, e);
std::shared_ptr<InodeWrapper> inode;
CURVEFS_ERROR rc = MakeNode(req, parent, name, S_IFDIR | mode,
FsFileType::TYPE_DIRECTORY, 0, internal, inode);
if (rc != CURVEFS_ERROR::OK) {
return rc;
}
inode->GetInodeAttr(&entryOut->attr);
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR FuseClient::FuseOpRmDir(fuse_req_t req, fuse_ino_t parent,
@ -526,7 +546,7 @@ CURVEFS_ERROR FuseClient::DeleteNode(uint64_t ino, fuse_ino_t parent,
<< ", parent = " << parent << ", name = " << name;
}
if (enableSumInDir_) {
if (enableSumInDir_.load()) {
// update parent summary info
XAttr xattr;
xattr.mutable_xattrinfos()->insert({XATTRENTRIES, "1"});
@ -544,8 +564,6 @@ CURVEFS_ERROR FuseClient::DeleteNode(uint64_t ino, fuse_ino_t parent,
<< ", xattr = " << xattr.DebugString();
}
}
inodeManager_->ClearInodeCache(ino);
return ret;
}
@ -558,10 +576,13 @@ std::string GetRecycleTimeDirName() {
return now;
}
CURVEFS_ERROR FuseClient::CreateManageNode(fuse_req_t req, uint64_t parent,
const char *name, mode_t mode, ManageInodeType manageType,
fuse_entry_param *e) {
if (strlen(name) > option_.maxNameLength) {
CURVEFS_ERROR FuseClient::CreateManageNode(fuse_req_t req,
uint64_t parent,
const char* name,
mode_t mode,
ManageInodeType manageType,
EntryOut* entryOut) {
if (strlen(name) > option_.fileSystemOption.maxNameLength) {
return CURVEFS_ERROR::NAMETOOLONG;
}
@ -626,7 +647,7 @@ CURVEFS_ERROR FuseClient::CreateManageNode(fuse_req_t req, uint64_t parent,
<< ", parent = " << parent << ", name = " << name
<< ", mode = " << mode;
if (enableSumInDir_) {
if (enableSumInDir_.load()) {
// update parent summary info
XAttr xattr;
xattr.mutable_xattrinfos()->insert({XATTRENTRIES, "1"});
@ -645,9 +666,7 @@ CURVEFS_ERROR FuseClient::CreateManageNode(fuse_req_t req, uint64_t parent,
}
}
InodeAttr attr;
inodeWrapper->GetInodeAttrLocked(&attr);
GetDentryParamFromInodeAttr(option_, attr, e);
inodeWrapper->GetInodeAttrLocked(&entryOut->attr);
return ret;
}
@ -661,9 +680,10 @@ CURVEFS_ERROR FuseClient::GetOrCreateRecycleDir(fuse_req_t req, Dentry *out) {
} else if (ret == CURVEFS_ERROR::NOTEXIST) {
LOG(INFO) << "recycle dir is not exist, create " << RECYCLENAME
<< ", parentid = " << ROOTINODEID;
fuse_entry_param param;
EntryOut entryOut;
ret = CreateManageNode(req, ROOTINODEID, RECYCLENAME,
S_IFDIR | 0755, ManageInodeType::TYPE_RECYCLE, &param);
S_IFDIR | 0755, ManageInodeType::TYPE_RECYCLE,
&entryOut);
if (ret != CURVEFS_ERROR::OK) {
LOG(ERROR) << "CreateManageNode failed, ret = " << ret
<< ", inode = " << ROOTINODEID
@ -700,17 +720,17 @@ CURVEFS_ERROR FuseClient::MoveToRecycle(fuse_req_t req, fuse_ino_t ino,
<< ", name = " << recycleTimeDirName;
return ret;
} else if (ret == CURVEFS_ERROR::NOTEXIST) {
fuse_entry_param param;
std::shared_ptr<InodeWrapper> inode;
bool internal = true;
ret = MakeNode(req, RECYCLEINODEID, recycleTimeDirName.c_str(),
S_IFDIR | 0755, FsFileType::TYPE_DIRECTORY, 0, internal, &param);
S_IFDIR | 0755, FsFileType::TYPE_DIRECTORY, 0, internal, inode);
if (ret != CURVEFS_ERROR::OK) {
LOG(ERROR) << "MakeNode failed, ret = " << ret
<< ", inode = " << RECYCLEINODEID
<< ", name = " << recycleTimeDirName;
return ret;
}
recycleTimeDirIno = param.ino;
recycleTimeDirIno = inode->GetInodeId();
} else {
recycleTimeDirIno = dentry.inodeid();
}
@ -720,7 +740,7 @@ CURVEFS_ERROR FuseClient::MoveToRecycle(fuse_req_t req, fuse_ino_t ino,
// 4. move inode to recycle time dir
ret = FuseOpRename(req, parent, name,
recycleTimeDirIno, newName.c_str());
recycleTimeDirIno, newName.c_str(), 0);
if (ret != CURVEFS_ERROR::OK) {
LOG(ERROR) << "MoveToRecycle failed, ret = " << ret
<< ", inodeid = " << ino
@ -757,7 +777,7 @@ bool FuseClient::ShouldMoveToRecycle(fuse_ino_t parent) {
CURVEFS_ERROR FuseClient::RemoveNode(fuse_req_t req, fuse_ino_t parent,
const char *name, FsFileType type) {
if (strlen(name) > option_.maxNameLength) {
if (strlen(name) > option_.fileSystemOption.maxNameLength) {
return CURVEFS_ERROR::NAMETOOLONG;
}
@ -813,146 +833,87 @@ CURVEFS_ERROR FuseClient::RemoveNode(fuse_req_t req, fuse_ino_t parent,
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR FuseClient::FuseOpOpenDir(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi) {
(void)req;
VLOG(1) << "FuseOpOpenDir ino = " << ino;
std::shared_ptr<InodeWrapper> inodeWrapper;
CURVEFS_ERROR ret = inodeManager_->GetInode(ino, inodeWrapper);
if (ret != CURVEFS_ERROR::OK) {
LOG(ERROR) << "inodeManager get inode fail, ret = " << ret
<< ", inodeid = " << ino;
return ret;
CURVEFS_ERROR FuseClient::FuseOpOpenDir(fuse_req_t req,
fuse_ino_t ino,
struct fuse_file_info* fi) {
CURVEFS_ERROR rc = fs_->OpenDir(req, ino, fi);
if (rc != CURVEFS_ERROR::OK) {
LOG(ERROR) << "opendir() failed, retCode = " << rc
<< ", ino = " << ino;
}
::curve::common::UniqueLock lgGuard = inodeWrapper->GetUniqueLock();
uint64_t dindex = dirBuf_->DirBufferNew();
fi->fh = dindex;
VLOG(1) << "FuseOpOpenDir, ino: " << ino << ", dindex: " << dindex;
return ret;
return rc;
}
CURVEFS_ERROR FuseClient::FuseOpReleaseDir(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi) {
(void)req;
uint64_t dindex = fi->fh;
VLOG(1) << "FuseOpReleaseDir, ino: " << ino << ", dindex: " << dindex;
dirBuf_->DirBufferRelease(dindex);
CURVEFS_ERROR FuseClient::FuseOpReadDir(fuse_req_t req,
fuse_ino_t ino,
size_t size,
off_t off,
struct fuse_file_info *fi,
char** bufferOut,
size_t* rSize,
bool plus) {
auto handler = fs_->FindHandler(fi->fh);
DirBufferHead* buffer = handler->buffer;
if (!handler->padding) {
auto entries = std::make_shared<DirEntryList>();
CURVEFS_ERROR rc = fs_->ReadDir(req, ino, fi, &entries);
if (rc != CURVEFS_ERROR::OK) {
LOG(ERROR) << "readdir() failed, retCode = " << rc
<< ", ino = " << ino << ", fh = " << fi->fh;
return rc;
}
// release inodeAttr cache
inodeManager_->ReleaseCache(ino);
entries->Iterate([&](DirEntry* dirEntry){
if (plus) {
fs_->AddDirEntryPlus(req, buffer, dirEntry);
} else {
fs_->AddDirEntry(req, buffer, dirEntry);
}
});
handler->padding = true;
}
if (off < buffer->size) {
*bufferOut = buffer->p + off;
*rSize = std::min(buffer->size - off, size);
} else {
*bufferOut = nullptr;
*rSize = 0;
}
return CURVEFS_ERROR::OK;
}
static void dirbuf_add(fuse_req_t req, struct DirBufferHead *b,
const Dentry &dentry,
const FuseClientOption &option,
bool cacheDir,
InodeAttr *attr = nullptr) {
struct stat stbuf;
struct fuse_entry_param param;
size_t oldsize = b->size;
if (!cacheDir) {
b->size += fuse_add_direntry(req, NULL, 0, dentry.name().c_str(),
NULL, 0);
b->p = static_cast<char *>(realloc(b->p, b->size));
memset(&stbuf, 0, sizeof(stbuf));
stbuf.st_ino = dentry.inodeid();
fuse_add_direntry(req, b->p + oldsize, b->size - oldsize,
dentry.name().c_str(), &stbuf, b->size);
} else {
b->size += fuse_add_direntry_plus(req, NULL, 0, dentry.name().c_str(),
NULL, 0);
b->p = static_cast<char *>(realloc(b->p, b->size));
GetDentryParamFromInodeAttr(option, *attr, &param);
fuse_add_direntry_plus(req, b->p + oldsize, b->size - oldsize,
dentry.name().c_str(), &param, b->size);
CURVEFS_ERROR FuseClient::FuseOpReleaseDir(fuse_req_t req,
fuse_ino_t ino,
struct fuse_file_info* fi) {
CURVEFS_ERROR rc = fs_->ReleaseDir(req, ino, fi);
if (rc != CURVEFS_ERROR::OK) {
LOG(ERROR) << "releasedir() failed, retCode = " << rc
<< ", ino = " << ino;
}
}
CURVEFS_ERROR FuseClient::FuseOpReadDirPlus(fuse_req_t req, fuse_ino_t ino,
size_t size, off_t off,
struct fuse_file_info *fi,
char **buffer, size_t *rSize,
bool cacheDir) {
VLOG(1) << "FuseOpReadDirPlus ino: " << ino << ", size: " << size
<< ", off = " << off << ", cacheDir = " << cacheDir;
std::shared_ptr<InodeWrapper> inodeWrapper;
CURVEFS_ERROR ret = inodeManager_->GetInode(ino, inodeWrapper);
if (ret != CURVEFS_ERROR::OK) {
LOG(ERROR) << "inodeManager get inode fail, ret = " << ret
<< ", inodeid = " << ino;
return ret;
}
uint64_t dindex = fi->fh;
DirBufferHead *bufHead = dirBuf_->DirBufferGet(dindex);
if (!bufHead->wasRead) {
std::list<Dentry> dentryList;
std::set<uint64_t> inodeIds;
std::map<uint64_t, InodeAttr> inodeAttrMap;
auto limit = option_.listDentryLimit;
ret = dentryManager_->ListDentry(ino, &dentryList, limit);
if (ret != CURVEFS_ERROR::OK) {
LOG(ERROR) << "dentryManager_ ListDentry fail, ret = " << ret
<< ", parent = " << ino;
return ret;
}
if (!cacheDir) {
for (const auto &dentry : dentryList) {
dirbuf_add(req, bufHead, dentry, option_, cacheDir);
}
} else {
for (const auto &dentry : dentryList) {
inodeIds.emplace(dentry.inodeid());
}
VLOG(3) << "batch get inode size = " << inodeIds.size();
ret = inodeManager_->BatchGetInodeAttrAsync(ino, &inodeIds,
&inodeAttrMap);
if (ret != CURVEFS_ERROR::OK) {
LOG(ERROR) << "BatchGetInodeAttr failed when FuseOpReadDir"
<< ", parentId = " << ino;
return ret;
}
for (const auto &dentry : dentryList) {
auto iter = inodeAttrMap.find(dentry.inodeid());
if (iter != inodeAttrMap.end()) {
dirbuf_add(req, bufHead, dentry, option_,
cacheDir, &iter->second);
} else {
LOG(WARNING) << "BatchGetInodeAttr missing some inodes,"
<< " inodeId = " << dentry.inodeid();
}
}
}
bufHead->wasRead = true;
}
if (off < static_cast<ssize_t>(bufHead->size)) {
*buffer = bufHead->p + off;
*rSize = std::min(bufHead->size - off, size);
} else {
*buffer = nullptr;
*rSize = 0;
}
return ret;
return rc;
}
CURVEFS_ERROR FuseClient::FuseOpRename(fuse_req_t req, fuse_ino_t parent,
const char *name, fuse_ino_t newparent,
const char *newname) {
(void)req;
const char *newname,
unsigned int flags) {
VLOG(1) << "FuseOpRename from (" << parent << ", " << name << ") to ("
<< newparent << ", " << newname << ")";
if (strlen(name) > option_.maxNameLength ||
strlen(newname) > option_.maxNameLength) {
// TODO(Wine93): the flag RENAME_EXCHANGE and RENAME_NOREPLACE
// is only used in linux interface renameat(), not required by posix,
// we can ignore it now
if (flags != 0) {
return CURVEFS_ERROR::INVALIDPARAM;
}
uint64_t maxNameLength = option_.fileSystemOption.maxNameLength;
if (strlen(name) > maxNameLength || strlen(newname) > maxNameLength) {
LOG(WARNING) << "FuseOpRename name too long, name = " << name
<< ", name len = " << strlen(name) << ", new name = "
<< newname << ", new name len = " << strlen(newname)
<< ", maxNameLength = " << option_.maxNameLength;
<< ", maxNameLength = " << maxNameLength;
return CURVEFS_ERROR::NAMETOOLONG;
}
@ -983,7 +944,7 @@ CURVEFS_ERROR FuseClient::FuseOpRename(fuse_req_t req, fuse_ino_t parent,
renameOp.UpdateInodeCtime();
renameOp.UpdateCache();
if (enableSumInDir_) {
if (enableSumInDir_.load()) {
xattrManager_->UpdateParentXattrAfterRename(
parent, newparent, newname, &renameOp);
}
@ -991,30 +952,24 @@ CURVEFS_ERROR FuseClient::FuseOpRename(fuse_req_t req, fuse_ino_t parent,
return rc;
}
CURVEFS_ERROR FuseClient::FuseOpGetAttr(fuse_req_t req, fuse_ino_t ino,
CURVEFS_ERROR FuseClient::FuseOpGetAttr(fuse_req_t req,
fuse_ino_t ino,
struct fuse_file_info *fi,
struct stat *attr) {
(void)req;
(void)fi;
VLOG(1) << "FuseOpGetAttr ino = " << ino;
InodeAttr inodeAttr;
CURVEFS_ERROR ret =
inodeManager_->GetInodeAttr(ino, &inodeAttr);
if (ret != CURVEFS_ERROR::OK) {
LOG(ERROR) << "inodeManager get inodeAttr fail, ret = " << ret
<< ", inodeid = " << ino;
return ret;
AttrOut* attrOut) {
CURVEFS_ERROR rc = fs_->GetAttr(req, ino, attrOut);
if (rc != CURVEFS_ERROR::OK) {
LOG(ERROR) << "getattr() fail, retCode = " << rc
<< ", ino = " << ino;
}
InodeAttr2ParamAttr(inodeAttr, attr);
return ret;
return rc;
}
CURVEFS_ERROR FuseClient::FuseOpSetAttr(fuse_req_t req, fuse_ino_t ino,
struct stat *attr, int to_set,
struct fuse_file_info *fi,
struct stat *attrOut) {
(void)req;
(void)fi;
CURVEFS_ERROR FuseClient::FuseOpSetAttr(fuse_req_t req,
fuse_ino_t ino,
struct stat* attr,
int to_set,
struct fuse_file_info* fi,
struct AttrOut* attrOut) {
VLOG(1) << "FuseOpSetAttr to_set: " << to_set << ", ino: " << ino
<< ", attr: " << *attr;
std::shared_ptr<InodeWrapper> inodeWrapper;
@ -1071,11 +1026,9 @@ CURVEFS_ERROR FuseClient::FuseOpSetAttr(fuse_req_t req, fuse_ino_t ino,
if (ret != CURVEFS_ERROR::OK) {
return ret;
}
InodeAttr inodeAttr;
inodeWrapper->GetInodeAttrLocked(&inodeAttr);
InodeAttr2ParamAttr(inodeAttr, attrOut);
inodeWrapper->GetInodeAttrLocked(&attrOut->attr);
if (enableSumInDir_ && changeSize != 0) {
if (enableSumInDir_.load() && changeSize != 0) {
// update parent summary info
const Inode* inode = inodeWrapper->GetInodeLocked();
XAttr xattr;
@ -1098,9 +1051,7 @@ CURVEFS_ERROR FuseClient::FuseOpSetAttr(fuse_req_t req, fuse_ino_t ino,
if (ret != CURVEFS_ERROR::OK) {
return ret;
}
InodeAttr inodeAttr;
inodeWrapper->GetInodeAttrLocked(&inodeAttr);
InodeAttr2ParamAttr(inodeAttr, attrOut);
inodeWrapper->GetInodeAttrLocked(&attrOut->attr);
return ret;
}
@ -1110,8 +1061,8 @@ CURVEFS_ERROR FuseClient::FuseOpGetXattr(fuse_req_t req, fuse_ino_t ino,
(void)req;
VLOG(9) << "FuseOpGetXattr, ino: " << ino
<< ", name: " << name << ", size = " << size;
if (option_.disableXattr) {
return CURVEFS_ERROR::NOTSUPPORT;
if (option_.fileSystemOption.disableXattr) {
return CURVEFS_ERROR::NOSYS;
}
InodeAttr inodeAttr;
@ -1122,7 +1073,8 @@ CURVEFS_ERROR FuseClient::FuseOpGetXattr(fuse_req_t req, fuse_ino_t ino,
return ret;
}
ret = xattrManager_->GetXattr(name, value, &inodeAttr, enableSumInDir_);
ret = xattrManager_->GetXattr(name, value,
&inodeAttr, enableSumInDir_.load());
if (CURVEFS_ERROR::OK != ret) {
LOG(ERROR) << "xattrManager get xattr failed, name = " << name;
return ret;
@ -1147,12 +1099,6 @@ CURVEFS_ERROR FuseClient::FuseOpGetXattr(fuse_req_t req, fuse_ino_t ino,
CURVEFS_ERROR FuseClient::FuseOpSetXattr(fuse_req_t req, fuse_ino_t ino,
const char* name, const char* value,
size_t size, int flags) {
(void)req;
(void)flags;
if (option_.disableXattr) {
return CURVEFS_ERROR::NOTSUPPORT;
}
std::string strname(name);
std::string strvalue(value, size);
VLOG(1) << "FuseOpSetXattr ino: " << ino << ", name: " << name
@ -1235,10 +1181,12 @@ CURVEFS_ERROR FuseClient::FuseOpListXattr(fuse_req_t req, fuse_ino_t ino,
return CURVEFS_ERROR::OUT_OF_RANGE;
}
CURVEFS_ERROR FuseClient::FuseOpSymlink(fuse_req_t req, const char *link,
fuse_ino_t parent, const char *name,
fuse_entry_param *e) {
if (strlen(name) > option_.maxNameLength) {
CURVEFS_ERROR FuseClient::FuseOpSymlink(fuse_req_t req,
const char* link,
fuse_ino_t parent,
const char* name,
EntryOut* entryOut) {
if (strlen(name) > option_.fileSystemOption.maxNameLength) {
return CURVEFS_ERROR::NAMETOOLONG;
}
const struct fuse_ctx *ctx = fuse_req_ctx(req);
@ -1292,7 +1240,7 @@ CURVEFS_ERROR FuseClient::FuseOpSymlink(fuse_req_t req, const char *link,
return ret;
}
if (enableSumInDir_) {
if (enableSumInDir_.load()) {
// update parent summary info
XAttr xattr;
xattr.mutable_xattrinfos()->insert({XATTRENTRIES, "1"});
@ -1307,18 +1255,17 @@ CURVEFS_ERROR FuseClient::FuseOpSymlink(fuse_req_t req, const char *link,
}
}
InodeAttr attr;
inodeWrapper->GetInodeAttr(&attr);
GetDentryParamFromInodeAttr(option_, attr, e);
inodeWrapper->GetInodeAttr(&entryOut->attr);
return ret;
}
CURVEFS_ERROR FuseClient::FuseOpLink(fuse_req_t req, fuse_ino_t ino,
fuse_ino_t newparent, const char *newname,
CURVEFS_ERROR FuseClient::FuseOpLink(fuse_req_t req,
fuse_ino_t ino,
fuse_ino_t newparent,
const char* newname,
FsFileType type,
fuse_entry_param *e) {
(void)req;
if (strlen(newname) > option_.maxNameLength) {
EntryOut* entryOut) {
if (strlen(newname) > option_.fileSystemOption.maxNameLength) {
return CURVEFS_ERROR::NAMETOOLONG;
}
std::shared_ptr<InodeWrapper> inodeWrapper;
@ -1363,7 +1310,7 @@ CURVEFS_ERROR FuseClient::FuseOpLink(fuse_req_t req, fuse_ino_t ino,
return ret;
}
if (enableSumInDir_) {
if (enableSumInDir_.load()) {
// update parent summary info
XAttr xattr;
xattr.mutable_xattrinfos()->insert({XATTRENTRIES, "1"});
@ -1379,9 +1326,7 @@ CURVEFS_ERROR FuseClient::FuseOpLink(fuse_req_t req, fuse_ino_t ino,
}
}
InodeAttr attr;
inodeWrapper->GetInodeAttr(&attr);
GetDentryParamFromInodeAttr(option_, attr, e);
inodeWrapper->GetInodeAttr(&entryOut->attr);
return ret;
}
@ -1400,24 +1345,18 @@ CURVEFS_ERROR FuseClient::FuseOpReadLink(fuse_req_t req, fuse_ino_t ino,
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR FuseClient::FuseOpRelease(fuse_req_t req, fuse_ino_t ino,
CURVEFS_ERROR FuseClient::FuseOpRelease(fuse_req_t req,
fuse_ino_t ino,
struct fuse_file_info *fi) {
(void)req;
(void)fi;
VLOG(1) << "FuseOpRelease, ino: " << ino;
if (FLAGS_enableCto) {
inodeManager_->RemoveOpenedInode(ino);
CURVEFS_ERROR rc = fs_->Release(req, ino);
if (rc != CURVEFS_ERROR::OK) {
LOG(ERROR) << "release() failed, ino = " << ino;
}
return CURVEFS_ERROR::OK;
return rc;
}
void FuseClient::FlushInode() { inodeManager_->FlushInodeOnce(); }
void FuseClient::FlushInodeAll() { inodeManager_->FlushAll(); }
void FuseClient::FlushAll() {
FlushData();
FlushInodeAll();
}
CURVEFS_ERROR
@ -1446,14 +1385,15 @@ FuseClient::SetMountStatus(const struct MountOption *mountOption) {
}
inodeManager_->SetFsId(fsInfo_->fsid());
dentryManager_->SetFsId(fsInfo_->fsid());
enableSumInDir_ = fsInfo_->enablesumindir() && !FLAGS_enableCto;
enableSumInDir_.store(fsInfo_->enablesumindir());
if (fsInfo_->has_recycletimehour()) {
enableSumInDir_ = enableSumInDir_ && (fsInfo_->recycletimehour() == 0);
enableSumInDir_.store(enableSumInDir_.load() &&
(fsInfo_->recycletimehour() == 0));
}
LOG(INFO) << "Mount " << fsName << " on " << mountpoint_.ShortDebugString()
<< " success!"
<< " enableSumInDir = " << enableSumInDir_;
<< " enableSumInDir = " << enableSumInDir_.load();
fsMetric_ = std::make_shared<FSMetric>(fsName);
@ -1471,5 +1411,32 @@ FuseClient::SetMountStatus(const struct MountOption *mountOption) {
return CURVEFS_ERROR::OK;
}
void FuseClient::InitQosParam() {
ReadWriteThrottleParams params;
params.iopsWrite = ThrottleParams(FLAGS_fuseClientAvgWriteIops,
FLAGS_fuseClientBurstWriteIops,
FLAGS_fuseClientBurstWriteIopsSecs);
params.bpsWrite = ThrottleParams(FLAGS_fuseClientAvgWriteBytes,
FLAGS_fuseClientBurstWriteBytes,
FLAGS_fuseClientBurstWriteBytesSecs);
params.iopsRead = ThrottleParams(FLAGS_fuseClientAvgReadIops,
FLAGS_fuseClientBurstReadIops,
FLAGS_fuseClientBurstReadIopsSecs);
params.bpsRead = ThrottleParams(FLAGS_fuseClientAvgReadBytes,
FLAGS_fuseClientBurstReadBytes,
FLAGS_fuseClientBurstReadBytesSecs);
throttle_.UpdateThrottleParams(params);
int ret = bthread_timer_add(&throttleTimer_, butil::seconds_from_now(1),
on_throttle_timer, this);
if (ret != 0) {
LOG(ERROR) << "Create fuse client throttle timer failed!";
}
}
} // namespace client
} // namespace curvefs

View File

@ -25,6 +25,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <bthread/unstable.h>
#include <map>
#include <memory>
@ -32,6 +33,7 @@
#include <list>
#include <utility>
#include <vector>
#include <atomic>
#include "curvefs/proto/common.pb.h"
#include "curvefs/proto/mds.pb.h"
@ -53,6 +55,9 @@
#include "curvefs/src/client/lease/lease_excutor.h"
#include "curvefs/src/client/xattr_manager.h"
#include "curvefs/src/client/warmup/warmup_manager.h"
#include "src/common/throttle.h"
#include "curvefs/src/client/filesystem/meta.h"
#include "curvefs/src/client/filesystem/filesystem.h"
#define DirectIOAlignment 512
@ -67,6 +72,7 @@ using ::curvefs::client::metric::FSMetric;
namespace curvefs {
namespace client {
namespace warmup {
class WarmupManager;
}
@ -77,6 +83,10 @@ using rpcclient::MdsClient;
using rpcclient::MdsClientImpl;
using rpcclient::MetaServerClient;
using rpcclient::MetaServerClientImpl;
using ::curvefs::client::filesystem::FileSystem;
using ::curvefs::client::filesystem::EntryOut;
using ::curvefs::client::filesystem::AttrOut;
using ::curvefs::client::filesystem::FileOut;
using curvefs::common::is_aligned;
@ -91,7 +101,6 @@ class FuseClient {
metaClient_(std::make_shared<MetaServerClientImpl>()),
inodeManager_(std::make_shared<InodeCacheManagerImpl>(metaClient_)),
dentryManager_(std::make_shared<DentryCacheManagerImpl>(metaClient_)),
dirBuf_(std::make_shared<DirBuffer>()),
fsInfo_(nullptr),
init_(false),
enableSumInDir_(false),
@ -110,7 +119,6 @@ class FuseClient {
metaClient_(metaClient),
inodeManager_(inodeManager),
dentryManager_(dentryManager),
dirBuf_(std::make_shared<DirBuffer>()),
fsInfo_(nullptr),
init_(false),
enableSumInDir_(false),
@ -134,31 +142,42 @@ class FuseClient {
virtual CURVEFS_ERROR FuseOpWrite(fuse_req_t req, fuse_ino_t ino,
const char* buf, size_t size, off_t off,
struct fuse_file_info* fi,
size_t* wSize) = 0;
FileOut* fileOut) = 0;
virtual CURVEFS_ERROR FuseOpRead(fuse_req_t req, fuse_ino_t ino,
size_t size, off_t off,
struct fuse_file_info* fi, char* buffer,
size_t* rSize) = 0;
virtual CURVEFS_ERROR FuseOpLookup(fuse_req_t req, fuse_ino_t parent,
const char* name, fuse_entry_param* e);
virtual CURVEFS_ERROR FuseOpLookup(fuse_req_t req,
fuse_ino_t parent,
const char* name,
EntryOut* entryOut);
virtual CURVEFS_ERROR FuseOpOpen(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info* fi);
virtual CURVEFS_ERROR FuseOpOpen(fuse_req_t req,
fuse_ino_t ino,
struct fuse_file_info* fi,
FileOut* fileOut);
virtual CURVEFS_ERROR FuseOpCreate(fuse_req_t req, fuse_ino_t parent,
const char* name, mode_t mode,
virtual CURVEFS_ERROR FuseOpCreate(fuse_req_t req,
fuse_ino_t parent,
const char* name,
mode_t mode,
struct fuse_file_info* fi,
fuse_entry_param* e) = 0;
EntryOut* entryOut) = 0;
virtual CURVEFS_ERROR FuseOpMkNod(fuse_req_t req, fuse_ino_t parent,
const char* name, mode_t mode, dev_t rdev,
fuse_entry_param* e) = 0;
virtual CURVEFS_ERROR FuseOpMkNod(fuse_req_t req,
fuse_ino_t parent,
const char* name,
mode_t mode,
dev_t rdev,
EntryOut* entryOut) = 0;
virtual CURVEFS_ERROR FuseOpMkDir(fuse_req_t req, fuse_ino_t parent,
const char* name, mode_t mode,
fuse_entry_param* e);
virtual CURVEFS_ERROR FuseOpMkDir(fuse_req_t req,
fuse_ino_t parent,
const char* name,
mode_t mode,
EntryOut* entryOut);
virtual CURVEFS_ERROR FuseOpUnlink(fuse_req_t req, fuse_ino_t parent,
const char* name) = 0;
@ -166,30 +185,38 @@ class FuseClient {
virtual CURVEFS_ERROR FuseOpRmDir(fuse_req_t req, fuse_ino_t parent,
const char* name);
virtual CURVEFS_ERROR FuseOpOpenDir(fuse_req_t req, fuse_ino_t ino,
virtual CURVEFS_ERROR FuseOpOpenDir(fuse_req_t req,
fuse_ino_t ino,
struct fuse_file_info* fi);
virtual CURVEFS_ERROR FuseOpReleaseDir(fuse_req_t req, fuse_ino_t ino,
virtual CURVEFS_ERROR FuseOpReleaseDir(fuse_req_t req,
fuse_ino_t ino,
struct fuse_file_info* fi);
virtual CURVEFS_ERROR FuseOpReadDirPlus(fuse_req_t req, fuse_ino_t ino,
size_t size, off_t off,
struct fuse_file_info* fi,
char** buffer, size_t* rSize,
bool cacheDir);
virtual CURVEFS_ERROR FuseOpReadDir(fuse_req_t req,
fuse_ino_t ino,
size_t size,
off_t off,
struct fuse_file_info* fi,
char** bufferOut,
size_t* rSize,
bool plus);
virtual CURVEFS_ERROR FuseOpRename(fuse_req_t req, fuse_ino_t parent,
const char* name, fuse_ino_t newparent,
const char* newname);
virtual CURVEFS_ERROR FuseOpRename(fuse_req_t req,
fuse_ino_t parent,
const char* name,
fuse_ino_t newparent,
const char* newname,
unsigned int flags);
virtual CURVEFS_ERROR FuseOpGetAttr(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info* fi,
struct stat* attr);
struct AttrOut* out);
virtual CURVEFS_ERROR FuseOpSetAttr(fuse_req_t req, fuse_ino_t ino,
struct stat* attr, int to_set,
struct fuse_file_info* fi,
struct stat* attrOut);
struct AttrOut* out);
virtual CURVEFS_ERROR FuseOpGetXattr(fuse_req_t req, fuse_ino_t ino,
const char* name, std::string* value,
@ -202,13 +229,17 @@ class FuseClient {
virtual CURVEFS_ERROR FuseOpListXattr(fuse_req_t req, fuse_ino_t ino,
char *value, size_t size, size_t *realSize);
virtual CURVEFS_ERROR FuseOpSymlink(fuse_req_t req, const char* link,
fuse_ino_t parent, const char* name,
fuse_entry_param* e);
virtual CURVEFS_ERROR FuseOpSymlink(fuse_req_t req,
const char* link,
fuse_ino_t parent,
const char* name,
EntryOut* entryOut);
virtual CURVEFS_ERROR FuseOpLink(fuse_req_t req, fuse_ino_t ino,
fuse_ino_t newparent, const char* newname,
fuse_entry_param* e) = 0;
virtual CURVEFS_ERROR FuseOpLink(fuse_req_t req,
fuse_ino_t ino,
fuse_ino_t newparent,
const char* newname,
EntryOut* entryOut) = 0;
virtual CURVEFS_ERROR FuseOpReadLink(fuse_req_t req, fuse_ino_t ino,
std::string* linkStr);
@ -242,10 +273,12 @@ class FuseClient {
stbuf->f_fsid = fsInfo_->fsid();
stbuf->f_flag = 0;
stbuf->f_namemax = option_.maxNameLength;
stbuf->f_namemax = option_.fileSystemOption.maxNameLength;
return CURVEFS_ERROR::OK;
}
virtual CURVEFS_ERROR Truncate(InodeWrapper* inode, uint64_t length) = 0;
void SetFsInfo(const std::shared_ptr<FsInfo>& fsInfo) {
fsInfo_ = fsInfo;
init_ = true;
@ -261,9 +294,9 @@ class FuseClient {
return fsInfo_;
}
virtual void FlushInode();
virtual void FlushInodeAll();
std::shared_ptr<FileSystem> GetFileSystem() {
return fs_;
}
virtual void FlushAll();
@ -296,18 +329,29 @@ class FuseClient {
CURVEFS_ERROR SetMountStatus(const struct MountOption *mountOption);
void Add(bool isRead, size_t size) { throttle_.Add(isRead, size); }
void InitQosParam();
protected:
CURVEFS_ERROR MakeNode(fuse_req_t req, fuse_ino_t parent, const char* name,
mode_t mode, FsFileType type, dev_t rdev,
bool internal, fuse_entry_param* e);
CURVEFS_ERROR MakeNode(fuse_req_t req,
fuse_ino_t parent,
const char* name,
mode_t mode,
FsFileType type,
dev_t rdev,
bool internal,
std::shared_ptr<InodeWrapper>& InodeWrapper); // NOLINT
CURVEFS_ERROR RemoveNode(fuse_req_t req, fuse_ino_t parent,
const char* name, FsFileType type);
CURVEFS_ERROR CreateManageNode(fuse_req_t req, uint64_t parent,
const char *name, mode_t mode,
CURVEFS_ERROR CreateManageNode(fuse_req_t req,
uint64_t parent,
const char* name,
mode_t mode,
ManageInodeType manageType,
fuse_entry_param *e);
EntryOut* entryOut);
CURVEFS_ERROR GetOrCreateRecycleDir(fuse_req_t req, Dentry *out);
@ -320,10 +364,17 @@ class FuseClient {
bool ShouldMoveToRecycle(fuse_ino_t parent);
CURVEFS_ERROR FuseOpLink(fuse_req_t req, fuse_ino_t ino,
fuse_ino_t newparent, const char* newname,
CURVEFS_ERROR FuseOpLink(fuse_req_t req,
fuse_ino_t ino,
fuse_ino_t newparent,
const char* newname,
FsFileType type,
fuse_entry_param* e);
EntryOut* entryOut);
CURVEFS_ERROR HandleOpenFlags(fuse_req_t req,
fuse_ino_t ino,
struct fuse_file_info* fi,
FileOut* fileOut);
int SetHostPortInMountPoint(Mountpoint* out) {
char hostname[kMaxHostNameLength];
@ -338,9 +389,8 @@ class FuseClient {
return 0;
}
private:
virtual CURVEFS_ERROR Truncate(InodeWrapper* inode, uint64_t length) = 0;
private:
virtual void FlushData() = 0;
CURVEFS_ERROR UpdateParentMCTimeAndNlink(
@ -351,8 +401,8 @@ class FuseClient {
std::string newName(name);
newName = std::to_string(parent) + "_" + std::to_string(ino)
+ "_" + newName;
if (newName.length() > option_.maxNameLength) {
newName = newName.substr(0, option_.maxNameLength);
if (newName.length() > option_.fileSystemOption.maxNameLength) {
newName = newName.substr(0, option_.fileSystemOption.maxNameLength);
}
return newName;
@ -376,9 +426,6 @@ class FuseClient {
std::shared_ptr<LeaseExecutor> leaseExecutor_;
// dir buffer
std::shared_ptr<DirBuffer> dirBuf_;
// filesystem info
std::shared_ptr<FsInfo> fsInfo_;
@ -388,7 +435,7 @@ class FuseClient {
bool init_;
// enable record summary info in dir inode xattr
bool enableSumInDir_;
std::atomic<bool> enableSumInDir_;
std::shared_ptr<FSMetric> fsMetric_;
@ -397,12 +444,18 @@ class FuseClient {
// warmup manager
std::shared_ptr<warmup::WarmupManager> warmupManager_;
std::shared_ptr<FileSystem> fs_;
private:
MDSBaseClient* mdsBase_;
Atomic<bool> isStop_;
curve::common::Mutex renameMutex_;
Throttle throttle_;
bthread_timer_t throttleTimer_;
};
} // namespace client

View File

@ -67,12 +67,20 @@ CURVEFS_ERROR FuseS3Client::Init(const FuseClientOption &option) {
auto s3Client = std::make_shared<S3ClientImpl>();
s3Client->Init(opt.s3Opt.s3AdaptrOpt);
const uint64_t writeCacheMaxByte =
opt.s3Opt.s3ClientAdaptorOpt.writeCacheMaxByte;
if (writeCacheMaxByte < MIN_WRITE_CACHE_SIZE) {
LOG(ERROR) << "writeCacheMaxByte is too small"
<< ", at least " << MIN_WRITE_CACHE_SIZE << " (8MB)"
", writeCacheMaxByte = " << writeCacheMaxByte;
return CURVEFS_ERROR::CACHETOOSMALL;
}
auto fsCacheManager = std::make_shared<FsCacheManager>(
dynamic_cast<S3ClientAdaptorImpl *>(s3Adaptor_.get()),
opt.s3Opt.s3ClientAdaptorOpt.readCacheMaxByte,
opt.s3Opt.s3ClientAdaptorOpt.writeCacheMaxByte,
opt.s3Opt.s3ClientAdaptorOpt.readCacheThreads,
kvClientManager_);
opt.s3Opt.s3ClientAdaptorOpt.readCacheMaxByte, writeCacheMaxByte,
opt.s3Opt.s3ClientAdaptorOpt.readCacheThreads, kvClientManager_);
if (opt.s3Opt.s3ClientAdaptorOpt.diskCacheOpt.diskCacheType !=
DiskCacheType::Disable) {
auto s3DiskCacheClient = std::make_shared<S3ClientImpl>();
@ -147,8 +155,8 @@ CURVEFS_ERROR FuseS3Client::FuseOpInit(void *userdata,
CURVEFS_ERROR FuseS3Client::FuseOpWrite(fuse_req_t req, fuse_ino_t ino,
const char *buf, size_t size, off_t off,
struct fuse_file_info *fi,
size_t *wSize) {
(void)req;
FileOut* fileOut) {
size_t *wSize = &fileOut->nwritten;
// check align
if (fi->flags & O_DIRECT) {
if (!(is_aligned(off, DirectIOAlignment) &&
@ -210,6 +218,8 @@ CURVEFS_ERROR FuseS3Client::FuseOpWrite(fuse_req_t req, fuse_ino_t ino,
}
}
}
inodeWrapper->GetInodeAttrLocked(&fileOut->attr);
return ret;
}
@ -272,33 +282,56 @@ CURVEFS_ERROR FuseS3Client::FuseOpRead(fuse_req_t req, fuse_ino_t ino,
CURVEFS_ERROR FuseS3Client::FuseOpCreate(fuse_req_t req, fuse_ino_t parent,
const char *name, mode_t mode,
struct fuse_file_info *fi,
fuse_entry_param *e) {
EntryOut* entryOut) {
VLOG(1) << "FuseOpCreate, parent: " << parent << ", name: " << name
<< ", mode: " << mode;
std::shared_ptr<InodeWrapper> inode;
CURVEFS_ERROR ret =
MakeNode(req, parent, name, mode, FsFileType::TYPE_S3, 0, false, e);
MakeNode(req, parent, name, mode, FsFileType::TYPE_S3, 0, false, inode);
if (ret != CURVEFS_ERROR::OK) {
return ret;
}
return FuseOpOpen(req, e->ino, fi);
auto openFiles = fs_->BorrowMember().openFiles;
openFiles->Open(inode->GetInodeId(), inode);
inode->GetInodeAttr(&entryOut->attr);
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR FuseS3Client::FuseOpMkNod(fuse_req_t req, fuse_ino_t parent,
const char *name, mode_t mode,
dev_t rdev, fuse_entry_param *e) {
CURVEFS_ERROR FuseS3Client::FuseOpMkNod(fuse_req_t req,
fuse_ino_t parent,
const char* name,
mode_t mode,
dev_t rdev,
EntryOut* entryOut) {
VLOG(1) << "FuseOpMkNod, parent: " << parent << ", name: " << name
<< ", mode: " << mode << ", rdev: " << rdev;
return MakeNode(req, parent, name, mode, FsFileType::TYPE_S3, rdev, false,
e);
std::shared_ptr<InodeWrapper> inode;
CURVEFS_ERROR rc = MakeNode(req, parent, name, mode,
FsFileType::TYPE_S3, rdev, false,
inode);
if (rc != CURVEFS_ERROR::OK) {
return rc;
}
InodeAttr attr;
inode->GetInodeAttr(&attr);
*entryOut = EntryOut(attr);
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR FuseS3Client::FuseOpLink(fuse_req_t req, fuse_ino_t ino,
fuse_ino_t newparent, const char *newname,
fuse_entry_param *e) {
CURVEFS_ERROR FuseS3Client::FuseOpLink(fuse_req_t req,
fuse_ino_t ino,
fuse_ino_t newparent,
const char* newname,
EntryOut* entryOut) {
VLOG(1) << "FuseOpLink, ino: " << ino << ", newparent: " << newparent
<< ", newname: " << newname;
return FuseClient::FuseOpLink(
req, ino, newparent, newname, FsFileType::TYPE_S3, e);
req, ino, newparent, newname, FsFileType::TYPE_S3, entryOut);
}
CURVEFS_ERROR FuseS3Client::FuseOpUnlink(fuse_req_t req, fuse_ino_t parent,

View File

@ -33,6 +33,7 @@
#include "curvefs/src/client/fuse_client.h"
#include "curvefs/src/client/s3/client_s3_cache_manager.h"
#include "curvefs/src/client/warmup/warmup_manager.h"
#include "curvefs/src/volume/common.h"
#include "src/common/s3_adapter.h"
namespace curvefs {
@ -40,6 +41,7 @@ namespace client {
using curve::common::GetObjectAsyncContext;
using curve::common::GetObjectAsyncCallBack;
using curvefs::volume::kMiB;
namespace warmup {
class WarmupManager;
class WarmupManagerS3Impl;
@ -79,7 +81,7 @@ class FuseS3Client : public FuseClient {
CURVEFS_ERROR FuseOpWrite(fuse_req_t req, fuse_ino_t ino,
const char *buf, size_t size, off_t off,
struct fuse_file_info *fi, size_t *wSize) override;
struct fuse_file_info *fi, FileOut* fileOut) override;
CURVEFS_ERROR FuseOpRead(fuse_req_t req,
fuse_ino_t ino, size_t size, off_t off,
@ -87,17 +89,25 @@ class FuseS3Client : public FuseClient {
char *buffer,
size_t *rSize) override;
CURVEFS_ERROR FuseOpCreate(fuse_req_t req, fuse_ino_t parent,
const char *name, mode_t mode, struct fuse_file_info *fi,
fuse_entry_param *e) override;
CURVEFS_ERROR FuseOpCreate(fuse_req_t req,
fuse_ino_t parent,
const char* name,
mode_t mode,
struct fuse_file_info *fi,
EntryOut* entryOut) override;
CURVEFS_ERROR FuseOpMkNod(fuse_req_t req, fuse_ino_t parent,
const char *name, mode_t mode, dev_t rdev,
fuse_entry_param *e) override;
CURVEFS_ERROR FuseOpMkNod(fuse_req_t req,
fuse_ino_t parent,
const char* name,
mode_t mode,
dev_t rdev,
EntryOut* entryOut) override;
CURVEFS_ERROR FuseOpLink(fuse_req_t req, fuse_ino_t ino,
fuse_ino_t newparent, const char *newname,
fuse_entry_param *e) override;
CURVEFS_ERROR FuseOpLink(fuse_req_t req,
fuse_ino_t ino,
fuse_ino_t newparent,
const char *newname,
EntryOut* entryOut) override;
CURVEFS_ERROR FuseOpUnlink(fuse_req_t req, fuse_ino_t parent,
const char *name) override;
@ -108,17 +118,19 @@ class FuseS3Client : public FuseClient {
CURVEFS_ERROR FuseOpFlush(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi) override;
CURVEFS_ERROR Truncate(InodeWrapper *inode, uint64_t length) override;
private:
bool InitKVCache(const KVClientManagerOpt &opt);
CURVEFS_ERROR Truncate(InodeWrapper *inode, uint64_t length) override;
void FlushData() override;
private:
// s3 adaptor
std::shared_ptr<S3ClientAdaptor> s3Adaptor_;
std::shared_ptr<KVClientManager> kvClientManager_;
static constexpr auto MIN_WRITE_CACHE_SIZE = 8 * kMiB;
};

View File

@ -32,7 +32,7 @@
#include "absl/cleanup/cleanup.h"
#include "absl/memory/memory.h"
#include "curvefs/proto/mds.pb.h"
#include "curvefs/src/client/error_code.h"
#include "curvefs/src/client/filesystem/error.h"
#include "curvefs/src/client/volume/default_volume_storage.h"
#include "curvefs/src/client/volume/extent_cache.h"
#include "curvefs/src/volume/common.h"
@ -111,12 +111,9 @@ CURVEFS_ERROR FuseVolumeClient::FuseOpInit(void *userdata,
volOpts_.allocatorOption.bitmapAllocatorOption.sizePerBit;
option.allocatorOption.bitmapAllocatorOption.smallAllocProportion =
volOpts_.allocatorOption.bitmapAllocatorOption.smallAllocProportion;
option.threshold = volOpts_.threshold;
option.releaseInterSec = volOpts_.releaseInterSec;
spaceManager_ = absl::make_unique<SpaceManagerImpl>(option, mdsClient_,
blockDeviceClient_);
spaceManager_->Run();
storage_ = absl::make_unique<DefaultVolumeStorage>(
spaceManager_.get(), blockDeviceClient_.get(), inodeManager_.get());
@ -136,11 +133,11 @@ CURVEFS_ERROR FuseVolumeClient::FuseOpWrite(fuse_req_t req,
size_t size,
off_t off,
struct fuse_file_info *fi,
size_t *wSize) {
(void)req;
FileOut* fileOut) {
VLOG(9) << "write start, ino: " << ino << ", offset: " << off
<< ", length: " << size;
size_t* wSize = &fileOut->nwritten;
if (fi->flags & O_DIRECT) {
if (!(is_aligned(off, DirectIOAlignment) &&
is_aligned(size, DirectIOAlignment))) {
@ -152,7 +149,7 @@ CURVEFS_ERROR FuseVolumeClient::FuseOpWrite(fuse_req_t req,
butil::Timer timer;
timer.start();
CURVEFS_ERROR ret = storage_->Write(ino, off, size, buf);
CURVEFS_ERROR ret = storage_->Write(ino, off, size, buf, fileOut);
if (ret != CURVEFS_ERROR::OK) {
if (fsMetric_) {
fsMetric_->userWrite.eps.count << 1;
@ -238,34 +235,57 @@ CURVEFS_ERROR FuseVolumeClient::FuseOpRead(fuse_req_t req,
CURVEFS_ERROR FuseVolumeClient::FuseOpCreate(fuse_req_t req, fuse_ino_t parent,
const char *name, mode_t mode,
struct fuse_file_info *fi,
fuse_entry_param *e) {
EntryOut* entryOut) {
VLOG(3) << "FuseOpCreate, parent: " << parent
<< ", name: " << name
<< ", mode: " << mode;
CURVEFS_ERROR ret =
MakeNode(req, parent, name, mode, FsFileType::TYPE_FILE, 0, false, e);
std::shared_ptr<InodeWrapper> inode;
CURVEFS_ERROR ret = MakeNode(
req, parent, name, mode, FsFileType::TYPE_FILE, 0, false, inode);
if (ret != CURVEFS_ERROR::OK) {
return ret;
}
return FuseOpOpen(req, e->ino, fi);
auto openFiles = fs_->BorrowMember().openFiles;
openFiles->Open(inode->GetInodeId(), inode);
inode->GetInodeAttr(&entryOut->attr);
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR FuseVolumeClient::FuseOpMkNod(fuse_req_t req, fuse_ino_t parent,
const char *name, mode_t mode,
dev_t rdev, fuse_entry_param *e) {
CURVEFS_ERROR FuseVolumeClient::FuseOpMkNod(fuse_req_t req,
fuse_ino_t parent,
const char* name,
mode_t mode,
dev_t rdev,
EntryOut* entryOut) {
VLOG(3) << "FuseOpMkNod, parent: " << parent << ", name: " << name
<< ", mode: " << mode << ", rdev: " << rdev;
return MakeNode(req, parent, name, mode, FsFileType::TYPE_FILE, rdev,
false, e);
std::shared_ptr<InodeWrapper> inode;
CURVEFS_ERROR rc = MakeNode(req, parent, name, mode,
FsFileType::TYPE_FILE, rdev,
false, inode);
if (rc != CURVEFS_ERROR::OK) {
return rc;
}
InodeAttr attr;
inode->GetInodeAttr(&attr);
*entryOut = EntryOut(attr);
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR FuseVolumeClient::FuseOpLink(fuse_req_t req, fuse_ino_t ino,
fuse_ino_t newparent, const char *newname,
fuse_entry_param *e) {
CURVEFS_ERROR FuseVolumeClient::FuseOpLink(fuse_req_t req,
fuse_ino_t ino,
fuse_ino_t newparent,
const char* newname,
EntryOut* entryOut) {
VLOG(1) << "FuseOpLink, ino: " << ino << ", newparent: " << newparent
<< ", newname: " << newname;
return FuseClient::FuseOpLink(
req, ino, newparent, newname, FsFileType::TYPE_FILE, e);
req, ino, newparent, newname, FsFileType::TYPE_FILE, entryOut);
}
CURVEFS_ERROR FuseVolumeClient::FuseOpUnlink(fuse_req_t req, fuse_ino_t parent,

View File

@ -65,24 +65,32 @@ class FuseVolumeClient : public FuseClient {
CURVEFS_ERROR FuseOpWrite(fuse_req_t req, fuse_ino_t ino,
const char *buf, size_t size, off_t off,
struct fuse_file_info *fi, size_t *wSize) override;
struct fuse_file_info *fi, FileOut* fileOut) override;
CURVEFS_ERROR FuseOpRead(fuse_req_t req,
fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info *fi,
char *buffer,
size_t *rSize) override;
CURVEFS_ERROR FuseOpCreate(fuse_req_t req, fuse_ino_t parent,
const char *name, mode_t mode, struct fuse_file_info *fi,
fuse_entry_param *e) override;
CURVEFS_ERROR FuseOpMkNod(fuse_req_t req, fuse_ino_t parent,
const char *name, mode_t mode, dev_t rdev,
fuse_entry_param *e) override;
CURVEFS_ERROR FuseOpCreate(fuse_req_t req,
fuse_ino_t parent,
const char* name,
mode_t mode,
struct fuse_file_info* fi,
EntryOut* entryOut) override;
CURVEFS_ERROR FuseOpMkNod(fuse_req_t req,
fuse_ino_t parent,
const char* name,
mode_t mode,
dev_t rdev,
EntryOut* entryOut) override;
CURVEFS_ERROR FuseOpLink(fuse_req_t req, fuse_ino_t ino,
fuse_ino_t newparent, const char *newname,
fuse_entry_param *e) override;
fuse_ino_t newparent,
const char *newname,
EntryOut* entryOut) override;
CURVEFS_ERROR FuseOpUnlink(fuse_req_t req, fuse_ino_t parent,
const char *name) override;
@ -93,13 +101,13 @@ class FuseVolumeClient : public FuseClient {
CURVEFS_ERROR FuseOpFlush(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi) override;
CURVEFS_ERROR Truncate(InodeWrapper *inode, uint64_t length) override;
void SetSpaceManagerForTesting(SpaceManager *manager);
void SetVolumeStorageForTesting(VolumeStorage *storage);
private:
CURVEFS_ERROR Truncate(InodeWrapper *inode, uint64_t length) override;
void FlushData() override;
private:

View File

@ -29,7 +29,7 @@
#include <memory>
#include <utility>
#include "curvefs/proto/metaserver.pb.h"
#include "curvefs/src/client/error_code.h"
#include "curvefs/src/client/filesystem/error.h"
#include "curvefs/src/client/inode_wrapper.h"
using ::curvefs::metaserver::Inode;
@ -46,36 +46,11 @@ DECLARE_bool(enableCto);
namespace curvefs {
namespace client {
using ::curvefs::client::filesystem::ToFSError;
using NameLockGuard = ::curve::common::GenericNameLockGuard<Mutex>;
using curvefs::client::common::FLAGS_enableCto;
class TrimICacheAsyncDone : public MetaServerClientDone {
public:
explicit TrimICacheAsyncDone(
const std::shared_ptr<InodeWrapper> &inodeWrapper,
const std::shared_ptr<InodeCacheManagerImpl> &inodeCacheManager)
: inodeWrapper_(inodeWrapper), inodeCacheManager_(inodeCacheManager) {}
void Run() override {
std::unique_ptr<TrimICacheAsyncDone> self_guard(this);
MetaStatusCode ret = GetStatusCode();
if (ret != MetaStatusCode::OK && ret != MetaStatusCode::NOT_FOUND) {
LOG(ERROR) << "metaClient_ UpdateInode failed, "
<< "MetaStatusCode: " << ret
<< ", MetaStatusCode_Name: " << MetaStatusCode_Name(ret)
<< ", inodeid: " << inodeWrapper_->GetInodeId();
inodeWrapper_->MarkInodeError();
}
VLOG(9) << "Trim inode " << inodeWrapper_->GetInodeId()
<< " async success.";
inodeCacheManager_->RemoveICache(inodeWrapper_);
};
private:
std::shared_ptr<InodeWrapper> inodeWrapper_;
std::shared_ptr<InodeCacheManagerImpl> inodeCacheManager_;
};
#define GET_INODE_REMOTE(FSID, INODEID, OUT, STREAMING) \
MetaStatusCode ret = metaClient_->GetInode(FSID, INODEID, OUT, STREAMING); \
if (ret != MetaStatusCode::OK) { \
@ -83,17 +58,7 @@ class TrimICacheAsyncDone : public MetaServerClientDone {
<< "metaClient_ GetInode failed, MetaStatusCode = " << ret \
<< ", MetaStatusCode_Name = " << MetaStatusCode_Name(ret) \
<< ", inodeid = " << INODEID; \
return MetaStatusCodeToCurvefsErrCode(ret); \
}
#define PUT_INODE_CACHE(INODEID, INODEWRAPPER) \
std::shared_ptr<InodeWrapper> eliminatedOne; \
bool eliminated = iCache_->Put(INODEID, INODEWRAPPER, &eliminatedOne); \
if (eliminated) { \
VLOG(3) << "GetInode eliminate one inode, ino: " \
<< eliminatedOne->GetInodeId() \
<< ", iCache does not evict inodes via put interface "; \
assert(0); \
return ToFSError(ret); \
}
#define REFRESH_DATA_REMOTE(OUT, STREAMING) \
@ -106,15 +71,8 @@ CURVEFS_ERROR
InodeCacheManagerImpl::GetInode(uint64_t inodeId,
std::shared_ptr<InodeWrapper> &out) {
NameLockGuard lock(nameLock_, std::to_string(inodeId));
// get inode from cache
bool ok = iCache_->Get(inodeId, &out);
if (ok && NeedUseCache(inodeId, out, false)) {
curve::common::UniqueLock lgGuard = out->GetUniqueLock();
if (out->GetType() == FsFileType::TYPE_FILE) {
return CURVEFS_ERROR::OK;
}
REFRESH_DATA_REMOTE(out, out->NeedRefreshData());
bool yes = openFiles_->IsOpened(inodeId, &out);
if (yes) {
return CURVEFS_ERROR::OK;
}
@ -129,24 +87,12 @@ InodeCacheManagerImpl::GetInode(uint64_t inodeId,
// refresh data
REFRESH_DATA_REMOTE(out, streaming);
// put to cache
PUT_INODE_CACHE(inodeId, out);
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR InodeCacheManagerImpl::GetInodeAttr(uint64_t inodeId,
InodeAttr *out) {
NameLockGuard lock(nameLock_, std::to_string(inodeId));
// 1. find in icache
std::shared_ptr<InodeWrapper> inodeWrapper;
bool ok = iCache_->Get(inodeId, &inodeWrapper);
if (ok && NeedUseCache(inodeId, inodeWrapper, true)) {
inodeWrapper->GetInodeAttr(out);
return CURVEFS_ERROR::OK;
}
// 2. get form metaserver
std::set<uint64_t> inodeIds;
std::list<InodeAttr> attrs;
inodeIds.emplace(inodeId);
@ -156,7 +102,7 @@ CURVEFS_ERROR InodeCacheManagerImpl::GetInodeAttr(uint64_t inodeId,
LOG(ERROR) << "metaClient BatchGetInodeAttr failed"
<< ", inodeId = " << inodeId << ", MetaStatusCode = " << ret
<< ", MetaStatusCode_Name = " << MetaStatusCode_Name(ret);
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
if (attrs.size() != 1) {
@ -173,21 +119,6 @@ CURVEFS_ERROR InodeCacheManagerImpl::GetInodeAttr(uint64_t inodeId,
CURVEFS_ERROR InodeCacheManagerImpl::BatchGetInodeAttr(
std::set<uint64_t> *inodeIds,
std::list<InodeAttr> *attrs) {
// get some inode attr in icache
for (auto iter = inodeIds->begin(); iter != inodeIds->end();) {
std::shared_ptr<InodeWrapper> inodeWrapper;
NameLockGuard lock(nameLock_, std::to_string(*iter));
bool ok = iCache_->Get(*iter, &inodeWrapper);
if (ok && NeedUseCache(*iter, inodeWrapper, true)) {
InodeAttr tmpAttr;
inodeWrapper->GetInodeAttr(&tmpAttr);
attrs->emplace_back(std::move(tmpAttr));
iter = inodeIds->erase(iter);
continue;
}
++iter;
}
if (inodeIds->empty()) {
return CURVEFS_ERROR::OK;
}
@ -199,7 +130,7 @@ CURVEFS_ERROR InodeCacheManagerImpl::BatchGetInodeAttr(
<< ret << ", MetaStatusCode_Name = "
<< MetaStatusCode_Name(ret);
}
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
CURVEFS_ERROR InodeCacheManagerImpl::BatchGetInodeAttrAsync(
@ -207,26 +138,6 @@ CURVEFS_ERROR InodeCacheManagerImpl::BatchGetInodeAttrAsync(
std::set<uint64_t> *inodeIds,
std::map<uint64_t, InodeAttr> *attrs) {
NameLockGuard lg(asyncNameLock_, std::to_string(parentId));
std::map<uint64_t, InodeAttr> cachedAttr;
bool cache = iAttrCache_->Get(parentId, &cachedAttr);
// get some inode attr in icache
for (auto iter = inodeIds->begin(); iter != inodeIds->end();) {
std::shared_ptr<InodeWrapper> inodeWrapper;
NameLockGuard lock(nameLock_, std::to_string(*iter));
bool ok = iCache_->Get(*iter, &inodeWrapper);
if (ok && NeedUseCache(*iter, inodeWrapper, true)) {
InodeAttr tmpAttr;
inodeWrapper->GetInodeAttr(&tmpAttr);
attrs->emplace(*iter, std::move(tmpAttr));
iter = inodeIds->erase(iter);
} else if (cache && cachedAttr.find(*iter) != cachedAttr.end()) {
attrs->emplace(*iter, cachedAttr[*iter]);
iter = inodeIds->erase(iter);
} else {
++iter;
}
}
if (inodeIds->empty()) {
return CURVEFS_ERROR::OK;
@ -238,12 +149,12 @@ CURVEFS_ERROR InodeCacheManagerImpl::BatchGetInodeAttrAsync(
return CURVEFS_ERROR::NOTEXIST;
}
::curve::common::Mutex mutex;
std::shared_ptr<CountDownEvent> cond =
std::make_shared<CountDownEvent>(inodeGroups.size());
for (const auto& it : inodeGroups) {
VLOG(3) << "BatchGetInodeAttrAsync Send " << it.size();
auto* done = new BatchGetInodeAttrAsyncDone(shared_from_this(),
cond, parentId);
auto* done = new BatchGetInodeAttrAsyncDone(attrs, &mutex, cond);
MetaStatusCode ret = metaClient_->BatchGetInodeAttrAsync(fsId_, it,
done);
if (MetaStatusCode::OK != ret) {
@ -256,30 +167,12 @@ CURVEFS_ERROR InodeCacheManagerImpl::BatchGetInodeAttrAsync(
// wait for all sudrequest finished
cond->Wait();
bool ok = iAttrCache_->Get(parentId, attrs);
if (!ok) {
LOG(WARNING) << "get attrs form iAttrCache_ failed.";
}
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR InodeCacheManagerImpl::BatchGetXAttr(
std::set<uint64_t> *inodeIds,
std::list<XAttr> *xattr) {
// get some inode in icache
for (auto iter = inodeIds->begin(); iter != inodeIds->end();) {
std::shared_ptr<InodeWrapper> inodeWrapper;
NameLockGuard lock(nameLock_, std::to_string(*iter));
bool ok = iCache_->Get(*iter, &inodeWrapper);
if (ok && NeedUseCache(*iter, inodeWrapper, true)) {
xattr->emplace_back(inodeWrapper->GetXattr());
iter = inodeIds->erase(iter);
} else {
++iter;
}
}
if (inodeIds->empty()) {
return CURVEFS_ERROR::OK;
}
@ -290,7 +183,7 @@ CURVEFS_ERROR InodeCacheManagerImpl::BatchGetXAttr(
<< ret << ", MetaStatusCode_Name = "
<< MetaStatusCode_Name(ret);
}
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
CURVEFS_ERROR InodeCacheManagerImpl::CreateInode(
@ -301,23 +194,11 @@ CURVEFS_ERROR InodeCacheManagerImpl::CreateInode(
if (ret != MetaStatusCode::OK) {
LOG(ERROR) << "metaClient_ CreateInode failed, MetaStatusCode = " << ret
<< ", MetaStatusCode_Name = " << MetaStatusCode_Name(ret);
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
uint64_t inodeid = inode.inodeid();
out = std::make_shared<InodeWrapper>(std::move(inode), metaClient_,
s3ChunkInfoMetric_, option_.maxDataSize,
option_.refreshDataIntervalSec);
std::shared_ptr<InodeWrapper> eliminatedOne;
bool eliminated = false;
{
NameLockGuard lock(nameLock_, std::to_string(inodeid));
eliminated = iCache_->Put(inodeid, out, &eliminatedOne);
}
if (eliminated) {
/* iCache does not evict inodes via put interface */
assert(0);
}
return CURVEFS_ERROR::OK;
}
@ -330,159 +211,29 @@ CURVEFS_ERROR InodeCacheManagerImpl::CreateManageInode(
LOG(ERROR) << "metaClient_ CreateManageInode failed, MetaStatusCode = "
<< ret << ", MetaStatusCode_Name = "
<< MetaStatusCode_Name(ret);
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
uint64_t inodeid = inode.inodeid();
out = std::make_shared<InodeWrapper>(std::move(inode), metaClient_,
s3ChunkInfoMetric_, option_.maxDataSize,
option_.refreshDataIntervalSec);
std::shared_ptr<InodeWrapper> eliminatedOne;
bool eliminated = false;
{
NameLockGuard lock(nameLock_, std::to_string(inodeid));
eliminated = iCache_->Put(inodeid, out, &eliminatedOne);
}
if (eliminated) {
/* iCache does not evict inodes via put interface */
assert(0);
}
return CURVEFS_ERROR::OK;
}
CURVEFS_ERROR InodeCacheManagerImpl::DeleteInode(uint64_t inodeId) {
NameLockGuard lock(nameLock_, std::to_string(inodeId));
iCache_->Remove(inodeId);
MetaStatusCode ret = metaClient_->DeleteInode(fsId_, inodeId);
if (ret != MetaStatusCode::OK && ret != MetaStatusCode::NOT_FOUND) {
LOG(ERROR) << "metaClient_ DeleteInode failed, MetaStatusCode = " << ret
<< ", MetaStatusCode_Name = " << MetaStatusCode_Name(ret)
<< ", inodeId = " << inodeId;
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
curve::common::LockGuard lg2(dirtyMapMutex_);
dirtyMap_.erase(inodeId);
return CURVEFS_ERROR::OK;
}
void InodeCacheManagerImpl::AddInodeAttrs(
uint64_t parentId, const RepeatedPtrField<InodeAttr>& inodeAttrs) {
iAttrCache_->Set(parentId, inodeAttrs);
}
void InodeCacheManagerImpl::ClearInodeCache(uint64_t inodeId) {
{
NameLockGuard lock(nameLock_, std::to_string(inodeId));
iCache_->Remove(inodeId);
}
curve::common::LockGuard lg2(dirtyMapMutex_);
dirtyMap_.erase(inodeId);
}
void InodeCacheManagerImpl::ShipToFlush(
const std::shared_ptr<InodeWrapper> &inodeWrapper) {
curve::common::LockGuard lg(dirtyMapMutex_);
dirtyMap_.emplace(inodeWrapper->GetInodeId(), inodeWrapper);
}
void InodeCacheManagerImpl::FlushAll() {
while (!dirtyMap_.empty()) {
FlushInodeOnce();
}
}
void InodeCacheManagerImpl::FlushInodeOnce() {
std::map<uint64_t, std::shared_ptr<InodeWrapper>> temp_;
{
curve::common::LockGuard lg(dirtyMapMutex_);
temp_.swap(dirtyMap_);
}
for (auto it = temp_.begin(); it != temp_.end(); it++) {
curve::common::UniqueLock ulk = it->second->GetUniqueLock();
it->second->Async(nullptr, true);
}
}
void InodeCacheManagerImpl::ReleaseCache(uint64_t parentId) {
NameLockGuard lg(asyncNameLock_, std::to_string(parentId));
iAttrCache_->Release(parentId);
}
void InodeCacheManagerImpl::FlushInodeBackground() {
LOG(INFO) << "flush thread is start.";
while (!isStop_.load()) {
if (iCache_->Size() > maxCacheSize_) {
TrimIcache(iCache_->Size() - maxCacheSize_);
}
FlushInodeOnce();
sleeper_.wait_for(std::chrono::seconds(flushPeriodSec_));
}
LOG(INFO) << "flush thread is stop.";
}
namespace {
// Wether an inode is dirty or not.
// if |needLock| is true, we acquire the lock firstly and do the test,
// otherwise, we assume the lock is already held.
bool IsDirtyInode(InodeWrapper *ino, bool needLock) {
auto check = [ino]() {
return ino->IsDirty() || !ino->S3ChunkInfoEmptyNolock() ||
ino->GetMutableExtentCacheLocked()->HasDirtyExtents();
};
if (needLock) {
auto lk = ino->GetUniqueLock();
return check();
}
return check();
}
} // namespace
void InodeCacheManagerImpl::RemoveICache(
const std::shared_ptr<InodeWrapper> &inode) {
if (!IsDirtyInode(inode.get(), true)) {
uint64_t inodeId = inode->GetInodeId();
NameLockGuard lock(nameLock_, std::to_string(inodeId));
::curve::common::UniqueLock lgGuard = inode->GetUniqueLock();
iCache_->Remove(inodeId);
}
}
void InodeCacheManagerImpl::TrimIcache(uint64_t trimSize) {
std::shared_ptr<InodeWrapper> inodeWrapper;
uint64_t inodeId;
VLOG(3) << "TrimIcache trimSize " << trimSize;
while (trimSize > 0) {
bool ok = iCache_->GetLast(&inodeId, &inodeWrapper);
if (ok) {
NameLockGuard lock(nameLock_, std::to_string(inodeId));
::curve::common::UniqueLock lgGuard = inodeWrapper->GetUniqueLock();
if (IsDirtyInode(inodeWrapper.get(), false)) {
VLOG(9) << "TrimIcache sync dirty inode " << inodeId;
dirtyMapMutex_.lock();
dirtyMap_.erase(inodeId);
dirtyMapMutex_.unlock();
auto *done =
new TrimICacheAsyncDone(inodeWrapper, shared_from_this());
inodeWrapper->Async(done);
} else {
VLOG(9) << "TrimIcache remove inode " << inodeId
<< " from iCache";
iCache_->Remove(inodeId);
}
trimSize--;
// remove the attr of the inode in iattrcache
auto parents = inodeWrapper->GetParentLocked();
for (uint64_t parent : parents) {
iAttrCache_->Remove(parent, inodeId);
}
} else {
LOG(ERROR) << "icache size " << iCache_->Size();
assert(0);
}
}
const std::shared_ptr<InodeWrapper>& inode) {
deferSync_->Push(inode);
}
CURVEFS_ERROR
@ -519,57 +270,5 @@ InodeCacheManagerImpl::RefreshData(std::shared_ptr<InodeWrapper> &inode,
return rc;
}
void InodeCacheManagerImpl::AddOpenedInode(uint64_t inodeId) {
VLOG(1) << "AddOpenedInode inodeId: " << inodeId;
curve::common::LockGuard lg(openInodesMutex_);
openedInodes_.emplace(inodeId);
}
void InodeCacheManagerImpl::RemoveOpenedInode(uint64_t inodeId) {
VLOG(1) << "RemoveOpenedInode inodeId: " << inodeId;
curve::common::LockGuard lg(openInodesMutex_);
auto iter = openedInodes_.find(inodeId);
if (iter != openedInodes_.end()) {
openedInodes_.erase(iter);
}
}
bool InodeCacheManagerImpl::OpenInodeCached(uint64_t inodeId) {
curve::common::LockGuard lg(openInodesMutex_);
auto iter = openedInodes_.find(inodeId);
return iter != openedInodes_.end();
}
bool InodeCacheManagerImpl::NeedUseCache(uint64_t inodeId,
const std::shared_ptr<InodeWrapper> &inodeWrapper,
bool onlyAttr) {
auto lock = inodeWrapper->GetUniqueLock();
if (onlyAttr) {
if (inodeWrapper->IsDirty()) {
return true;
}
} else {
if (IsDirtyInode(inodeWrapper.get(), false)) {
return true;
}
}
if (((FLAGS_enableCto && OpenInodeCached(inodeId)) || !FLAGS_enableCto)
&& !IsTimeOut(inodeWrapper)) {
return true;
}
return false;
}
bool InodeCacheManagerImpl::IsTimeOut(
const std::shared_ptr<InodeWrapper> &inodeWrapper) const {
uint32_t time = inodeWrapper->GetCachedTime();
if (cacheTimeOutSec_ > 0 &&
TimeUtility::GetTimeofDaySec() - time >= cacheTimeOutSec_) {
return true;
}
return false;
}
} // namespace client
} // namespace curvefs

View File

@ -38,12 +38,14 @@
#include "curvefs/src/client/rpcclient/metaserver_client.h"
#include "curvefs/proto/metaserver.pb.h"
#include "curvefs/src/client/error_code.h"
#include "curvefs/src/client/filesystem/error.h"
#include "src/common/concurrent/concurrent.h"
#include "src/common/interruptible_sleeper.h"
#include "curvefs/src/client/inode_wrapper.h"
#include "src/common/concurrent/name_lock.h"
#include "curvefs/src/client/common/config.h"
#include "curvefs/src/client/filesystem/openfile.h"
#include "curvefs/src/client/filesystem/defer_sync.h"
using ::curve::common::LRUCache;
using ::curve::common::CacheMetrics;
@ -64,57 +66,8 @@ using rpcclient::BatchGetInodeAttrDone;
using curve::common::CountDownEvent;
using metric::S3ChunkInfoMetric;
using common::RefreshDataOption;
class InodeAttrCache {
public:
InodeAttrCache() {}
~InodeAttrCache() {}
bool Get(uint64_t parentId, std::map<uint64_t, InodeAttr> *imap) {
curve::common::LockGuard lg(iAttrCacheMutex_);
auto iter = iAttrCache_.find(parentId);
if (iter != iAttrCache_.end()) {
imap->insert(iter->second.begin(), iter->second.end());
return true;
}
return false;
}
void Set(uint64_t parentId, const RepeatedPtrField<InodeAttr>& inodeAttrs) {
curve::common::LockGuard lg(iAttrCacheMutex_);
VLOG(1) << "parentId = " << parentId
<< ", iAttrCache set size = " << inodeAttrs.size();
auto& inner = iAttrCache_[parentId];
for (const auto &it : inodeAttrs) {
inner.emplace(it.inodeid(), it);
}
}
void Release(uint64_t parentId) {
curve::common::LockGuard lg(iAttrCacheMutex_);
auto size = iAttrCache_.size();
auto iter = iAttrCache_.find(parentId);
if (iter != iAttrCache_.end()) {
iAttrCache_.erase(iter);
}
VLOG(1) << "inodeId = " << parentId
<< ", inode attr cache release, before = "
<< size << ", after = " << iAttrCache_.size();
}
void Remove(uint64_t parentId, uint64_t inodeId) {
curve::common::LockGuard lg(iAttrCacheMutex_);
auto iter = iAttrCache_.find(parentId);
if (iter != iAttrCache_.end()) {
iter->second.erase(inodeId);
}
}
private:
// inodeAttr cache; <parentId, <inodeId, inodeAttr>>
std::map<uint64_t, std::map<uint64_t, InodeAttr>> iAttrCache_;
curve::common::Mutex iAttrCacheMutex_;
};
using ::curvefs::client::filesystem::OpenFiles;
using ::curvefs::client::filesystem::DeferSync;
class InodeCacheManager {
public:
@ -126,14 +79,9 @@ class InodeCacheManager {
fsId_ = fsId;
}
virtual CURVEFS_ERROR Init(uint64_t cacheSize, bool enableCacheMetrics,
uint32_t flushPeriodSec,
RefreshDataOption option,
uint32_t cacheTimeOutSec) = 0;
virtual void Run() = 0;
virtual void Stop() = 0;
virtual CURVEFS_ERROR Init(RefreshDataOption option,
std::shared_ptr<OpenFiles> openFiles,
std::shared_ptr<DeferSync> deferSync) = 0;
virtual CURVEFS_ERROR
GetInode(uint64_t inodeId,
@ -161,24 +109,9 @@ class InodeCacheManager {
virtual CURVEFS_ERROR DeleteInode(uint64_t inodeId) = 0;
virtual void AddInodeAttrs(uint64_t parentId,
const RepeatedPtrField<InodeAttr>& inodeAttrs) = 0;
virtual void ClearInodeCache(uint64_t inodeId) = 0;
virtual void ShipToFlush(
const std::shared_ptr<InodeWrapper> &inodeWrapper) = 0;
virtual void FlushAll() = 0;
virtual void FlushInodeOnce() = 0;
virtual void ReleaseCache(uint64_t parentId) = 0;
virtual void AddOpenedInode(uint64_t inodeId) = 0;
virtual void RemoveOpenedInode(uint64_t inodeId) = 0;
protected:
uint32_t fsId_;
};
@ -187,59 +120,22 @@ class InodeCacheManagerImpl : public InodeCacheManager,
public std::enable_shared_from_this<InodeCacheManagerImpl> {
public:
InodeCacheManagerImpl()
: metaClient_(std::make_shared<MetaServerClientImpl>()),
iCache_(nullptr),
iAttrCache_(nullptr),
isStop_(true),
cacheTimeOutSec_(0) {}
: metaClient_(std::make_shared<MetaServerClientImpl>()) {}
explicit InodeCacheManagerImpl(
const std::shared_ptr<MetaServerClient> &metaClient)
: metaClient_(metaClient),
iCache_(nullptr),
iAttrCache_(nullptr),
cacheTimeOutSec_(0) {}
: metaClient_(metaClient) {}
CURVEFS_ERROR Init(uint64_t cacheSize, bool enableCacheMetrics,
uint32_t flushPeriodSec,
RefreshDataOption option,
uint32_t cacheTimeOutSec) override {
if (enableCacheMetrics) {
iCache_ = std::make_shared<
LRUCache<uint64_t, std::shared_ptr<InodeWrapper>>>(0,
std::make_shared<CacheMetrics>("icache"));
} else {
iCache_ = std::make_shared<
LRUCache<uint64_t, std::shared_ptr<InodeWrapper>>>(0);
}
maxCacheSize_ = cacheSize;
CURVEFS_ERROR Init(RefreshDataOption option,
std::shared_ptr<OpenFiles> openFiles,
std::shared_ptr<DeferSync> deferSync) override {
option_ = option;
flushPeriodSec_ = flushPeriodSec;
cacheTimeOutSec_ = cacheTimeOutSec;
iAttrCache_ = std::make_shared<InodeAttrCache>();
s3ChunkInfoMetric_ = std::make_shared<S3ChunkInfoMetric>();
openFiles_ = openFiles;
deferSync_ = deferSync;
return CURVEFS_ERROR::OK;
}
void Run() {
isStop_.exchange(false);
flushThread_ =
Thread(&InodeCacheManagerImpl::FlushInodeBackground, this);
LOG(INFO) << "Start inodeManager flush thread ok.";
}
void Stop() {
isStop_.exchange(true);
LOG(INFO) << "stop inodeManager flush thread ...";
sleeper_.interrupt();
flushThread_.join();
}
bool IsDirtyMapExist(uint64_t inodeId) {
curve::common::LockGuard lg(dirtyMapMutex_);
return dirtyMap_.count(inodeId) > 0;
}
CURVEFS_ERROR GetInode(uint64_t inodeId,
std::shared_ptr<InodeWrapper> &out) override;
@ -263,78 +159,37 @@ class InodeCacheManagerImpl : public InodeCacheManager,
CURVEFS_ERROR DeleteInode(uint64_t inodeId) override;
void AddInodeAttrs(uint64_t parentId,
const RepeatedPtrField<InodeAttr>& inodeAttrs) override;
void ClearInodeCache(uint64_t inodeId) override;
void ShipToFlush(
const std::shared_ptr<InodeWrapper> &inodeWrapper) override;
void FlushAll() override;
void FlushInodeOnce() override;
void ReleaseCache(uint64_t parentId) override;
void RemoveICache(const std::shared_ptr<InodeWrapper> &inode);
void AddOpenedInode(uint64_t inodeId) override;
void RemoveOpenedInode(uint64_t inodeId) override;
bool NeedUseCache(uint64_t inodeId,
const std::shared_ptr<InodeWrapper> &inodeWrapper,
bool onlyAttr);
bool IsTimeOut(const std::shared_ptr<InodeWrapper> &inodeWrapper) const;
private:
virtual void FlushInodeBackground();
void TrimIcache(uint64_t trimSize);
CURVEFS_ERROR RefreshData(std::shared_ptr<InodeWrapper> &inode, // NOLINT
bool streaming = true);
bool OpenInodeCached(uint64_t inodeId);
private:
std::shared_ptr<MetaServerClient> metaClient_;
std::shared_ptr<LRUCache<uint64_t,
std::shared_ptr<InodeWrapper>>> iCache_;
std::shared_ptr<S3ChunkInfoMetric> s3ChunkInfoMetric_;
std::shared_ptr<InodeAttrCache> iAttrCache_;
std::shared_ptr<OpenFiles> openFiles_;
// dirty map, key is inodeid
std::map<uint64_t, std::shared_ptr<InodeWrapper>> dirtyMap_;
curve::common::Mutex dirtyMapMutex_;
// record opened inode
std::multiset<uint64_t> openedInodes_;
curve::common::Mutex openInodesMutex_;
std::shared_ptr<DeferSync> deferSync_;
curve::common::GenericNameLock<Mutex> nameLock_;
curve::common::GenericNameLock<Mutex> asyncNameLock_;
uint64_t maxCacheSize_;
RefreshDataOption option_;
uint32_t flushPeriodSec_;
Thread flushThread_;
InterruptibleSleeper sleeper_;
Atomic<bool> isStop_;
// cache timeout seconds, 0 means never timeout
uint32_t cacheTimeOutSec_;
};
class BatchGetInodeAttrAsyncDone : public BatchGetInodeAttrDone {
public:
BatchGetInodeAttrAsyncDone(
const std::shared_ptr<InodeCacheManager> &inodeCacheManager,
std::shared_ptr<CountDownEvent> cond,
uint64_t parentId):
inodeCacheManager_(inodeCacheManager),
cond_(cond),
parentId_(parentId) {}
BatchGetInodeAttrAsyncDone(std::map<uint64_t, InodeAttr>* attrs,
::curve::common::Mutex* mutex,
std::shared_ptr<CountDownEvent> cond):
attrs_(attrs),
mutex_(mutex),
cond_(cond) {}
~BatchGetInodeAttrAsyncDone() {}
void Run() override {
@ -342,22 +197,25 @@ class BatchGetInodeAttrAsyncDone : public BatchGetInodeAttrDone {
MetaStatusCode ret = GetStatusCode();
if (ret != MetaStatusCode::OK) {
LOG(ERROR) << "BatchGetInodeAttrAsync failed, "
<< "parentId = " << parentId_
<< ", MetaStatusCode: " << ret
<< ", MetaStatusCode_Name: " << MetaStatusCode_Name(ret);
} else {
auto inodeAttrs = GetInodeAttrs();
VLOG(3) << "BatchGetInodeAttrAsyncDone update inodeAttrCache"
<< " size = " << inodeAttrs.size();
inodeCacheManager_->AddInodeAttrs(parentId_, inodeAttrs);
curve::common::LockGuard lk(*mutex_);
for (const auto& attr : inodeAttrs) {
attrs_->emplace(attr.inodeid(), attr);
}
}
cond_->Signal();
};
private:
std::shared_ptr<InodeCacheManager> inodeCacheManager_;
::curve::common::Mutex* mutex_;
std::map<uint64_t, InodeAttr>* attrs_;
std::shared_ptr<CountDownEvent> cond_;
uint64_t parentId_;
};
} // namespace client

View File

@ -33,7 +33,6 @@
#include "curvefs/proto/metaserver.pb.h"
#include "curvefs/src/client/async_request_closure.h"
#include "curvefs/src/client/error_code.h"
#include "curvefs/src/client/rpcclient/metaserver_client.h"
#include "curvefs/src/client/rpcclient/task_excutor.h"
#include "curvefs/src/client/xattr_manager.h"
@ -47,6 +46,7 @@ namespace client {
using rpcclient::MetaServerClient;
using rpcclient::MetaServerClientImpl;
using rpcclient::DataIndices;
using ::curvefs::client::filesystem::ToFSError;
bvar::Adder<int64_t> g_alive_inode_count{"alive_inode_count"};
@ -193,7 +193,7 @@ CURVEFS_ERROR InodeWrapper::SyncAttr(bool internal) {
<< "MetaStatusCode: " << ret
<< ", MetaStatusCode_Name: " << MetaStatusCode_Name(ret)
<< ", inodeid: " << inode_.inodeid();
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
dirty_ = false;
@ -213,7 +213,7 @@ CURVEFS_ERROR InodeWrapper::SyncS3ChunkInfo(bool internal) {
<< "MetaStatusCode: " << ret
<< ", MetaStatusCode_Name: " << MetaStatusCode_Name(ret)
<< ", inodeid: " << inode_.inodeid();
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
ClearS3ChunkInfoAdd();
}
@ -294,7 +294,7 @@ CURVEFS_ERROR InodeWrapper::RefreshS3ChunkInfo() {
<< "MetaStatusCode: " << ret
<< ", MetaStatusCode_Name: " << MetaStatusCode_Name(ret)
<< ", inodeid: " << inode_.inodeid();
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
auto before = s3ChunkInfoSize_;
inode_.mutable_s3chunkinfomap()->swap(s3ChunkInfoMap);
@ -328,7 +328,7 @@ CURVEFS_ERROR InodeWrapper::Link(uint64_t parent) {
<<", MetaStatusCode = " << ret
<< ", MetaStatusCode_Name = " << MetaStatusCode_Name(ret)
<< ", inodeid = " << inode_.inodeid();
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
dirty_ = false;
@ -396,7 +396,7 @@ CURVEFS_ERROR InodeWrapper::UnLink(uint64_t parent) {
<< ", MetaStatusCode = " << ret
<< ", MetaStatusCode_Name = " << MetaStatusCode_Name(ret)
<< ", inodeid = " << inode_.inodeid();
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
dirty_ = false;
dirtyAttr_.Clear();
@ -427,7 +427,7 @@ CURVEFS_ERROR InodeWrapper::UpdateParent(
<< ", MetaStatusCode = " << ret
<< ", MetaStatusCode_Name = " << MetaStatusCode_Name(ret)
<< ", inodeid = " << inode_.inodeid();
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
dirty_ = false;
dirtyAttr_.Clear();
@ -514,7 +514,7 @@ CURVEFS_ERROR InodeWrapper::SyncS3(bool internal) {
<< "MetaStatusCode: " << ret
<< ", MetaStatusCode_Name: " << MetaStatusCode_Name(ret)
<< ", inodeid: " << inode_.inodeid();
return MetaStatusCodeToCurvefsErrCode(ret);
return ToFSError(ret);
}
ClearS3ChunkInfoAdd();
dirty_ = false;
@ -583,7 +583,7 @@ void InodeWrapper::AsyncS3(MetaServerClientDone *done, bool internal) {
}
CURVEFS_ERROR InodeWrapper::RefreshVolumeExtent() {
VolumeExtentSliceList extents;
VolumeExtentList extents;
auto st = metaClient_->GetVolumeExtent(inode_.fsid(), inode_.inodeid(),
true, &extents);
VLOG(9) << "RefreshVolumeExtent, ino: " << inode_.inodeid()
@ -597,7 +597,7 @@ CURVEFS_ERROR InodeWrapper::RefreshVolumeExtent() {
LOG(ERROR) << "GetVolumeExtent failed, inodeid: " << inode_.inodeid();
}
return MetaStatusCodeToCurvefsErrCode(st);
return ToFSError(st);
}
CURVEFS_ERROR InodeWrapper::RefreshNlink() {

View File

@ -34,12 +34,12 @@
#include "curvefs/src/common/define.h"
#include "curvefs/proto/metaserver.pb.h"
#include "curvefs/src/client/error_code.h"
#include "curvefs/src/client/rpcclient/metaserver_client.h"
#include "src/common/concurrent/concurrent.h"
#include "curvefs/src/client/volume/extent_cache.h"
#include "curvefs/src/client/metric/client_metric.h"
#include "src/common/timeutility.h"
#include "curvefs/src/client/filesystem/error.h"
using ::curvefs::metaserver::Inode;
using ::curvefs::metaserver::S3ChunkInfoList;
@ -52,16 +52,14 @@ constexpr int kAccessTime = 1 << 0;
constexpr int kChangeTime = 1 << 1;
constexpr int kModifyTime = 1 << 2;
using ::curvefs::metaserver::VolumeExtentSliceList;
using ::curvefs::metaserver::VolumeExtentList;
using ::curvefs::client::filesystem::CURVEFS_ERROR;
enum class InodeStatus {
kNormal = 0,
kError = -1,
};
// TODO(xuchaojie) : get from conf maybe?
const uint32_t kOptimalIOBlockSize = 0x10000u;
using rpcclient::MetaServerClient;
using rpcclient::MetaServerClientImpl;
using rpcclient::MetaServerClientDone;

View File

@ -41,7 +41,7 @@ LeaseExecutor::~LeaseExecutor() {
bool LeaseExecutor::Start() {
if (opt_.leaseTimeUs <= 0 || opt_.refreshTimesPerLease <= 0) {
LOG(ERROR) << "LeaseExecutor start fail. Invalid param in leaseopt, "
"leasTimesUs = "
"leaseTimeUs = "
<< opt_.leaseTimeUs
<< ", refreshTimePerLease = " << opt_.refreshTimesPerLease;
return false;
@ -78,7 +78,8 @@ bool LeaseExecutor::RefreshLease() {
// refresh from mds
std::vector<PartitionTxId> latestTxIdList;
FSStatusCode ret = mdsCli_->RefreshSession(txIds, &latestTxIdList,
fsName_, mountpoint_);
fsName_, mountpoint_,
enableSumInDir_);
if (ret != FSStatusCode::OK) {
LOG(ERROR) << "LeaseExecutor refresh session fail, ret = " << ret
<< ", errorName = " << FSStatusCode_Name(ret);

View File

@ -25,6 +25,7 @@
#include <memory>
#include <string>
#include <atomic>
#include "curvefs/src/client/rpcclient/metacache.h"
#include "curvefs/src/client/rpcclient/mds_client.h"
@ -44,8 +45,10 @@ namespace client {
class LeaseExecutor : public LeaseExecutorBase {
public:
LeaseExecutor(const LeaseOpt &opt, std::shared_ptr<MetaCache> metaCache,
std::shared_ptr<MdsClient> mdsCli)
: opt_(opt), metaCache_(metaCache), mdsCli_(mdsCli) {}
std::shared_ptr<MdsClient> mdsCli,
std::atomic<bool>* enableSumInDir)
: opt_(opt), metaCache_(metaCache), mdsCli_(mdsCli),
enableSumInDir_(enableSumInDir) {}
~LeaseExecutor();
@ -73,6 +76,7 @@ class LeaseExecutor : public LeaseExecutorBase {
std::unique_ptr<RefreshSessionTask> task_;
std::string fsName_;
Mountpoint mountpoint_;
std::atomic<bool>* enableSumInDir_;
};
} // namespace client

View File

@ -51,13 +51,11 @@ static const struct fuse_lowlevel_ops curve_ll_oper = {
release : FuseOpRelease,
fsync : FuseOpFsync,
opendir : FuseOpOpenDir,
// TODO(wuhongsong): readdirplus is problematic,
// resulting in inconsistent metadata
// #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
// readdir : 0,
// #else
#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
readdir : 0,
#else
readdir : FuseOpReadDir,
// #endif
#endif
releasedir : FuseOpReleaseDir,
fsyncdir : 0,
statfs : FuseOpStatFs,
@ -81,11 +79,11 @@ static const struct fuse_lowlevel_ops curve_ll_oper = {
flock : 0,
fallocate : 0,
#endif
// TODO(wuhongsong): The current implementation is problematic,
// resulting in inconsistent metadata
// #if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
readdirplus : FuseOpReadDirPlus,
#else
readdirplus : 0,
// #endif
#endif
#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 4)
copy_file_range : 0,
#endif
@ -222,8 +220,8 @@ int main(int argc, char *argv[]) {
fuse_daemonize(opts.foreground);
if (InitGlog(mOpts.conf, argv[0]) < 0) {
printf("Init glog failed, confpath = %s\n", mOpts.conf);
if (InitLog(mOpts.conf, argv[0]) < 0) {
printf("Init log failed, confpath = %s\n", mOpts.conf);
}
ret = InitFuseClient(&mOpts);

View File

@ -92,12 +92,13 @@ struct MetaServerClientMetric {
// volume extent
InterfaceMetric updateVolumeExtent;
InterfaceMetric getVolumeExtent;
InterfaceMetric updateDeallocatableBlockGroup;
MetaServerClientMetric()
: getDentry(prefix, "getDentry"), listDentry(prefix, "listDentry"),
: getDentry(prefix, "getDentry"),
listDentry(prefix, "listDentry"),
createDentry(prefix, "createDentry"),
deleteDentry(prefix, "deleteDentry"), getInode(prefix, "getInode"),
deleteDentry(prefix, "deleteDentry"),
getInode(prefix, "getInode"),
batchGetInodeAttr(prefix, "batchGetInodeAttr"),
batchGetXattr(prefix, "batchGetXattr"),
createInode(prefix, "createInode"),
@ -106,9 +107,7 @@ struct MetaServerClientMetric {
appendS3ChunkInfo(prefix, "appendS3ChunkInfo"),
prepareRenameTx(prefix, "prepareRenameTx"),
updateVolumeExtent(prefix, "updateVolumeExtent"),
getVolumeExtent(prefix, "getVolumeExtent"),
updateDeallocatableBlockGroup(prefix,
"updateDeallocatableBlockGroup") {}
getVolumeExtent(prefix, "getVolumeExtent") {}
};
struct InflightGuard {

View File

@ -501,7 +501,8 @@ FSStatusCode
MdsClientImpl::RefreshSession(const std::vector<PartitionTxId> &txIds,
std::vector<PartitionTxId> *latestTxIdList,
const std::string& fsName,
const Mountpoint& mountpoint) {
const Mountpoint& mountpoint,
std::atomic<bool>* enableSumInDir) {
auto task = RPCTask {
(void)addrindex;
(void)rpctimeoutMS;
@ -532,6 +533,11 @@ MdsClientImpl::RefreshSession(const std::vector<PartitionTxId> &txIds,
LOG(INFO) << "RefreshSession need update partition txid list: "
<< response.DebugString();
}
if (enableSumInDir->load() && !response.enablesumindir()) {
enableSumInDir->store(response.enablesumindir());
LOG(INFO) << "update enableSumInDir to "
<< response.enablesumindir();
}
return ret;
};

View File

@ -26,6 +26,7 @@
#include <memory>
#include <string>
#include <vector>
#include <atomic>
#include "curvefs/proto/mds.pb.h"
#include "curvefs/proto/topology.pb.h"
@ -115,7 +116,8 @@ class MdsClient {
RefreshSession(const std::vector<PartitionTxId> &txIds,
std::vector<PartitionTxId> *latestTxIdList,
const std::string& fsName,
const Mountpoint& mountpoint) = 0;
const Mountpoint& mountpoint,
std::atomic<bool>* enableSumInDir) = 0;
virtual FSStatusCode GetLatestTxId(uint32_t fsId,
std::vector<PartitionTxId>* txIds) = 0;
@ -202,7 +204,8 @@ class MdsClientImpl : public MdsClient {
FSStatusCode RefreshSession(const std::vector<PartitionTxId> &txIds,
std::vector<PartitionTxId> *latestTxIdList,
const std::string& fsName,
const Mountpoint& mountpoint) override;
const Mountpoint& mountpoint,
std::atomic<bool>* enableSumInDir) override;
FSStatusCode GetLatestTxId(uint32_t fsId,
std::vector<PartitionTxId>* txIds) override;

View File

@ -65,7 +65,6 @@ using BatchGetXAttrExcutor = TaskExecutor;
using GetOrModifyS3ChunkInfoExcutor = TaskExecutor;
using UpdateVolumeExtentExecutor = TaskExecutor;
using GetVolumeExtentExecutor = TaskExecutor;
using UpdateDeallocatableBlockGroupExcutor = TaskExecutor;
using ::curvefs::common::LatencyUpdater;
using ::curvefs::common::StreamConnection;
@ -1466,7 +1465,7 @@ void UpdateVolumeExtentRpcDone::Run() {
} while (0)
void MetaServerClientImpl::AsyncUpdateVolumeExtent(
uint32_t fsId, uint64_t inodeId, const VolumeExtentSliceList &extents,
uint32_t fsId, uint64_t inodeId, const VolumeExtentList &extents,
MetaServerClientDone *done) {
auto task = AsyncRPCTask {
(void)txId;
@ -1474,7 +1473,7 @@ void MetaServerClientImpl::AsyncUpdateVolumeExtent(
metric_.updateVolumeExtent.qps.count << 1;
metaserver::UpdateVolumeExtentRequest request;
SET_COMMON_FIELDS;
request.set_allocated_extents(new VolumeExtentSliceList{extents});
request.set_allocated_extents(new VolumeExtentList{extents});
auto *rpcDone =
new UpdateVolumeExtentRpcDone(taskExecutorDone, &metric_);
@ -1494,8 +1493,7 @@ void MetaServerClientImpl::AsyncUpdateVolumeExtent(
namespace {
struct ParseVolumeExtentCallBack {
explicit ParseVolumeExtentCallBack(VolumeExtentSliceList *ext)
: extents(ext) {}
explicit ParseVolumeExtentCallBack(VolumeExtentList *ext) : extents(ext) {}
bool operator()(butil::IOBuf *data) const {
metaserver::VolumeExtentSlice slice;
@ -1508,7 +1506,7 @@ struct ParseVolumeExtentCallBack {
return true;
}
VolumeExtentSliceList *extents;
VolumeExtentList *extents;
};
} // namespace
@ -1516,7 +1514,7 @@ struct ParseVolumeExtentCallBack {
MetaStatusCode
MetaServerClientImpl::GetVolumeExtent(uint32_t fsId, uint64_t inodeId,
bool streaming,
VolumeExtentSliceList *extents) {
VolumeExtentList *extents) {
auto task = RPCTask {
(void)txId;
(void)applyIndex;
@ -1598,66 +1596,9 @@ MetaServerClientImpl::GetVolumeExtent(uint32_t fsId, uint64_t inodeId,
return ConvertToMetaStatusCode(executor.DoRPCTask());
}
MetaStatusCode MetaServerClientImpl::UpdateDeallocatableBlockGroup(
uint32_t fsId, uint64_t inodeId, DeallocatableBlockGroupMap *statistic) {
auto task = RPCTask {
metric_.updateDeallocatableBlockGroup.qps.count << 1;
LatencyUpdater updater(&metric_.updateDeallocatableBlockGroup.latency);
metaserver::UpdateDeallocatableBlockGroupRequest request;
metaserver::UpdateDeallocatableBlockGroupResponse response;
request.set_poolid(poolID);
request.set_copysetid(copysetID);
request.set_partitionid(partitionID);
request.set_fsid(fsId);
auto *upadte = request.mutable_update();
for (auto &it : *statistic) {
upadte->Add()->CopyFrom(std::move(it.second));
}
curvefs::metaserver::MetaServerService_Stub stub(channel);
stub.UpdateDeallocatableBlockGroup(cntl, &request, &response, nullptr);
if (cntl->Failed()) {
metric_.updateDeallocatableBlockGroup.eps.count << 1;
LOG(WARNING) << "UpdateDeallocatableBlockGroup failed"
<< ", errorCode = " << cntl->ErrorCode()
<< ", errorText = " << cntl->ErrorText()
<< ", logId = " << cntl->log_id();
return -cntl->ErrorCode();
}
auto rc = response.statuscode();
if (rc != MetaStatusCode::OK) {
metric_.updateDeallocatableBlockGroup.eps.count << 1;
LOG(WARNING) << "UpdateDeallocatableBlockGroup: retCode = " << rc
<< ", message = " << MetaStatusCode_Name(rc);
} else if (response.has_appliedindex()) {
metaCache_->UpdateApplyIndex(CopysetGroupID(poolID, copysetID),
response.appliedindex());
} else {
LOG(WARNING) << "UpdateDeallocatableBlockGroup OK"
<< ", but applyIndex not set in response:"
<< response.DebugString();
return -1;
}
VLOG(6) << "UpdateDeallocatableBlockGroup done, request: "
<< request.DebugString()
<< "response: " << response.DebugString();
return rc;
};
auto taskCtx = std::make_shared<TaskContext>(
MetaServerOpType::UpdateDeallocatableBlockGroup, task, fsId, inodeId);
UpdateDeallocatableBlockGroupExcutor excutor(
opt_, metaCache_, channelManager_, std::move(taskCtx));
return ConvertToMetaStatusCode(excutor.DoRPCTask());
}
MetaStatusCode MetaServerClientImpl::GetInodeAttr(
uint32_t fsId, uint64_t inodeid, InodeAttr *attr) {
MetaStatusCode MetaServerClientImpl::GetInodeAttr(uint32_t fsId,
uint64_t inodeid,
InodeAttr *attr) {
std::set<uint64_t> inodeIds;
inodeIds.insert(inodeid);
std::list<InodeAttr> attrs;

View File

@ -30,7 +30,6 @@
#include <set>
#include <unordered_map>
#include <utility>
#include <map>
#include "curvefs/proto/common.pb.h"
#include "curvefs/proto/metaserver.pb.h"
@ -50,24 +49,21 @@ using ::curvefs::metaserver::InodeAttr;
using ::curvefs::metaserver::XAttr;
using ::curvefs::metaserver::MetaStatusCode;
using ::curvefs::metaserver::S3ChunkInfoList;
using ::curvefs::metaserver::DeallocatableBlockGroup;
using ::curvefs::common::StreamStatus;
using ::curvefs::common::StreamClient;
using ::curvefs::metaserver::Time;
using DeallocatableBlockGroupMap = std::map<uint64_t, DeallocatableBlockGroup>;
using S3ChunkInfoMap = google::protobuf::Map<uint64_t, S3ChunkInfoList>;
using ::curvefs::metaserver::Time;
namespace curvefs {
namespace client {
namespace rpcclient {
using S3ChunkInfoMap = google::protobuf::Map<uint64_t, S3ChunkInfoList>;
using ::curvefs::metaserver::VolumeExtentSliceList;
using ::curvefs::metaserver::VolumeExtentList;
struct DataIndices {
absl::optional<S3ChunkInfoMap> s3ChunkInfoMap;
absl::optional<VolumeExtentSliceList> volumeExtents;
absl::optional<VolumeExtentList> volumeExtents;
};
class MetaServerClient {
@ -165,17 +161,13 @@ class MetaServerClient {
virtual void AsyncUpdateVolumeExtent(uint32_t fsId,
uint64_t inodeId,
const VolumeExtentSliceList &extents,
const VolumeExtentList &extents,
MetaServerClientDone *done) = 0;
virtual MetaStatusCode GetVolumeExtent(uint32_t fsId,
uint64_t inodeId,
bool streaming,
VolumeExtentSliceList *extents) = 0;
virtual MetaStatusCode
UpdateDeallocatableBlockGroup(uint32_t fsId, uint64_t inodeId,
DeallocatableBlockGroupMap *statistic) = 0;
VolumeExtentList *extents) = 0;
};
class MetaServerClientImpl : public MetaServerClient {
@ -273,17 +265,13 @@ class MetaServerClientImpl : public MetaServerClient {
void AsyncUpdateVolumeExtent(uint32_t fsId,
uint64_t inodeId,
const VolumeExtentSliceList &extents,
const VolumeExtentList &extents,
MetaServerClientDone *done) override;
MetaStatusCode GetVolumeExtent(uint32_t fsId,
uint64_t inodeId,
bool streaming,
VolumeExtentSliceList *extents) override;
MetaStatusCode UpdateDeallocatableBlockGroup(
uint32_t fsId, uint64_t inodeId,
DeallocatableBlockGroupMap *statistic) override;
VolumeExtentList *extents) override;
private:
MetaStatusCode UpdateInode(const UpdateInodeRequest &request,

View File

@ -42,7 +42,6 @@ S3ClientAdaptorImpl::Init(
std::shared_ptr<DiskCacheManagerImpl> diskCacheManagerImpl,
std::shared_ptr<KVClientManager> kvClientManager,
bool startBackGround) {
pendingReq_ = 0;
blockSize_ = option.blockSize;
chunkSize_ = option.chunkSize;
pageSize_ = option.pageSize;
@ -52,7 +51,6 @@ S3ClientAdaptorImpl::Init(
<< blockSize_;
return CURVEFS_ERROR::INVALIDPARAM;
}
fuseMaxSize_ = option.fuseMaxSize;
prefetchBlocks_ = option.prefetchBlocks;
prefetchExecQueueNum_ = option.prefetchExecQueueNum;
diskCacheType_ = option.diskCacheOpt.diskCacheType;
@ -113,30 +111,25 @@ int S3ClientAdaptorImpl::Write(uint64_t inodeId, uint64_t offset,
VLOG(6) << "write start offset:" << offset << ", len:" << length
<< ", fsId:" << fsId_ << ", inodeId:" << inodeId;
uint64_t start = butil::cpuwide_time_us();
FileCacheManagerPtr fileCacheManager =
fsCacheManager_->FindOrCreateFileCacheManager(fsId_, inodeId);
{
std::lock_guard<std::mutex> lockguard(ioMtx_);
pendingReq_.fetch_add(1, std::memory_order_seq_cst);
VLOG(6) << "pendingReq_ is: " << pendingReq_;
uint64_t pendingReq = pendingReq_.load(std::memory_order_seq_cst);
std::lock_guard<std::mutex> lockGuard(ioMtx_);
fsCacheManager_->DataCacheByteInc(length);
uint64_t size = fsCacheManager_->GetDataCacheSize();
uint64_t maxSize = fsCacheManager_->GetDataCacheMaxSize();
if ((size + pendingReq * fuseMaxSize_) >= maxSize) {
const uint64_t maxSize = fsCacheManager_->GetDataCacheMaxSize();
if (size >= maxSize) {
VLOG(6) << "write cache is full, wait flush. size: " << size
<< ", maxSize:" << maxSize;
<< ", maxSize: " << maxSize;
// offer to do flush
waitInterval_.StopWait();
fsCacheManager_->WaitFlush();
}
}
uint64_t memCacheRatio = fsCacheManager_->MemCacheRatio();
const uint64_t memCacheRatio = fsCacheManager_->MemCacheRatio();
int64_t exceedRatio = memCacheRatio - memCacheNearfullRatio_;
if (exceedRatio > 0) {
// offer to do flush
waitInterval_.StopWait();
// upload to s3 derectly or cache disk full
// upload to s3 directly or cache disk full
bool needSleep =
(DisableDiskCache() || IsReadCache()) ||
(IsReadWriteCache() && diskCacheManagerImpl_->IsDiskCacheFull());
@ -147,15 +140,15 @@ int S3ClientAdaptorImpl::Write(uint64_t inodeId, uint64_t offset,
<< memCacheRatio << ", exponent is: " << exponent;
}
}
FileCacheManagerPtr fileCacheManager =
fsCacheManager_->FindOrCreateFileCacheManager(fsId_, inodeId);
int ret = fileCacheManager->Write(offset, length, buf);
pendingReq_.fetch_sub(1, std::memory_order_seq_cst);
fsCacheManager_->DataCacheByteDec(length);
if (s3Metric_.get() != nullptr) {
if (s3Metric_ != nullptr) {
CollectMetrics(&s3Metric_->adaptorWrite, ret, start);
s3Metric_->writeSize.set_value(length);
}
VLOG(6) << "write end inodeId:" << inodeId << ",ret:" << ret
<< ", pendingReq_ is: " << pendingReq_;
VLOG(6) << "write end inodeId: " << inodeId << ", ret: " << ret;
return ret;
}

View File

@ -33,7 +33,7 @@
#include "curvefs/proto/metaserver.pb.h"
#include "curvefs/src/client/common/common.h"
#include "curvefs/src/client/common/config.h"
#include "curvefs/src/client/error_code.h"
#include "curvefs/src/client/filesystem/error.h"
#include "curvefs/src/client/inode_cache_manager.h"
#include "curvefs/src/client/rpcclient/mds_client.h"
#include "curvefs/src/client/s3/client_s3.h"
@ -249,7 +249,6 @@ class S3ClientAdaptorImpl : public S3ClientAdaptor {
std::shared_ptr<S3Client> client_;
uint64_t blockSize_;
uint64_t chunkSize_;
uint32_t fuseMaxSize_;
uint32_t prefetchBlocks_;
uint32_t prefetchExecQueueNum_;
std::string allocateServerEps_;
@ -270,7 +269,6 @@ class S3ClientAdaptorImpl : public S3ClientAdaptor {
std::shared_ptr<InodeCacheManager> inodeManager_;
std::shared_ptr<DiskCacheManagerImpl> diskCacheManagerImpl_;
DiskCacheType diskCacheType_;
std::atomic<uint64_t> pendingReq_;
std::shared_ptr<MdsClient> mdsClient_;
uint32_t fsId_;
std::string fsName_;

View File

@ -34,7 +34,7 @@
#include <set>
#include "curvefs/proto/metaserver.pb.h"
#include "curvefs/src/client/error_code.h"
#include "curvefs/src/client/filesystem/error.h"
#include "curvefs/src/client/s3/client_s3.h"
#include "src/common/concurrent/concurrent.h"
#include "src/common/concurrent/task_thread_pool.h"

View File

@ -30,7 +30,7 @@
#include <vector>
#include "absl/meta/type_traits.h"
#include "curvefs/src/client/error_code.h"
#include "curvefs/src/client/filesystem/error.h"
#include "curvefs/src/client/inode_cache_manager.h"
#include "curvefs/src/client/inode_wrapper.h"
#include "curvefs/src/client/volume/extent_cache.h"
@ -74,7 +74,8 @@ std::ostream& operator<<(std::ostream& os, const std::vector<IOPart>& iov) {
CURVEFS_ERROR DefaultVolumeStorage::Write(uint64_t ino,
off_t offset,
size_t len,
const char* data) {
const char* data,
FileOut* fileOut) {
std::shared_ptr<InodeWrapper> inodeWrapper;
LatencyUpdater updater(&metric_.writeLatency);
auto ret = inodeCacheManager_->GetInode(ino, inodeWrapper);
@ -116,6 +117,7 @@ CURVEFS_ERROR DefaultVolumeStorage::Write(uint64_t ino,
}
inodeWrapper->UpdateTimestampLocked(kModifyTime | kChangeTime);
inodeWrapper->GetInodeAttrLocked(&fileOut->attr);
}
inodeCacheManager_->ShipToFlush(inodeWrapper);

View File

@ -31,12 +31,16 @@
#include "curvefs/src/client/volume/volume_storage.h"
#include "curvefs/src/volume/block_device_client.h"
#include "curvefs/src/volume/space_manager.h"
#include "curvefs/src/client/filesystem/error.h"
#include "curvefs/src/client/filesystem/meta.h"
namespace curvefs {
namespace client {
using ::curvefs::volume::BlockDeviceClient;
using ::curvefs::volume::SpaceManager;
using ::curvefs::client::filesystem::CURVEFS_ERROR;
using ::curvefs::client::filesystem::FileOut;
class InodeCacheManager;
@ -66,7 +70,8 @@ class DefaultVolumeStorage final : public VolumeStorage {
CURVEFS_ERROR Write(uint64_t ino,
off_t offset,
size_t len,
const char* data) override;
const char* data,
FileOut* fileOut) override;
CURVEFS_ERROR Flush(uint64_t ino) override;

View File

@ -228,7 +228,7 @@ void ExtentCache::SetOption(const ExtentCacheOption& option) {
LOG(INFO) << "ExtentCacheOption: [" << option_ << "]";
}
void ExtentCache::Build(const VolumeExtentSliceList &extents) {
void ExtentCache::Build(const VolumeExtentList &extents) {
WriteLockGuard lk(lock_);
slices_.clear();
dirties_.clear();
@ -238,8 +238,8 @@ void ExtentCache::Build(const VolumeExtentSliceList &extents) {
}
}
VolumeExtentSliceList ExtentCache::GetDirtyExtents() {
VolumeExtentSliceList result;
VolumeExtentList ExtentCache::GetDirtyExtents() {
VolumeExtentList result;
WriteLockGuard lk(lock_);
for (const auto* slice : dirties_) {
*result.add_slices() = slice->ToVolumeExtentSlice();

View File

@ -43,7 +43,7 @@ namespace client {
using ::curvefs::volume::ReadPart;
using ::curvefs::volume::WritePart;
using ::curvefs::metaserver::VolumeExtentSlice;
using ::curvefs::metaserver::VolumeExtentSliceList;
using ::curvefs::metaserver::VolumeExtentList;
struct ExtentCacheOption {
// preallocation size if offset ~ length is not allocated
@ -61,7 +61,7 @@ class ExtentCache {
static void SetOption(const ExtentCacheOption& option);
void Build(const VolumeExtentSliceList& extents);
void Build(const VolumeExtentList& extents);
void DivideForWrite(uint64_t offset,
uint64_t len,
@ -81,7 +81,7 @@ class ExtentCache {
bool HasDirtyExtents() const;
VolumeExtentSliceList GetDirtyExtents();
VolumeExtentList GetDirtyExtents();
std::unordered_map<uint64_t, std::map<uint64_t, PExtent>>
GetExtentsForTesting() const;

View File

@ -28,11 +28,15 @@
#include <cstddef>
#include <cstdint>
#include "curvefs/src/client/error_code.h"
#include "curvefs/src/client/filesystem/error.h"
#include "curvefs/src/client/filesystem/meta.h"
namespace curvefs {
namespace client {
using ::curvefs::client::filesystem::CURVEFS_ERROR;
using ::curvefs::client::filesystem::FileOut;
class VolumeStorage {
public:
virtual ~VolumeStorage() = default;
@ -45,7 +49,8 @@ class VolumeStorage {
virtual CURVEFS_ERROR Write(uint64_t ino,
off_t offset,
size_t len,
const char* data) = 0;
const char* data,
FileOut* fileOut) = 0;
virtual CURVEFS_ERROR Flush(uint64_t ino) = 0;

View File

@ -473,7 +473,7 @@ void WarmupManagerS3Impl::WarmUpAllObjs(
}
if (context->retCode == 0) {
VLOG(9) << "Get Object success: " << context->key;
PutObjectToCache(key, context->key, context->buf, context->len);
PutObjectToCache(key, context);
CollectMetrics(&warmupS3Metric_.warmupS3Cached, context->len,
start);
warmupS3Metric_.warmupS3CacheSize << context->len;
@ -481,7 +481,6 @@ void WarmupManagerS3Impl::WarmUpAllObjs(
VLOG(6) << "pendingReq is over";
cond.Signal();
}
delete[] context->buf;
return;
}
warmupS3Metric_.warmupS3Cached.eps.count << 1;
@ -678,9 +677,8 @@ void WarmupManagerS3Impl::AddFetchS3objectsTask(fuse_ino_t key,
}
}
void WarmupManagerS3Impl::PutObjectToCache(fuse_ino_t key,
const std::string &filename,
const char *data, uint64_t len) {
void WarmupManagerS3Impl::PutObjectToCache(
fuse_ino_t key, const std::shared_ptr<GetObjectAsyncContext> &context) {
ReadLockGuard lock(inode2ProgressMutex_);
auto iter = FindWarmupProgressByKeyLocked(key);
if (iter == inode2Progress_.end()) {
@ -692,17 +690,21 @@ void WarmupManagerS3Impl::PutObjectToCache(fuse_ino_t key,
iter->second.FinishedPlusOne();
switch (iter->second.GetStorageType()) {
case curvefs::client::common::WarmupStorageType::kWarmupStorageTypeDisk:
ret = s3Adaptor_->GetDiskCacheManager()->WriteReadDirect(filename, data,
len);
ret = s3Adaptor_->GetDiskCacheManager()->WriteReadDirect(
context->key, context->buf, context->len);
if (ret < 0) {
LOG_EVERY_SECOND(INFO)
<< "write read directly failed, key: " << filename;
<< "write read directly failed, key: " << context->key;
}
delete[] context->buf;
break;
case curvefs::client::common::WarmupStorageType::kWarmupStorageTypeKvClient:
if (kvClientManager_ != nullptr) {
kvClientManager_->Set(
std::make_shared<SetKVCacheTask>(filename, data, len));
kvClientManager_->Set(std::make_shared<SetKVCacheTask>(
context->key, context->buf, context->len,
[context](const std::shared_ptr<SetKVCacheTask> &) {
delete[] context->buf;
}));
}
break;
default:

View File

@ -413,8 +413,9 @@ class WarmupManagerS3Impl : public WarmupManager {
void AddFetchS3objectsTask(fuse_ino_t key, std::function<void()> task);
void PutObjectToCache(fuse_ino_t key, const std::string &filename,
const char *data, uint64_t len);
void
PutObjectToCache(fuse_ino_t key,
const std::shared_ptr<GetObjectAsyncContext> &context);
protected:
std::deque<WarmupFilelist> warmupFilelistDeque_;

View File

@ -78,20 +78,14 @@ CURVEFS_ERROR XattrManager::CalOneLayerSumInfo(InodeAttr *attr) {
summaryInfo.entries++;
summaryInfo.fbytes += it.length();
}
if (!(AddUllStringToFirst(
&(attr->mutable_xattr()->find(XATTRFILES)->second),
summaryInfo.files, true) &&
AddUllStringToFirst(
&(attr->mutable_xattr()->find(XATTRSUBDIRS)->second),
summaryInfo.subdirs, true) &&
AddUllStringToFirst(
&(attr->mutable_xattr()->find(XATTRENTRIES)->second),
summaryInfo.entries, true) &&
AddUllStringToFirst(
&(attr->mutable_xattr()->find(XATTRFBYTES)->second),
summaryInfo.fbytes + attr->length(), true))) {
ret = CURVEFS_ERROR::INTERNAL;
}
(*attr->mutable_xattr())[XATTRFILES] =
std::to_string(summaryInfo.files);
(*attr->mutable_xattr())[XATTRSUBDIRS] =
std::to_string(summaryInfo.subdirs);
(*attr->mutable_xattr())[XATTRENTRIES] =
std::to_string(summaryInfo.entries);
(*attr->mutable_xattr())[XATTRFBYTES] =
std::to_string(summaryInfo.fbytes + attr->length());
}
return ret;
}

View File

@ -36,7 +36,7 @@
#include "curvefs/src/common/define.h"
#include "curvefs/proto/metaserver.pb.h"
#include "curvefs/src/client/error_code.h"
#include "curvefs/src/client/filesystem/error.h"
#include "curvefs/src/client/client_operator.h"
#include "src/common/interruptible_sleeper.h"

View File

@ -113,6 +113,10 @@ void FsInfoWrapper::AddMountPoint(const Mountpoint& mp) {
*p = mp;
fsInfo_.set_mountnum(fsInfo_.mountnum() + 1);
if (fsInfo_.enablesumindir() && fsInfo_.mountnum() > 1) {
fsInfo_.set_enablesumindir(false);
}
}
FSStatusCode FsInfoWrapper::DeleteMountPoint(const Mountpoint& mp) {

View File

@ -843,6 +843,16 @@ void FsManager::RefreshSession(const RefreshSessionRequest* request,
// update this client's alive time
UpdateClientAliveTime(request->mountpoint(), request->fsname());
FsInfoWrapper wrapper;
FSStatusCode ret = fsStorage_->Get(request->fsname(), &wrapper);
if (ret != FSStatusCode::OK) {
LOG(WARNING) << "GetFsInfo fail, get fs fail, fsName = "
<< request->fsname()
<< ", errCode = " << FSStatusCode_Name(ret);
return;
}
response->set_enablesumindir(wrapper.ProtoFsInfo().enablesumindir());
}
FSStatusCode FsManager::ReloadMountedFsVolumeSpace() {

View File

@ -359,6 +359,15 @@ bool PersisKVStorage::LoadAllFs() {
idToName_.emplace(fsInfo.fsid(), fsInfo.fsname());
// For compatibility when upgrading, the new field 'optional
// objectPrefix` in message `S3Info` needs to be set to the default
// value
if (fsInfo.fstype() == FSType::TYPE_S3) {
if (!fsInfo.detail().s3info().has_objectprefix()) {
fsInfo.mutable_detail()->mutable_s3info()->set_objectprefix(0);
}
}
fs_.emplace(fsInfo.fsname(), std::move(fsInfo));
}

View File

@ -27,7 +27,6 @@ cc_library(
"//curvefs/proto:curvefs_topology_cc_proto",
"//curvefs/proto:metaserver_cc_proto",
"//curvefs/src/mds/topology:curvefs_topology",
"//curvefs/src/mds/space:curvefs_mds_space",
"//external:brpc",
"//external:gflags",
"//external:glog",

View File

@ -42,9 +42,8 @@ namespace mds {
namespace heartbeat {
HeartbeatManager::HeartbeatManager(
const HeartbeatOption &option, const std::shared_ptr<Topology> &topology,
const std::shared_ptr<Coordinator> &coordinator,
const std::shared_ptr<SpaceManager> &spaceManager)
: topology_(topology), spaceManager_(spaceManager) {
const std::shared_ptr<Coordinator> &coordinator)
: topology_(topology) {
healthyChecker_ =
std::make_shared<MetaserverHealthyChecker>(option, topology);
@ -87,6 +86,24 @@ void HeartbeatManager::Stop() {
}
}
void HeartbeatManager::MetaServerHealthyChecker() {
while (sleeper_.wait_for(
std::chrono::milliseconds(metaserverHealthyCheckerRunInter_))) {
healthyChecker_->CheckHeartBeatInterval();
}
}
void HeartbeatManager::UpdateMetaServerSpace(
const MetaServerHeartbeatRequest &request) {
MetaServerSpace space(request.spacestatus());
TopoStatusCode ret =
topology_->UpdateMetaServerSpace(space, request.metaserverid());
if (ret != TopoStatusCode::TOPO_OK) {
LOG(ERROR) << "heartbeat UpdateMetaServerSpace fail, ret = "
<< TopoStatusCode_Name(ret);
}
}
void HeartbeatManager::MetaServerHeartbeat(
const MetaServerHeartbeatRequest &request,
MetaServerHeartbeatResponse *response) {
@ -110,42 +127,6 @@ void HeartbeatManager::MetaServerHeartbeat(
UpdateMetaServerSpace(request);
// dealing with copysets included in the heartbeat request
Coordinate(request, response);
// update deallocatable block group info
UpdateDeallocatableBlockGroup(request, response);
}
void HeartbeatManager::MetaServerHealthyChecker() {
while (sleeper_.wait_for(
std::chrono::milliseconds(metaserverHealthyCheckerRunInter_))) {
healthyChecker_->CheckHeartBeatInterval();
auto metaservers =
topology_->GetMetaServerInCluster([](const MetaServer &ms) {
return ms.GetOnlineState() == OnlineState::ONLINE;
});
uint32_t currentOnlineMetaServerNum =
onlineMetaServerNum_.load(std::memory_order_acquire);
onlineMetaServerNum_.compare_exchange_strong(currentOnlineMetaServerNum,
metaservers.size());
}
}
void HeartbeatManager::UpdateMetaServerSpace(
const MetaServerHeartbeatRequest &request) {
MetaServerSpace space(request.spacestatus());
TopoStatusCode ret =
topology_->UpdateMetaServerSpace(space, request.metaserverid());
if (ret != TopoStatusCode::TOPO_OK) {
LOG(ERROR) << "heartbeat UpdateMetaServerSpace fail, ret = "
<< TopoStatusCode_Name(ret);
}
}
void HeartbeatManager::Coordinate(const MetaServerHeartbeatRequest &request,
MetaServerHeartbeatResponse *response) {
for (auto &value : request.copysetinfos()) {
// convert copysetInfo from heartbeat format to topology format
::curvefs::mds::topology::CopySetInfo reportCopySetInfo;
@ -187,34 +168,6 @@ void HeartbeatManager::Coordinate(const MetaServerHeartbeatRequest &request,
}
}
void HeartbeatManager::UpdateDeallocatableBlockGroup(
const MetaServerHeartbeatRequest &request,
MetaServerHeartbeatResponse *response) {
uint32_t metaserverId = request.metaserverid();
for (auto &info : request.blockgroupstatinfos()) {
auto volumeSpace = spaceManager_->GetVolumeSpace(info.fsid());
if (volumeSpace == nullptr) {
LOG(ERROR) << "HeartbeatManager fsid=" << info.fsid()
<< " do not have volumeSpace manager";
response->set_statuscode(HeartbeatStatusCode::hbMetaServerFSUnkown);
return;
}
uint64_t issued = 0;
bool hasissued = volumeSpace->UpdateDeallocatableBlockGroup(
metaserverId, onlineMetaServerNum_, info.deallocatableblockgroups(),
info.blockgroupdeallocatestatus(), &issued);
if (hasissued) {
response->mutable_issuedblockgroups()->insert(
{info.fsid(), issued});
LOG(INFO) << "HeartbeatManager issue metaserverid=" << metaserverId
<< " blockgroup, fsid=" << info.fsid()
<< ", issued=" << issued;
}
}
}
HeartbeatStatusCode HeartbeatManager::CheckRequest(
const MetaServerHeartbeatRequest &request) {
MetaServer metaServer;

View File

@ -36,7 +36,6 @@
#include "curvefs/src/mds/heartbeat/topo_updater.h"
#include "curvefs/src/mds/schedule/coordinator.h"
#include "curvefs/src/mds/topology/topology.h"
#include "curvefs/src/mds/space/manager.h"
#include "src/common/concurrent/concurrent.h"
#include "src/common/interruptible_sleeper.h"
@ -44,7 +43,6 @@ using ::curvefs::mds::topology::PoolIdType;
using ::curvefs::mds::topology::CopySetIdType;
using ::curvefs::mds::topology::Topology;
using ::curvefs::mds::schedule::Coordinator;
using ::curvefs::mds::space::SpaceManager;
using ::curve::common::Thread;
using ::curve::common::Atomic;
@ -67,8 +65,7 @@ class HeartbeatManager {
public:
HeartbeatManager(const HeartbeatOption &option,
const std::shared_ptr<Topology> &topology,
const std::shared_ptr<Coordinator> &coordinator,
const std::shared_ptr<SpaceManager> &spaceManager);
const std::shared_ptr<Coordinator> &coordinator);
~HeartbeatManager() { Stop(); }
@ -101,7 +98,6 @@ class HeartbeatManager {
MetaServerHeartbeatResponse *response);
private:
FRIEND_TEST(TestHeartbeatManager, TEST_UpdateDeallocatableBlockGroup);
/**
* @brief Background thread for heartbeat timeout inspection
*/
@ -144,18 +140,10 @@ class HeartbeatManager {
void UpdateMetaServerSpace(const MetaServerHeartbeatRequest &request);
void Coordinate(const MetaServerHeartbeatRequest &request,
MetaServerHeartbeatResponse *response);
void
UpdateDeallocatableBlockGroup(const MetaServerHeartbeatRequest &request,
MetaServerHeartbeatResponse *response);
private:
// Dependencies of heartbeat
std::shared_ptr<Topology> topology_;
std::shared_ptr<Coordinator> coordinator_;
std::shared_ptr<SpaceManager> spaceManager_;
// healthyChecker_ health checker running in background thread
std::shared_ptr<MetaserverHealthyChecker> healthyChecker_;
@ -168,8 +156,6 @@ class HeartbeatManager {
// Manage metaserverHealthyChecker threads
Thread backEndThread_;
std::atomic<uint32_t> onlineMetaServerNum_;
Atomic<bool> isStop_;
InterruptibleSleeper sleeper_;
int metaserverHealthyCheckerRunInter_;

View File

@ -66,8 +66,8 @@ void MDS::InitOptions(std::shared_ptr<Configuration> conf) {
conf_ = std::move(conf);
conf_->GetValueFatalIfFail("mds.listen.addr", &options_.mdsListenAddr);
conf_->GetValueFatalIfFail("mds.dummy.port", &options_.dummyPort);
conf_->GetValueFatalIfFail("mds.space.calIntervalSec",
&options_.mdsSpaceCalIntervalSec);
conf_->GetValueFatalIfFail("mds.server.idleTimeoutSec",
&options_.idleTimeoutSec);
InitMetaServerOption(&options_.metaserverOptions);
InitTopologyOption(&options_.topologyOptions);
@ -171,8 +171,8 @@ void MDS::Init() {
space::MdsProxyManager::SetProxyOptions(options_.bsMdsProxyOptions);
fsStorage_ = std::make_shared<PersisKVStorage>(etcdClient_);
spaceManager_ = std::make_shared<SpaceManagerImpl>(
etcdClient_, fsStorage_, options_.mdsSpaceCalIntervalSec);
spaceManager_ =
std::make_shared<SpaceManagerImpl>(etcdClient_, fsStorage_);
metaserverClient_ =
std::make_shared<MetaserverClient>(options_.metaserverOptions);
auto dlock = std::make_shared<DLock>(options_.dLockOptions, etcdClient_);
@ -277,6 +277,7 @@ void MDS::Run() {
// start rpc server
brpc::ServerOptions option;
option.idle_timeout_sec = options_.idleTimeoutSec;
LOG_IF(FATAL, server.Start(options_.mdsListenAddr.c_str(), &option) != 0)
<< "start brpc server error";
running_ = true;
@ -419,7 +420,7 @@ void MDS::InitHeartbeatManager() {
heartbeatOption.mdsStartTime = steady_clock::now();
heartbeatManager_ = std::make_shared<HeartbeatManager>(
heartbeatOption, topology_, coordinator_, spaceManager_);
heartbeatOption, topology_, coordinator_);
heartbeatManager_->Init();
}

View File

@ -85,11 +85,11 @@ using ::curvefs::mds::space::MdsProxyOptions;
struct MDSOptions {
int dummyPort;
std::string mdsListenAddr;
int idleTimeoutSec;
MetaserverOptions metaserverOptions;
// TODO(add EtcdConf): add etcd configure
uint64_t mdsSpaceCalIntervalSec;
TopologyOption topologyOptions;
HeartbeatOption heartbeatOption;
ScheduleOption scheduleOption;

View File

@ -27,8 +27,6 @@ cc_library(
deps = [
"//curvefs/proto:mds_cc_proto",
"//curvefs/proto:space_cc_proto",
"//curvefs/proto:metaserver_cc_proto",
"//curvefs/proto:curvefs_heartbeat_cc_proto",
"//curvefs/src/mds:curvefs_mds_fs_storage",
"//curvefs/src/mds/codec:fs_mds_codec",
"//external:brpc",

Some files were not shown because too many files have changed in this diff Show More