Repository: happyfish100/FastCFS
Branch: master
Commit: e7d609e56cba
Files: 261
Total size: 1.5 MB
Directory structure:
gitextract_24sao1go/
├── .gitignore
├── FastCFS-auth.spec.in
├── FastCFS-vote.spec.in
├── FastCFS.spec.in
├── LICENSE
├── README-zh_CN.md
├── README.md
├── conf/
│ ├── full/
│ │ ├── fuse.conf
│ │ └── papi.conf
│ ├── fuse.conf
│ └── papi.conf
├── debian/
│ ├── changelog
│ ├── compat
│ ├── control
│ ├── copyright
│ ├── fastcfs-api-dev.install
│ ├── fastcfs-api-libs.install
│ ├── fastcfs-api-tests.install
│ ├── fastcfs-auth-client.install
│ ├── fastcfs-auth-config.install
│ ├── fastcfs-auth-dev.install
│ ├── fastcfs-auth-server-config.install
│ ├── fastcfs-auth-server.dirs
│ ├── fastcfs-auth-server.install
│ ├── fastcfs-fuse-config.install
│ ├── fastcfs-fused.dirs
│ ├── fastcfs-fused.install
│ ├── fastcfs-utils.install
│ ├── fastcfs-vote-client.install
│ ├── fastcfs-vote-config.install
│ ├── fastcfs-vote-dev.install
│ ├── fastcfs-vote-server.dirs
│ ├── fastcfs-vote-server.install
│ ├── rules
│ ├── source/
│ │ └── format
│ ├── substvars
│ └── watch
├── docs/
│ ├── APT-INSTALL-zh_CN.md
│ ├── AUTH-zh_CN.md
│ ├── CONFIGURE-zh_CN.md
│ ├── Easy-install-detail-zh_CN.md
│ ├── FAQ-zh_CN.md
│ ├── INSTALL-zh_CN.md
│ ├── INSTALL.md
│ ├── ReleaseNotes.md
│ ├── TODO-zh_CN.md
│ ├── VoteNode-zh_CN.md
│ ├── YUM-INSTALL-Diy-5nodes-zh_CN.md
│ ├── YUM-INSTALL-zh_CN.md
│ ├── benchmark-step-by-step.md
│ ├── benchmark.md
│ ├── cluster-expansion-zh_CN.md
│ ├── fcfs-ops-tool-zh_CN.md
│ ├── fcfs-ops-tool.md
│ ├── index.md
│ ├── shared-storage-guide-zh_CN.md
│ ├── version-history-zh_CN.md
│ └── versions.json
├── fastcfs.sh
├── helloWorld.sh
├── libfuse_setup.sh
├── make.sh
├── mkdocs.yml
├── shell/
│ ├── Dockerfile
│ ├── conf_tpl_tar.sh
│ ├── fcfs.settings
│ ├── fcfs.sh
│ ├── fcfs_conf.settings
│ ├── fcfs_conf.sh
│ └── template/
│ └── dependency.2.0.1.settings
├── src/
│ ├── api/
│ │ ├── Makefile.in
│ │ ├── async_reporter.c
│ │ ├── async_reporter.h
│ │ ├── fcfs_api.c
│ │ ├── fcfs_api.h
│ │ ├── fcfs_api_allocator.c
│ │ ├── fcfs_api_allocator.h
│ │ ├── fcfs_api_file.c
│ │ ├── fcfs_api_file.h
│ │ ├── fcfs_api_types.h
│ │ ├── fcfs_api_util.c
│ │ ├── fcfs_api_util.h
│ │ ├── inode_htable.c
│ │ ├── inode_htable.h
│ │ ├── std/
│ │ │ ├── api_types.h
│ │ │ ├── capi.c
│ │ │ ├── capi.h
│ │ │ ├── fd_manager.c
│ │ │ ├── fd_manager.h
│ │ │ ├── papi.c
│ │ │ ├── papi.h
│ │ │ ├── posix_api.c
│ │ │ └── posix_api.h
│ │ └── tests/
│ │ ├── Makefile.in
│ │ ├── fcfs_beachmark.c
│ │ ├── fcfs_test_file_copy.c
│ │ ├── fcfs_test_file_op.c
│ │ ├── fcfs_test_papi_copy.c
│ │ └── fcfs_test_read_ahead.c
│ ├── auth/
│ │ ├── client/
│ │ │ ├── Makefile.in
│ │ │ ├── client_func.c
│ │ │ ├── client_func.h
│ │ │ ├── client_global.c
│ │ │ ├── client_global.h
│ │ │ ├── client_proto.c
│ │ │ ├── client_proto.h
│ │ │ ├── client_types.h
│ │ │ ├── fcfs_auth_client.c
│ │ │ ├── fcfs_auth_client.h
│ │ │ ├── fcfs_auth_for_server.c
│ │ │ ├── fcfs_auth_for_server.h
│ │ │ ├── session_regenerate.c
│ │ │ ├── session_regenerate.h
│ │ │ ├── session_sync.c
│ │ │ ├── session_sync.h
│ │ │ ├── simple_connection_manager.c
│ │ │ ├── simple_connection_manager.h
│ │ │ └── tools/
│ │ │ ├── Makefile.in
│ │ │ ├── fauth_cluster_stat.c
│ │ │ ├── fauth_list_servers.c
│ │ │ ├── fcfs_pool.c
│ │ │ ├── fcfs_user.c
│ │ │ ├── tool_func.c
│ │ │ └── tool_func.h
│ │ ├── common/
│ │ │ ├── auth_func.c
│ │ │ ├── auth_func.h
│ │ │ ├── auth_global.c
│ │ │ ├── auth_global.h
│ │ │ ├── auth_proto.c
│ │ │ ├── auth_proto.h
│ │ │ ├── auth_types.h
│ │ │ ├── server_session.c
│ │ │ └── server_session.h
│ │ ├── conf/
│ │ │ ├── auth.conf
│ │ │ ├── client.conf
│ │ │ ├── cluster.conf
│ │ │ ├── full/
│ │ │ │ ├── auth.conf
│ │ │ │ ├── client.conf
│ │ │ │ ├── cluster.conf
│ │ │ │ ├── server.conf
│ │ │ │ └── session.conf
│ │ │ ├── keys/
│ │ │ │ └── session_validate.key
│ │ │ ├── server.conf
│ │ │ └── session.conf
│ │ └── server/
│ │ ├── Makefile.in
│ │ ├── cluster_handler.c
│ │ ├── cluster_handler.h
│ │ ├── cluster_info.c
│ │ ├── cluster_info.h
│ │ ├── cluster_relationship.c
│ │ ├── cluster_relationship.h
│ │ ├── common_handler.c
│ │ ├── common_handler.h
│ │ ├── db/
│ │ │ ├── auth_db.c
│ │ │ ├── auth_db.h
│ │ │ ├── dao/
│ │ │ │ ├── dao.c
│ │ │ │ ├── dao.h
│ │ │ │ ├── func.c
│ │ │ │ ├── func.h
│ │ │ │ ├── granted_pool.c
│ │ │ │ ├── granted_pool.h
│ │ │ │ ├── storage_pool.c
│ │ │ │ ├── storage_pool.h
│ │ │ │ ├── types.h
│ │ │ │ ├── user.c
│ │ │ │ └── user.h
│ │ │ ├── pool_usage_updater.c
│ │ │ └── pool_usage_updater.h
│ │ ├── fcfs_authd.c
│ │ ├── server_func.c
│ │ ├── server_func.h
│ │ ├── server_global.c
│ │ ├── server_global.h
│ │ ├── server_types.h
│ │ ├── service_handler.c
│ │ ├── service_handler.h
│ │ ├── session_subscribe.c
│ │ └── session_subscribe.h
│ ├── common/
│ │ ├── fcfs_global.c
│ │ └── fcfs_global.h
│ ├── fuse/
│ │ ├── Makefile.in
│ │ ├── fcfs_fused.c
│ │ ├── fuse_wrapper.c
│ │ ├── fuse_wrapper.h
│ │ ├── getgroups.c
│ │ ├── getgroups.h
│ │ ├── global.c
│ │ ├── global.h
│ │ ├── groups_htable.c
│ │ └── groups_htable.h
│ ├── java/
│ │ ├── jni/
│ │ │ ├── Makefile.in
│ │ │ ├── com_fastken_fcfs_FCFSConstants.h
│ │ │ ├── com_fastken_fcfs_FCFSDirectory.c
│ │ │ ├── com_fastken_fcfs_FCFSDirectory.h
│ │ │ ├── com_fastken_fcfs_FCFSFile.c
│ │ │ ├── com_fastken_fcfs_FCFSFile.h
│ │ │ ├── com_fastken_fcfs_FCFSPosixAPI.c
│ │ │ ├── com_fastken_fcfs_FCFSPosixAPI.h
│ │ │ ├── common.c
│ │ │ ├── common.h
│ │ │ ├── global.c
│ │ │ └── global.h
│ │ └── src/
│ │ └── main/
│ │ └── java/
│ │ └── com/
│ │ └── fastken/
│ │ └── fcfs/
│ │ ├── FCFSConstants.java
│ │ ├── FCFSDirectory.java
│ │ ├── FCFSFile.java
│ │ ├── FCFSFileStat.java
│ │ ├── FCFSPosixAPI.java
│ │ └── FCFSVFSStat.java
│ ├── preload/
│ │ ├── Makefile.in
│ │ ├── api.c
│ │ ├── api.h
│ │ ├── global.c
│ │ ├── global.h
│ │ └── types.h
│ ├── tools/
│ │ ├── Makefile.in
│ │ ├── fcfs_active_test.c
│ │ └── fcfs_pool_stat.c
│ └── vote/
│ ├── client/
│ │ ├── Makefile.in
│ │ ├── client_func.c
│ │ ├── client_func.h
│ │ ├── client_global.c
│ │ ├── client_global.h
│ │ ├── client_proto.c
│ │ ├── client_proto.h
│ │ ├── client_types.h
│ │ ├── fcfs_vote_client.h
│ │ └── tools/
│ │ ├── Makefile.in
│ │ └── fvote_cluster_stat.c
│ ├── common/
│ │ ├── vote_global.c
│ │ ├── vote_global.h
│ │ ├── vote_proto.c
│ │ ├── vote_proto.h
│ │ └── vote_types.h
│ ├── conf/
│ │ ├── client.conf
│ │ ├── cluster.conf
│ │ ├── full/
│ │ │ ├── client.conf
│ │ │ ├── cluster.conf
│ │ │ └── server.conf
│ │ └── server.conf
│ └── server/
│ ├── Makefile.in
│ ├── cluster_handler.c
│ ├── cluster_handler.h
│ ├── cluster_info.c
│ ├── cluster_info.h
│ ├── cluster_relationship.c
│ ├── cluster_relationship.h
│ ├── common_handler.c
│ ├── common_handler.h
│ ├── fcfs_voted.c
│ ├── server_func.c
│ ├── server_func.h
│ ├── server_global.c
│ ├── server_global.h
│ ├── server_types.h
│ ├── service_group_htable.c
│ ├── service_group_htable.h
│ ├── service_handler.c
│ └── service_handler.h
└── systemd/
├── fastauth.service
├── fastcfs.service
└── fastvote.service
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Makefile.in
src/api/Makefile
src/api/tests/Makefile
src/preload/Makefile
src/fuse/Makefile
src/tools/Makefile
src/auth/server/Makefile
src/auth/client/Makefile
src/auth/client/tools/Makefile
src/vote/server/Makefile
src/vote/client/Makefile
src/vote/client/tools/Makefile
src/java/jni/Makefile
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
*.class
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dSYM
*.dll
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.out
src/api/tests/fcfs_test_file_op
src/api/tests/fcfs_test_file_copy
src/api/tests/fcfs_test_papi_copy
src/api/tests/fcfs_test_read_ahead
src/api/tests/fcfs_beachmark
src/fuse/fcfs_fused
src/tools/fcfs_active_test
src/tools/fcfs_pool_stat
src/auth/server/fcfs_authd
src/auth/client/tools/fcfs_user
src/auth/client/tools/fcfs_pool
src/auth/client/tools/fauth_list_servers
src/auth/client/tools/fauth_cluster_stat
src/vote/server/fcfs_voted
src/vote/client/tools/fvote_cluster_stat
# other
logs
data
*.pid
*.swp
*.swo
# Build tmp path after execute fastcfs.sh
build
.DS_Store
.fcfs
.idea
================================================
FILE: FastCFS-auth.spec.in
================================================
%define FastCFSAuthClient FastCFS-auth-client
%define FastCFSAuthDevel FastCFS-auth-devel
%define FastCFSAuthConfig FastCFS-auth-config
%define CommitVersion %(echo $COMMIT_VERSION)
Name: FastCFS-auth
Version: 5.5.0
Release: 1%{?dist}
Summary: the auth client library and config files of FastCFS. FastCFS is a high performance cloud native distributed file system for databases, KVM and K8s
License: AGPL v3.0
Group: Arch/Tech
URL: http://github.com/happyfish100/FastCFS/
Source: http://github.com/happyfish100/FastCFS/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: libserverframe-devel >= 1.2.10
Requires: %__cp %__mv %__chmod %__grep %__mkdir %__install %__id
Requires: libserverframe >= 1.2.10
Requires: FastCFS-auth-server = %{version}-%{release}
Requires: %{FastCFSAuthClient} = %{version}-%{release}
Requires: %{FastCFSAuthConfig} >= 2.0.0
%description
the auth client library and config files of FastCFS.
FastCFS is a high performance distributed file system which can be used as the back-end storage of databases and cloud platforms.
commit version: %{CommitVersion}
%package -n %{FastCFSAuthDevel}
Requires: %{FastCFSAuthClient} = %{version}-%{release}
Summary: header files of FastCFS auth client
%package -n %{FastCFSAuthClient}
Requires: libserverframe >= 1.2.10
Summary: FastCFS auth client
%package -n %{FastCFSAuthConfig}
Summary: FastCFS auth config files for sample
%description -n %{FastCFSAuthDevel}
This package provides the header files of libfcfsauthclient
commit version: %{CommitVersion}
%description -n %{FastCFSAuthClient}
FastCFS auth client
commit version: %{CommitVersion}
%description -n %{FastCFSAuthConfig}
FastCFS auth config files for sample
commit version: %{CommitVersion}
%prep
%setup -q
%build
./make.sh --module=authclient clean && ./make.sh --module=authclient
%install
rm -rf %{buildroot}
DESTDIR=$RPM_BUILD_ROOT ./make.sh --module=authclient install
AUTH_CONFDIR=%{buildroot}/etc/fastcfs/auth/
mkdir -p $AUTH_CONFDIR
cp src/auth/conf/*.conf $AUTH_CONFDIR
cp -R src/auth/conf/keys $AUTH_CONFDIR
%post
%preun
%postun
%clean
rm -rf %{buildroot}
%files
%files -n %{FastCFSAuthClient}
/usr/lib64/libfcfsauthclient.so*
/usr/bin/fcfs_user
/usr/bin/fcfs_pool
/usr/bin/fauth_list_servers
/usr/bin/fauth_cluster_stat
%files -n %{FastCFSAuthDevel}
%defattr(-,root,root,-)
/usr/include/fastcfs/auth/*
%files -n %{FastCFSAuthConfig}
%defattr(-,root,root,-)
%config(noreplace) /etc/fastcfs/auth/*.conf
%config(noreplace) /etc/fastcfs/auth/keys/*
%changelog
* Thu Apr 22 2021 YuQing <384681@qq.com>
- first RPM release (1.0)
================================================
FILE: FastCFS-vote.spec.in
================================================
%define FastCFSVoteClient FastCFS-vote-client
%define FastCFSVoteDevel FastCFS-vote-devel
%define FastCFSVoteConfig FastCFS-vote-config
%define CommitVersion %(echo $COMMIT_VERSION)
Name: FastCFS-vote
Version: 5.5.0
Release: 1%{?dist}
Summary: the vote client library and config files of FastCFS. FastCFS is a high performance cloud native distributed file system for databases, KVM and K8s
License: AGPL v3.0
Group: Arch/Tech
URL: http://github.com/happyfish100/FastCFS/
Source: http://github.com/happyfish100/FastCFS/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: libserverframe-devel >= 1.2.10
Requires: %__cp %__mv %__chmod %__grep %__mkdir %__install %__id
Requires: libserverframe >= 1.2.10
Requires: FastCFS-vote-server = %{version}-%{release}
Requires: %{FastCFSVoteClient} = %{version}-%{release}
Requires: %{FastCFSVoteConfig} >= 3.5.0
%description
the vote client library and config files of FastCFS.
FastCFS is a high performance distributed file system which can be used as the back-end storage of databases and cloud platforms.
commit version: %{CommitVersion}
%package -n %{FastCFSVoteDevel}
Requires: %{FastCFSVoteClient} = %{version}-%{release}
Summary: header files of FastCFS vote client
%package -n %{FastCFSVoteClient}
Requires: libserverframe >= 1.2.10
Summary: FastCFS vote client
%package -n %{FastCFSVoteConfig}
Summary: FastCFS vote config files for sample
%description -n %{FastCFSVoteDevel}
This package provides the header files of libfcfsvoteclient
commit version: %{CommitVersion}
%description -n %{FastCFSVoteClient}
FastCFS vote client
commit version: %{CommitVersion}
%description -n %{FastCFSVoteConfig}
FastCFS vote config files for sample
commit version: %{CommitVersion}
%prep
%setup -q
%build
./make.sh --module=voteclient clean && ./make.sh --module=voteclient
%install
rm -rf %{buildroot}
DESTDIR=$RPM_BUILD_ROOT ./make.sh --module=voteclient install
VOTE_CONFDIR=%{buildroot}/etc/fastcfs/vote/
mkdir -p $VOTE_CONFDIR
cp src/vote/conf/*.conf $VOTE_CONFDIR
%post
%preun
%postun
%clean
rm -rf %{buildroot}
%files
%files -n %{FastCFSVoteClient}
/usr/lib64/libfcfsvoteclient.so*
/usr/bin/fvote_cluster_stat
%files -n %{FastCFSVoteDevel}
%defattr(-,root,root,-)
/usr/include/fastcfs/vote/*
%files -n %{FastCFSVoteConfig}
%defattr(-,root,root,-)
%config(noreplace) /etc/fastcfs/vote/*.conf
%changelog
* Thu Apr 22 2021 YuQing <384681@qq.com>
- first RPM release (1.0)
================================================
FILE: FastCFS.spec.in
================================================
%define FastCFSFused FastCFS-fused
%define FastCFSUtils FastCFS-utils
%define FastCFSAPI FastCFS-api-libs
%define FastCFSAPITests FastCFS-api-tests
%define FastCFSAuthServer FastCFS-auth-server
%define FastCFSVoteServer FastCFS-vote-server
%define FastCFSAPIDevel FastCFS-api-devel
%define FastCFSFuseConfig FastCFS-fuse-config
%define CommitVersion %(echo $COMMIT_VERSION)
Name: FastCFS
Version: 5.5.0
Release: 1%{?dist}
Summary: a high performance cloud native distributed file system for databases, KVM and K8s
License: AGPL v3.0
Group: Arch/Tech
URL: http://github.com/happyfish100/FastCFS/
Source: http://github.com/happyfish100/FastCFS/%{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: fastDIR-devel >= 5.5.0
BuildRequires: faststore-devel >= 5.5.0
BuildRequires: fuse3-devel >= 3.16.2
Requires: %__cp %__mv %__chmod %__grep %__mkdir %__install %__id
Requires: %{FastCFSFused} = %{version}-%{release}
Requires: %{FastCFSUtils} = %{version}-%{release}
Requires: %{FastCFSAPITests} = %{version}-%{release}
%description
a high performance distributed file system which can be used as the back-end storage of databases and cloud platforms.
commit version: %{CommitVersion}
%package -n %{FastCFSFused}
Requires: fuse3 >= 3.16.2
Requires: %{FastCFSAPI} = %{version}-%{release}
Requires: %{FastCFSFuseConfig} >= 1.0.0
Summary: FastCFS fuse
%package -n %{FastCFSUtils}
Requires: %{FastCFSAPI} = %{version}-%{release}
Summary: FastCFS utils
%package -n %{FastCFSAPI}
Requires: fastDIR-client >= 5.5.0
Requires: faststore-client >= 5.5.0
Summary: FastCFS api library
%package -n %{FastCFSAPITests}
Requires: %{FastCFSAPI} = %{version}-%{release}
Requires: %{FastCFSFuseConfig} >= 1.0.0
Summary: FastCFS api tests
%package -n %{FastCFSAPIDevel}
Requires: %{FastCFSAPI} = %{version}-%{release}
Summary: header files of FastCFS api library
%package -n %{FastCFSAuthServer}
Requires: fastDIR-client >= 5.5.0
Requires: FastCFS-auth-config >= 2.0.0
Summary: FastCFS auth server
%package -n %{FastCFSVoteServer}
Requires: libserverframe >= 1.2.10
Requires: FastCFS-vote-config >= 3.5.0
Summary: FastCFS vote server
%package -n %{FastCFSFuseConfig}
Requires: faststore-config >= 1.0.0
Summary: FastCFS fuse config files for sample
%description -n %{FastCFSFused}
FastCFS fuse
commit version: %{CommitVersion}
%description -n %{FastCFSUtils}
FastCFS utils
commit version: %{CommitVersion}
%description -n %{FastCFSAPI}
FastCFS api library
commit version: %{CommitVersion}
%description -n %{FastCFSAPITests}
FastCFS api tests
commit version: %{CommitVersion}
%description -n %{FastCFSAPIDevel}
This package provides the header files of libfcfsapi
commit version: %{CommitVersion}
%description -n %{FastCFSAuthServer}
FastCFS auth server
commit version: %{CommitVersion}
%description -n %{FastCFSVoteServer}
FastCFS vote server
commit version: %{CommitVersion}
%description -n %{FastCFSFuseConfig}
FastCFS fuse config files for sample
commit version: %{CommitVersion}
%prep
%setup -q
%build
./make.sh clean && ./make.sh --exclude=client
%install
rm -rf %{buildroot}
DESTDIR=$RPM_BUILD_ROOT ./make.sh --exclude=client install
FUSE_CONFDIR=%{buildroot}/etc/fastcfs/fcfs/
SYSTEMDIR=%{buildroot}/usr/lib/systemd/system/
mkdir -p $FUSE_CONFDIR
mkdir -p $SYSTEMDIR
cp conf/*.conf $FUSE_CONFDIR
cp systemd/fastcfs.service $SYSTEMDIR
cp systemd/fastauth.service $SYSTEMDIR
cp systemd/fastvote.service $SYSTEMDIR
%post
%preun
%postun
%clean
rm -rf %{buildroot}
%files
%post -n %{FastCFSFused}
mkdir -p /opt/fastcfs/fcfs
mkdir -p /opt/fastcfs/fuse
systemctl enable fastcfs
%files -n %{FastCFSFused}
/usr/bin/fcfs_fused
%config(noreplace) /usr/lib/systemd/system/fastcfs.service
%files -n %{FastCFSUtils}
/usr/bin/fcfs_active_test
/usr/bin/fcfs_pool_stat
%files -n %{FastCFSAPI}
%defattr(-,root,root,-)
/usr/lib64/libfcfsapi.so*
/usr/lib64/libfcfspreload.so*
%files -n %{FastCFSAPITests}
/usr/bin/fcfs_beachmark
/usr/bin/fcfs_test_file_op
/usr/bin/fcfs_test_file_copy
/usr/bin/fcfs_test_papi_copy
/usr/bin/fcfs_test_read_ahead
%files -n %{FastCFSAPIDevel}
%defattr(-,root,root,-)
/usr/include/fastcfs/api/*
%post -n %{FastCFSAuthServer}
mkdir -p /opt/fastcfs/auth
systemctl enable fastauth
%post -n %{FastCFSVoteServer}
mkdir -p /opt/fastcfs/vote
systemctl enable fastvote
%files -n %{FastCFSAuthServer}
/usr/bin/fcfs_authd
%config(noreplace) /usr/lib/systemd/system/fastauth.service
%files -n %{FastCFSVoteServer}
/usr/bin/fcfs_voted
%config(noreplace) /usr/lib/systemd/system/fastvote.service
%files -n %{FastCFSFuseConfig}
%defattr(-,root,root,-)
%config(noreplace) /etc/fastcfs/fcfs/*.conf
%changelog
* Fri Jan 1 2021 YuQing <384681@qq.com>
- first RPM release (1.0)
================================================
FILE: LICENSE
================================================
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
.
================================================
FILE: README-zh_CN.md
================================================
# FastCFS -- 可以跑数据库的高性能通用分布式文件系统
[English](README.md) | 简体中文
## 1. 简介
FastCFS 是一款强一致性、高性能、高可用、支持百亿级海量文件的通用分布式文件系统,可以作为MySQL、PostgreSQL、Oracle等数据库,k8s、KVM、FTP、SMB和NFS等系统的后端存储。
### FastCFS 主要特点
* 保证数据强一致前提下实现了高性能:性能完胜Ceph;
* 完全兼容POSIX文件接口,支持文件锁,64G内存即可支持百亿级海量文件;
* 高可用:不存在单点,自动failover;
* 简洁高效的架构和原生实现,不依赖第三方组件,内置运维工具,易用性较好;
* 随机写性能强悍:FCFS基于trunk顺序分配空间,将客户端的随机写转换为顺序写。
### FastCFS 典型应用场景
* **数据库**:支持常规的独享数据和高阶的共享数据两种存储方式,支持数据库云化;
* **文件存储**:如文档、图片、视频等等,FastCFS比对象存储更容易与通用软件集成;
* **超融合存储**:数据库和文件存储共用一个存储集群,显著提升存储资源利用率;
* **高性能计算**:高可靠和高性能的FastCFS,支持RDMA,天然适合高性能计算场景;
* **视频监控**:FastCFS采用顺序写盘方式,使用SATA硬盘也可保证多路视频流畅写入。
## 2. 当前版本:V5.5.0
[FastCFS重大版本一览](docs/version-history-zh_CN.md)
## 3. 支持的操作系统
* Linux: Kernel version >= 3.10 (完全支持,推荐使用4.18及更高版本)
* MacOS or FreeBSD (仅支持服务端,不支持FUSE)
## 4. 依赖
* [libfuse](https://gitee.com/mirrors/libfuse) (版本 3.9.4 或更高版本,推荐3.16.2)
* [Python](https://python.org/) (版本 3.5 或更高版本)
* [Ninja](https://ninja-build.org/) (版本 1.7 或更高版本)
* [gcc](https://www.gnu.org/software/gcc/) (版本 4.7.0 或更高版本)
* [libfastcommon](https://gitee.com/fastdfs100/libfastcommon) (tag: V1.0.83)
* [libserverframe](https://gitee.com/fastdfs100/libserverframe) (tag: V1.2.11)
* [libdiskallocator](https://gitee.com/fastdfs100/libdiskallocator) (tag: V1.1.13)
* [fastDIR](https://gitee.com/fastdfs100/fastDIR) (tag: V5.5.0)
* [faststore](https://gitee.com/fastdfs100/faststore) (tag: V5.5.0)
* [FastCFS](https://gitee.com/fastdfs100/FastCFS) (tag: V5.5.0)
## 5. 部署 & 运维
FastCFS包含 libfastcommon、libserverframe、libdiskallocator、fastDIR、faststore和FastCFS 六个安装包。
### 一键部署
如果你打算快速体验一下FastCFS,可以一键搭建(包括部署和运行)单节点(需要root身份执行):
```
git clone https://gitee.com/fastdfs100/FastCFS.git; cd FastCFS/
./helloWorld.sh
# 注意:helloWorld.sh将更改FastCFS相关配置文件,请不要在多节点集群上执行!
```
上述操作完成后,执行命令:
```
df -h /opt/fastcfs/fuse | grep fuse
```
可以看到FastCFS挂载的文件目录,你可以当作本地文件系统访问该目录。
一键部署的详细说明,请参见这里[一键部署详细说明](docs/Easy-install-detail-zh_CN.md)
### 集群部署工具
推荐使用 [FastCFS集群运维工具](docs/fcfs-ops-tool-zh_CN.md)
### DIY安装
如果你要自己搭建FastCFS环境,可以采用如下三种安装方式之一:
* yum安装(针对CentOS、Rocky、Fedora、RHEL等),参阅 [yum安装文档](docs/YUM-INSTALL-zh_CN.md)
* apt安装(针对Ubuntu、Debian 和 Deepin),参阅 [apt 安装文档](docs/APT-INSTALL-zh_CN.md)
* 源码编译安装,参阅 [安装文档](docs/INSTALL-zh_CN.md)
### 配置指南
FastCFS安装完成后,请参阅[配置指南](docs/CONFIGURE-zh_CN.md)
### 集群扩容
详情参见 [FastCFS集群扩容手册](docs/cluster-expansion-zh_CN.md)
## 6. 性能测试
FastCFS性能明显优于Ceph:顺序写是Ceph的6.x倍,顺序读是Ceph的2.x倍,随机写大约是Ceph的2倍。
* [FastCFS与Ceph性能对比测试结果概要](docs/benchmark.md)
* 详情参见 [完整PDF文档](docs/benchmark-20210621.pdf)
* 如何进行性能测试点击 [这里](docs/benchmark-step-by-step.md)
## 7. K8s CSI驱动
参见项目 [fastcfs-csi](https://gitee.com/fastdfs100/fastcfs-csi)
## 8. 技术文章
参见 技术博客
## 9. 常见问题
参见 [FastCFS常见问题](docs/FAQ-zh_CN.md)
## 10. 待完成工作
* [fstore] 单盘故障恢复后,自动恢复数据(已完成)
* [fstore] 机器故障或网络短暂故障恢复后,master需重新均衡分配(已完成)
* [fauth & fdir & fstore] leader选举支持过半原则,防止脑裂(已完成)
* [fauth & fdir & fstore] 实现公用选举节点,双副本防脑裂(已完成)
* [fdir & fstore] binlog去重及历史数据清理(已完成)
* [fdir & fstore] 数据提交采用多数派确认机制保证数据一致性和可靠性(已完成)
* [fdir & fstore] 针对两副本,数据提交多数派机制智能化(已完成)
* [fstore] 文件读写性能优化(已完成)
* [fdir & api] POSIX兼容性测试及改进(已完成)
* [fstore] slice存储引擎插件,有限内存支持海量数据(已完成)
* [all] 适配RDMA网络,突破网络瓶颈(已完成)
* [fdir] 支持回收站功能,不用担心误删除文件(已完成)
* [all] 支持集群在线扩容
参见更多 [TODO List](docs/TODO-zh_CN.md),欢迎大家参与。
## 11. 商业支持
我们提供商业技术支持和定制化开发,欢迎微信或邮件洽谈。
email: 384681(at)qq(dot)com
## 12. 联系我们
查看FastCFS相关技术文章,请关注微信公众号:
微信交流群:
================================================
FILE: README.md
================================================
# FastCFS -- a high performance general distributed file system for databases, K8s and KVM etc.
English | [Chinese](README-zh_CN.md)
## 1. About
FastCFS is a general distributed file system with strong consistency, high performance, high availability and supporting 10 billion massive files.
FastCFS can be used as the back-end storage of databases (MySQL, PostgreSQL, Oracle etc.), K8s, KVM, FTP, SMB and NFS.
### Main Features
* High performance on the premise of strong data consistency: performance is more better than ceph
* Fully compatible with POSIX, supporting file lock and 10 billion massive files
* High availability: no single point & automatic failover
* Easy to use:
* simple and efficient architecture and native implementation
* independent of third-party components
* built-in operation and maintenance tools
* Strong random write performance: FCFS allocates space based on the trunk file, converts random writes from the client to sequential writes
### Classical Application Scene
* **Database**: supports two storage methods (conventional exclusive data and high-level shared data) and database cloudification
* **File Storage**: documents, pictures, videos, etc., FastCFS is easier to integrate with general software than the object storage
* **Unified Storage**: database and file storage share a storage cluster, which significantly improves the utilization of storage resources
* **High Performance Computing**: FastCFS with high reliability and high performance is naturally suitable for the HPC scene
* **Video monitoring**: smooth writing for multi-channel videos with HDD such as SATA because FastCFS uses sequential writing approach
## 2. Current Version: V5.5.0
## 3. Supported Platforms
* Linux: Kernel version >= 3.10 (Full support, >= 4.18 is recommended)
* MacOS or FreeBSD (Only server side)
## 4. Dependencies
* [libfuse](https://github.com/libfuse/libfuse) (version 3.9.4 or newer, 3.16.2 is recommended)
* [Python](https://python.org/) (version 3.5 or newer)
* [Ninja](https://ninja-build.org/) (version 1.7 or newer)
* [gcc](https://www.gnu.org/software/gcc/) (version 4.7.0 or newer)
* [libfastcommon](https://github.com/happyfish100/libfastcommon) (tag: V1.0.83)
* [libserverframe](https://github.com/happyfish100/libserverframe) (tag: V1.2.11)
* [libdiskallocator](https://github.com/happyfish100/libdiskallocator) (tag: V1.1.13)
* [fastDIR](https://github.com/happyfish100/fastDIR) (tag: V5.5.0)
* [faststore](https://github.com/happyfish100/faststore) (tag: V5.5.0)
* [FastCFS](https://github.com/happyfish100/FastCFS) (tag: V5.5.0)
## 5. Installation
### 5.1 DIY installation
you can use [Cluster Operation Tool](docs/fcfs-ops-tool.md) to deploy FastCFS
step by step please see [INSTALL](docs/INSTALL.md)
recommend to execute libfuse_setup.sh for compiling and installing libfuse
### 5.2 easy installation
libfastcommon, libserverframe, fastDIR, faststore and FastCFS can be compiled, installed and auto configurated by fastcfs.sh
fastcfs.sh can automatically pull or update above six projects codes from GitHub, compile and install according to dependency orders, and automatically generate cluster related configuration files according to the config templates.
```
git clone https://github.com/happyfish100/FastCFS.git; cd FastCFS/
```
fastcfs.sh usage:
```
* install: pull/update codes from gitee, then make and install
* config: copy config files and configure them with local ip
* start | stop | restart: for service processes control
```
one click to build (deploy and run) single node demo environment (MUST run by root):
```
./helloWorld.sh
```
or execute following commands (MUST run by root):
```
./fastcfs.sh install
./fastcfs.sh config --force
./fastcfs.sh restart
```
now you can see the mounted path of FastCFS by the command:
```
df -h /opt/fastcfs/fuse | grep fuse
```
## 6. Benchmark
FastCFS has huge better performance than Ceph: the IOPS ratio of sequential write is 6.x, sequential read is 2.x, random write is about 2.0.
* [FastCFS vs. Ceph benchmark](docs/benchmark.md)
## 7. K8s CSI Driver
[fastcfs-csi](https://github.com/happyfish100/fastcfs-csi)
## 8. Chinese Relative articles
CSDN blog
## 9. TODO List
* [fstore] data recovery after single disk fault (done)
* [fstore] after the machine recovery, the data masters should be rebalanced (done)
* [fauth & fdir & fstore] leader election uses more than half principle to prevent brain-split (done)
* [fauth & fdir & fstore] import public vote node under 2 copies scene to prevent brain-split (done)
* [fdir & fstore] binlog deduplication and historical data deletion (done)
* [fdir & fstore] data submission by majority confirmation to ensure data consistency (done)
* [fdir & fstore] for two replicas, the data submission majority mechanism is intelligent (done)
* [fstore] file read & write performance optimization (done)
* [fdir & api] POSIX compatibility test and improvement (done)
* [fstore] slice storage engine plugin to support massive data with limited memory (done)
* [all] adapt to RDMA network to break through network bottlenecks (done)
* [fdir] support recycle bin, don't worry accidentally deleting files (done)
* [all] cluster online expansion
## 10. Business Support
We provide technical support service and customized development. Welcome to use WeChat or email for discuss.
## 11. Contact us
email: 384681(at)qq(dot)com
WeChat subscription: search "fastdfs" for the related articles (Chinese Only)
================================================
FILE: conf/full/fuse.conf
================================================
# the base path to store log files
# this path must exist
base_path = /opt/fastcfs/fcfs
# the mount point (local path) for FUSE
# the local path must exist
mountpoint = /opt/fastcfs/fuse
#standard log level as syslog, case insensitive, value list:
### emerg for emergency
### alert
### crit for critical
### error
### warn for warning
### notice
### info
### debug
log_level = info
#unix group name to run this program,
#not set (empty) means run by the group of current user
run_by_group =
#unix username to run this program,
#not set (empty) means run by current user
run_by_user =
# sync log buff to disk every interval seconds
# default value is 1 seconds
sync_log_buff_interval = 1
# if rotate the error log every day
# default value is false
rotate_error_log = false
# rotate error log time base, time format: Hour:Minute
# Hour from 0 to 23, Minute from 0 to 59
# default value is 00:00
error_log_rotate_time = 00:00
# if compress the old error log by gzip
# default value is false
compress_old_error_log = false
# compress the error log days before
# default value is 1
compress_error_log_days_before = 7
# rotate error log when the log file exceeds this size
# 0 means never rotates log file by log file size
# default value is 0
rotate_error_log_size = 0
# keep days of the log files
# 0 means do not delete old log files
# default value is 0
log_file_keep_days = 0
# connect timeout in seconds
# default value is 10
# Note: in the intranet network (LAN), 10 seconds is enough.
connect_timeout = 10
# network timeout in seconds
# default value is 60
network_timeout = 60
# TCP quick ack for Linux (setsockopt with TCP_QUICKACK option)
# default value is true
tcp_quick_ack = true
# the rule of read data, value list:
### any : any available server
### slave : slave first, access master when all slaves down or offline
### master : master only (default)
# this parameter can be overriden / redefined in section [FastDIR] and [FastStore]
read_rule = master
# the mode of retry interval, value list:
### fixed for fixed interval
### multiple for multiplication (default)
# this parameter can be overriden / redefined in section [FastDIR] and [FastStore]
retry_interval_mode = multiple
# the max retry interval in milliseconds
# valid when retry_interval_mode set to multiple
# default value is 3000 ms
# this parameter can be overriden / redefined in section [FastDIR] and [FastStore]
retry_max_interval_ms = 3000
# retry times when connect to server fail
### 0 for never retry
### < 0 for infinite retry
# default value is 200
# this parameter can be overriden / redefined in section [FastDIR] and [FastStore]
connect_retry_times = 200
# retry interval when connect to server fail
# unit: milliseconds
# default value is 100 ms
# this parameter can be overriden / redefined in section [FastDIR] and [FastStore]
connect_retry_interval_ms = 100
# retry times when communicate with server fail
### 0 for never retry
### < 0 for infinite retry
# default value is 200
# this parameter can be overriden / redefined in section [FastDIR] and [FastStore]
network_retry_times = 200
# retry interval when communicate with server fail
# unit: milliseconds
# default value is 100 ms
# this parameter can be overriden / redefined in section [FastDIR] and [FastStore]
network_retry_interval_ms = 100
# if use busy polling for RDMA network
# should set to true for HPC
# default value is false
busy_polling = false
[idempotency]
# if enable RPC idempotency for highest level consistency
# default value is false
enabled = true
# the idempotency channel hashtable capacity
# default value is 1361
channel_htable_capacity = 1361
# the heartbeat interval for RPC idempotency channel
# unit: seconds
# default value is 3s
channel_heartbeat_interval = 3
# close the idempotency channel when max idle time reachs
# unit: seconds
# default value is 300s
channel_max_idle_time = 300
# max connections for RPC idempotency report
# you should set this parameter larger than the total server count of
# FastDIR and FastStore
# default value is 256
max_connections = 1024
# work thread count for RPC idempotency report
# default value is 1
work_threads = 1
# max pkg size for RPC idempotency report
# default value is 256KB
max_pkg_size = 256KB
# thread stack size, should >= 320KB
thread_stack_size = 512KB
[FastDIR]
# connect timeout in seconds
# default value is 10
# Note: in the intranet network (LAN), 10 seconds is enough.
connect_timeout = 10
# network timeout in seconds
# default value is 60
network_timeout = 60
# the namespace for FastDIR
namespace = fs
# config the cluster servers
cluster_config_filename = ../fdir/cluster.conf
# if use sys lock for file append and truncate to avoid conflict
# set true when the files appended or truncated by many nodes (FUSE instances)
# default value is false
use_sys_lock_for_append = false
# if async report file attributes (size, modify time etc.) to the FastDIR server
# default value is true
async_report_enabled = true
# the interval in milliseconds for async report file attributes to the FastDIR server
# default value is 100 ms
async_report_interval_ms = 100
# the sharding count of hashtable
# NO more than 1000 is recommended
# default value is 17
hashtable_sharding_count = 17
# the capacity (bucket count) of all sharding hashtables
# default value is 1403641
hashtable_total_capacity = 1403641
# the shared allocators for hashtabe entry, task etc.
# NO more than the CPU cores is recommended
# default value is 11
shared_allocator_count = 11
# set the owner (user and group) of new created files and directories
# the values are:
## caller: current user and group from the calling process (default)
## fixed: fixed user and group
owner_type = caller
# set the user owner (username) of the new created files and directories
# this parameter is valid only when owner_type set to fixed
# empty for the user who runs the fcfs_fused program
owner_user =
# set the group owner (group name) of the new created files and directories
# this parameter is valid only when owner_type set to fixed
# empty for the group of the user who runs the fcfs_fused program
owner_group =
[FastStore]
# connect timeout in seconds
# default value is 10
# Note: in the intranet network (LAN), 10 seconds is enough.
connect_timeout = 10
# network timeout in seconds
# default value is 60
network_timeout = 60
# config the cluster servers and groups
cluster_config_filename = ../fstore/cluster.conf
# the sharding count of hashtable
# NO more than 1000 is recommended
# default value is 163
hashtable_sharding_count = 163
# the capacity (bucket count) of all sharding hashtables
# default value is 1403641
hashtable_total_capacity = 1403641
# the shared allocators for hashtabe entry, task, slice etc.
# NO more than the CPU cores is recommended
# default value is 17
shared_allocator_count = 17
[write-combine]
# if enable write combine feature for FastStore
# default value is true
enabled = true
# the buffer size for write combine
# the min value is 64KB and the max value is the data block size such as 4MB
# default value is 256KB
buffer_size = 256KB
# the min wait time in milliseconds for write combine
# the min value is 10ms and the max value is 100ms
# default value is 20ms
min_wait_time_ms = 50
# the max wait time in milliseconds for write combine
# the min value is 100ms and the max value is 10000ms
# default value is 1000ms
max_wait_time_ms = 1000
# the slice size for skipping write combine
# skip combine when the slice size >= this parameter
# the min value is 64KB and the max value is the data block size such as 4MB
# default value is 256KB
skip_combine_on_slice_size = 256KB
# the merged slice count of last combine for skipping write combine
# skip combine when the last combine is in progress and
# it's merged slice count <= this parameter
# default value is 1
skip_combine_on_last_merged_slices = 1
# the shared locks for timer (timeout manager)
# default value is 163
timer_shared_lock_count = 163
# the max waiting slice count in queue for flow control
# default value is 16
max_waiting_slice_count = 16
# the thread limit (max threads) for the thread pool
# default value is 8
thread_pool_max_threads = 8
# the min idle thread count for the thread pool
# default value is 2
thread_pool_min_idle_count = 2
# the max idle time in seconds for the thread pool
# the running thread will exit on three conditions:
## 1. this paramter > 0
## 2. running thread count > thread_pool_min_idle_count
## 3. the thread's idle time exceeds this parameter
# default value is 300 (seconds)
thread_pool_max_idle_time = 300
[read-ahead]
# if enable read ahead feature for FastStore
# default value is true
enabled = true
# the TTL in miliseconds for preread cache
# the min value is 100ms and the max value is 10000ms
# default value is 1000ms
cache_ttl_ms = 1000
# the min buffer size for preread
# the min value is 1KB and the max value is 16KB
# default value is 4KB
min_buffer_size = 4KB
# the max buffer size for preread
# the min value is 16KB and the max value is 256KB
# default value is 128KB
max_buffer_size = 128KB
# the slice size for skipping read ahead
# skip read ahead when the slice size >= this parameter
# the min value is 8KB and the max value is 128KB
# default value is half of max_buffer_size
skip_preread_on_slice_size = 64KB
# the shared locks for preread hashtable
# default value is 1361
shared_lock_count = 1361
[FUSE]
# if single thread mode
# set true to disable multi-threaded operation
# default value is false
singlethread = false
# if use separate fuse device fd for each thread
# set to true for more high performance
# default value is false
clone_fd = true
# the max worker threads for FUSE
# this parameter is valid when the version of libfuse >= 3.12
# default value is 10
max_threads = 10
# the max idle worker threads for FUSE
# default value is 10
max_idle_threads = 10
# access permissions for other users
# the values are:
## all for all users
## root for root only
## empty or other values for none
allow_others = all
# mount the filesystem read-only as mount option: ro
# default value is false
read_only = false
# auto unmount on process termination
# default value is false
auto_unmount = false
# cache time for file entry in seconds
# default value is 1.0s
entry_timeout = 5.0
# cache time for file attribute in seconds
# default value is 1.0s
attribute_timeout = 5.0
# if enable kernel writeback cache
# set to true for unshared data scene (private data for single node)
# default value is true
writeback_cache = true
# if keep kernel cache for read
# set to true for unshared data scene (private data for single node)
# should set to false on shared data scene for multi nodes
# default value is true
kernel_cache = true
# if enable x-attribute
# default value is false
# IMPORTANT NOTE:
### because Linux kernel get the xattr "security.capability" *EVERY* write,
### do NOT change this parameter to true unless your application need
### setxattr, getxattr or listxattr really!
xattr_enabled = false
# if enable additional groups for POSIX ACL
# default value is true
groups_enabled = true
[groups-cache]
# if enable additional groups cache
# default value is true
enabled = true
# the timeout of additional groups cache in seconds
# default value is 300 seconds
timeout = 300
# element limit for less memory usage
# default value is 65536
element_limit = 65536
# the sharding count of hashtable
# NO more than 1000 is recommended
# default value is 163
hashtable_sharding_count = 163
# the capacity (bucket count) of all sharding hashtables
# default value is 175447
hashtable_total_capacity = 175447
# the shared allocators for hashtabe entry, task etc.
# NO more than the CPU cores is recommended
# default value is 7
shared_allocator_count = 7
================================================
FILE: conf/full/papi.conf
================================================
# the base path to store log files
# this path must exist
base_path = /opt/fastcfs/fcfs
# the virtual mount point
mountpoint = /opt/fastcfs/fuse
#standard log level as syslog, case insensitive, value list:
### emerg for emergency
### alert
### crit for critical
### error
### warn for warning
### notice
### info
### debug
log_level = info
#unix group name to run this program,
#not set (empty) means run by the group of current user
run_by_group =
#unix username to run this program,
#not set (empty) means run by current user
run_by_user =
# sync log buff to disk every interval seconds
# default value is 1 seconds
sync_log_buff_interval = 1
# if rotate the error log every day
# default value is false
rotate_error_log = false
# rotate error log time base, time format: Hour:Minute
# Hour from 0 to 23, Minute from 0 to 59
# default value is 00:00
error_log_rotate_time = 00:00
# if compress the old error log by gzip
# default value is false
compress_old_error_log = false
# compress the error log days before
# default value is 1
compress_error_log_days_before = 7
# rotate error log when the log file exceeds this size
# 0 means never rotates log file by log file size
# default value is 0
rotate_error_log_size = 0
# keep days of the log files
# 0 means do not delete old log files
# default value is 0
log_file_keep_days = 0
# connect timeout in seconds
# default value is 10
# Note: in the intranet network (LAN), 10 seconds is enough.
connect_timeout = 10
# network timeout in seconds
# default value is 60
network_timeout = 60
# TCP quick ack for Linux (setsockopt with TCP_QUICKACK option)
# default value is true
tcp_quick_ack = true
# the rule of read data, value list:
### any : any available server
### slave : slave first, access master when all slaves down or offline
### master : master only (default)
# this parameter can be overriden / redefined in section [FastDIR] and [FastStore]
read_rule = master
# the mode of retry interval, value list:
### fixed for fixed interval
### multiple for multiplication (default)
# this parameter can be overriden / redefined in section [FastDIR] and [FastStore]
retry_interval_mode = multiple
# the max retry interval in milliseconds
# valid when retry_interval_mode set to multiple
# default value is 3000 ms
# this parameter can be overriden / redefined in section [FastDIR] and [FastStore]
retry_max_interval_ms = 3000
# retry times when connect to server fail
### 0 for never retry
### < 0 for infinite retry
# default value is 200
# this parameter can be overriden / redefined in section [FastDIR] and [FastStore]
connect_retry_times = 200
# retry interval when connect to server fail
# unit: milliseconds
# default value is 100 ms
# this parameter can be overriden / redefined in section [FastDIR] and [FastStore]
connect_retry_interval_ms = 100
# retry times when communicate with server fail
### 0 for never retry
### < 0 for infinite retry
# default value is 200
# this parameter can be overriden / redefined in section [FastDIR] and [FastStore]
network_retry_times = 200
# retry interval when communicate with server fail
# unit: milliseconds
# default value is 100 ms
# this parameter can be overriden / redefined in section [FastDIR] and [FastStore]
network_retry_interval_ms = 100
[idempotency]
# if enable RPC idempotency for highest level consistency
# default value is false
enabled = true
# the idempotency channel hashtable capacity
# default value is 1361
channel_htable_capacity = 1361
# the heartbeat interval for RPC idempotency channel
# unit: seconds
# default value is 3s
channel_heartbeat_interval = 3
# close the idempotency channel when max idle time reachs
# unit: seconds
# default value is 300s
channel_max_idle_time = 300
# max connections for RPC idempotency report
# you should set this parameter larger than the total server count of
# FastDIR and FastStore
# default value is 256
max_connections = 1024
# work thread count for RPC idempotency report
# default value is 1
work_threads = 1
# max pkg size for RPC idempotency report
# default value is 256KB
max_pkg_size = 256KB
# thread stack size, should >= 320KB
thread_stack_size = 512KB
[FastDIR]
# connect timeout in seconds
# default value is 10
# Note: in the intranet network (LAN), 10 seconds is enough.
connect_timeout = 10
# network timeout in seconds
# default value is 60
network_timeout = 60
# the namespace for FastDIR
namespace = fs
# config the cluster servers
cluster_config_filename = ../fdir/cluster.conf
# if use sys lock for file append and truncate to avoid conflict
# set true when the files appended or truncated by many nodes (FUSE instances)
# default value is false
use_sys_lock_for_append = false
# if async report file attributes (size, modify time etc.) to the FastDIR server
# default value is true
async_report_enabled = true
# the interval in milliseconds for async report file attributes to the FastDIR server
# default value is 100 ms
async_report_interval_ms = 100
# the sharding count of hashtable
# NO more than 1000 is recommended
# default value is 17
hashtable_sharding_count = 17
# the capacity (bucket count) of all sharding hashtables
# default value is 1403641
hashtable_total_capacity = 1403641
# the shared allocators for hashtabe entry, task etc.
# NO more than the CPU cores is recommended
# default value is 11
shared_allocator_count = 11
# set the owner (user and group) of new created files and directories
# the values are:
## caller: current user and group from the calling process (default)
## fixed: fixed user and group
owner_type = caller
# set the user owner (username) of the new created files and directories
# this parameter is valid only when owner_type set to fixed
# empty for the user who runs the fs_fused program
owner_user =
# set the group owner (group name) of the new created files and directories
# this parameter is valid only when owner_type set to fixed
# empty for the group of the user who runs the fs_fused program
owner_group =
[FastStore]
# connect timeout in seconds
# default value is 10
# Note: in the intranet network (LAN), 10 seconds is enough.
connect_timeout = 10
# network timeout in seconds
# default value is 60
network_timeout = 60
# config the cluster servers and groups
cluster_config_filename = ../fstore/cluster.conf
# the sharding count of hashtable
# NO more than 1000 is recommended
# default value is 163
hashtable_sharding_count = 163
# the capacity (bucket count) of all sharding hashtables
# default value is 1403641
hashtable_total_capacity = 1403641
# the shared allocators for hashtabe entry, task, slice etc.
# NO more than the CPU cores is recommended
# default value is 17
shared_allocator_count = 17
[write-combine]
# if enable write combine feature for FastStore
# default value is true
enabled = true
# the buffer size for write combine
# the min value is 64KB and the max value is the data block size such as 4MB
# default value is 256KB
buffer_size = 256KB
# the min wait time in milliseconds for write combine
# the min value is 10ms and the max value is 100ms
# default value is 20ms
min_wait_time_ms = 50
# the max wait time in milliseconds for write combine
# the min value is 100ms and the max value is 10000ms
# default value is 1000ms
max_wait_time_ms = 1000
# the slice size for skipping write combine
# skip combine when the slice size >= this parameter
# the min value is 64KB and the max value is the data block size such as 4MB
# default value is 256KB
skip_combine_on_slice_size = 256KB
# the merged slice count of last combine for skipping write combine
# skip combine when the last combine is in progress and
# it's merged slice count <= this parameter
# default value is 1
skip_combine_on_last_merged_slices = 1
# the shared locks for timer (timeout manager)
# default value is 163
timer_shared_lock_count = 163
# the max waiting slice count in queue for flow control
# default value is 16
max_waiting_slice_count = 16
# the thread limit (max threads) for the thread pool
# default value is 8
thread_pool_max_threads = 8
# the min idle thread count for the thread pool
# default value is 2
thread_pool_min_idle_count = 2
# the max idle time in seconds for the thread pool
# the running thread will exit on three conditions:
## 1. this paramter > 0
## 2. running thread count > thread_pool_min_idle_count
## 3. the thread's idle time exceeds this parameter
# default value is 300 (seconds)
thread_pool_max_idle_time = 300
[read-ahead]
# if enable read ahead feature for FastStore
# default value is true
enabled = true
# the TTL in miliseconds for preread cache
# the min value is 100ms and the max value is 10000ms
# default value is 1000ms
cache_ttl_ms = 1000
# the min buffer size for preread
# the min value is 1KB and the max value is 16KB
# default value is 4KB
min_buffer_size = 4KB
# the max buffer size for preread
# the min value is 16KB and the max value is 256KB
# default value is 128KB
max_buffer_size = 128KB
# the slice size for skipping read ahead
# skip read ahead when the slice size >= this parameter
# the min value is 8KB and the max value is 128KB
# default value is half of max_buffer_size
skip_preread_on_slice_size = 64KB
# the shared locks for preread hashtable
# default value is 1361
shared_lock_count = 1361
================================================
FILE: conf/fuse.conf
================================================
# the base path to store log files
# this path must exist
base_path = /opt/fastcfs/fcfs
# the mount point (local path) for FUSE
# the local path must exist
mountpoint = /opt/fastcfs/fuse
# if use busy polling for RDMA network
# should set to true for HPC
# default value is false
busy_polling = false
[idempotency]
# if enable RPC idempotency for highest level consistency
# default value is false
enabled = true
# thread stack size, should >= 320KB
thread_stack_size = 512KB
[FastDIR]
# the namespace for FastDIR
namespace = fs
# config the cluster servers
cluster_config_filename = ../fdir/cluster.conf
# if use sys lock for file append and truncate to avoid conflict
# set true when the files appended or truncated by many nodes (FUSE instances)
# default value is false
use_sys_lock_for_append = false
# if async report file attributes (size, modify time etc.) to the FastDIR server
# default value is true
async_report_enabled = true
# the interval in milliseconds for async report file attributes to the FastDIR server
# default value is 100 ms
async_report_interval_ms = 100
[FastStore]
# config the cluster servers and groups
cluster_config_filename = ../fstore/cluster.conf
[write-combine]
# if enable write combine feature for FastStore
# default value is true
enabled = true
[read-ahead]
# if enable read ahead feature for FastStore
# default value is true
enabled = true
[FUSE]
# if use separate fuse device fd for each thread
# set to true for more high performance
# default value is false
clone_fd = true
# access permissions for other users
# the values are:
## all for all users
## root for root only
## empty or other values for none
allow_others = all
# cache time for file attribute in seconds
# default value is 1.0s
attribute_timeout = 5.0
# cache time for file entry in seconds
# default value is 1.0s
entry_timeout = 5.0
# if enable kernel writeback cache
# set to true for unshared data scene (private data for single node)
# default value is true
writeback_cache = true
# if keep kernel cache for read
# set to true for unshared data scene (private data for single node)
# should set to false on shared data scene for multi nodes
# default value is true
kernel_cache = true
# if enable x-attribute
# default value is false
# IMPORTANT NOTE:
### because Linux kernel get the xattr "security.capability" *EVERY* write,
### do NOT change this parameter to true unless your application need
### setxattr, getxattr or listxattr really!
xattr_enabled = false
================================================
FILE: conf/papi.conf
================================================
# the base path to store log files
# this path must exist
base_path = /opt/fastcfs/fcfs
# the virtual mount point
mountpoint = /
[idempotency]
# if enable RPC idempotency for highest level consistency
# default value is false
enabled = true
# thread stack size, should >= 320KB
thread_stack_size = 512KB
[FastDIR]
# the namespace for FastDIR
namespace = fs
# config the cluster servers
cluster_config_filename = ../fdir/cluster.conf
# if use sys lock for file append and truncate to avoid conflict
# set true when the files appended or truncated by many nodes (FUSE instances)
# default value is false
use_sys_lock_for_append = false
# if async report file attributes (size, modify time etc.) to the FastDIR server
# default value is true
async_report_enabled = true
# the interval in milliseconds for async report file attributes to the FastDIR server
# default value is 100 ms
async_report_interval_ms = 100
[FastStore]
# config the cluster servers and groups
cluster_config_filename = ../fstore/cluster.conf
[write-combine]
# if enable write combine feature for FastStore
# default value is true
enabled = true
[read-ahead]
# if enable read ahead feature for FastStore
# default value is true
enabled = true
================================================
FILE: debian/changelog
================================================
fastcfs (5.5.0-1) unstable; urgency=medium
* upgrade to 5.5.0-1
-- YuQing <384681@qq.com> Sun, 23 Nov 2025 10:53:21 +0000
fastcfs (5.5.0-1) unstable; urgency=medium
* upgrade to 5.5.0-1
-- YuQing <384681@qq.com> Sun, 23 Nov 2025 10:06:42 +0000
fastcfs (5.5.0-1) unstable; urgency=medium
* upgrade to 5.5.0-1
-- YuQing <384681@qq.com> Sun, 23 Nov 2025 09:11:49 +0000
fastcfs (5.4.1-1) unstable; urgency=medium
* upgrade to 5.4.1-1
-- YuQing <384681@qq.com> Sat, 16 Aug 2025 16:37:13 +0000
fastcfs (5.4.0-1) unstable; urgency=medium
* upgrade to 5.4.0-1
-- YuQing <384681@qq.com> Sun, 06 Apr 2025 17:01:49 +0000
fastcfs (5.3.2-1) unstable; urgency=medium
* upgrade to 5.3.2-1
-- YuQing <384681@qq.com> Sun, 29 Sep 2024 15:29:40 +0000
fastcfs (5.3.1-1) unstable; urgency=medium
* upgrade to 5.3.1-1
-- YuQing <384681@qq.com> Sat, 15 Jun 2024 14:50:36 +0000
fastcfs (5.3.0-1) unstable; urgency=medium
* upgrade to 5.3.0-1
-- YuQing <384681@qq.com> Sun, 17 Mar 2024 15:16:01 +0000
fastcfs (5.2.0-1) unstable; urgency=medium
* upgrade to 5.2.0-1
-- YuQing <384681@qq.com> Wed, 31 Jan 2024 12:05:19 +0000
fastcfs (5.1.0-1) unstable; urgency=medium
* upgrade to 5.1.0-1
-- YuQing <384681@qq.com> Mon, 01 Jan 2024 11:30:03 +0000
fastcfs (5.0.0-3) unstable; urgency=medium
* upgrade to 5.0.0-3
-- YuQing <384681@qq.com> Tue, 21 Nov 2023 14:41:40 +0000
fastcfs (5.0.0-2) unstable; urgency=medium
* upgrade to 5.0.0-2
-- YuQing <384681@qq.com> Mon, 20 Nov 2023 13:29:08 +0000
fastcfs (5.0.0-1) unstable; urgency=medium
* upgrade to 5.0.0-1
-- YuQing <384681@qq.com> Sun, 19 Nov 2023 14:50:41 +0000
fastcfs (4.3.0-1) unstable; urgency=medium
* upgrade to 4.3.0-1
-- YuQing <384681@qq.com> Sun, 06 Aug 2023 07:28:20 +0000
fastcfs (4.2.0-1) unstable; urgency=medium
* upgrade to 4.2.0-1
-- YuQing <384681@qq.com> Sun, 23 Jul 2023 14:33:49 +0000
fastcfs (4.1.0-1) unstable; urgency=medium
* upgrade to 4.1.0-1
-- YuQing <384681@qq.com> Sat, 24 Jun 2023 06:57:02 +0000
fastcfs (4.0.0-1) unstable; urgency=medium
* upgrade to 4.0.0-1
-- YuQing <384681@qq.com> Sun, 04 Jun 2023 10:59:03 +0000
fastcfs (3.7.2-1) unstable; urgency=medium
* upgrade to 3.7.2-1
-- YuQing <384681@qq.com> Sat, 18 Feb 2023 05:50:44 +0000
fastcfs (3.7.1-1) unstable; urgency=medium
* upgrade to 3.7.1-1
-- YuQing <384681@qq.com> Sun, 15 Jan 2023 13:56:32 +0000
fastcfs (3.7.0-1) unstable; urgency=medium
* upgrade to 3.7.0-1
-- YuQing <384681@qq.com> Mon, 21 Nov 2022 15:01:45 +0000
fastcfs (3.6.2-1) unstable; urgency=medium
* upgrade to 3.6.2-1
-- YuQing <384681@qq.com> Sat, 08 Oct 2022 13:30:32 +0000
fastcfs (3.6.1-1) unstable; urgency=medium
* upgrade to 3.6.1-1
-- YuQing <384681@qq.com> Thu, 22 Sep 2022 12:24:49 +0000
fastcfs (3.6.0-1) unstable; urgency=medium
* upgrade to 3.6.0-1
-- YuQing <384681@qq.com> Wed, 07 Sep 2022 13:38:59 +0000
fastcfs (3.5.0-2) unstable; urgency=medium
* upgrade to 3.5.0-2
-- YuQing <384681@qq.com> Sat, 30 Jul 2022 12:58:43 +0000
fastcfs (3.5.0-1) unstable; urgency=medium
* upgrade to 3.5.0-1
-- YuQing <384681@qq.com> Mon, 25 Jul 2022 13:54:45 +0000
fastcfs (3.4.0-2) unstable; urgency=medium
* upgrade to 3.4.0-2
-- YuQing <384681@qq.com> Thu, 30 Jun 2022 15:20:18 +0000
fastcfs (3.4.0-1) unstable; urgency=medium
* upgrade to 3.4.0-1
-- YuQing <384681@qq.com> Wed, 15 Jun 2022 14:28:17 +0000
fastcfs (3.3.0-1) unstable; urgency=medium
* upgrade to 3.3.0-1
-- YuQing <384681@qq.com> Thu, 28 Apr 2022 11:56:12 +0000
fastcfs (3.2.0-1) unstable; urgency=medium
[ sungness ]
* Update README.md
* Update AUTH-zh_CN.md
* Update docs style
* Update CONFIGURE-zh_CN.md
* update docs style
* Update fcfs.sh add status command
* Update fcfs-ops-tool.md add description for status command
* Update fcfs.sh
[ YuQing ]
* CONFIGURE-zh_CN.md changed for storage engine
[ sungness ]
* Update fcfs.sh and fcfs_conf.sh add storage.conf for fdir
[ YuQing ]
* AUTH-zh_CN.md changed
* AUTH-zh_CN.md refined
* AUTH-zh_CN.md format
* fcfs_authd.service rename to fastauth.service
* README: description improved
* fix permission check for storage pool list
* fcfs_pool.c: beautify spool output
* fix list_spool and list_gpool return status
* [fauth] support regenerate secret key
* use -y option to confirm when the user is same with the admin
* beautify prompt for -y option
* change FUSEOwnerType to FCFSAPIOwnerType
* add files src/api/fcfs_posix_api.[hc]
* move fcfs_posix_api.[hc] to std/posix_api.[hc]
* add files: std/fd_manager.[hc]
* add files: std/papi_file.[hc] and std/papi_dir.[hc]
* fcfs_write and fcfs_pwrite impl.
* fcfs_writev and fcfs_pwritev impl.
* fcfs_read[v] and fcfs_pread[v] impl.
* impl. fcfs_fstat, fcfs_symlinkat, etc.
* rename papi_file.[hc] to papi.[hc]
* call stat_dentry_xxx with flags
* call link_dentry_xxx with flags
* fcfs_api_file.c: check_writable and check_readable
* impl. fcfs_utimes, fcfs_rename etc.
* call remove_dentry_xxx with flags
* impl. fcfs_setxattr, fcfs_getxattr etc.
* impl. opendir, readdir, closedir ...
* fcntl impl.
* chdir and getcwd impl.
* wrapper chroot, dup, dup2 etc.
* add src/api/tests/test_papi_copy.c and test passed
* test_papi_copy.c: support readv & writev
* add preload files: types.h and global.[hc]
* adapt dlsym in mac OS
* preload api wrapper done.
* set get size flags for getxattr and listxattr
* proxy api correctly (such as use syscall) when not inited
* __xstat, __lxstat etc. implement OK.
[ vazmin ]
* fcfs_authd service rename to fastauth
[ YuQing ]
* support posix_fallocate, dprintf etc.
* support euidaccess and eaccess
* preload support posix_fallocate, dprintf etc.
* C API fcfs_fopen impl.
* remove ctx parameter for posix functions with fd
* fdopen, freopen impl.
* impl. fputc, fgetc, fread, fwrite etc.
* impl. getdelim, getline etc.
* support function fcfs_readline
* preload for c APIs
* change function prototypes for __xmknod and __xmknodat
* compile passed in MacOS
* impl. __fprintf_chk and __vfprintf_chk
* impl. fsync, fdatasync and fcloseall
* preload use syscall to forward request
* papi.[hc] use fcfs_getcwd for current directory
* extract common codes for posix_api_init
* impl. fcfs_api_log_client_common_configs and fcfs_posix_api_log_configs
* add docs/cluster-expansion-zh_CN.md
* docs/cluster-expansion-zh_CN.md refined
* docs/cluster-expansion-zh_CN.md refined v2
* docs/cluster-expansion-zh_CN.md refined v3
* upgrade version to 3.2.0
* upgrade versions for RPM spec files
* compile passed in CentOS 7.4
* fuse.conf add parameter: xattr_enabled
* docs/cluster-expansion-zh_CN.md refined v4
* add link to docs/cluster-expansion-zh_CN.md
[ Jerry ]
* add mkdocs for documents build
[ YuQing ]
* add comments for posix_api.h
* cluster-expansion-zh_CN.md refined v5
* change version declare for README.md
* README refined
-- YuQing <384681@qq.com> Sun, 13 Mar 2022 17:07:08 +0800
fastcfs (3.1.0-1) unstable; urgency=medium
* upgrade version to 3.1.0
-- YuQing <384681@qq.com> Sat, 15 Jan 2022 20:54:06 +0800
fastcfs (3.0.0-1) unstable; urgency=medium
* upgrade version to 3.0.0
-- YuQing <384681@qq.com> Sun, 26 Dec 2021 21:55:51 +0800
fastcfs (2.3.0-1) unstable; urgency=medium
* Initial release.
-- YuQing <384681@qq.com> Tue, 20 Jul 2021 00:55:33 +0800
================================================
FILE: debian/compat
================================================
11
================================================
FILE: debian/control
================================================
Source: fastcfs
Section: admin
Priority: optional
Maintainer: YuQing <384681@qq.com>
Build-Depends: debhelper (>=11~),
fastdir-dev (>= 3.2.0) ,
faststore-dev (>= 3.2.0) ,
libfuse3-dev (>= 3.10.1) ,
fastcfs-auth-dev (>=3.6.0) ,
fastcfs-vote-dev (>=3.6.0) ,
libfastcommon-dev (>= 1.0.56),
libserverframe-dev (>= 1.1.13)
Standards-Version: 4.1.4
Homepage: http://github.com/happyfish100/FastCFS/
Package: fastcfs
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: fastcfs-fused (= ${binary:Version}),
fastcfs-utils (= ${binary:Version}),
${misc:Depends}, ${shlibs:Depends}
Description: the auth client library and config files of FastCFS.
a high performance distributed file system which can be used as the back-end storage of databases and cloud platforms.
Package: fastcfs-fused
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: fastcfs-api-libs (= ${binary:Version}),
fuse3 (>= 3.10.1),
fastcfs-fuse-config (>= ${fastcfs-fuse-config:Version}),
${misc:Depends}, ${shlibs:Depends}
Description: FastCFS fuse
Package: fastcfs-utils
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: libserverframe (>= ${libserverframe:Version}),
${misc:Depends}, ${shlibs:Depends}
Description: FastCFS utils
Package: fastcfs-api-libs
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: fastdir-client (>= ${fastdir-client:Version}),
faststore-client (>= ${faststore-client:Version}),
${misc:Depends}, ${shlibs:Depends}
Description: FastCFS api library
Package: fastcfs-api-tests
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: fastcfs-fuse-config (>= ${fastcfs-fuse-config:Version}),
${misc:Depends}, ${shlibs:Depends}
Description: FastCFS api tests
Package: fastcfs-api-dev
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: fastcfs-api-libs (= ${binary:Version}),
${misc:Depends}, ${shlibs:Depends}
Description: header files of FastCFS api library
Package: fastcfs-auth-server
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: fastdir-client (>= ${fastdir-client:Version}),
fastcfs-auth-config (>= ${fastcfs-auth-config:Version}),
${misc:Depends}, ${shlibs:Depends}
Description: FastCFS auth server
Package: fastcfs-fuse-config
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: faststore-config (>= ${faststore-config:Version})
${misc:Depends}, ${shlibs:Depends}
Description: FastCFS fuse config files for sample
Package: fastcfs-auth
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: libfastcommon (>= ${libfastcommon:Version}),
libserverframe (>= ${libserverframe:Version}),
fastcfs-auth-server (= ${binary:Version}),
fastcfs-auth-client (= ${binary:Version}),
fastcfs-auth-config (>= ${fastcfs-auth-config:Version}),
${misc:Depends}
Description: the auth client library and config files of FastCFS.
FastCFS is a high performance distributed file system which can be used as the back-end storage of databases and cloud platforms.
Package: fastcfs-auth-dev
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: fastcfs-auth-client (= ${binary:Version}),
${misc:Depends}
Description: header files of FastCFS auth client
This package provides the header files of libfcfsauthclient
Package: fastcfs-auth-client
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: libfastcommon (>= ${libfastcommon:Version}),
libserverframe (>= ${libserverframe:Version}),
${misc:Depends}, ${shlibs:Depends}
Description: FastCFS auth client
FastCFS auth client
Package: fastcfs-auth-config
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: ${misc:Depends}
Description: FastCFS auth config files for sample
FastCFS auth config files for sample
Package: fastcfs-vote-server
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: libserverframe (>= ${libserverframe:Version}),
fastcfs-vote-config (>= ${fastcfs-vote-config:Version}),
${misc:Depends}, ${shlibs:Depends}
Description: FastCFS vote server
Package: fastcfs-vote
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: libfastcommon (>= ${libfastcommon:Version}),
libserverframe (>= ${libserverframe:Version}),
fastcfs-vote-server (= ${binary:Version}),
fastcfs-vote-client (= ${binary:Version}),
fastcfs-vote-config (>= ${fastcfs-vote-config:Version}),
${misc:Depends}
Description: the vote client library and config files of FastCFS.
FastCFS is a high performance distributed file system which can be used as the back-end storage of databases and cloud platforms.
Package: fastcfs-vote-dev
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: fastcfs-vote-client (= ${binary:Version}),
${misc:Depends}
Description: header files of FastCFS vote client
This package provides the header files of libfcfsauthclient
Package: fastcfs-vote-client
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: libfastcommon (>= ${libfastcommon:Version}),
libserverframe (>= ${libserverframe:Version}),
${misc:Depends}, ${shlibs:Depends}
Description: FastCFS vote client
FastCFS vote client
Package: fastcfs-vote-config
Architecture: any
Multi-Arch: foreign
Build-Profiles:
Depends: ${misc:Depends}
Description: FastCFS vote config files for sample
FastCFS vote config files for sample
================================================
FILE: debian/copyright
================================================
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: fastcfs
Source:
#
# Please double check copyright with the licensecheck(1) command.
Files: *
Copyright: 2020 YuQing <384681@qq.com>
License: AGPL-3.0+
This program is free software: you can use, redistribute, and/or modify
it under the terms of the GNU Affero General Public License, version 3
or later ("AGPL"), as published by the Free Software Foundation.
.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
# License file: LICENSE
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
.
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
.
Preamble
.
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
.
The precise terms and conditions for copying, distribution and
modification follow.
.
TERMS AND CONDITIONS
.
0. Definitions.
.
"This License" refers to version 3 of the GNU Affero General Public License.
.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
.
A "covered work" means either the unmodified Program or a work based
on the Program.
.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
.
1. Source Code.
.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
.
The Corresponding Source for a work in source code form is that
same work.
.
2. Basic Permissions.
.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
.
4. Conveying Verbatim Copies.
.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
.
5. Conveying Modified Source Versions.
.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
.
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
.
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
.
6. Conveying Non-Source Forms.
.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
.
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
.
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
.
7. Additional Terms.
.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
.
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
.
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
.
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
.
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
.
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
.
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
.
8. Termination.
.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
.
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
.
9. Acceptance Not Required for Having Copies.
.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
.
10. Automatic Licensing of Downstream Recipients.
.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
.
11. Patents.
.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
.
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
.
12. No Surrender of Others' Freedom.
.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
.
13. Remote Network Interaction; Use with the GNU General Public License.
.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
.
14. Revised Versions of this License.
.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
.
15. Disclaimer of Warranty.
.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
.
16. Limitation of Liability.
.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
.
17. Interpretation of Sections 15 and 16.
.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
.
END OF TERMS AND CONDITIONS
.
How to Apply These Terms to Your New Programs
.
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
.
Copyright (C)
.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
.
Also add information on how to contact you by electronic and paper mail.
.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
.
================================================
FILE: debian/fastcfs-api-dev.install
================================================
usr/include/fastcfs/api/*
================================================
FILE: debian/fastcfs-api-libs.install
================================================
usr/lib/libfcfsapi.so*
================================================
FILE: debian/fastcfs-api-tests.install
================================================
usr/bin/fcfs_beachmark
usr/bin/fcfs_test_file_op
usr/bin/fcfs_test_file_copy
usr/bin/fcfs_test_papi_copy
usr/bin/fcfs_test_read_ahead
================================================
FILE: debian/fastcfs-auth-client.install
================================================
usr/lib/libfcfsauthclient.so*
usr/bin/fcfs_user
usr/bin/fcfs_pool
usr/bin/fauth_list_servers
usr/bin/fauth_cluster_stat
================================================
FILE: debian/fastcfs-auth-config.install
================================================
etc/fastcfs/auth/*.conf
etc/fastcfs/auth/keys/*
================================================
FILE: debian/fastcfs-auth-dev.install
================================================
usr/include/fastcfs/auth/*
================================================
FILE: debian/fastcfs-auth-server-config.install
================================================
usr/lib/systemd/system/fastauth.service
================================================
FILE: debian/fastcfs-auth-server.dirs
================================================
opt/fastcfs/auth
================================================
FILE: debian/fastcfs-auth-server.install
================================================
usr/bin/fcfs_authd
================================================
FILE: debian/fastcfs-fuse-config.install
================================================
etc/fastcfs/fcfs/*.conf
================================================
FILE: debian/fastcfs-fused.dirs
================================================
opt/fastcfs/fuse
opt/fastcfs/fcfs
================================================
FILE: debian/fastcfs-fused.install
================================================
usr/bin/fcfs_fused
================================================
FILE: debian/fastcfs-utils.install
================================================
usr/bin/fcfs_active_test
usr/bin/fcfs_pool_stat
================================================
FILE: debian/fastcfs-vote-client.install
================================================
usr/lib/libfcfsvoteclient.so*
usr/bin/fvote_cluster_stat
================================================
FILE: debian/fastcfs-vote-config.install
================================================
etc/fastcfs/vote/*.conf
================================================
FILE: debian/fastcfs-vote-dev.install
================================================
usr/include/fastcfs/vote/*
================================================
FILE: debian/fastcfs-vote-server.dirs
================================================
opt/fastcfs/vote
================================================
FILE: debian/fastcfs-vote-server.install
================================================
usr/bin/fcfs_voted
================================================
FILE: debian/rules
================================================
#!/usr/bin/make -f
export DESTDIR = $(CURDIR)/debian/tmp
export FUSE_CONFDIR=$(DESTDIR)/etc/fastcfs/fcfs/
export AUTH_CONFDIR=$(DESTDIR)/etc/fastcfs/auth/
export VOTE_CONFDIR=$(DESTDIR)/etc/fastcfs/vote/
%:
dh $@
override_dh_auto_build:
ifneq ($(filter pkg.fastcfs.core,$(DEB_BUILD_PROFILES)),)
./make.sh --exclude=client clean && ./make.sh --exclude=client
endif
ifneq ($(filter pkg.auth.client,$(DEB_BUILD_PROFILES)),)
./make.sh --module=auth_client clean && ./make.sh --module=auth_client
endif
ifneq ($(filter pkg.vote.client,$(DEB_BUILD_PROFILES)),)
./make.sh --module=vote_client clean && ./make.sh --module=vote_client
endif
override_dh_auto_install:
ifneq ($(filter pkg.fastcfs.core,$(DEB_BUILD_PROFILES)),)
./make.sh --exclude=client install
mkdir -p $(FUSE_CONFDIR)
cp conf/*.conf $(FUSE_CONFDIR)
cp systemd/fastcfs.service debian/fastcfs-fused.fastcfs.service
cp systemd/fastauth.service debian/fastcfs-auth-server.fastauth.service
cp systemd/fastvote.service debian/fastcfs-vote-server.fastvote.service
endif
ifneq ($(filter pkg.auth.client,$(DEB_BUILD_PROFILES)),)
./make.sh --module=auth_client install
AUTH_CONFDIR=$(DESTDIR)/etc/fastcfs/auth/
mkdir -p $(AUTH_CONFDIR)
cp src/auth/conf/*.conf $(AUTH_CONFDIR)
cp -R src/auth/conf/keys $(AUTH_CONFDIR)
endif
ifneq ($(filter pkg.vote.client,$(DEB_BUILD_PROFILES)),)
./make.sh --module=vote_client install
VOTE_CONFDIR=%{buildroot}/etc/fastcfs/vote/
mkdir -p $(VOTE_CONFDIR)
cp src/vote/conf/*.conf $(VOTE_CONFDIR)
endif
dh_auto_install
override_dh_installsystemd:
dh_installsystemd --package=fastcfs-fused --name=fastcfs --no-start --no-restart-on-upgrade
dh_installsystemd --package=fastcfs-auth-server --name=fastauth --no-start --no-restart-on-upgrade
dh_installsystemd --package=fastcfs-vote-server --name=fastvote --no-start --no-restart-on-upgrade
.PHONY: override_dh_gencontrol
override_dh_gencontrol:
dh_gencontrol -- -Tdebian/substvars
================================================
FILE: debian/source/format
================================================
3.0 (quilt)
================================================
FILE: debian/substvars
================================================
libfastcommon:Version=1.0.83
libserverframe:Version=1.2.11
fastcfs-auth-config:Version=2.0.0
fastcfs-vote-config:Version=3.4.0
fastdir-client:Version=5.5.0
faststore-config:Version=1.0.0
faststore-client:Version=5.5.0
fastcfs-fuse-config:Version=1.0.0
================================================
FILE: debian/watch
================================================
version=3
opts="mode=git" https://github.com/happyfish100/FastCFS.git \
refs/tags/v([\d\.]+) debian uupdate
================================================
FILE: docs/APT-INSTALL-zh_CN.md
================================================
## 支持Debian 10及以上版本,Ubuntu 18.04及以上版本 和 Deepin 20及以上版本,amd64 和arm64 两种架构。
### 1. 配置 apt 存储库
配置 apt 存储库和签名密钥,以使系统的包管理器启用自动更新。
```shell
sudo apt-get install curl gpg
curl http://www.fastken.cn/aptrepo/packages.fastos.pub | gpg --dearmor > fastos-archive-keyring.gpg
sudo install -D -o root -g root -m 644 fastos-archive-keyring.gpg /usr/share/keyrings/fastos-archive-keyring.gpg
sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/fastos-archive-keyring.gpg] http://www.fastken.cn/aptrepo/fastos/ fastos main" > /etc/apt/sources.list.d/fastos.list'
rm -f fastos-archive-keyring.gpg
```
如果需要安装调试包,执行:
```shell
sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/fastos-archive-keyring.gpg] http://www.fastken.cn/aptrepo/fastos-debug/ fastos-debug main" > /etc/apt/sources.list.d/fastos-debug.list'
```
然后更新包缓存
```
sudo apt update
```
### 2. fastDIR server安装
在需要运行 fastDIR server的服务器上执行:
```shell
sudo apt install fastdir-server -y
```
### 3. faststore server安装
在需要运行 faststore server的服务器上执行:
```shell
sudo apt install faststore-server -y
```
### 4. FastCFS客户端安装
在需要使用FastCFS存储服务的机器(即FastCFS客户端)上执行:
```shell
# 注:fastcfs-fused依赖fuse3
sudo apt install fastcfs-fused -y
```
### 5. Vote server安装(可选)
Vote server作为FastCFS多个服务模块共用的选举节点,主要作用是实现双副本防脑裂(即双活互备防脑裂)。
在需要运行选举节点的服务器上执行:
```shell
sudo apt install fastcfs-vote-server -y
```
### 6. Auth server安装(可选)
如果需要存储池或访问控制,则需要安装本模块。
在需要运行 Auth server的服务器上执行:
```shell
sudo apt install fastcfs-auth-server -y
```
### 7. 集群配置(必须)
安装完成后,需要修改对应的配置文件,服务才可以正常启动。请参阅[配置指南](CONFIGURE-zh_CN.md)
### 8. 启动
FastCFS后台程序可通过systemd管理。systemd服务名称如下:
* fastdir: 目录服务,对应程序为 fdir_serverd
* faststore:存储服务,对应程序为 fs_serverd
* fastcfs: FUSE后台服务,对应程序为 fcfs_fused
* fastvote: 选举节点,对应程序为 fcfs_voted
* fastauth: 认证服务,对应程序为 fcfs_authd
可以使用标准的systemd命令对上述5个服务进行管理,例如:
```shell
sudo systemctl restart fastdir
sudo systemctl restart faststore
sudo systemctl restart fastcfs
sudo systemctl restart fastvote
sudo systemctl restart fastauth
```
================================================
FILE: docs/AUTH-zh_CN.md
================================================
# Auth (认证模块)配置及运行
如果你不需要使用存储池或访问权限控制,可以跳过本文档。
本文档以FastCFS RPM包设定的路径(配置文件目录和程序工作目录等)进行说明,如果你采用自助编译安装方式的话,请自行对应。
为了防脑裂,建议配置3个节点(服务器),因认证服务占用资源较少,可以和其他服务共用服务器。
## 1. Auth配置文件目录结构
```
/etc/fastcfs/
|
|__ auth: 认证中心
|__ keys: 存放用户密钥文件,每个用户对应一个密钥文件,例如 admin.key
| |__ session_validate.key: 用于FastDIR和FastStore请求auth服务验证session和权限
|__ cluster.conf: 服务器列表,配置服务器ID、IP和端口
|__ server.conf: fcfs_authd对应的配置文件
|__ client.conf: 客户端配置文件
|__ auth.conf: 认证相关的公共配置文件,在FastDIR和FastStore的cluster.conf中引用
|__ session.conf: session相关配置文件,在Auth、FastDIR和FastStore的server.conf中引用
```
## 2. authd程序工作目录
```
/opt/fastcfs/
|
|__ auth
|__ authd.pid: 服务进程fcfs_authd的pid文件
|__ logs: 日志文件目录
|__ fcfs_authd.log: 错误日志
|__ slow.log: 慢查询日志
```
开启认证功能需要设置认证中心、FastDIR server、FastStore server和FastCFS客户端。
## 3. 认证中心(authd server)配置
配置文件路径:/etc/fastcfs/auth
Auth集群内各个server配置的cluster.conf必须完全一样。
建议配置一次,分发到其他服务器即可。
### 3.1 把Auth集群中的所有服务实例配置到cluster.conf中
每个Auth服务实例包含2个服务端口:cluster 和 service
一个Auth服务实例需要配置一个[server-$id]的section,其中$id为实例ID。
### 3.2 配置 server.conf
* [cluster] 和 [service] 配置的端口(port)必须与cluster.conf中本机的一致,否则启动会报错
### 3.3 配置 auth.conf
将 auth_enabled 设置为 true 以开启认证功能
### 3.4 复制FastDIR server上的如下配置文件到 /etc/fastcfs/fdir/
```
/etc/fastcfs/fdir/client.conf
/etc/fastcfs/fdir/cluster.conf
```
### 3.5 启动authd
authd命令直接重启:
```
/usr/bin/fcfs_authd /etc/fastcfs/auth/server.conf restart
```
或者系统服务命令启动:
```
sudo systemctl restart fastauth
```
查看日志:
```
tail /opt/fastcfs/auth/logs/fcfs_authd.log
```
* 第一次运行将自动创建 admin 用户,默认生成的密钥文件名为 **/etc/fastcfs/auth/keys/admin.key**
* 友情提示:只在master上生成该密钥文件,请在master上分发密钥文件。
### 3.6 创建存储池
创建名为 fs 的存储池,配额无限制:
```
fcfs_pool create fs unlimited
```
**_注:存储池名称必须和FastCFS fuse客户端配置文件fuse.conf中的命名空间一致(缺省配置为fs,可按需修改)_**
## 4. FastDIR server
### 4.1 复制auth server上的如下配置文件到 /etc/fastcfs/auth/
```
/etc/fastcfs/auth/auth.conf
/etc/fastcfs/auth/session.conf
/etc/fastcfs/auth/cluster.conf
/etc/fastcfs/auth/client.conf
```
### 4.2 复制auth server上的如下密钥文件到 /etc/fastcfs/auth/keys/
```
/etc/fastcfs/auth/keys/admin.key
/etc/fastcfs/auth/keys/session_validate.key
```
拷贝完成后重启FastDIR服务(fdir_serverd)
## 5. FastStore server
* 参见 4. FastDIR server 部分
拷贝完成后重启FastStore服务(fs_serverd)
## 6. FastCFS客户端(fused)
* 参见 4. FastDIR server 部分
拷贝完成后重启fuse服务(fcfs_fused)
## 友情提示
* 4 ~ 6部分的配置及启动参见 [配置指南](CONFIGURE-zh_CN.md)
## 7. 命令行工具
* fcfs_user:用户管理,主要包括创建用户、删除用户、设置用户权限(权限包括用户管理、创建存储池等等)
* fcfs_pool:储存池管理,主要包括创建pool、删除pool、把pool读写权限授权给其他用户
友情提示:直接执行上述命令可以查看使用帮助。
## 8. 注意事项
* Auth server依赖FastDIR server,需要先启动FastDIR server,然后启动Auth server。
================================================
FILE: docs/CONFIGURE-zh_CN.md
================================================
# 配置及运行
本文档以FastCFS RPM包设定的路径(配置文件目录和程序工作目录等)进行说明,如果你采用自助编译安装方式的话,请自行对应。
FastCFS集群配置包含如下五部分:
* fastDIR server(服务实例)配置
* faststore server(服务实例)配置
* FastCFS客户端配置
* 选举节点配置(可选)
* 认证配置(可选)
## 1. 配置文件目录结构
```
/etc/fastcfs/
|
|__ fcfs: fused服务
| |__ fuse.conf: fcfs_fused对应的配置文件
|
|__ fdir: FastDIR目录服务
| |__ cluster.conf: 服务器列表,配置服务器ID、IP和端口
| |__ server.conf: fdir_serverd对应的配置文件
| |__ storage.conf: 持久化存储配置文件
| |__ client.conf: 客户端配置文件
|
|__ fstore: faststore存储服务
|__ cluster.conf: 服务器列表(配置服务器ID、IP和端口),并配置服务器分组及数据分组之间的对应关系
|__ storage.conf: 存储路径及空间分配和回收配置
|__ server.conf: fs_serverd对应的配置文件
|__ client.conf: 客户端配置文件
```
## 2. 程序工作目录
```
/opt/fastcfs/
|
|__ fcfs
| |__ fused.pid: 服务进程fcfs_fused的pid文件
| |__ logs: 日志文件目录
| |__ fcfs_fused.log: 错误日志
|
|__ fdir
| |__ serverd.pid: 服务进程fdir_serverd的pid文件
| |__ data: 系统数据文件目录,包含集群拓扑结构和binlog
| | |__ cluster.info: 集群拓扑信息
| | |__ .inode.sn: 当前inode顺序号
| | |__ binlog: 存放binlog文件
| |
| |__ db: 存储引擎默认数据目录
| | |__ trunk: trunk binlog
| | |__ inode: segment索引(一个segment包含多个inode,最多65536个,segment id顺序递增)
| | |__ ####(如0001、0002等等): 以trunk file方式存放inode数据
| |
| |__ logs: 日志文件目录
| |__ fdir_serverd.log: 错误日志
| |__ slow.log: 慢查询日志
|
|__ fstore
|__ serverd.pid: 服务进程fs_serverd的pid文件
|__ data: 系统数据文件目录,包含集群拓扑结构和binlog
| |__ data_group.info: 集群数据分组信息
| |__ .store_path_index.dat: 存储路径索引
| |__ .trunk_id.dat: 当前trunk id信息
| |__ replica: replica binlog,一个DG对应一个子目录
| |__ slice: slice binlog
| |__ trunk: trunk binlog
| |__ recovery: slave追加master历史数据,一个DG对应一个子目录
| |__ migrate: 迁移出去的DG数据清理
| |__ rebuild: 单盘数据恢复
|
|__ db: slice索引存储引擎默认数据目录
| |__ trunk: trunk binlog
| |__ block: segment索引(一个segment包含多个block,segment id哈希分布)
| |__ ####(如0001、0002等等): 以trunk file方式存放block索引数据
|
|__ logs: 日志文件目录
|__ fs_serverd.log: 错误日志
|__ slow.log: 慢查询日志
```
## 3. fastDIR server(服务实例)配置
配置文件路径:
> /etc/fastcfs/fdir
fastDIR集群内各个server配置的cluster.conf必须完全一样,建议配置一次,分发到集群中的所有服务器和客户端即可。
### 3.1 把fastDIR集群中的所有服务实例配置到cluster.conf中
每个 **fastDIR** 服务实例包含2个服务端口:**cluster** 和 **service**;
**cluster.conf** 中配置集群所有实例,一个实例由IP + 端口(包括 cluster和service 2个端口 )组成;
一个fastDIR服务实例需要配置一个[server-$id]的section,其中$id为实例ID(从1开始编号);
如果一台服务器上启动了多个实例,因端口与全局配置的不一致,此时必须指定端口。
一个服务实例的配置示例如下:
```
[server-3]
cluster-port = 11015
service-port = 11016
host = 172.16.168.128
```
### 3.2 配置 server.conf
* 如果需要修改数据存放路径,修改配置项 data_path 为绝对路径
* 本机端口包含cluster和service 2个端口,分配在[cluster] 和 [service] 中配置
* 本机IP + 本机端口必须配置在cluster.conf的一个实例中,否则启动时会出现下面类似的出错信息
```
ERROR - file: cluster_info.c, line: 119, cluster config file: /etc/fastcfs/fdir/cluster.conf,
can't find myself by my local ip and listen port
```
* V3.0支持的持久化特性默认是关闭的,在 [storage-engine] 中设置,详情参见源码的conf目录下的配置示例。
启用存储引擎配置示例:
```
[storage-engine]
# if enable the storage engine
### false: use binlog directly
### true: use storage engine for massive files
# default value is false
enabled = true
# the config filename for storage
storage_config_filename = storage.conf
# the path to store the data files
# can be an absolute path or a relative path
# the relative path for sub directory under the base_path
# this path will be created auto when not exist
# default value is db
data_path = db
# the memory limit ratio for dentry
# the valid limit range is [1%, 99%]
# default value is 80%
memory_limit = 80%
```
### 3.3 配置 storage.conf
* 开启持久化存储特性的情况下,才需要配置storage.conf
* 通常采用默认设置即可
fastDIR重启:
```
/usr/bin/fdir_serverd /etc/fastcfs/fdir/server.conf restart
```
或者:
```
sudo systemctl restart fastdir
```
查看日志:
```
tail /opt/fastcfs/fdir/logs/fdir_serverd.log
```
## 4. faststore server(服务实例)配置
配置文件路径:
> /etc/fastcfs/fstore
faststore集群各个服务实例配置的cluster.conf必须完全一样,建议把cluster.conf一次性配置好,然后分发到集群中的所有服务器和客户端。
### 4.1 把 faststore 集群中的所有服务实例配置到 cluster.conf 中
每个 **faststore** 服务实例包含3个服务端口:cluster、replica 和 service,和 **fastDIR** 的 cluster.conf 相比,多了一个replica端口,二者配置方式完全相同。
### 4.2 在 cluster.conf 中配置服务器分组和数据分组对应关系
对于生产环境,为了便于今后扩容,建议数据分组数目至少为64,最好不要超过1024(视业务未来5年发展规模而定)。
### 4.3 在storage.conf 中配置存储路径等参数
支持配置多个存储路径。为了充分发挥出硬盘性能,建议挂载单盘,每块盘作为一个存储路径。
配置示例:
```
store_path_count = 1
[store-path-1]
path = /opt/faststore/data
```
### 4.4 配置 server.conf
* 如果需要修改binlog存放路径,修改配置项 data_path 为绝对路径
* 本机端口包含cluster、replica和service 3个端口,分配在[cluster]、[replica] 和 [service] 中配置
* 本机IP + 本机端口必须配置在cluster.conf的一个实例中,否则启动时会出现类似下面的出错信息
```
ERROR - file: server_group_info.c, line: 347, cluster config file: /etc/fastcfs/fstore/cluster.conf,
can't find myself by my local ip and listen port
```
* V4.0支持的slice索引持久化特性默认是关闭的,在 [storage-engine] 中设置,详情参见源码的conf目录下的配置示例。
启用存储引擎配置示例:
```
[storage-engine]
# if enable the storage engine
### false: use binlog directly
### true: use storage engine for huge storage
# default value is false
enabled = true
# the config filename for storage
storage_config_filename = dbstore.conf
# the path to store the data files
# can be an absolute path or a relative path
# the relative path for sub directory under the base_path
# this path will be created auto when not exist
# default value is db
data_path = db
# the memory limit ratio for slice index
# the valid limit range is [1%, 99%]
# default value is 60%
memory_limit = 60%
```
### 4.5 配置 dbstore.conf
* slice索引开启持久化存储特性的情况下,才需要配置dbstore.conf
* 通常采用默认设置即可
faststore重启:
```
/usr/bin/fs_serverd /etc/fastcfs/fstore/server.conf restart
```
或者:
```
sudo systemctl restart faststore
```
查看日志:
```
tail /opt/fastcfs/fstore/logs/fs_serverd.log
```
## 5. FastCFS客户端配置
fused 配置文件路径:
> /etc/fastcfs/fcfs
_注:如果fused客户端与faststore和fastDIR部署在同一个服务器上,可跳过5.1、5.2节,否则需要将faststore和fastDIR的cluster.conf配置文件复制到fused客户端所在服务器上。_
### 5.1 复制faststore server上的如下配置文件到 /etc/fastcfs/fstore/
```
/etc/fastcfs/fstore/cluster.conf
```
### 5.2 复制fastDIR server上的如下配置文件到 /etc/fastcfs/fdir/
```
/etc/fastcfs/fdir/cluster.conf
```
### 5.3 修改fuse挂载点(可选)
如有必要,可修改配置文件 **fuse.conf** 中的 **mountpoint** 参数来指定挂载点:
> mountpoint = /opt/fastcfs/fuse
fused 重启:
> /usr/bin/fcfs_fused /etc/fastcfs/fcfs/fuse.conf restart
或者:
> sudo systemctl restart fastcfs
查看日志:
> tail /opt/fastcfs/fcfs/logs/fcfs_fused.log
查看fastDIR集群状态:
> fdir_cluster_stat
查看单台fastDIR 服务状态:
> fdir_service_stat $IP:$port
**_友情提示:可以拷贝fdir_cluster_stat 输出的IP和服务端口_**
查看faststore集群状态:
> fs_cluster_stat
查看非ACTIVE的服务列表,使用:
> fs_cluster_stat -N
使用 -h 查看更多选项
查看FastCFS磁盘使用情况:
> df -h /opt/fastcfs/fuse | grep fuse
至此,mountpoint(如:/opt/fastcfs/fuse)可以作为本地文件目录访问了。
## 6. 选举节点配置(可选)
如果需要实现双副本防脑裂(即双活互备防脑裂),请参阅 [选举节点配置文档](VoteNode-zh_CN.md)
## 7. 认证配置(可选)
如果需要开启存储池或访问权限控制,请参阅 [认证配置文档](AUTH-zh_CN.md)
## 8. 共享数据配置(可选)
将FastCFS作为Oracle RAC等系统的共享存储,请参阅 [共享数据配置指南](shared-storage-guide-zh_CN.md)
祝顺利! have a nice day!
================================================
FILE: docs/Easy-install-detail-zh_CN.md
================================================
# 快速体验FastCFS
以CentOS 8为例,用单个服务节点,以一键安装的方式体验下FastCFS。 此方式仅供体验使用,不适合在生产环境使用.
## 1. 获得最新的代码
```
git clone https://gitee.com/fastdfs100/FastCFS.git
```
## 2. 安装
涉及到libfuse的安装更新以及在/usr/local下创建目录,请务必使用sudo或者root的方式安装。
```
cd FastCFS/
sudo ./helloWorld.sh
```
安装过程中会有进度提示信息,全自动进行,当看到以下提示时说明安装成功了。
```
INFO: Copy file fuse.conf to /etc/fastcfs/fcfs/
waiting services ready ...
/dev/fuse 38G 0 38G 0% /opt/fastcfs/fuse
the mounted path is: /opt/fastcfs/fuse
have a nice day!
```
## 3. 验证:查看安装的文件目录
安装成功后,通过df -h 可以看到新增一个/dev/fuse的设备,默认容量与你的磁盘容量有关,非固定值。比如我的是38G.
```
Filesystem Size Used Avail Use% Mounted on
devtmpfs 189M 0 189M 0% /dev
tmpfs 219M 0 219M 0% /dev/shm
tmpfs 219M 6.6M 212M 4% /run
tmpfs 219M 0 219M 0% /sys/fs/cgroup
/dev/mapper/cs-root 47G 5.9G 42G 13% /
/dev/sda1 1014M 242M 773M 24% /boot
tmpfs 44M 4.0K 44M 1% /run/user/1000
/dev/fuse 38G 0 38G 0% /opt/fastcfs/fuse
```
## 4. 使用:在新挂载的目录/opt/fastcfs/fuse 中,可以进行标准的文件创建/编辑/删除操作
```
[first@192.168.126.50 /opt/fastcfs/fuse]
$ pwd
/opt/fastcfs/fuse
[first@192.168.126.50 /opt/fastcfs/fuse]
$ touch abc // 创建文件
[first@192.168.126.50 /opt/fastcfs/fuse]
$ ll
total 0
-rw-rw-r--. 1 first first 0 May 14 17:06 abc
[first@192.168.126.50 /opt/fastcfs/fuse]
$ rm abc // 删除文件
[first@192.168.126.50 /opt/fastcfs/fuse]
$ mkdir -p d1/d2/d3 // 创建目录
[first@192.168.126.50 /opt/fastcfs/fuse]
$ ll
total 0
drwxrwxr-x. 2 first first 0 May 14 17:06 d1
[first@192.168.126.50 /opt/fastcfs/fuse]
$ touch d1/d2/d3/123 // 创建文件
[first@192.168.126.50 /opt/fastcfs/fuse]
$ ll d1/d2/d3/123
-rw-rw-r--. 1 first first 0 May 14 17:06 d1/d2/d3/123
[first@192.168.126.50 /opt/fastcfs/fuse]
$ rm -rf d1 // 删除目录
[first@192.168.126.50 /opt/fastcfs/fuse]
$ ll
total 0
```
## 5. 停止服务
使用fashcfs.sh为管理脚本,可以停止、重启服务:
```
[first@192.168.126.50 ~/FastCFS]
$ sudo ./fastcfs.sh stop
[sudo] password for first:
waiting for pid [2364] exit ...
pid [2364] exit.
waiting for pid [2379] exit ...
pid [2379] exit.
waiting for pid [2383] exit ...
pid [2383] exit.
waiting for pid [2400] exit ...
pid [2400] exit.
```
## 6. 移除安装包恢复初始环境
```
sudo yum remove FastCFS-auth-server FastCFS-fused fastDIR-server faststore-server -y
sudo yum remove fastDIR-config faststore-config FastCFS-auth-config FastCFS-fuse-config -y
sudo rm -rf /etc/fastcfs /opt/fastcfs /opt/faststore
```
================================================
FILE: docs/FAQ-zh_CN.md
================================================
# FAQ
## 1. 服务器最低配置要求
2核CPU、4G内存、10G硬盘
## 2. 网络连接异常
当日志出现`Connection refused`或者`Transport endpoint is not connected`之类的异常记录。
请检查防火墙设置。FastCFS 共有9个服务端口,这些对应的端口应该打开:
* fdir
* 默认集群端口 `11011`
* 默认服务端口 `11012`
* fvote
* 默认集群端口 `41011`
* 默认服务端口 `41012`
* fauth
* 默认集群端口 `31011`
* 默认服务端口 `31012`
* fstore
* 默认集群端口 `21014`
* 默认副本端口 `21015`
* 默认服务端口 `21016`
## 3. 服务有没有启动顺序?
有。应按顺序启动`fvote`(可选),`fdir`, `fauth`(可选),`fstore`,`fuseclient`。
## 4. FastCFS支持单盘数据恢复吗?
```
支持。
实现机制:从本组的其他服务器上获取数据,恢复指定硬盘(即存储路径)上的所有数据。
使用场景:硬盘坏掉后更换为新盘,或者因某种原因重新格式化硬盘。
单盘故障恢复后,重启fs_serverd时,加上命令行参数 --data-rebuild ,
其中 store_path为要恢复数据硬盘对应的存储路径。
```
## 5. FastCFS是如何防脑裂的?
```
leader/master选举时采用过半数机制,一个分组的节点数最好为奇数(比如3个)。
配置项为 quorum,默认值为auto,表示节点数为奇数时开启,为偶数时关闭。
详情参见源码目录下的conf/full/cluster.conf
v3.4引入公用选举节点,在偶数节点数(比如双副本)时也可以防脑裂,详情参见配置文档。
```
## 6. fdir和fstore多副本(如3副本)情况下,停机后重启不能写入数据
```
为了保证数据一致性,当停机时间超过配置参数max_shutdown_duration(默认配置300秒),
需要等待本组的其他服务器在线才可以选出master/leader。
以3副本为例,如果3台服务器停机均超过max_shutdown_duration,而有的服务器没有启动,
那么master/leader选举不出来,导致不能写入数据。此时启动fdir_serverd需要加上命令行
参数--force-master-election,启动fs_serverd需要加上命令行参数--force-leader-election
```
## 7. 如何验证多个副本的数据一致性?
```
faststore需要源码编译,修改make.sh,将
CFLAGS='-Wall'
修改为:
CFLAGS='-Wall -DFS_DUMP_SLICE_FOR_DEBUG=32'
启动fs_serverd,数据将导出到 $base_path/data/dump/slice.index,例如:
/opt/fastcfs/fstore/data/dump/slice.index
文件格式:
类型 文件ID block偏移量 slice偏移量 slice长度 数据长度 数据CRC32
可以通过 diff 命令比较同一组服务器下的两个节点导出的slice.index是否相同。
注意:-DFS_DUMP_SLICE_FOR_DEBUG=32 这个编译选项仅供测试环境进行数据一致性验证,请不要在生产环境使用。
```
## 8. fuse客户端通过df看到的空间明显大于存储池配额
这是因为客户端没有启用auth,需要将配置文件/etc/fastcfs/auth/auth.conf中的auth_enabled设置为true,修改后重启fcfs_fused生效。
友情提示:如何配置auth服务请参阅 [认证配置文档](AUTH-zh_CN.md)
## 9. FastCFS作为NFS后端存储时NFS client mount失败
出错信息:reason given by server: No such file or directory
解决方法:
NFS v3直接使用服务端配置的目录如:/opt/fastcfs/fuse,而v4将服务端配置的路径作为基路径,mount要使用/
NFS挂载默认会使用最新的NFS协议,挂载命令示例(支持v4前提下使用):
```
mount -t nfs -onolock 172.16.168.131:/ /mnt/nfs
```
NFS v3挂载命令示例:
```
mount -t nfs -onolock 172.16.168.131:/opt/fastcfs/fuse /mnt/nfs
```
指定NFS v4挂载命令示例:
```
mount -t nfs -onolock,nfsvers=4 172.16.168.131:/ /mnt/nfs
```
友情提示:
* CentOS 6需要使用NFS v3挂载
* /etc/exports中需要设置fsid=0,例如:/opt/fastcfs/fuse 172.16.168.130(fsid=0,rw,sync,no_root_squash,no_all_squash)
## 10. 为何删除了足够多的数据,df看到磁盘占用空间不见降低呢?
FastCFS基于trunk file进行空间分配,目前trunk file只会增加而不会释放。文件数据删除后空间会回收利用,通过fuse client上df命令可以看到FastCFS的可用空间将增加。
磁盘空间使用率达到阈值后才会启动空间回收,默认阈值为50%,可以根据实际需要调整。配置示例参见faststore源码目录下的conf/full/storage.conf。
## 11. 如何将fastore的数据清除干净?
一些特殊情况下,需要清除掉faststore的数据,此时要删除faststore的系统目录(server.conf中配置的base_path,默认为/opt/fastcfs/fstore)和用户数据存放目录(默认为/opt/faststore/data,配置多盘的情况要逐一删除数据目录),删除命令示例(文件删除后不可恢复,请再三确认后执行):
```
rm -rf /opt/fastcfs/fstore /opt/faststore/data
```
## 12. 日志中报没有访问权限,如何进行排查?
/opt/fastcfs/fcfs/logs/fcfs_fused.log 中的错误示例:
[2023-02-25 06:39:08] ERROR - file: client_proto.c, line: 607, fdir server 192.168.3.210:11012 response message: response status 1, error info: Operation not permitted
问题排查:
依次查看各台fdir server上的日志文件 /opt/fastcfs/fdir/logs/fdir_serverd.log,找到对应的出错信息,然后使用最新版本的fdir_stat 查看对应的完整路径(文件名),根据文件或目录owner、权限、访问用户及其用户组进行排查。
按文件或目录inode查询示例:
```
fdir_stat -Fn fs 9007199660325177
```
按父目录inode + 子目录名或者文件名查询示例:
```
fdir_stat -Fn fs 9007199667318991 test
```
友情提示:如果采用的是装包方式,程序fdir_stat 所在的rpm包名为fastDIR-client,deb包名为fastdir-client
================================================
FILE: docs/INSTALL-zh_CN.md
================================================
# FastCFS安装手册
## 1、fastcfs.sh 脚本统一安装
通过执行fastcfs.sh脚本,可自动安装软件包,并能根据配置文件模版自动生成集群相关配置文件。
fastcfs.sh 命令参数说明:
```
* install: 安装程序包
* config: 复制配置文件并自动配置为单节点
* start | stop | restart: 服务进程控制
```
或执行如下命令(需要root身份执行):
```
./fastcfs.sh install
./fastcfs.sh config
./fastcfs.sh restart
```
通过 df 命令查看FastCFS挂载的文件目录:
```
df -h /opt/fastcfs/fuse | grep fuse
```
以上命令执行成功,你就可以通过本地目录 /opt/fastcfs/fuse 访问FastCFS了。
## 2、DIY编译和安装
### 2.1 安装libaio devel包
对于 CentOS或REHL,执行:
```
yum install libaio-devel -y
```
对于 Unbuntu或Debian,执行:
```
apt install libaio-dev -y
```
其他Linux系统,需要编译安装 **libaio** 库。
### 2.2 安装存储插件包和RDMA通信包【可选】
fastDIR 和faststore 的存储插件以及RDMA通信库都是闭源的,可以通过 yum 或 apt 安装使用。
配置我们的yum源和apt源:
* yum安装方式(针对CentOS、Rocky、Fedora、RHEL等),参阅 [yum安装文档](YUM-INSTALL-zh_CN.md)
* apt安装方式(针对Ubuntu、Debian 和 Deepin),参阅 [apt 安装文档](APT-INSTALL-zh_CN.md)
如果使用存储插件特性,需要通过 yum 或 apt 安装相应的存储插件。
* fastDIR 存储插件包名:libfdirstorage
* faststore 存储插件包名:libfsstorage
具备RDMA网络环境,要启动 RDMA 通信方式,需要安装RDMA通信包:libfastrdma
### 2.3 libfastcommon 编译安装
```
git clone https://gitee.com/fastdfs100/libfastcommon.git; cd libfastcommon/
git checkout master
./make.sh clean && ./make.sh && ./make.sh install
```
默认安装目录:
```
/usr/lib64
/usr/lib
/usr/include/fastcommon
```
### 2.4 libserverframe 编译安装
```
git clone https://gitee.com/fastdfs100/libserverframe.git; cd libserverframe/
./make.sh clean && ./make.sh && ./make.sh install
```
### 2.5 libdiskallocator 编译安装
```
git clone https://gitee.com/fastdfs100/libdiskallocator.git; cd libdiskallocator/
./make.sh clean && ./make.sh && ./make.sh install
```
### 2.6 Vote Node client 编译安装
```
git clone https://gitee.com/fastdfs100/FastCFS.git; cd FastCFS/
./make.sh clean && ./make.sh --module=voteclient && ./make.sh --module=voteclient install
```
### 2.7 Auth client 编译安装
```
git clone https://gitee.com/fastdfs100/FastCFS.git; cd FastCFS/
./make.sh clean && ./make.sh --module=authclient && ./make.sh --module=authclient install
```
### 2.8 fastDIR 编译安装
```
git clone https://gitee.com/fastdfs100/fastDIR.git; cd fastDIR/
./make.sh clean && ./make.sh && ./make.sh install
mkdir -p /etc/fastcfs/fdir/
cp conf/*.conf /etc/fastcfs/fdir/
```
### 2.9 faststore 编译安装
```
git clone https://gitee.com/fastdfs100/faststore.git; cd faststore/
./make.sh clean && ./make.sh && ./make.sh install
mkdir -p /etc/fastcfs/fstore/
cp conf/*.conf /etc/fastcfs/fstore/
```
### 2.10 fuse客户端编译安装
#### 2.10.1 libfuse 编译安装
libfuse 编译依赖比较复杂,建议使用脚本libfuse_setup.sh一键编译和安装。或者执行如下步骤DIY:
构建libfuse需要先安装meson和ninja。安装meson和ninja需要python3.5及更高版本。
##### 2.10.1.1 gcc 安装
友情提示:gcc版本必须 >= 4.7.0
Ubuntu下安装命令:
```
apt install gcc g++ -y
```
CentOS下安装命令:
```
yum install gcc gcc-c++ -y
```
##### 2.10.1.2 pkg-config 和 python安装
需要安装的包名:
* pkg-config
* python3
* python3-pip
Ubuntu下安装命令:
```
apt install pkg-config python3 python3-pip -y
```
CentOS下安装命令:
```
yum install pkgconfig python3 python3-pip -y
```
##### 2.10.1.3 meson 和 ninja 安装
友情提示: ninja 版本必须 >= 1.7
```
pip3 install meson
pip3 install ninja
```
##### 2.10.1.4 libfuse 安装
```
git clone https://gitee.com/mirrors/libfuse.git; cd libfuse/
git checkout fuse-3.16.2
mkdir build/; cd build/
meson ..
meson configure -D prefix=/usr
meson configure -D examples=false
ninja && ninja install
sed -i 's/#user_allow_other/user_allow_other/g' /etc/fuse.conf
sed -i "s#prefix=.*#prefix=/usr#g" /usr/lib64/pkgconfig/fuse3.pc
```
#### 2.10.2 依赖的项目编译和安装
参见上面的2.3 ~2.8,按照步骤逐一编译和安装
#### 2.10.3 fcfs_fused 编译安装
进入之前clone下来的FastCFS目录,然后执行:
```
./make.sh --module=fuseclient clean && ./make.sh --module=fuseclient && ./make.sh --module=fuseclient install
mkdir -p /etc/fastcfs/fcfs/
mkdir -p /etc/fastcfs/vote/
mkdir -p /etc/fastcfs/auth/
cp conf/*.conf /etc/fastcfs/fcfs/
cp -R src/vote/conf/* /etc/fastcfs/vote/
cp -R src/auth/conf/* /etc/fastcfs/auth/
```
配置参见 [配置文档](CONFIGURE-zh_CN.md)
================================================
FILE: docs/INSTALL.md
================================================
### 1. install libaio devel
for CentOS or REHL:
```
yum install libaio-devel -y
```
for Unbuntu or Debian:
```
apt install libaio-dev -y
```
### 2. libfastcommon
```
git clone git@github.com:happyfish100/libfastcommon.git || git clone https://github.com/happyfish100/libfastcommon.git
cd libfastcommon/
git checkout master
./make.sh clean && ./make.sh && ./make.sh install
```
default install directories:
```
/usr/lib64
/usr/lib
/usr/include/fastcommon
```
### 3. libserverframe
```
git clone git@github.com:happyfish100/libserverframe.git || git clone https://github.com/happyfish100/libserverframe.git
cd libserverframe/
./make.sh clean && ./make.sh && ./make.sh install
```
### 4. libdiskallocator
```
git clone https://gitee.com/fastdfs100/libdiskallocator.git || git clone https://github.com/happyfish100/libdiskallocator.git
cd libdiskallocator/
./make.sh clean && ./make.sh && ./make.sh install
```
### 5. Vote Node client
```
git clone git@github.com:happyfish100/FastCFS.git || git clone https://github.com/happyfish100/FastCFS.git
cd FastCFS/
./make.sh clean && ./make.sh --module=voteclient && ./make.sh --module=voteclient install
```
### 6. Auth client
```
git clone git@github.com:happyfish100/FastCFS.git || git clone https://github.com/happyfish100/FastCFS.git
cd FastCFS/
./make.sh clean && ./make.sh --module=authclient && ./make.sh --module=authclient install
```
### 7. fastDIR
```
git clone git@github.com:happyfish100/fastDIR.git || git clone https://github.com/happyfish100/fastDIR.git
cd fastDIR/
./make.sh clean && ./make.sh && ./make.sh install
mkdir -p /etc/fastcfs/fdir/
cp conf/*.conf /etc/fastcfs/fdir/
```
### 8. faststore
```
git clone git@github.com:happyfish100/faststore.git || git clone https://github.com/happyfish100/faststore.git
cd faststore/
./make.sh clean && ./make.sh && ./make.sh install
mkdir -p /etc/fastcfs/fstore/
cp conf/*.conf /etc/fastcfs/fstore/
```
### 9. fuse client
#### 9.1. libfuse
libfuse requires meson and ninja which require python3.5 or higher version
##### 9.1.1. pkg-config and python
packages: pkg-config python3 python3-pip
Ubuntu:
```
apt install pkg-config python3 python3-pip -y
```
CentOS:
```
yum install pkgconfig python3 python3-pip -y
```
##### 9.1.2. meson and ninja
```
pip3 install meson
pip3 install ninja
```
##### 9.1.3. gcc
Ubuntu:
```
apt install gcc g++ -y
```
CentOS:
```
yum install gcc gcc-c++ -y
```
##### 9.1.4. libfuse
```
git clone git@github.com:libfuse/libfuse.git || git clone https://github.com/libfuse/libfuse.git
cd libfuse/
git checkout fuse-3.10.1
mkdir build/; cd build/
meson ..
meson configure -D prefix=/usr
meson configure -D examples=false
ninja && ninja install
sed -i 's/#user_allow_other/user_allow_other/g' /etc/fuse.conf
sed -i "s#prefix=.*#prefix=/usr#g" /usr/lib64/pkgconfig/fuse3.pc
```
#### 9.2. fcfs_fused
```
cd FastCFS/
./make.sh --module=fuseclient clean && ./make.sh --module=fuseclient && ./make.sh --module=fuseclient install
mkdir -p /etc/fastcfs/fcfs/
mkdir -p /etc/fastcfs/vote/
mkdir -p /etc/fastcfs/auth/
cp conf/*.conf /etc/fastcfs/fcfs/
cp -R src/vote/conf/* /etc/fastcfs/vote/
cp -R src/auth/conf/* /etc/fastcfs/auth/
```
================================================
FILE: docs/ReleaseNotes.md
================================================
## FastCFS V3.1.0 发布,主要改进如下:
### 新特性
1. [fdir] 对核心组件FastDIR进行改进,实现了LRU淘汰算法,以有限内存支持海量文件
分布式目录服务FastDIR的淘汰算法具有两大特性:
1. 按目录结构淘汰:先淘汰子节点,然后淘汰父节点;
2. 按数据线程淘汰:每个数据线程作为一个独立的数据单元,数据存取和淘汰均在其数据线程中以无锁方式完成。
### Bug修复
1. 采用引用计数方式,不再延迟释放 dentry;
2. delay free namespace string for lockless;
3. bugfixed: get trunk_file_size from ini file correctly。
---------------
## FastCFS V3.0.0 发布,主要改进如下:
### 新特性
1. [fdir] 核心组件FastDIR通过插件方式实现数据存储引擎,采用binlog + 存储引擎插件,按需加载inode数据,单机以有限内存(如64GB)支持100亿级的海量文件
### Bug修复
1. [fdir] increase/decrease parent's nlink on rename operation
1. [fdir] set dentry->kv_array->count to 0 correctly
1. [fstore] should init barray->count to 0
---------------
## FastCFS V2.3.0发布,主要改进如下:
### 新特性
1. [fauth] auth server以主备方式支持多节点,避免单点;
1. [fstore&fdir] leader/master选举/切换引入超时机制,选举时长可控;
1. [网络] 网络通信相关改进:
1)握手失败,server端主动断开连接;
2)cluster内部通信server端超时控制;
3)调整网络通信超时默认值(连接超时由10秒调整为2秒,收发数据超时由30秒调整为10秒)。
### Bug修复
---------------
## FastCFS V2.2.0 发布,主要改进如下:
### 新特性
1. [fstore] 使用libaio实现异步读,随机读性能提升明显;
1. [fstore] 支持预读机制,顺序读性能提升显著;
1. [csi] k8s驱动(fastcfs-csi)已同步发布,
1. [devOPS] 集群运维工具(fcfs.sh)
### Bug修复
1. [fstore] 修复V2.1.0引入的bug:第一次运行时,一个关键bool变量没有正确赋值;
2. [fuseclient] 修复列举目录导致元数据缓存的一致性问题;
3. [fauth] 修复username和poolname格式修饰符不当导致的乱码问题。
---------------
## FastCFS V2.0.0 发布,为了更好地对接虚拟机和K8s,V2.0主要实现了存储池和访问权限控制,并支持配额:
### 新特性
1. [fauth] 用户和权限体系
### Bug修复
---------------
## FastCFS V1.2.0 发布,主要对数据恢复和master任命机制做了改进,修复了5个稳定性bug,FastCFS的可靠性和稳定性上了一个新台阶:
### 新特性
### Bug修复
---------------
## FastCFS V1.0.0 发布:
FastCFS 3人小团队历经11个月的研发,推出了FastCFS第一个可用版本,MySQL、PostgresSQL和Oracle可以跑通。
FastCFS服务端两个核心组件是 FastStore 和 FastDIR。FastStore是基于块存储的分布式数据存储服务,其文件block大小为4MB,文件 inode + 文件偏移量 (offset)作为block的key,对应的文件内容为 value,FastStore本质是一个分布式Key-Value系统。
### 主要特性
1. [fdir] 高性能分布式目录服务,管理文件元数据,支持命名空间
1. [fstore] FastStore是一个分布式Key-Value系统,提供了文件块操作,基于数据块的无中心设计,(类一致性Hash),理论上可以无限扩容;
1. [fuseclient] 基于FUSE的标准文件接口已经实现,可以使用fused模块mount到本地,为数据库、虚拟机以及其他使用标准文件接口的应用提供存储。
================================================
FILE: docs/TODO-zh_CN.md
================================================
# TODO List
欢迎有志之士参与完善!
## 一、测试与反馈
## 二、对外接口
### 1. 对象存储
#### 1.1 S3
#### 1.2 OSS
#### 1.3 OBS
#### 1.4 COS
### 2. VFS
### 3. NBD
### 4. iSCSI
================================================
FILE: docs/VoteNode-zh_CN.md
================================================
# Vote Node (选举节点)配置及运行
如果你不需要实现双副本防脑裂(即双活互备防脑裂),可以跳过本文档。
本文档以FastCFS RPM包设定的路径(配置文件目录和程序工作目录等)进行说明,如果你采用自助编译安装方式的话,请自行对应。
为了防脑裂,建议配置3个节点(服务器),因选举服务占用资源较少,可以和其他服务共用服务器。
## 1. Vote Node配置文件目录结构
```
/etc/fastcfs/
|
|__ vote: 选举节点
|__ cluster.conf: 服务器列表,配置服务器ID、IP和端口
|__ server.conf: fcfs_voted对应的配置文件
|__ client.conf: 客户端配置文件
```
## 2. voted程序工作目录
```
/opt/fastcfs/
|
|__ vote
|__ voted.pid: 服务进程fcfs_voted的pid文件
|__ logs: 日志文件目录
|__ fcfs_voted.log: 错误日志
```
开启共用选举服务需要设置选举节点、Auth server、FastDIR server和FastStore server。
## 3. 选举节点(vote server)配置
配置文件路径:/etc/fastcfs/vote
Vote集群内各个server配置的cluster.conf必须完全一样。
建议配置一次,分发到其他服务器即可。
### 3.1 把Vote集群中的所有服务实例配置到cluster.conf中
每个Vote服务实例包含2个服务端口:cluster 和 service
一个Vote服务实例需要配置一个[server-$id]的section,其中$id为实例ID。
### 3.2 配置 server.conf
* [cluster] 和 [service] 配置的端口(port)必须与cluster.conf中本机的一致,否则启动会报错
### 3.3 启动voted
voted命令直接重启:
```
/usr/bin/fcfs_voted /etc/fastcfs/vote/server.conf restart
```
或者系统服务命令启动:
```
sudo systemctl restart fastvote
```
查看日志:
```
tail /opt/fastcfs/vote/logs/fcfs_voted.log
```
## 4. Auth server
### 4.1 复制vote server上的如下配置文件到 /etc/fastcfs/vote/
```
/etc/fastcfs/vote/cluster.conf
/etc/fastcfs/vote/client.conf
```
修改 /etc/fastcfs/auth/cluster.conf,将vote_node_enabled 设置为true。
配置片段如下:
```
[master-election]
# if enable vote node when the number of servers is even
# the default value is false
vote_node_enabled = true
# the cluster config filename of the vote node
# this parameter is valid when vote_node_enabled is true
vote_node_cluster_filename = ../vote/cluster.conf
```
拷贝完成后重启认证服务(fcfs_authd)
## 5. FastDIR server
修改 /etc/fastcfs/fdir/cluster.conf,将vote_node_enabled 设置为true。
* 详情参见 4. Auth server 部分
拷贝和设置完成后重启FastDIR服务(fdir_serverd)
## 6. FastStore server
* 参见 4. Auth server 部分
修改 /etc/fastcfs/fstore/cluster.conf,将vote_node_enabled 设置为true。
配置片段如下:
```
[leader-election]
# if enable vote node when the number of servers is even
# the default value is false
vote_node_enabled = true
# the cluster config filename of the vote node
# this parameter is valid when vote_node_enabled is true
vote_node_cluster_filename = ../vote/cluster.conf
```
拷贝完成后重启FastStore服务(fs_serverd)
## 友情提示
* 4 ~ 6部分的配置及启动参见 [配置指南](CONFIGURE-zh_CN.md)
================================================
FILE: docs/YUM-INSTALL-Diy-5nodes-zh_CN.md
================================================
### 安装的集群架构
FastCFS支持大规模的集群,下面以最为典型的最小化集群的部署方式,说明下自定义安装的过程。更大规模的安装方式可参照此过程扩展安装。
1. 节点类型和数量:共计5个节点,3个服务端节点(3副本策略),2客户端节点
2. 服务端集群:FastStore和FastDir公用,也可以分开独立部署,生产环境建议分开。本说明为了降低节点数量,采用了公用部署的方式。
3. 客户端:为了说明支持多客户端,使用了2个客户端节点。生产环境中如果只需要1个客户端,也是没问题的。
### 前置依赖
先安装FastOS.repo yum源,FastCFS所需要的pkg都在此源中,安装成功后就可以安装FastCFS相关软件包了。
- CentOS 7等el7系列的Linux发行版
```
rpm -ivh http://www.fastken.cn/yumrepo/el7/noarch/FastOSrepo-1.0.1-1.el7.noarch.rpm
```
- CentOS 8等el8系列的Linux发行版
```
rpm -ivh http://www.fastken.cn/yumrepo/el8/noarch/FastOSrepo-1.0.1-1.el8.noarch.rpm
```
友情提示:支持的Linux发行版以及与el7或el8的对应关系参见 [yum安装方式](YUM-INSTALL-zh_CN.md)
### 服务端集群安装
在192.168.126.[101,102,103]上分别安装FastStore、FastDIR 两个服务.
#### 安装FastDIR
```
yum install fastDIR-server
```
安装过程中会安装所依赖的包,选y就可以了.
```
==================================================================================================================
Package Architecture Version Repository Size
==================================================================================================================
Installing:
fastDIR-server x86_64 2.0.1-1.el8 FastOS 71 k
Installing dependencies:
FastCFS-auth-client x86_64 2.0.1-1.el8 FastOS 36 k
FastCFS-auth-config x86_64 2.0.1-1.el8 FastOS 10 k
fastDIR-config x86_64 2.0.1-1.el8 FastOS 9.5 k
libfastcommon x86_64 1.0.50-1.el8 FastOS 140 k
libserverframe x86_64 1.1.7-1.el8 FastOS 47 k
Transaction Summary
==================================================================================================================
Install 6 Packages
Total download size: 313 k
Installed size: 711 k
Is this ok [y/N]: y // 安装过程中会安装所依赖的包,选y就可以了.
```
安装完毕后,在/etc/fastcfs 下可看到fdir的目录,存储的是FastDIR的配置文件. 配置项的内容,后续会说明。
```
$ ll /etc/fastcfs/fdir/
total 16
-rw-r--r--. 1 root root 1565 May 9 13:49 client.conf
-rw-r--r--. 1 root root 753 May 9 13:49 cluster.conf
-rw-r--r--. 1 root root 5242 May 9 13:49 server.conf
```
#### 安装FastStore
```
yum install faststore-server
```
再说明下:实际生产环境部署中,FastDIR是和FastStore两个服务可以分开部署的,不需要再同一台服务器上。
```
==================================================================================================================
Package Architecture Version Repository Size
==================================================================================================================
Installing:
faststore-server x86_64 2.0.1-1.el8 FastOS 134 k
Installing dependencies:
faststore-config x86_64 2.0.1-1.el8 FastOS 11 k
Transaction Summary
==================================================================================================================
Install 2 Packages
Total download size: 145 k
Installed size: 422 k
Is this ok [y/N]: y // 安装过程中会安装所依赖的包,选y就可以了.
```
安装完毕后,在/etc/fastcfs 下可看到fstore目录,存储的是FastStore的配置文件。配置项的内容,后续会说明。
```
$ ll /etc/fastcfs/fstore/
total 20
-rw-r--r--. 1 root root 1577 May 9 13:52 client.conf
-rw-r--r--. 1 root root 3256 May 9 13:52 cluster.conf
-rw-r--r--. 1 root root 4965 May 9 13:52 server.conf
-rw-r--r--. 1 root root 2609 May 9 13:52 storage.conf
```
### 安装客户端
在192.168.126.[201,202]上安装Client包, 包名为FastCFS-fused.
```
yum install FastCFS-fused -y
```
安装完毕后,在/etc/fastcfs 下可看到以下目录,存储是对应服务的配置文件.
```
$ ll /etc/fastcfs/
drwxr-xr-x. 3 root root 113 May 14 15:20 auth
drwxr-xr-x. 2 root root 23 May 14 15:20 fcfs
drwxr-xr-x. 2 root root 64 May 14 15:20 fdir
drwxr-xr-x. 2 root root 84 May 14 15:20 fstore
```
**为什么在Client的节点上,需要有fdir和fstore的目录呢?因为FastCFS是无中心配置的,Client需要知道fdir和fstore的集群情况,所以就需要fdir和fstore的配置文件。**
### 自定义安装配置
#### 说明
FastCFS并没有统一的配置中心,需要在各个节点上单独部署配置文件。配置文件分为两大类:集群配置文件和服务配置文件。
1. **集群配置文件:** 指的是描述 FastDir 和 FastStore 的配置文件,入口文件名称为cluster.conf . 该配置文件中设定是集群的参数,如服务节点的IP和端口号,服务节点的数量等。 cluster.conf 文件全局统一,各个节点上的内容是相同的, FastDir 和 FastStore 有各自的cluster.conf文件。
2. **服务配置文件:** 指的是服务本身的配置文件,入口文件名称server.conf 如线程数量、链接数量、缓冲区大小、日志配置等。 服务配置文件的内容,可以全局不统一。不过从集群的角度考虑,如果各服务器配置相同,最好是统一的。
#### FastDIR 配置
1. **配置文件说明**
```
$ ll /etc/fastcfs/fdir/
-rw-r--r--. 1 root root 1565 May 9 13:49 client.conf // 暂时不使用,不用关注
-rw-r--r--. 1 root root 753 May 9 13:49 cluster.conf // 集群配置文件
-rw-r--r--. 1 root root 5242 May 9 13:49 server.conf // 服务配置文件
```
2. **集群配置文件** :在101节点上,修改/etc/fastcfs/fdir/cluster.conf 文件,修改为正确的IP地址,修改后的内容如下
```
1 # config the auth config filename
2 auth_config_filename = /etc/fastcfs/auth/auth.conf
3
4
5 [group-cluster]
6 # the default cluster port
7 port = 11011 // 集群之间的通信使用的默认端口号,不用修改
8
9 [group-service]
10 # the default service port
11 port = 11012 // 对client提供服务,使用的默认端口号,不用修改
12
13 # config a server instance
14 # section format: [server-$id]
15 # server id is a 32 bits natural number (1, 2, 3 etc.),
16 [server-1]
17
18 # format: host[:port]
19 # host can be an IP address or a hostname
20 # IP address is recommended
21 # can occur more than once
22 host = 192.168.126.101 // 节点101的地址,使用默认的端口号
23
24 [server-2]
25 # cluster-port = 11013
26 # service-port = 11014
27 host = 192.168.126.102 // 节点102的地址,使用默认的端口号
28
29 [server-3]
30 # cluster-port = 11015
31 # service-port = 11016
32 host = 192.168.126.103 // 节点103的地址,使用默认的端口号
```
3. **服务配置文件** : 在101节点上,/etc/fastcfs/fdir/server.conf, 该文件配置项较多,但默认不用任何调整,确认文件底部的[service]区内容就好.
```
180 [cluster]
181 # bind an address of this host
182 # empty for bind all addresses of this host
183 bind_addr =
184
185 # the listen port
186 port = 11011
187
188 # the accept thread count
189 # default value is 1 which is recommended
190 accept_threads = 1
191
192 # the network thread count
193 # these threads deal network io
194 # dispatched by the incoming socket fd
195 # default value is 4
196 work_threads = 2
197
198 [service]
199 bind_addr = // 保持为空,FastDIR 会自动使用本机的IP地址
200 port = 11012 // 确保与cluster.conf 中 group-service 的设定值相同
201 accept_threads = 1
202 work_threads = 4
```
4. 把cluster.conf文件复制到102-103,201-202 这5台服务器上,保证所有节点都能知道集群配置
```
scp /etc/fastcfs/fdir/cluster.conf 192.168.126.102:/etc/fastcfs/fdir/
scp /etc/fastcfs/fdir/cluster.conf 192.168.126.103:/etc/fastcfs/fdir/
scp /etc/fastcfs/fdir/cluster.conf 192.168.126.201:/etc/fastcfs/fdir/
scp /etc/fastcfs/fdir/cluster.conf 192.168.126.202:/etc/fastcfs/fdir/
```
#### FastStore 配置
1. **配置文件说明**
```
$ ll /etc/fastcfs/fstore
-rw-r--r--. 1 root root 1577 May 9 13:52 client.conf // 暂时不使用,不用关注
-rw-r--r--. 1 root root 3253 May 14 13:08 cluster.conf // 集群配置文件
-rw-r--r--. 1 root root 4965 May 9 13:52 server.conf // 服务配置文件
-rw-r--r--. 1 root root 2609 May 9 13:52 storage.conf // 服务配置文件
```
2. **集群配置文件** :在101节点上,修改/etc/fastcfs/fstore/cluster.conf 文件,仅需要修改server_ids的值和[group-cluster]部分,其它参数不需要调整。修改后的内容如下.
```
57 [server-group-1]
58
59 # config one or more server id(s) from servers.conf
60 ## multiple server ids separated by comma(s).
61 ## [start, end] for range, including start and end.
62 # this parameter can occurs more than once.
63 # server_ids = [1, 3]
64 server_ids = [1,3] // 使用了3副本的策略,有3个服务节点101/102/103,所以设定为[1,3]
65
66 # the data group id based 1. the formats as:
67 ## * multiple data group ids separated by comma(s).
68 ## * [start, end] for range, including start and end.
69 # this parameter can occurs more than once.
70 data_group_ids = [1, 32]
71 data_group_ids = [33, 64]
72
73
74 [group-cluster]
75 # the default cluster port
76 port = 21014 // 集群之间的通信使用的默认端口号,不用修改
77
78 [group-replica]
79 # the default replica port
80 port = 21015 // Master-Slave 之间同步数据使用的默认端口号,不用修改
81
82 [group-service]
83 # the default service port
84 port = 21016 // 对Client提供服务,使用的默认端口号,不用修改
85
86 # config a server
87 # section format: [server-$id]
88 # server id is a 32 bits natural number (1, 2, 3 etc.),
89 [server-1]
90
91 # format: host[:port]
92 # host can be an IP address or a hostname
93 # IP address is recommended
94 # can occur more than once
95 host = 192.168.126.101 // 节点101的地址,使用默认的端口号
96
97 [server-2]
99 host = 192.168.126.102 // 节点102的地址,使用默认的端口号
100
101 [server-3]
103 host = 192.168.126.103 // 节点103的地址,使用默认的端口号
```
3. **服务配置文件** 在101节点上,/etc/fastcfs/fstore/server.conf 和 /etc/fastcfs/fstore/storage.conf. 默认均需要修改,只需确认下server.conf的配置是否正确
```
190 [replica]
191 bind_addr =
192 port = 21015 // 保持与fstore/server.conf 中 [group-replica]设定的port值相同
193 accept_threads = 1
194 work_threads = 4
195
196 [service]
197 bind_addr =
198 port = 21016 // 保持与fstore/server.conf 中 [group-service]设定的port值相同
199 accept_threads = 1
200 work_threads = 4
```
4. 把cluster.conf文件复制到102-103,201-202 这5台服务器上,保证所有节点都能知道集群配置
```
scp /etc/fastcfs/fstore/cluster.conf 192.168.126.102:/etc/fastcfs/fstore/
scp /etc/fastcfs/fstore/cluster.conf 192.168.126.103:/etc/fastcfs/fstore/
scp /etc/fastcfs/fstore/cluster.conf 192.168.126.201:/etc/fastcfs/fstore/
scp /etc/fastcfs/fstore/cluster.conf 192.168.126.202:/etc/fastcfs/fstore/
```
#### FastClient 配置
1. Client 需要知道FastDIR和FastStore的集群配置数据,在上述scp过程中,已经分别scp到了对应的目录下,不需要修改.
2. Client 自身的配置文件为 /etc/fastcfs/fcfs/fuse.conf 属于服务配置文件,也不需要修改.
### 启动服务
安装并配置完成后,可以启动服务并验证.
1. **关闭防火墙:** CentOS 8 默认情况下开启防火墙,会导致各节点之间无法访问,可暂关闭防火墙。
```
sudo systemctl stop firewalld.service
```
2. **启动FastDir:*** 在101/102/103 三个节点上,执行下列命令启动. 注意必须是3个节点都启动。
```
sudo systemctl restart fastdir
```
或者
```
sudo /usr/bin/fdir_serverd /etc/fastcfs/fdir/server.conf restart
```
查看日志,确认启动成功.
```
$ tail /opt/fastcfs/fdir/logs/fdir_serverd.log
[2021-05-14 15:39:36] ERROR - file: connection_pool.c, line: 140, connect to server 192.168.126.102:11011 fail, errno: 113, error info: No route to host
[2021-05-14 15:39:36] ERROR - file: connection_pool.c, line: 140, connect to server 192.168.126.103:11011 fail, errno: 113, error info: No route to host
[2021-05-14 15:39:36] INFO - file: cluster_relationship.c, line: 668, round 19th select master, alive server count: 1 < server count: 3, the candidate server status: 0 (INIT) does not match the selection rule. you must start ALL servers in the first time, or remove the deprecated server(s) from the config file. try again after 32 seconds.
[2021-05-14 15:40:01] INFO - file: cluster_relationship.c, line: 474, the master server id: 3, ip 192.168.126.103:11011
```
日志中有error提示,是因为防火墙导致的3个节点无法互相通信产生的,关闭防火墙后FastDIR会自动进行尝试链接。从最后一行INFO日志可看到,服务已经启动成功了,并且选择了103节点作为Master.
3. **启动FastStore:** 与FastDir的启动方式类似,在101/102/103 三个节点上,执行下列命令启动. 注意必须是3个节点都启动。
```
sudo systemctl restart faststore
```
或者
```
sudo /usr/bin/fs_serverd /etc/fastcfs/fstore/server.conf restart
```
查看日志,确认启动成功.
```
[2021-05-14 16:06:08.326966] INFO - file: replication/replication_processor.c, line: 419, connect to replication peer id: 3, 192.168.126.103:21015 successfully
[2021-05-14 16:06:08.344415] INFO - file: replication/replication_processor.c, line: 419, connect to replication peer id: 3, 192.168.126.103:21015 successfully
[2021-05-14 16:06:08.368437] INFO - file: replica_handler.c, line: 598, replication peer id: 1, 192.168.126.101:21014 join in
[2021-05-14 16:06:09.942673] INFO - file: replica_handler.c, line: 598, replication peer id: 1, 192.168.126.101:21014 join in
[2021-05-14 16:06:10.374344] INFO - file: recovery/binlog_fetch.c, line: 589, data group id: 1, wait replica channel of master id 1 ready success, waiting count: 2
[2021-05-14 16:06:10.415848] INFO - file: recovery/binlog_fetch.c, line: 589, data group id: 6, wait replica channel of master id 1 ready success, waiting count: 2
```
看到以上类似的日志,即是启动成功了。
4. **启动FastClient:** 在201、202 节点上启动Client.
```
sudo systemctl restart fastcfs
```
或者
```
sudo /usr/bin/fcfs_fused /etc/fastcfs/fcfs/fuse.conf restart
```
查看日志,确认启动成功
```
$ tail /opt/fastcfs/fcfs/logs/fcfs_fused.log
[2021-05-14 16:14:15] INFO - file: sf_nio.c, line: 205, connect to server 192.168.126.101:11012 successfully
[2021-05-14 16:14:15] INFO - file: sf_nio.c, line: 205, connect to server 192.168.126.103:11012 successfully
[2021-05-14 16:14:15] INFO - file: sf_connection_manager.c, line: 827, [FastDIR] connection manager thread start
[2021-05-14 16:14:15] INFO - file: sf_connection_manager.c, line: 827, [FastStore] connection manager thread start
[2021-05-14 16:14:55] INFO - file: sf_nio.c, line: 205, connect to server 192.168.126.101:21016 successfully
```
查看文件目录是否成功挂载
```
$ df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 189M 0 189M 0% /dev
tmpfs 219M 0 219M 0% /dev/shm
tmpfs 219M 6.6M 212M 4% /run
tmpfs 219M 0 219M 0% /sys/fs/cgroup
/dev/mapper/cs-root 47G 4.9G 43G 11% /
/dev/sda1 1014M 242M 773M 24% /boot
tmpfs 44M 4.0K 44M 1% /run/user/1000
/dev/fuse 38G 0 38G 0% /opt/fastcfs/fuse // 这是即是FastCFS挂载的根目录
```
5. 验证 :在201节点上创建文件
```
[first@192.168.126.201 /opt/fastcfs/fuse]
$ mkdir -p abc/123
[first@192.168.126.201 /opt/fastcfs/fuse]
$ touch abc/123/demo.txt
[first@192.168.126.201 /opt/fastcfs/fuse]
$ vim abc/123/demo.txt
[first@192.168.126.201 /opt/fastcfs/fuse]
$ ll abc/123
total 1
-rw-rw-r--+ 1 first first 13 May 14 16:22 demo.txt
```
在202节点上查看该文件,可见文件已经创建成功了
```
[first@192.168.126.202 /opt/fastcfs/fuse]
$ tail abc/123/demo.txt
hello world
[first@192.168.126.202 /opt/fastcfs/fuse]
```
### 服务监控
1. 查看FastDir集群状态
```
$ fdir_cluster_stat
server_id: 1, host: 192.168.126.101:11012, status: 23 (ACTIVE), is_master: 0
server_id: 2, host: 192.168.126.102:11012, status: 23 (ACTIVE), is_master: 0
server_id: 3, host: 192.168.126.103:11012, status: 23 (ACTIVE), is_master: 1
server count: 3
```
2. 查看单个FastDir节点状态
```
[first@192.168.126.201 /etc/fastcfs/fcfs]
$ fdir_service_stat 192.168.126.101:11012
server_id: 1
status: 23 (ACTIVE)
is_master: false
connection : {current: 4, max: 4}
binlog : {current_version: 24}
dentry : {current_inode_sn: 1000009, ns_count: 1, dir_count: 3, file_count: 1}
```
3. 查看FastStore集群状态
```
$ fs_cluster_stat | more
data_group_id: 1
server_id: 1, host: 192.168.126.101:21016, status: 5 (ACTIVE), is_preseted: 1, is_master: 1, data_version: 0
server_id: 2, host: 192.168.126.102:21016, status: 5 (ACTIVE), is_preseted: 0, is_master: 0, data_version: 0
server_id: 3, host: 192.168.126.103:21016, status: 5 (ACTIVE), is_preseted: 0, is_master: 0, data_version: 0
data_group_id: 2
server_id: 1, host: 192.168.126.101:21016, status: 5 (ACTIVE), is_preseted: 0, is_master: 0, data_version: 0
server_id: 2, host: 192.168.126.102:21016, status: 5 (ACTIVE), is_preseted: 1, is_master: 1, data_version: 0
.....................
```
4. 查看磁盘使用情况
```
df -h
```
================================================
FILE: docs/YUM-INSTALL-zh_CN.md
================================================
## yum安装方式
yum 安装方式支持intel的x86_64和ARM的aarch64架构,主要用于测试和生产环境搭建。
支持的Linux发行版如下:
* CentOS & CentOS Stream
* Fedora
* Rocky
* Anolis
* AlmaLinux
* RHEL (Red Hat Enterprise Linux)
* Oracle Linux
* Amazon Linux
* Alibaba Cloud Linux
* openEuler
* Kylin
* UOS
### 1. 安装FastOS.repo
先安装FastOS.repo yum源,然后就可以安装FastCFS相关软件包了。
CentOS 7、RHEL 7、Oracle Linux 7、Alibaba Cloud Linux 2、Anolis OS 7、AlmaLinux 7、Amazon Linux 2、Fedora 27及以下版本:
```
rpm -ivh http://www.fastken.cn/yumrepo/el7/noarch/FastOSrepo-1.0.1-1.el7.noarch.rpm
```
CentOS 8、Rocky Linux 8、RHEL 8、Oracle Linux 8、Alibaba Cloud Linux 3、Anolis OS 8、AlmaLinux 8、openEuler [20, 23]、Kylin V10、UOS 20、Amazon Linux 3、Fedora [28, 37]:
```
rpm -ivh http://www.fastken.cn/yumrepo/el8/noarch/FastOSrepo-1.0.1-1.el8.noarch.rpm
```
CentOS Stream 9、Rocky Linux 9、RHEL 9、Oracle Linux 9、Alibaba Cloud Linux 4、Anolis OS 23、AlmaLinux 9、openEuler 24.03、Kylin V11、Amazon Linux 2023、Fedora 38及以上版本:
```
rpm -ivh http://www.fastken.cn/yumrepo/el9/noarch/FastOSrepo-1.0.1-1.el9.noarch.rpm
```
### 2. fastDIR server安装
在需要运行 fastDIR server的服务器上执行:
```
yum install fastDIR-server -y
```
### 3. faststore server安装
在需要运行 faststore server的服务器上执行:
```
yum install faststore-server -y
```
### 4. FastCFS客户端安装
在需要使用FastCFS存储服务的机器(即FastCFS客户端)上,除了openEuler之外的其他Linux发行版执行:
```
yum install FastCFS-fused -y
```
对于openEuler 20.03和Kylin V10,因需安装的fuse3和系统已有的fuse在依赖关系上存在冲突,需要用rpm命令强制安装fuse3,执行:
```
arch=$(uname -r | awk -F '.' '{print $NF}');
dist=el8;
ver='3.16.2-2';
rpm -ivh http://www.fastken.cn/yumrepo/$dist/$arch/fuse3-libs-$ver.$dist.$arch.rpm \
http://www.fastken.cn/yumrepo/$dist/$arch/fuse-common-$ver.$dist.$arch.rpm \
http://www.fastken.cn/yumrepo/$dist/$arch/fuse3-$ver.$dist.$arch.rpm --force --nodeps;
yum install FastCFS-fused -y
```
对于openEuler 22.03及更高版本,直接执行:
```
yum install FastCFS-fused -y
```
### 5. Vote server安装(可选)
Vote server作为FastCFS多个服务模块共用的选举节点,主要作用是实现双副本防脑裂(即双活互备防脑裂)。
在需要运行选举节点的服务器上执行:
```
yum install FastCFS-vote-server -y
```
### 6. Auth server安装(可选)
如果需要存储池或访问控制,则需要安装本模块。
在需要运行 Auth server的服务器上执行:
```
yum install FastCFS-auth-server -y
```
安装完成后,需要修改对应的配置文件,服务才可以正常启动。请参阅[配置指南](CONFIGURE-zh_CN.md)
FastCFS后台程序可通过systemd管理。systemd服务名称如下:
```
* fastdir: 目录服务,对应程序为 fdir_serverd
* faststore:存储服务,对应程序为 fs_serverd
* fastcfs: FUSE后台服务,对应程序为 fcfs_fused
* fastvote: 选举节点,对应程序为 fcfs_voted
* fastauth: 认证服务,对应程序为 fcfs_authd
```
可以使用标准的systemd命令对上述5个服务进行管理,例如:
```
systemctl restart fastdir
systemctl restart faststore
systemctl restart fastcfs
systemctl restart fastvote
systemctl restart fastauth
```
### 6. 一个包含5个节点的安装过程的详细文档
请参与[5节点安装文档](YUM-INSTALL-Diy-5nodes-zh_CN.md)
================================================
FILE: docs/benchmark-step-by-step.md
================================================
## FastCFS性能测试参考文档
服务器之间需要实现免密登录,集群部署参见:[FastCFS集群部署工具介绍](fcfs-ops-tool-zh_CN.md)
### 集群快速部署
在施压服务器(即client机器)上执行如下命令:
```
curl -o /usr/bin/fcfs.sh http://fastken.cn/fastcfs/ops/fcfs.sh && sudo chmod +x /usr/bin/fcfs.sh;
curl -o /usr/bin/fcfs_conf.sh http://fastken.cn/fastcfs/ops/fcfs_conf.sh && sudo chmod +x /usr/bin/fcfs_conf.sh;
mkdir -p fastcfs-ops && cd fastcfs-ops;
server_ips='请替换为西文逗号分隔的服务器IP列表';
client_ip=$(ip addr | grep -w inet | grep -v 127.0.0.1 | awk '{print $2}' | tr -d 'addr:' | awk -F '/' '{print $1}' | head -n 1);
cat > fcfs_conf.settings < fcfs.settings <= this parameter,
# otherwise switch to Linux epoll
# default value is 10240
polling_switch_on_iops = 1024
```
修改conf/fcfs/fuse.conf的配置项,配置示例如下:
```
# the mount point (local path) for FUSE
# the local path must exist
mountpoint = /opt/fastcfs/fuse
# if use busy polling for RDMA network
# should set to true for HPC
# default value is false
busy_polling = true
[read-ahead]
# if enable read ahead feature for FastStore
# default value is true
enabled = false
```
首次部署:
```
fcfs.sh setup;
```
修改配置后重新部署:
```
fcfs.sh config;
fcfs.sh restart;
```
### 安装压测工具
CentOS、Alibaba Cloud Linux等发行版:
```
yum install fio FastCFS-api-tests -y
```
Ubuntu 或者Debian:
```
apt install fio fastcfs-api-tests -y
```
### fio压测示例
```
cd /opt/fastcfs/fuse;
jobnum=4; rw=randread;
out_path=FastCFS-fio/$rw-$jobnum;
log_file=$out_path/fio;
mkdir -p $out_path;
fio --filename_format=test_file.\$jobnum --direct=1 --rw=$rw --thread --numjobs=$jobnum --iodepth=16 --ioengine=psync --bs=4k --group_reporting --name=FastCFS --loops=1000 --log_avg_msec=500 --write_bw_log=$log_file --write_lat_log=$log_file --write_iops_log=$log_file --runtime=300 --size=256M
```
### fcfs_beachmark压测示例
```
fcfs_beachmark -m randread -s 256M -T 4 -t 300 -f /opt/fastcfs/fuse/test_file
```
================================================
FILE: docs/benchmark.md
================================================
## FastCFS vs. Ceph benchmark under 3 nodes cluster (three copies of data)
| read/write type |
fio jobs |
IOPS(4KB Block) |
ratio |
| FastCFS |
Ceph |
| sequential write |
4 |
32,256 |
5,120 |
630% |
| 8 |
55,296 |
8,371 |
661% |
| 16 |
76,800 |
11,571 |
664% |
| rand write |
4 |
6,374 |
4,454 |
143% |
| 8 |
11,264 |
6,400 |
176% |
| 16 |
16,870 |
7,091 |
238% |
| sequential read |
4 |
34,880 |
14,848 |
235% |
| 8 |
62,751 |
24,883 |
252% |
| 16 |
86,508 |
38,912 |
222% |
| rand read |
4 |
12,527 |
12,160 |
103% |
| 8 |
23,610 |
22,220 |
106% |
| 16 |
41,790 |
36,608 |
114% |
more info see Chinese doc: [FastCFS vs. Ceph benchmark detail](benchmark-20210621.pdf)
================================================
FILE: docs/cluster-expansion-zh_CN.md
================================================
# FastCFS集群扩容手册
FastCFS集群三个服务组件:fauth、fdir 和fstore,下面将分别介绍这三个服务组件的扩容方法和步骤。
## 1. fauth(认证服务)
认证服务的用户和权限等数据保存在fdir中,服务采用热备模式,建议部署2 ~ 3个服务器(节点),主节点失效后会自动切换到备用节点。
因认证服务器自身不保存数据,因此可以根据实际需要随时增加或减少认证服务器。
## 2. fdir(目录服务)
FastCFS目录服务用于文件元数据管理,目前只支持一组服务器,使用常规服务器(如64GB内存 + SSD)可以支持百亿级文件。
详情参见[高性能大容量分布式目录服务FastDIR简介](https://my.oschina.net/u/3334339/blog/5405816)
建议将fdir部署在3台服务器上,可以根据实际需要随时增加或减少fdir服务器,fdir将基于binlog自动完成数据同步。
## 3. fstore(数据存储)
fstore 采用分组方式保存文件内容。为了便于扩容,FastCFS引入了数据分组(DG)的概念。
按4MB分块的文件内容(文件块),根据其hash code(文件ID + 文件块偏移量),路由到对应的数据分组。计算公式如下:
```
DGI = HashCode % DGC
DGI:数据分组索引号
HashCode:文件分块哈希值
DGC:数据分组总数
```
数据分组是逻辑或虚拟概念,映射到的物理或实体概念是服务器分组(SG),二者是多对一关系,即:一个服务器分组(SG)可以容纳多个数据分组(DG)。
fstore集群的服务器分组总数,英文缩写为SGC。
DG 和SG映射关系配置在fstore的cluster.conf中,配置示例片段(简洁起见,只配置了一个3副本的SG):
```
# SGC
server_group_count = 1
# DGC
data_group_count = 256
# 配置SG1
[server-group-1]
server_ids = [1-3]
data_group_ids = [1, 256]
```
fstore集群扩容,可以一次增加一个SG。当集群规模较小(比如SGC小于等于4)时,建议一次扩容一倍(SGC翻番)。
DGC一旦确定就不可更改,除非建立新集群。因此在初始化集群时,需要确定好数据分组总数(DGC),可以根据业务发展规划,充分预估出DGC。
比如根据存储量预估5年后需要的服务器分组数(SGC)为20,为了充分发挥多核性能,每台服务器上跑32个数据分组(DG),DGC为20 * 32 = 640,按2次幂向上对齐,最终配置为1024。
* 友情提示:建议生产环境DGC至少配置为256。
fstore在线扩容分为两个步骤修改cluster.conf:
1. 增加扩容的SG 和迁移过去的DG映射;
2. 新增的SG自动同步完成后,将原有SG迁移出去的DG映射删除。
上述两个步骤将cluster.conf修改完成后,都需要将cluster.conf分发到fstore集群和fuseclient,然后重启fstore集群和fuseclient。推荐重启步骤如下:
```
1. 停止fuseclient
2. 重启fstore集群
3. 启动fuseclient
```
将上述配置示例的1个SG扩容为2个SG(均采用3副本),我们如何调整cluster.conf:
### 步骤1
修改后的cluster.conf内容片段如下:
```
# SGC,由1扩容为2
server_group_count = 2
# DGC
data_group_count = 256
# 修改DG映射,将 [129, 256]迁移至SG2
[server-group-1]
server_ids = [1-3]
data_group_ids = [1, 128]
# 配置SG2
# 必须加上server [1-3]用于同步已有数据
[server-group-2]
server_ids = [1-6]
data_group_ids = [129, 256]
```
将cluster.conf分发到fstore集群所有服务器以及所有fuseclient后,重启fstore集群和fuseclient。
等待新增的SG同步完成,然后进入步骤2。
* 友情提示:
* 数据同步过程中fstore集群正常提供服务;
* 可以使用工具 fs_cluster_stat 查看fstore集群状态,比如:
```
# 查看ACTIVE列表,确保所有服务器状态为ACTIVE,确认一下最后一行输出的总数
fs_cluster_stat -A
# 查看非ACTIVE列表,确保输出为空
fs_cluster_stat -N
# 抽查某个数据分组(如ID为256)的ACTIVE状态,确保全部为ACTIVE
fs_cluster_stat -g 256
# 查看帮助
fs_cluster_stat -h
```
### 步骤2
修改后的cluster.conf内容片段如下:
```
# SGC
server_group_count = 2
# DGC
data_group_count = 256
[server-group-1]
server_ids = [1-3]
data_group_ids = [1, 128]
# 去掉server [1-3]
[server-group-2]
server_ids = [4-6]
data_group_ids = [129, 256]
```
将cluster.conf分发到fstore集群所有服务器以及所有fuseclient后,重启fstore集群和fuseclient
### 清除已迁走的数据
数据迁移完成后,为了清除迁移出去的数据占用空间,V3.2支持清除迁移出去的replica和slice binlog,启动 fs_serverd时带上参数 --migrate-clean 即可,示例如下:
```
/usr/bin/fs_serverd /etc/fastcfs/fstore/server.conf restart --migrate-clean
```
**注意:** 为了防止误操作,正常情况下启动fs_serverd **不要** 使用--migrate-clean!
* 友情提示:
* 配置文件分发和程序启停可以使用fcfs.sh,使用说明参见[FastCFS集群运维工具](fcfs-ops-tool-zh_CN.md)
* 步骤1和2重启fstore集群和fuseclient的过程,会导致服务不可用,建议在业务低峰期进行
================================================
FILE: docs/fcfs-ops-tool-zh_CN.md
================================================
# FastCFS 运维工具介绍
* [fcfs.sh](#fcfs.sh) -- 用于管理 FastCFS 集群的快捷运维工具
* [fcfs_conf.sh](#fcfs_conf.sh) -- 用于快速创建集群配置文件的工具
## 1. fcfs.sh 介绍
fcfs.sh 是一个用于快速部署和管理 FastCFS 集群的脚本工具。它基于 SSH 访问协议连接远程节点服务器,并使用服务器上带有 sudo 功能的账号(也可以使用root)进行相关命令的执行。它只需在你的工作站机器上运行,不需要服务器、数据库或者其他额外资源。
如果你需要经常搭建、卸载或配置 FastCFS集群,又想节省大量的重复工作,那么它很适合你。
***注: 该脚本工具目前适用于以下操作系统:***
* CentOS 7 和 CentOS 8 及以上版本
* Red Hat Linux 8 及以上版本
* Rocky Linux 8 及以上版本
* Anolis 7及以上版本
* AlmaLinux 7及以上版本
* Fedora Linux 20 及以上版本
* Oracle Linux 8 及以上版本
* Amazon Linux
* Alibaba Cloud Linux
* BigCLoud 21及以上版本
* openEuler 20及以上版本
* Kylin V10及以上版本
* UOS 20及以上版本
* Debian 10 及以上版本
* Ubuntu 18.04 及以上版本
### 1.1. 这个工具能做什么?
它能快速构建 FastCFS 集群,包括安装软件、分发配置文件,以及管理集群服务和查看集群日志。
它也能对 FastCFS 单节点或整个集群的相关软件进行升级或降级。
它能重新安装软件或者重新分发配置文件。
### 1.2. 这个工具不能做什么?
它不是一个通用的部署工具, 仅适用于 FastCFS 集群。除了将配置文件分发到集群的各个服务器节点以外,它不对集群配置做任何处理。你必须为它提供可用的集群配置文件。
### 1.3. 获取 fcfs.sh
从以下地址下载 fcfs.sh,并将其放置在工作站机器的bin目录下,以便命令行能够找到:
> http://fastken.cn/fastcfs/ops/fcfs.sh
获取命令:
> sudo curl -o /usr/bin/fcfs.sh http://fastken.cn/fastcfs/ops/fcfs.sh && sudo chmod +x /usr/bin/fcfs.sh
下载完成后可通过命令 ***which fcfs.sh*** 测试工具是否生效。
### 1.4. 使用工具的前置条件
* fcfs.settings -- 集群运维配置,放置在当前工作目录中
* conf -- 集群配置文件目录,放置在当前工作目录中
* 远程服务器 SSH 免密登录,参见 [5. SSH 免密登录](#SSH-password-free-login)
你必须为每个集群创建一个独立的工作目录(例如:***fastcfs-ops***),将 ***fcfs.settings*** 和 ***conf*** 放入其中。然后所有针对该集群的后续命令操作,都必须在该工作目录中执行。
#### 1.4.1. fcfs.settings
fcfs.settings 包括两个字段 ***fastcfs_version*** 和 ***fuseclient_ips***,fastcfs_version 用于指定 FastCFS 主版本号,fuseclient_ips 用于指定要部署 fuse client 的服务器主机。当需要对 FastCFS 集群软件进行升级或降级操作时,你需要先修改 fastcfs_version 对应的版本号为你期望的版本。
fcfs.settings 配置文件内容举例:
```
# 要安装的集群版本号(例如:5.5.0)
fastcfs_version=5.5.0
# 要安装 fuseclient 客户端的IP列表,多个ip以英文逗号分隔
fuseclient_ips=10.0.1.14
```
***注:推荐使用 5.5.0 及更高版本用于集群部署。***
#### 1.4.2. conf
FastCFS集群的所有配置文件必须提前放置在工作目录中的 ***conf*** 目录,conf 包含以下四个子目录:
* vote -- fvote 服务器的配置文件
* fdir -- fdir 服务器的配置文件
* fstore -- fstore 服务器的配置文件
* auth -- fauth 服务器的配置文件
* fcfs -- fuseclient 客户端的配置文件
**获取配置文件样例**
```
mkdir fastcfs-ops
cd fastcfs-ops/
curl -o fcfs-config-sample.tar.gz http://fastken.cn/fastcfs/ops/fcfs-config-sample.tar.gz
tar -xzvf fcfs-config-sample.tar.gz
```
**使用fcfs_conf.sh创建集群配置文件**
也可以根据自己的需要,使用脚本工具 fcfs_conf.sh 创建 FastCFS集群配置文件。参见:[fcfs_conf.sh](#fcfs_conf.sh)
### 1.5. SSH 免密登录
fcfs.sh 将通过 SSH 连接所有集群主机。它需要工作站机器可以通过 SSH 在远程主机上执行脚本,执行命令的用户身份可以是 root 或带 sudo的用户,并且必须支持免密登录。
为了开启免密登录,你需要先为 SSH 生成 rsa 公钥/私钥对:
> ssh-keygen -t rsa -C cfs -f cfs-ssh-key
将生成密钥文件:
* cfs-ssh-key -- 私钥文件
* cfs-ssh-key.pub -- 公钥文件
#### 1.5.1. 部署私钥
将私钥文件 cfs-ssh-key 拷贝到工作站机器的当前用户home目录 ***"~/.ssh/"***,然后将下面的配置片段加入配置文件 ~/.ssh/config(每个集群主机一份):
```
Host [node ip]
HostName [node host name]
User [ssh user]
Port 22
PubkeyAuthentication yes
IdentityFile ~/.ssh/cfs-ssh-key
```
#### 1.5.2. 部署公钥
将公钥文件内容加入到每个节点服务器sudo 用户的home目录下 ***.ssh/authorized_keys*** 文件中:
> ssh-copy-id -i cfs-ssh-key.pub [user name]@[node server ip]
并确保服务器上sshd的配置文件中开启了以下配置参数:
```
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
```
### 1.6. 工具命令介绍
fcfs.sh工具的命令包括三部分:command,module 和 node。Command 是必须的,module 和 node 是可选的。
用法:
> fcfs.sh command [module] [node]
**Commands**:
* setup -- 安装并运行 FastCFS 软件的快捷命令,组合了 install、config 和 restart三个命令
* install -- 安装 FastCFS 软件
* reinstall -- 重新安装 FastCFS 软件
* remove -- 移除 FastCFS 软件,功能与 erase 命令相同
* erase -- 移除 FastCFS 软件
* config -- 将集群配置文件拷贝到目标主机目录
* start -- 启动集群中的所有或单个模块服务
* restart -- 重启集群中的所有或单个模块服务
* stop -- 停止集群中的所有或单个模块服务
* tail -- 查看指定模块日志的最后一部分内容(等同于远程服务器的tail命令)
* status -- 查看指定模块服务进程状态
* help -- 查看命令的详细说明和样例
**Modules**:
* fvote -- Vote 服务器
* fdir -- fastDIR 服务器
* fstore -- faststore 服务器
* fauth -- FastCFS auth 服务器
* fuseclient -- FastCFS fuse 客户端
**Node**:
可以用于指定要执行命令的单个集群节点主机名或IP,如果不指定,命令将在所有节点上执行。node 参数必须在使用了 module 参数的情况下使用,不能单独直接使用。
#### 1.6.1. FastCFS 一键安装
你可以使用命令 ***setup*** 在集群节点上快速安装 FastCFS 软件,并自动配置和启动模块服务.
**样例**
安装并启动整个 FastCFS 集群:
> fcfs.sh setup
在所有 fdir 节点上安装并启动 fdir 服务器:
> fcfs.sh setup fdir
在节点 10.0.1.11 上安装 fdir 服务器:
> fcfs.sh setup fdir 10.0.1.11
节点 10.0.1.11 必须属于 fdir 集群,否则命令将失败。
#### 1.6.2. FastCFS 软件安装
你可以使用命令 ***install*** 只安装 FastCFS 软件。这个命令是 setup 命令的一部分。
第一次执行该命令时,必须在所有节点上安装所有软件(也就是说,此时不能指定module和node)。之后,当需要增加新节点时,可以携带 module 和 node 参数使用。
**样例**
在所有节点安装所需的 FastCFS 软件:
> fcfs.sh install
在所有 fdir 节点上安装 fdir 服务器:
> fcfs.sh install fdir
在 10.0.1.11 节点上安装 fdir 服务器:
> fcfs.sh install fdir 10.0.1.11
#### 1.6.3. FastCFS 软件升级
当你想升级 FastCFS 软件时,你需要先将配置文件 fcfs.settings 中的 fastcfs_version 字段的值修改为新的版本号,然后执行 install 命令:
> fcfs.sh install
#### 1.6.4. FastCFS 软件降级
如果你确实需要将 FastCFS 软件降级为旧的版本,你必须先执行 ***remove*** 命令:
> fcfs.sh remove
或:
> fcfs.sh erase
并将字段 fastcfs_version 的值修改为旧的版本号,然后执行 install 命令:
> fcfs.sh install
#### 1.6.5. FastCFS 软件卸载
可以使用命令 ***remove*** 或 ***erase*** 卸载 FastCFS 软件。
**样例**
移除所有节点上的所有软件:
> fcfs.sh remove
移除所有 fdir 节点上的 fdir 服务器:
> fcfs.sh remove fdir
移除节点10.0.1.11上的 fdir 服务器:
> fcfs.sh remove fdir 10.0.1.11
#### 1.6.6. FastCFS 配置文件分发
成功安装 FastCFS 软件之后,你必须通过执行命令 ***config*** 来将配置文件分发到各个集群节点。如果节点上的目标配置文件目录不存在,它将会自动创建它们。
**样例**
将所有模块的配置文件分发到所有相应的节点上:
> fcfs.sh config
将 fdir 服务器的配置文件分发到所有 fdir 节点上:
> fcfs.sh config fdir
将 fdir 服务器的配置文件分发到 fdir 节点 10.0.1.11 上:
> fcfs.sh config fdir 10.0.1.11
#### 1.6.7. 集群管理
管理集群的命令包括 ***start***, ***stop***, ***restart***。你可以同时操作所有模块的所有节点,也可以同时操作某一模块的所有节点,也可以单独操作某一模块的某一个节点。
如果想操作单个节点,你必须在 module 参数后指定 node(host)参数(也就是说,你不能同时操作某一节点上的所有模块)。
**样例**
启动所有节点上的所有服务:
> fcfs.sh start
重启所有 fdir 节点上的 fdir 服务:
> fcfs.sh restart fdir
停止 节点10.0.1.11上的 fdir 服务:
> fcfs.sh stop fdir 10.0.1.11
#### 1.6.8. 查看集群日志
当你想查看 FastCFS 服务的最新日志时,你可以使用命令 ***tail*** 来显示指定模块日志文件的最后一部分。
**样例**
显示 10.0.1.11节点上 fdir 服务日志文件的最后 100 行:
> fcfs.sh tail fdir 10.0.1.11 -n 100
或:
> fcfs.sh tail fdir 10.0.1.11 -100
显示每个 fdir 服务器日志的最后 10 行:
> fcfs.sh tail fdir
#### 1.6.9. 查看集群服务进程状态
当你想查看 FastCFS 服务的进程状态时,你可以使用命令 ***status*** 来显示指定模块的服务进程状态。
**样例**
显示 10.0.1.11 节点上 fdir 服务进程状态:
> fcfs.sh status fdir 10.0.1.11
显示每个 fdir 服务器进程状态:
> fcfs.sh status fdir
显示所有服务进程状态:
> fcfs.sh status
## 2. fcfs_conf.sh 介绍
fcfs_conf.sh 是一个快速创建 FastCFS集群配置文件的运维工具。它通过 bash shell 访问本地配置文件 fcfs_conf.settings。它只需在你的工作站机器上运行,不需要服务器、数据库或者其他额外资源。
如果你需要在指定的服务器IP列表上快速生成集群配置文件,那么它很适合你。
### 2.1. 获取 fcfs_conf.sh
从以下地址下载 fcfs_conf.sh,并将其放置在工作站机器的bin目录下,以便命令行能够找到:
> http://fastken.cn/fastcfs/ops/fcfs_conf.sh
获取命令:
> sudo curl -o /usr/bin/fcfs_conf.sh http://fastken.cn/fastcfs/ops/fcfs_conf.sh && sudo chmod +x /usr/bin/fcfs_conf.sh
下载完成后可通过命令 ***which fcfs_conf.sh*** 测试工具是否生效。
### 2.2. 使用fcfs_conf.sh的前置条件
* fcfs_conf.settings -- 生成集群配置文件的参数配置,放置在当前工作目录中
你必须为每个集群创建一个独立的工作目录(例如:***fastcfs-ops***),将 ***fcfs_conf.settings***放入其中。然后在该工作目录中执行fcfs_conf.sh命令。
#### 2.2.1. fcfs_conf.settings
fcfs_conf.settings 包括以下六种字段:
* fastcfs_version -- 要生成哪个版本集群的配置文件
* vote_ips -- vote 服务器IP地址列表,多个IP以英文半角逗号分隔
* auth_ips -- FastCFS auth 服务器IP地址列表,多个IP以英文半角逗号分隔
* fdir_ips -- fastDIR服务器IP地址列表,多个IP以英文半角逗号分隔
* fstore_group_count -- faststore服务器分组数量
* fstore_group_[N] -- faststore服务器分组IP地址列表,多个IP以英文半角逗号分隔
* data_group_count -- faststore服务区数据分组数(推荐64的整数倍,建议至少配置256)
参数 fstore_group_count 设置的数量必须与 fstore_group_[N] 数量相匹配,并且编号从1开始递增。
fcfs_conf.settings 配置文件内容举例:
```
# 要生成配置的集群版本号(例如:5.5.0)
fastcfs_version=5.5.0
# 集群主机列表和分组
vote_ips=10.0.1.11,10.0.1.12,10.0.1.13
auth_ips=10.0.1.11,10.0.1.12,10.0.1.13
fdir_ips=10.0.1.11,10.0.1.12,10.0.1.13
fstore_group_count=2
fstore_group_1=10.0.1.11,10.0.1.12,10.0.1.13
fstore_group_2=10.0.2.14,10.0.2.15,10.0.2.16
data_group_count=256
```
***注:推荐使用 5.5.0 及以后的版本用于生成集群配置文件,尤其是vote(投票)模块。***
### 2.3. fcfs_conf.sh工具命令介绍
fcfs_conf.sh工具的命令包括两部分:command,module。Command 是必须的,module 是可选的。
用法:
> fcfs_conf.sh command [module]
**Commands**:
* create -- 创建配置文件
* help -- 查看命令的详细说明和样例
**Modules**:
* fvote -- vote 服务器
* fdir -- fastDIR 服务器
* fstore -- faststore 服务器
* fauth -- FastCFS auth 服务器
* fuseclient -- FastCFS fuse 客户端
## 3. conf_tpl_tar.sh 介绍
一个简单的集群配置文件模版打包工具,仅供FastCFS开发者使用。
它将从FastCFS, fastDIR, faststore的源代码仓库将FastCFS 集群配置文件模版打包成tar包。
这三个仓库必须在同一个目录,并且 conf_tpl_tar.sh 必须在子目录 FastCFS/shell/ 中执行。
命令格式:
```
conf_tpl_tar.sh [update]
```
* version -- 要创建模版压缩包的集群版本号.
* update -- 在创建之前获取最新的源代码,可选。
举例:
> ./conf_tpl_tar.sh 5.5.0 update
将在当前目录创建配置模版压缩包文件 **conf.5.5.0.tpl.tar.gz**。
================================================
FILE: docs/fcfs-ops-tool.md
================================================
# FastCFS ops tools introduction
* [fcfs.sh](#fcfs.sh) -- a ops tool for quickly manage FastCFS clusters
* [fcfs_conf.sh](#fcfs_conf.sh) -- a ops tool for quickly create FastCFS clusters config files
## 1. fcfs.sh introduction
fcfs.sh is a ops tool for quickly deploy and manage FastCFS clusters. It only relying on SSH access to the servers and sudo. It runs fully on your workstation, requiring no servers, databases, or anything like that.
If you set up and tear down FastCFS clusters a lot, and want minimal extra repeating works, this is for you.
***Tip: This shell support for the following operating systems:***
* CentOS 7, CentOS 8 or higher
* Red Hat Linux 8 or higher
* Rocky Linux 8 or higher
* Fedora Linux 20 or higher
* Oracle Linux 8 or higher
* Amazon Linux
* Alibaba Cloud Linux
* Debian 10 or higher
* Ubuntu 18.04 or higher
### 1.1. What this tool can do?
It can quickly setup FastCFS cluster, include install softwares, distribute config files, manage cluster services and query cluster logs.
It can also upgrade or downgrade FastCFS softwares on single node or full cluster.
It can reinstall software or redistribute config files.
### 1.2. What this tool cannot do?
It is not a generic deployment tool, it is only for FastCFS. It does not handle cluster configuration beyond distribute config files to cluster servers. You must provide usable cluster config files for it.
### 1.3. Fetch fcfs.sh
Get it from http://fastken.cn/fastcfs/ops/fcfs.sh and put it in workstation's bin path.
> sudo curl -o /usr/bin/fcfs.sh http://fastken.cn/fastcfs/ops/fcfs.sh && sudo chmod +x /usr/bin/fcfs.sh
### 1.4. Use preconditions
* fcfs.settings -- cluster ops settings, in current working directory
* conf -- cluster config files, in current working directory
* remote server SSH password-free login, see also [SSH password-free login](#SSH-password-free-login)
You must create a independent working directory(exp: ***fastcfs-ops***) for a cluster, put "fcfs.settings" and "conf" into it. And then, all subsequent commands for this cluster must be execute at the same working directory.
#### 1.4.1. fcfs.settings
fcfs.settings include two fields ***fastcfs_version*** and ***fuseclient_ips***, fastcfs_version specify FastCFS main version number, fuseclient_ips specify host to deploy fuse client. When upgrade or downgrade FastCFS, you need change fastcfs_version to version you expect.
fcfs.settings content Example:
```
# Version of FastCFS cluster
fastcfs_version=5.5.0
# Hosts which fuseclient will install,multiple hosts separated by comma
fuseclient_ips=10.0.1.14
```
***Tip:Use version 5.5.0 and later for deploy.***
#### 1.4.2. conf
All config files of FastCFS cluster must be put into working directory beforehand, conf include five subdirectories:
* vote -- config files for fvote server
* fdir -- config files for fdir server
* fstore -- config files for fstore server
* auth -- config files for fauth server
* fcfs -- config files for fuseclient
**Fetch config sample**
```
mkdir fastcfs-ops
cd fastcfs-ops/
curl -o fcfs-config-sample.tar.gz http://fastken.cn/fastcfs/ops/fcfs-config-sample.tar.gz
tar -xzvf fcfs-config-sample.tar.gz
```
**Create config files use fcfs_conf.sh**
You can also create FastCFS cluster config files use fcfs_conf.sh according to your own needs. see also [fcfs_conf.sh](#fcfs_conf.sh)
### 1.5. SSH password-free login
fcfs.sh will connect to cluster hosts via SSH. It requires that the workstation machine from which the shell is being run can connect via SSH as root(or sudo user) without password into cluster nodes.
To enable password-free login, you need generate rsa key pair for ssh:
> ssh-keygen -t rsa -C cfs -f cfs-ssh-key
it will generate key files:
* cfs-ssh-key -- private key file
* cfs-ssh-key.pub -- public key file
#### 1.5.1. Deploy private key
Copy private key file cfs-ssh-key to workstation machine's current user directory ***"~/.ssh/"***, and add the following phrase to ~/.ssh/config(for each host):
```
Host [node ip]
HostName [node host name]
User [ssh user]
Port 22
PubkeyAuthentication yes
IdentityFile ~/.ssh/cfs-ssh-key
```
#### 1.5.2. Deploy public key
Copy public key to file .ssh/authorized_keys in every node server's sudo user home:
> ssh-copy-id -i cfs-ssh-key.pub [user name]@[node server ip]
and ensure that the following lines are in server's sshd config:
```
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
```
### 1.6. Tool commands introduction
The tool's command include three parts: command, module and node. Command is required, module and node are optional.
Usage:
> fcfs.sh command [module] [node]
**Commands**:
* setup -- Setup FastCFS softwares, a shortcut command combines install, config, and restart
* install -- Install FastCFS softwares
* reinstall -- Reinstall FastCFS softwares
* remove -- Remove FastCFS softwares, same as erase
* erase -- Erase FastCFS softwares
* config -- Copy cluster config files to target host path
* start -- Start all or one module service in cluster
* restart -- Restart all or one module service in cluster
* stop -- Stop all or one module service in cluster
* tail -- Display the last part of the specified module's log
* status -- Display the service processes status
* help -- Show the detail of commands and examples
**Modules**:
* fvote -- Vote server
* fdir -- fastDIR server
* fstore -- faststore server
* fauth -- FastCFS auth server
* fuseclient -- FastCFS fuse client
**Node**:
You can specify a single cluster IP, or command will be executed on all nodes.
#### 1.6.1. FastCFS setup
You can use command ***setup*** to quickly setup FastCFS softwares on nodes, then config and start module services.
**Examples**
Setup the full FastCFS cluster:
> fcfs.sh setup
Setup fdir server on all fdir nodes:
> fcfs.sh setup fdir
Setup fdir server on node 10.0.1.11:
> fcfs.sh setup fdir 10.0.1.11
node 10.0.1.11 must belong to fdir cluster, or it will fail.
#### 1.6.2. FastCFS softwares install
You can use command ***install*** to install softwares only. This command is part of setup.
First time, you must install all softwares on all nodes(that is to say you can't specify module and node). After that, you can install a new node with module and node params.
**Examples**
Install all FastCFS softwares on all nodes:
> fcfs.sh install
Install fdir server on all fdir nodes:
> fcfs.sh install fdir
Install fdir server on node 10.0.1.11:
> fcfs.sh install fdir 10.0.1.11
#### 1.6.3. FastCFS softwares upgrade
When you want to upgrade FastCFS's software, you can modify fcfs.settings, change field fastcfs_version to new version, then execute install command:
> fcfs.sh install
#### 1.6.4. FastCFS softwares downgrade
If you realy want to downgrade FastCFS softwares to an old version, you must execute command ***remove*** first:
> fcfs.sh remove
or:
> fcfs.sh erase
and change field fastcfs_version to old version, then execute install command:
> fcfs.sh install
#### 1.6.5. FastCFS softwares remove
You can use command ***remove*** or ***erase*** to remove FastCFS softwares.
**Examples**
Remove all softwares on all nodes:
> fcfs.sh remove
Remove fdir server on all nodes:
> fcfs.sh remove fdir
Remove fdir server on node 10.0.1.11:
> fcfs.sh remove fdir 10.0.1.11
#### 1.6.6. FastCFS config files distribute
After install FastCFS softwares, you must execute command ***config*** to distribute config files to cluster nodes. If target config file directory does't exist on node, it will create it automatically.
**Exmaples**
Distribute all module config files to all nodes respective:
> fcfs.sh config
Distribute fdir server config files to all fdir nodes:
> fcfs.sh config fdir
Distribute fdir server config files to fdir node 10.0.1.11:
> fcfs.sh config fdir 10.0.1.11
#### 1.6.7. Cluster manage
Manage commands include ***start***, ***stop***, ***restart***. You can operate on all modules or one module's all nodes at same time, or a single node for one module.
If you want to operate on a single node, you must specify node host after module, that is to say you can't operate on all modules on a single node at same time.
Start all service on all nodes:
> fcfs.sh start
Restart fdir service on all fdir nodes:
> fcfs.sh restart fdir
Stop fdir service on fdir node 10.0.1.11:
> fcfs.sh stop fdir 10.0.1.11
#### 1.6.8. Display cluster logs
When you want to query FastCFS services last logs, you can use command ***tail*** to display the last part of the specified module's log.
**Example**
Display the last 100 lines of fdir server log:
> fcfs.sh tail fdir 10.0.1.11 -n 100
or:
> fcfs.sh tail fdir 10.0.1.11 -100
Display the last 10 lines of each fdir server log:
> fcfs.sh tail fdir
#### 1.6.9. Display cluster service status
When you want to query FastCFS services process status, you can use command ***status*** to display the status of the specified module's service process.
**Example**
Display the status of fdir service process:
> fcfs.sh status fdir 10.0.1.11
Display the status of each fdir service process:
> fcfs.sh status fdir
Display the status of all service processes:
> fcfs.sh status
## 2. fcfs_conf.sh introduction
fcfs_conf.sh is a ops tool for quickly generate FastCFS cluster config files.It only relying on bash shell access to the local fcfs_conf.settings file. It runs fully on your workstation, requiring no servers, databases, or anything like that.
If you want to generate cluster config files with specify server ips quickly, this is for you.
### 2.1. Fetch fcfs_conf.sh
Get it from http://fastken.cn/fastcfs/ops/fcfs_conf.sh and put it in workstation's bin path.
> sudo curl -o /usr/bin/fcfs_conf.sh http://fastken.cn/fastcfs/ops/fcfs_conf.sh && sudo chmod +x /usr/bin/fcfs_conf.sh
### 2.2. Use preconditions of fcfs_conf.sh
* fcfs_conf.settings -- cluster ops settings for create config files, in current working directory
You must create a independent working directory(exp: ***fastcfs-ops***) for a cluster, put "fcfs_conf.settings" into it. And then, subsequent commands for fcfs_conf.sh must be execute at the same working directory.
#### 2.2.1. fcfs_conf.settings
fcfs.settings include six fields: ***fastcfs_version*** and ***fuseclient_ips***, fastcfs_version specify FastCFS main version number, fuseclient_ips specify host to deploy fuse client. When upgrade or downgrade FastCFS, you need change fastcfs_version to version you expect.
* fastcfs_version -- The FastCFS version you expect to create config files for.
* vote_ips -- vote server IP list, multiple hosts separated by comma
* auth_ips -- FastCFS auth server IP list, multiple hosts separated by comma
* fdir_ips -- fastDIR server IP list, multiple hosts separated by comma
* fstore_group_count -- faststore server group count
* fstore_group_[N] -- faststore server group IP list, multiple hosts separated by comma
* data_group_count - faststore data group count(multiples of 64 are recommended)
Parameter fstore_group_count's value must match fstore_group_[N], and N increases from 1。
fcfs_conf.settings content Example:
```
# Version of FastCFS cluster
fastcfs_version=5.5.0
# Cluster hosts list and group count
vote_ips=10.0.1.11,10.0.1.12,10.0.1.13
auth_ips=10.0.1.11,10.0.1.12,10.0.1.13
fdir_ips=10.0.1.11,10.0.1.12,10.0.1.13
fstore_group_count=2
fstore_group_1=10.0.1.11,10.0.1.12,10.0.1.13
fstore_group_2=10.0.2.14,10.0.2.15,10.0.2.16
data_group_count=128
```
***Tip:Use version 5.5.0 and later for create config files, especially for vote server.***
### 2.3. fcfs_conf.sh Tool commands introduction
The fcfs_conf.sh command include two parts: command and module. Command is required, module is optional.
Usage:
> fcfs_conf.sh command [module]
**Commands**:
* create -- Create config files.
* help -- Show the detail of commands and examples
**Modules**:
* fvote -- Vote server
* fdir -- fastDIR server
* fstore -- faststore server
* fauth -- FastCFS auth server
* fuseclient -- FastCFS fuse client
## 3. conf_tpl_tar.sh introduction
A simple cluster config file templates pack tool for developer of FastCFS.
It will pack FastCFS cluster config file templates to a tar file from source code repository FastCFS, fastDIR, faststore.
Three repository FastCFS, fastDIR, faststore must at same path, and execute conf_tpl_tar.sh in FastCFS/shell/
Command:
```
conf_tpl_tar.sh [update]
```
* version -- Cluster version number to create template tar file.
* update -- Pull the last source codes before create tar file. Optional
Exmaple:
> ./conf_tpl_tar.sh 5.5.0 update
It will create tar file **conf.5.5.0.tpl.tar.gz** in current dir.
================================================
FILE: docs/index.md
================================================
# FastCFS -- a high performance general distributed file system for databases, K8s and VM etc.
English | [Chinese](./README-zh_CN.md)
## 1. About
FastCFS is a general distributed file system with strong consistency, high performance, high availability and supporting 10 billion massive files.
FastCFS can be used as the back-end storage of databases (MySQL, PostgresSQL, Oracle etc.), K8s and NAS.
## 2. Current Version
V3.1.0
## 3. Supported Platforms
* Linux: Kernel version >= 3.10 (Full support)
* MacOS or FreeBSD (Only server side)
## 4. Dependencies
* [libfuse](https://github.com/libfuse/libfuse) (version 3.9.4 or newer)
* [Python](https://python.org/) (version 3.5 or newer)
* [Ninja](https://ninja-build.org/) (version 1.7 or newer)
* [gcc](https://www.gnu.org/software/gcc/) (version 4.7.0 or newer)
* [libfastcommon](https://github.com/happyfish100/libfastcommon) (tag: V1.0.55)
* [libserverframe](https://github.com/happyfish100/libserverframe) (tag: V1.1.12)
* [libdiskallocator](https://github.com/happyfish100/libdiskallocator) (tag: V1.0.1)
* [fastDIR](https://github.com/happyfish100/fastDIR) (tag: V3.1.0)
* [faststore](https://github.com/happyfish100/faststore) (tag: V3.1.0)
* [FastCFS](https://github.com/happyfish100/FastCFS) (tag: V3.1.0)
## 5. Installation
### 5.1 DIY installation
you can use [Cluster Operation Tool](docs/fcfs-ops-tool.md) to deploy FastCFS
step by step please see [INSTALL](docs/INSTALL.md)
recommend to execute libfuse_setup.sh for compiling and installing libfuse
### 5.2 easy installation
libfastcommon, libserverframe, fastDIR, faststore and FastCFS can be compiled, installed and auto configurated by fastcfs.sh
fastcfs.sh can automatically pull or update above six projects codes from GitHub, compile and install according to dependency orders, and automatically generate cluster related configuration files according to the config templates.
```
git clone https://github.com/happyfish100/FastCFS.git; cd FastCFS/
```
fastcfs.sh usage:
```
* install: pull/update codes from gitee, then make and install
* config: copy config files and configure them with local ip
* start | stop | restart: for service processes control
```
one click to build (deploy and run) single node demo environment (MUST run by root):
```
./helloWorld.sh
```
or execute following commands (MUST run by root):
```
./fastcfs.sh install
./fastcfs.sh config --force
./fastcfs.sh restart
```
now you can see the mounted path of FastCFS by the command:
```
df -h /opt/fastcfs/fuse | grep fuse
```
## 6. Benchmark
FastCFS has huge better performance than Ceph: the IOPS ratio of sequential write is 6.x, sequential read is 2.x, random write is about 2.0.
* [FastCFS vs. Ceph benchmark](docs/benchmark.md)
## 7. K8s CSI Driver
[fastcfs-csi](https://github.com/happyfish100/fastcfs-csi)
## 8. Chinese Relative articles
CSDN blog
## 9. TODO List
* [fstore] provide cluster tools for automatic expansion
* [fstore] hierarchical storage & slice merging: supporting two-level storage, such as SSD + HDD
* [fdir & fstore] binlog deduplication (fdir binlog, fstore replica & slice binlog)
* [fstore] after the machine recovery, the data masters should be rebalanced
## 10. Contact us
email: 384681(at)qq(dot)com
WeChat subscription: search "fastdfs" for the related articles (Chinese Only)
================================================
FILE: docs/shared-storage-guide-zh_CN.md
================================================
# 共享数据配置指南
FastCFS客户端缓存默认是开启的,这主要针对独享数据场景(对同一文件单节点读写),也可以支持非实时场景下对同一文件一写多读。
如果将FastCFS作为Oracle RAC等系统的共享存储(对同一文件多节点写入和多节点读取),为了保证数据一致性,需要关闭客户端相关缓存。
默认安装的客户端配置文件为 /etc/fastcfs/fcfs/fuse.conf,下面列出需要修改的配置项:
```
[FastDIR]
# 对于文件追加写或文件truncate操作,通过加锁避免冲突
# if use sys lock for file append and truncate to avoid conflict
# set true when the files appended or truncated by many nodes (FUSE instances)
# default value is false
use_sys_lock_for_append = true
# 禁用异步报告文件属性(即采用同步报告方式)
# if async report file attributes (size, modify time etc.) to the FastDIR server
# default value is true
async_report_enabled = false
# 禁用合并写
[write-combine]
# if enable write combine feature for FastStore
# default value is true
enabled = false
# 禁用预读机制
[read-ahead]
# if enable read ahead feature for FastStore
# default value is true
enabled = false
[FUSE]
# 禁用Linux对inode缓存
# cache time for file entry in seconds
# default value is 1.0s
entry_timeout = 0.0
# 禁用Linux对文件属性缓存
# cache time for file attribute in seconds
# default value is 1.0s
attribute_timeout = 0.0
# 禁用内核合并写
# if enable kernel writeback cache
# default value is true
writeback_cache = false
# 禁用内核读缓存
# if keep kernel cache for read
# set to true for unshared data scene (private data for single node)
# should set to false on shared data scene for multi nodes
# default value is true
kernel_cache = false
```
友情提示:配置文件修改后,需要重启fcfs_fused方可生效。
================================================
FILE: docs/version-history-zh_CN.md
================================================
# FastCFS 重大版本一览
* V1.0:2020年12月第一个版本(历时12个月)
* V2.0:2021年4月支持k8s(历时3个月)
* V3.0:2021年12月实现fdir存储插件,支持百亿级海量文件(历时6个月)
* V3.3:2022年4月生产环境可用(从V3.1到V3.3,历时4个月)
* V3.6:2022年9月文件读写性能大幅提升(从V3.4到V3.6,历时5个月)
* V3.7:2022年11月遵循POSIX ACL,有用户用作NFS后端存储(历时2个月)
* V4.0:2023年6月实现fstore存储插件,支持单机PB级存储(历时4个月)
* V4.3:2023年8月V4系列稳定版本(从V4.1到V4.3,历时2个月)
* V5.0:2023年11月原生支持RDMA,解决网络瓶颈(历时4个月)
* V5.3:2024年3月支持IPv6和bug修复(从V5.1到V5.3,历时4个月)
* V5.4:2025年4月存储插件性能优化和bug修复(历时3个月)
* V5.5:2025年11月适配io_uring高性能异步IO框架,最新稳定版本
================================================
FILE: docs/versions.json
================================================
[
{"version": "v3.1.0", "title": "v3.2.0", "aliases": ["latest"]},
{"version": "v3.1.0", "title": "v3.1.0", "aliases": []}
]
================================================
FILE: fastcfs.sh
================================================
#!/bin/bash
#
# fastcfs install, config and start a local fastcfs cluster on Linux.
# fastcfs's primary goals are to be the best shell for local FastCFS
# application development and to support all fastcfs features that fit.
#
# fastcfs shell support commands
# setup -- combin install, config and restart, quickly setup single node FastCFS cluster
# install -- pull code, make, install
# config -- copy config files to default conf path(/etc/fastcfs/)
# start -- start fdir_serverd, fs_serverd, fcfs_fused service
# restart -- restart fdir_serverd, fs_serverd, fcfs_fused service
# stop -- stop fdir_serverd, fs_serverd, fcfs_fused service
#
# When setup, This shell will make and install these six libs in order:
# libfastcommon
# libserverframe
# libdiskallocator
# auth_client
# fastDIR
# faststore
# FastCFS
#
# If no source code in build path, it will git clone from:
# https://gitee.com/fastdfs100/libfastcommon.git
# https://gitee.com/fastdfs100/libserverframe.git
# https://gitee.com/fastdfs100/libdiskallocator.git
# https://gitee.com/fastdfs100/fastDIR.git
# https://gitee.com/fastdfs100/faststore.git
#
# FastCFS modules and repositores
COMMON_LIB="libfastcommon"
COMMON_LIB_URL="https://gitee.com/fastdfs100/libfastcommon.git"
FRAME_LIB="libserverframe"
FRAME_LIB_URL="https://gitee.com/fastdfs100/libserverframe.git"
DISK_ALLOCATOR_LIB="libdiskallocator"
DISK_ALLOCATOR_LIB_URL="https://gitee.com/fastdfs100/libdiskallocator.git"
FDIR_LIB="fastDIR"
FDIR_LIB_URL="https://gitee.com/fastdfs100/fastDIR.git"
STORE_LIB="faststore"
STORE_LIB_URL="https://gitee.com/fastdfs100/faststore.git"
FASTCFS_LIB=".."
VOTECLIENT_LIB=".."
AUTHCLIENT_LIB=".."
STORE_CONF_FILES=(client.conf server.conf cluster.conf storage.conf dbstore.conf)
STORE_CONF_PATH="/etc/fastcfs/fstore/"
FDIR_CONF_FILES=(client.conf cluster.conf server.conf dbstore.conf)
FDIR_CONF_PATH="/etc/fastcfs/fdir/"
AUTH_CONF_FILES=(auth.conf client.conf cluster.conf server.conf session.conf)
AUTH_CONF_PATH="/etc/fastcfs/auth/"
AUTH_KEYS_FILES=(session_validate.key)
AUTH_KEYS_PATH="/etc/fastcfs/auth/keys/"
FUSE_CONF_FILES=(fuse.conf)
FUSE_CONF_PATH="/etc/fastcfs/fcfs/"
YUM_OS_ARRAY=(Red Rocky Oracle Fedora CentOS AlmaLinux Alibaba Anolis Amazon openEuler Kylin UOS BigCLoud)
BUILD_PATH="build"
this_shell_name=$0
mode=$1 # setup|install|config|start|restart|stop
make_shell=make.sh
force_reconfig=0
uname=$(uname)
pull_source_code() {
if [ $# != 2 ]; then
echo "ERROR: $0 - pull_source_code() function need repository name and url!"
exit 1
fi
module_name=$1
module_url=$2
if ! [ -d $module_name ]; then
echo "INFO: The $module_name local repository does not exist!"
echo "INFO: =====Begin to clone $module_name , it will take some time...====="
git clone $module_url
git checkout master
else
echo "INFO: The $module_name local repository have existed."
cd $module_name
echo "INFO: =====Begin to pull $module_name, it will take some time...====="
git checkout master
git pull
cd ..
fi
}
make_op() {
if [ $# -lt 3 ]; then
echo "ERROR: $0 - make_op() function need module repository name and mode!"
exit 1
fi
module_name=$1
module_src_path=$2
extend_options=$4
make_mode=$3
module_lib_path=$BUILD_PATH/$module_src_path
if ! [ -d $module_lib_path ]; then
echo "ERROR: $0 - module repository {$module_name} does not exist!"
echo "ERROR: You must checkout from remote repository first!"
exit 1
else
cd $module_lib_path
echo "INFO: =====Begin to $make_mode module [$module_name]====="
command="./$make_shell"
if [ ${#extend_options} -gt 0 ]; then
command="$command $extend_options"
fi
if [ $make_mode != "make" ]; then
command="$command $make_mode"
fi
echo "INFO: Execute command ($command) in path ($PWD)"
result=`$command`
echo "INFO: Execute result=("
echo "$result"
echo ")"
cd -
fi
}
sed_replace()
{
sed_cmd=$1
filename=$2
if [ "$uname" = "FreeBSD" ] || [ "$uname" = "Darwin" ]; then
sed -i "" "$sed_cmd" $filename
else
sed -i "$sed_cmd" $filename
fi
}
split_to_array() {
if ! [ -z $2 ]; then
IFS=',' read -ra $2 <<< "$1"
fi
}
placeholder_replace() {
filename=$1
placeholder=$2
value=$3
sed_replace "s#\${$placeholder}#$value#g" $filename
}
parse_config_arguments() {
for arg do
case "$arg" in
--force)
force_reconfig=1
;;
esac
done
}
check_paths_infile() {
# Check all paths in this config file, if not exist, will create it.
check_conf_file=$1
check_result=`sed -n \
-e '/^mountpoint *=/ p' \
-e '/^base_path *=/ p' \
-e '/^path *=/ p' \
$check_conf_file|sed 's/\([^=]*\)=\([^=]\)/\2/g'`
for check_path in ${check_result[@]}; do
if ! [ -d $check_path ]; then
if ! mkdir -p $check_path; then
echo "ERROR: Create target path in file $check_conf_file failed:$check_path!"
exit 1
else
echo "INFO: Created target path in file $check_conf_file successfully:$check_path!"
fi
fi
done
}
replace_host() {
# Replace host with ip of current host.
replace_conf_file=$1
target_ip=$2
sed_replace "s#^host *=.*#host = $target_ip#g" $replace_conf_file
}
copy_config_to() {
config_file_array=$1
src_path=$2
dest_path=$3
if ! [ -d $dest_path ]; then
if ! mkdir -p $dest_path; then
echo "ERROR: Create target conf path failed:$dest_path!"
exit 1
fi
fi
for CONF_FILE in ${config_file_array[@]}; do
tmp_src_file=$src_path/$CONF_FILE
tmp_dest_file=${dest_path}$CONF_FILE
if [ -f $tmp_src_file ]; then
if [ -f $tmp_dest_file ]; then
if ! [ $force_reconfig -eq 1 ]; then
echo "ERROR: file $tmp_dest_file exist, "
echo 'you must specify --force to force reconfig, it will overwrite the exists files!'
echo "Usage: $this_shell_name config --force"
exit 1
else
# Backup exists file
cp -f $tmp_dest_file $tmp_dest_file.bak
fi
fi
echo "INFO: Copy file $CONF_FILE to $dest_path"
cp -f $tmp_src_file $tmp_dest_file
elif ! [ -f $tmp_dest_file ]; then
echo "ERROR: file $tmp_dest_file not exist"
exit 1
fi
file_extension="${tmp_dest_file##*.}"
if [ $file_extension = "conf" ]; then
check_paths_infile $tmp_dest_file
replace_host $tmp_dest_file "$IP"
fi
done
}
config_faststore() {
# Copy faststore's config file to target config path
echo "INFO: Config faststore:"
store_src_conf_path=$BUILD_PATH/$STORE_LIB/conf
copy_config_to "${STORE_CONF_FILES[*]}" $store_src_conf_path $STORE_CONF_PATH
}
config_fastdir() {
# Copy fastDIR's config file to target config path
echo "INFO: Config fastDIR:"
fdir_src_conf_path=$BUILD_PATH/$FDIR_LIB/conf
copy_config_to "${FDIR_CONF_FILES[*]}" $fdir_src_conf_path $FDIR_CONF_PATH
}
config_auth() {
# Copy auth's config file to target config path
echo "INFO: Config auth:"
auth_src_conf_path=src/auth/conf
copy_config_to "${AUTH_CONF_FILES[*]}" $auth_src_conf_path $AUTH_CONF_PATH
auth_src_keys_path=src/auth/conf/keys
copy_config_to "${AUTH_KEYS_FILES[*]}" $auth_src_keys_path $AUTH_KEYS_PATH
}
config_fuse() {
# Copy fuse's config file to target config path
echo "INFO: Config fuse:"
fuse_src_conf_path=conf
copy_config_to "${FUSE_CONF_FILES[*]}" $fuse_src_conf_path $FUSE_CONF_PATH
}
get_first_local_ip() {
ip_cmd=`which ip`
if [ -z "$ip_cmd" ]; then
ipconfig_cmd=`which ifconfig`
if [ -z "$ipconfig_cmd" ]; then
echo "ERROR: Command ip or ifconfig not found, please install one first." 1>&2
exit
else
CMD="$ipconfig_cmd -a | grep -w inet | grep -v 127.0.0.1 | awk '{print \$2}' | tr -d 'addr:' | head -n 1"
fi
else
CMD="$ip_cmd addr | grep -w inet | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v 127.0.0.1 | head -n 1"
fi
sh -c "$CMD"
}
pull_source_codes() {
# Clone or pull source code from github.com if not exists.
echo "INFO: Begin to pull source codes..."
# Pull fastCFS self.
git pull
# Create build path if not exists.
if ! [ -d $BUILD_PATH ]; then
mkdir -m 775 $BUILD_PATH
echo "INFO: Build path {$BUILD_PATH} not exist, created."
fi
cd $BUILD_PATH
# Pull libfastcommon
pull_source_code $COMMON_LIB $COMMON_LIB_URL
# Pull libserverframe
pull_source_code $FRAME_LIB $FRAME_LIB_URL
# Pull libdiskallocator
pull_source_code $DISK_ALLOCATOR_LIB $DISK_ALLOCATOR_LIB_URL
# Pull fastDIR
pull_source_code $FDIR_LIB $FDIR_LIB_URL
# Pull faststore
pull_source_code $STORE_LIB $STORE_LIB_URL
cd ..
}
make_install() {
lib_name=$1
lib_src_path=$2
op_extend_param=$3
make_op $lib_name $lib_src_path clean
make_op $lib_name $lib_src_path make $op_extend_param
make_op $lib_name $lib_src_path install $op_extend_param
}
make_installs() {
# Make and install all lib repositories sequentially.
make_install $COMMON_LIB $COMMON_LIB
make_install $FRAME_LIB $FRAME_LIB
make_install $DISK_ALLOCATOR_LIB $DISK_ALLOCATOR_LIB
make_install vote_client $VOTECLIENT_LIB --module=vote_client
make_install auth_client $AUTHCLIENT_LIB --module=auth_client
make_install $FDIR_LIB $FDIR_LIB
make_install $STORE_LIB $STORE_LIB
make_install FastCFS $FASTCFS_LIB --exclude=auth_client
echo "INFO: Congratulation, setup complete successfully!"
echo "INFO: Then, you can execute command [fastcfs.sh config] next step."
}
service_op() {
operate_mode=$1
fs_serverd ${STORE_CONF_PATH}server.conf $operate_mode
fdir_serverd ${FDIR_CONF_PATH}server.conf $operate_mode
if [ $operate_mode != 'stop' ]; then
sleep 3
fi
fcfs_authd ${AUTH_CONF_PATH}server.conf $operate_mode
if [ $operate_mode != 'stop' ]; then
sleep 1
fi
fcfs_fused ${FUSE_CONF_PATH}fuse.conf $operate_mode
}
uname=$(uname)
if [ $uname = 'Linux' ]; then
osname=$(cat /etc/os-release | grep -w NAME | awk -F '=' '{print $2;}' | \
awk -F '"' '{if (NF==3) {print $2} else {print $1}}' | awk '{print $1}')
if [ $osname = 'CentOS' ]; then
osversion=$(cat /etc/system-release | awk '{print $4}')
fi
if [ -z $osversion ]; then
osversion=$(cat /etc/os-release | grep -w VERSION_ID | awk -F '=' '{print $2;}' | \
awk -F '"' '{if (NF==3) {print $2} else {print $1}}')
fi
os_major_version=$(echo $osversion | awk -F '.' '{print $1}')
if [ $osname = 'Fedora' ]; then
if [ $os_major_version -lt 20 ]; then
os_major_version=6
elif [ $os_major_version -lt 28 ]; then
os_major_version=7
elif [ $os_major_version -lt 34 ]; then
os_major_version=8
else
os_major_version=9
fi
elif [ $osname = 'Alibaba' ]; then
if [ $os_major_version -lt 3 ]; then
os_major_version=7
else
os_major_version=8
fi
elif [ $osname = 'Amazon' ]; then
if [ $os_major_version -le 2 ]; then
os_major_version=7
else
os_major_version=8
fi
elif [ $osname = 'openEuler' ] || [ $osname = 'Kylin' ] || [ $osname = 'UOS' ] || [ $osname = 'BigCLoud' ]; then
os_major_version=8
fi
else
echo "Unsupport OS: $uname" 1>&2
exit 1
fi
check_install_fastos_repo() {
if [ $osname = 'Ubuntu' ] || [ $osname = 'Debian' ] || [ $osname = 'Deepin' ]; then
if [ ! -f /etc/apt/sources.list.d/fastos.list ]; then
apt install curl gpg -y
curl http://www.fastken.com/aptrepo/packages.fastos.pub | gpg --dearmor > /tmp/fastos-archive-keyring.gpg
install -D -o root -g root -m 644 /tmp/fastos-archive-keyring.gpg /usr/share/keyrings/fastos-archive-keyring.gpg
sh -c 'echo "deb [signed-by=/usr/share/keyrings/fastos-archive-keyring.gpg] http://www.fastken.com/aptrepo/fastos/ fastos main" > /etc/apt/sources.list.d/fastos.list'
sh -c 'echo "deb [signed-by=/usr/share/keyrings/fastos-archive-keyring.gpg] http://www.fastken.com/aptrepo/fastos-debug/ fastos-debug main" > /etc/apt/sources.list.d/fastos-debug.list'
rm -f /tmp/fastos-archive-keyring.gpg
fi
else
repo=$(rpm -q FastOSrepo 2>/dev/null)
if [ $? -ne 0 ]; then
if [ $os_major_version -eq 7 ]; then
rpm -ivh http://www.fastken.com/yumrepo/el7/noarch/FastOSrepo-1.0.1-1.el7.noarch.rpm
else
rpm -ivh http://www.fastken.com/yumrepo/el8/noarch/FastOSrepo-1.0.1-1.el8.noarch.rpm
fi
fi
fi
}
install_all_softwares() {
if [ $osname = 'Ubuntu' -a $os_major_version -ge 18 ] || \
[ $osname = 'Debian' -a $os_major_version -ge 10 ] || \
[ $osname = 'Deepin' -a $os_major_version -ge 20 ]; then
check_install_fastos_repo
apt update
apt install fastcfs-auth-server fastcfs-vote-server fastdir-server faststore-server fastcfs-fused -y
elif [[ " ${YUM_OS_ARRAY[@]} " =~ " ${osname} " ]] && [ $os_major_version -ge 7 ]; then
check_install_fastos_repo
yum install FastCFS-auth-server FastCFS-vote-server fastDIR-server faststore-server FastCFS-fused -y
else
./libfuse_setup.sh
pull_source_codes
make_installs
fi
}
config_all_modules() {
IP=$(get_first_local_ip)
parse_config_arguments $*
config_faststore
config_fastdir
config_auth
config_fuse
}
case "$mode" in
'setup')
install_all_softwares
config_all_modules $*
service_op restart
;;
'install')
install_all_softwares
;;
'config')
config_all_modules $*
;;
'start')
# Start services.
service_op start
;;
'restart')
# Restart services.
service_op restart
;;
'stop')
# Start services.
service_op stop
;;
*)
# usage
echo "Usage: $0 {setup|install|config|start|restart|stop}"
exit 1
;;
esac
exit 0
================================================
FILE: helloWorld.sh
================================================
#!/bin/bash
echo "just for FastCFS demo: 1 fdir instance and 1 fstore instance"
mounted_path=/opt/fastcfs/fuse
./fastcfs.sh install || exit 1
./fastcfs.sh config --force
./fastcfs.sh restart
echo "waiting services ready ..."
sleep 3
if [ -d $mounted_path ]; then
df -h $mounted_path | grep fuse
if [ $? -eq 0 ]; then
echo ""
echo "the mounted path is: $mounted_path"
echo "have a nice day!"
exit 0
fi
fi
tail_cmd='tail -n 20 /opt/fastcfs/fcfs/logs/fcfs_fused.log'
echo 'some mistake happen!'
echo $tail_cmd
sh -c "$tail_cmd"
exit 1
================================================
FILE: libfuse_setup.sh
================================================
#!/bin/bash
YUM_OS_ARRAY=(Red Rocky Oracle Fedora CentOS AlmaLinux Alibaba Anolis Amazon)
get_gcc_version() {
old_lang=$LANG
LANG=en_US.UTF-8 && gcc -v 2>&1 | grep 'gcc version' | \
awk -F 'version' '{print $2}' | awk '{print $1}' | \
awk -F '.' '{print $1}'
LANG=$old_lang
}
apt_check_install_gcc() {
version=$1
pkg_gcc="gcc-$version"
pkg_cpp="g++-$version"
apt list $pkg_gcc 2>&1 | grep $pkg_gcc && apt install $pkg_gcc $pkg_cpp -y
}
apt_install_gcc() {
apt_check_install_gcc 7
if [ $? -ne 0 ]; then
apt_check_install_gcc 8
if [ $? -ne 0 ]; then
apt_check_install_gcc 9
fi
fi
}
apt_install_required_gcc() {
os_major_version=$1
apt install gcc g++ -y
if [ $? -ne 0 ]; then
apt_install_gcc $os_major_version
else
gcc_version=$(get_gcc_version)
if [ -z "$gcc_version" ] || [ "$gcc_version" -lt 4 ]; then
apt_install_gcc $os_major_version
fi
fi
}
yum_check_install_gcc() {
prefix=$1
version=$2
pkg_prefix="${prefix}toolset-${version}"
pkg_gcc="${pkg_prefix}-gcc"
pkg_cpp="${pkg_prefix}-gcc-c++"
yum list $pkg_gcc 2>&1 | grep "$pkg_gcc" && \
yum install $pkg_gcc $pkg_cpp -y && \
source /opt/rh/$pkg_prefix/enable
}
yum_install_gcc() {
os_major_version=$1
if [ $os_major_version -lt 8 ]; then
yum install centos-release-scl scl-utils-build -y
prefix='dev'
else
prefix='gcc-'
fi
yum_check_install_gcc "$prefix" 7
if [ $? -ne 0 ]; then
yum_check_install_gcc "$prefix" 8
if [ $? -ne 0 ]; then
yum_check_install_gcc "$prefix" 9
fi
fi
}
yum_install_required_gcc() {
os_major_version=$1
yum install gcc gcc-c++ -y
if [ $? -ne 0 ]; then
yum_install_gcc $os_major_version
else
gcc_version=$(get_gcc_version)
if [ -z "$gcc_version" ] || [ "$gcc_version" -lt 4 ]; then
yum_install_gcc $os_major_version
fi
fi
}
if [ -z "$LANG" ]; then
export LANG=en_US.UTF-8
fi
uname=$(uname)
if [ $uname = 'Linux' ]; then
osname=$(cat /etc/os-release | grep -w NAME | awk -F '=' '{print $2;}' | \
awk -F '"' '{if (NF==3) {print $2} else {print $1}}' | awk '{print $1}')
if [ $osname = 'CentOS' ]; then
osversion=$(cat /etc/system-release | awk '{print $4}')
fi
if [ -z $osversion ]; then
osversion=$(cat /etc/os-release | grep -w VERSION_ID | awk -F '=' '{print $2;}' | \
awk -F '"' '{if (NF==3) {print $2} else {print $1}}')
fi
os_major_version=$(echo $osversion | awk -F '.' '{print $1}')
if [ $osname = 'Fedora' ]; then
if [ $os_major_version -lt 20 ]; then
os_major_version=6
elif [ $os_major_version -lt 28 ]; then
os_major_version=7
elif [ $os_major_version -lt 34 ]; then
os_major_version=8
else
os_major_version=9
fi
elif [ $osname = 'Alibaba' ]; then
if [ $os_major_version -lt 3 ]; then
os_major_version=7
else
os_major_version=8
fi
elif [ $osname = 'Amazon' ]; then
if [ $os_major_version -le 2 ]; then
os_major_version=7
else
os_major_version=8
fi
fi
else
echo "Unsupport OS: $uname" 1>&2
exit 1
fi
if [[ " ${YUM_OS_ARRAY[@]} " =~ " ${osname} " ]] && [ $os_major_version -ge 7 ]; then
repo=$(rpm -q FastOSrepo 2>/dev/null)
if [ $? -ne 0 ]; then
if [ $os_major_version -eq 7 ]; then
rpm -ivh http://www.fastken.com/yumrepo/el7/x86_64/FastOSrepo-1.0.0-1.el7.centos.x86_64.rpm
else
rpm -ivh http://www.fastken.com/yumrepo/el8/x86_64/FastOSrepo-1.0.0-1.el8.x86_64.rpm
fi
fi
rpm -q fuse-devel >/dev/null && yum remove fuse-devel -y
rpm -q fuse >/dev/null && yum remove fuse -y
yum install fuse3-devel -y
exit 0
else
git_version=$(git --version 2>&1 | grep 'version' | awk '{print $3}')
make_version=$(make --version 2>&1 | grep 'Make' | awk '{print $3}')
PKG_CONFIG_PRG=$(which pkg-config 2>&1)
if [ $? -ne 0 ]; then
PKG_CONFIG_PRG=''
fi
gcc_version=$(get_gcc_version)
python_version=$(python3 --version 2>&1 | grep Python | awk '{print $2}')
pip3_version=$(pip3 --version 2>&1 | awk '{print $2}')
if [ $osname = 'Ubuntu' -o $osname = 'Debian' ]; then
if [ -z "$git_version" ]; then
apt install git -y
fi
if [ -z "$make_version" ]; then
apt install make -y
fi
dpkg -s libaio-dev >/dev/null 2>&1 || apt install libaio-dev -y
if [ -z "$PKG_CONFIG_PRG" ]; then
apt install pkg-config -y
fi
if [ -z "$python_version" ]; then
apt install python3 -y
fi
if [ -z "$pip3_version" ]; then
apt install python3-pip -y
fi
if [ -z "$gcc_version" ] || [ "$gcc_version" -lt 4 ]; then
apt_install_required_gcc
fi
else
if [ -z "$git_version" ]; then
yum install git -y
fi
if [ -z "$make_version" ]; then
yum install make -y
fi
if [ -z "$PKG_CONFIG_PRG" ]; then
yum install pkgconfig -y || yum install pkgconf-pkg-config -y
fi
if [ -z "$python_version" ]; then
yum install python3 -y || yum install python36 -y || yum install python38 -y || exit 2
fi
if [ -z "$pip3_version" ]; then
yum install python3-pip -y
fi
if [ -z "$gcc_version" ] || [ "$gcc_version" -lt 4 ]; then
yum_install_required_gcc
fi
fi
fi
MESON_PRG=$(which meson 2>&1)
if [ $? -ne 0 ]; then
pip3 install meson || exit
fi
NINJA_PRG=$(which ninja 2>&1)
if [ $? -ne 0 ]; then
pip3 install ninja || exit
fi
mkdir -p build; cd build
git clone https://gitee.com/mirrors/libfuse.git
cd libfuse/
git checkout fuse-3.10.1
rm -rf build/ && mkdir build/ && cd build/
meson ..
meson configure -D prefix=/usr
meson configure -D examples=false
ninja
ninja install
sed -i 's/#user_allow_other/user_allow_other/g' /etc/fuse.conf
cd ..
================================================
FILE: make.sh
================================================
ENABLE_STATIC_LIB=0
ENABLE_SHARED_LIB=1
TARGET_PREFIX=$DESTDIR/usr
TARGET_CONF_PATH=$DESTDIR/etc/fdir
module=''
exclude=''
jni_file=''
start=1
for arg do
case "$arg" in
--module=*)
module=${arg#--module=}
start=$(expr $start + 1)
;;
--exclude=*)
exclude=${arg#--exclude=}
start=$(expr $start + 1)
;;
--jni=*)
jni_file=${arg#--jni=}
start=$(expr $start + 1)
;;
esac
done
index=$start
eval param1="\$$index"
index=$(expr $index + 1)
eval param2="\$$index"
DEBUG_FLAG=0
PRELOAD_WITH_CAPI=1
arch=$(uname -r | awk -F '.' '{print $NF;}')
if [ "$arch" = "x86_64" ]; then
PRELOAD_WITH_PAPI=1
else
PRELOAD_WITH_PAPI=0
fi
export CC=gcc
CFLAGS='-Wall'
GCC_VERSION=$(gcc -dM -E - < /dev/null | grep -w __GNUC__ | awk '{print $NF;}')
if [ -n "$GCC_VERSION" ] && [ $GCC_VERSION -ge 7 ]; then
CFLAGS="$CFLAGS -Wformat-truncation=0 -Wformat-overflow=0"
fi
CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE"
if [ "$PRELOAD_WITH_CAPI" = "1" ]; then
CFLAGS="$CFLAGS -DFCFS_PRELOAD_WITH_CAPI"
fi
if [ "$PRELOAD_WITH_PAPI" = "1" ]; then
CFLAGS="$CFLAGS -DFCFS_PRELOAD_WITH_PAPI"
fi
if [ "$DEBUG_FLAG" = "1" ]; then
CFLAGS="$CFLAGS -g -DDEBUG_FLAG"
else
CFLAGS="$CFLAGS -g -O3"
fi
if [ -f /usr/include/fastcommon/_os_define.h ]; then
OS_BITS=$(grep -F OS_BITS /usr/include/fastcommon/_os_define.h | awk '{print $NF;}')
elif [ -f /usr/local/include/fastcommon/_os_define.h ]; then
OS_BITS=$(grep -F OS_BITS /usr/local/include/fastcommon/_os_define.h | awk '{print $NF;}')
else
OS_BITS=64
fi
uname=$(uname)
LIB_VERSION=
if [ "$OS_BITS" -eq 64 ]; then
if [ $uname = 'Linux' ]; then
osname=$(cat /etc/os-release | grep -w NAME | awk -F '=' '{print $2;}' | \
awk -F '"' '{if (NF==3) {print $2} else {print $1}}' | awk '{print $1}')
if [ $osname = 'Ubuntu' -o $osname = 'Debian' ]; then
LIB_VERSION=lib
else
LIB_VERSION=lib64
fi
else
LIB_VERSION=lib
fi
else
LIB_VERSION=lib
fi
LIBS=''
if [ "$uname" = "Linux" ]; then
if [ "$OS_BITS" -eq 64 ]; then
LIBS="$LIBS -L/usr/lib64"
else
LIBS="$LIBS -L/usr/lib"
fi
CFLAGS="$CFLAGS"
elif [ "$uname" = "FreeBSD" ] || [ "$uname" = "Darwin" ]; then
LIBS="$LIBS -L/usr/lib"
CFLAGS="$CFLAGS"
if [ "$uname" = "Darwin" ]; then
CFLAGS="$CFLAGS -DDARWIN"
TARGET_PREFIX=$TARGET_PREFIX/local
fi
elif [ "$uname" = "SunOS" ]; then
LIBS="$LIBS -L/usr/lib"
CFLAGS="$CFLAGS -D_THREAD_SAFE"
LIBS="$LIBS -lsocket -lnsl -lresolv"
elif [ "$uname" = "AIX" ]; then
LIBS="$LIBS -L/usr/lib"
CFLAGS="$CFLAGS -D_THREAD_SAFE"
elif [ "$uname" = "HP-UX" ]; then
LIBS="$LIBS -L/usr/lib"
CFLAGS="$CFLAGS"
fi
have_pthread=0
if [ -f /usr/lib/libpthread.so ] || [ -f /usr/local/lib/libpthread.so ] || [ -f /lib64/libpthread.so ] || [ -f /usr/lib64/libpthread.so ] || [ -f /usr/lib/libpthread.a ] || [ -f /usr/local/lib/libpthread.a ] || [ -f /lib64/libpthread.a ] || [ -f /usr/lib64/libpthread.a ]; then
LIBS="$LIBS -lpthread"
have_pthread=1
elif [ "$uname" = "HP-UX" ]; then
lib_path="/usr/lib/hpux$OS_BITS"
if [ -f $lib_path/libpthread.so ]; then
LIBS="-L$lib_path -lpthread"
have_pthread=1
fi
elif [ "$uname" = "FreeBSD" ]; then
if [ -f /usr/lib/libc_r.so ]; then
line=$(nm -D /usr/lib/libc_r.so | grep -F pthread_create | grep -w T)
if [ $? -eq 0 ]; then
LIBS="$LIBS -lc_r"
have_pthread=1
fi
elif [ -f /lib64/libc_r.so ]; then
line=$(nm -D /lib64/libc_r.so | grep -F pthread_create | grep -w T)
if [ $? -eq 0 ]; then
LIBS="$LIBS -lc_r"
have_pthread=1
fi
elif [ -f /usr/lib64/libc_r.so ]; then
line=$(nm -D /usr/lib64/libc_r.so | grep -F pthread_create | grep -w T)
if [ $? -eq 0 ]; then
LIBS="$LIBS -lc_r"
have_pthread=1
fi
fi
fi
if [ $have_pthread -eq 0 ] && [ "$uname" != "Darwin" ]; then
/sbin/ldconfig -p | grep -F libpthread.so > /dev/null
if [ $? -eq 0 ]; then
LIBS="$LIBS -lpthread"
else
echo -E 'Require pthread lib, please check!'
exit 2
fi
fi
sed_replace()
{
sed_cmd=$1
filename=$2
if [ "$uname" = "FreeBSD" ] || [ "$uname" = "Darwin" ]; then
sed -i "" "$sed_cmd" $filename
else
sed -i "$sed_cmd" $filename
fi
}
replace_makefile()
{
cp Makefile.in Makefile
sed_replace "s#\\\$(CFLAGS)#$CFLAGS#g" Makefile
sed_replace "s#\\\$(LIBS)#$LIBS#g" Makefile
sed_replace "s#\\\$(TARGET_PREFIX)#$TARGET_PREFIX#g" Makefile
sed_replace "s#\\\$(LIB_VERSION)#$LIB_VERSION#g" Makefile
sed_replace "s#\\\$(TARGET_CONF_PATH)#$TARGET_CONF_PATH#g" Makefile
sed_replace "s#\\\$(ENABLE_STATIC_LIB)#$ENABLE_STATIC_LIB#g" Makefile
sed_replace "s#\\\$(ENABLE_SHARED_LIB)#$ENABLE_SHARED_LIB#g" Makefile
}
base_path=$(pwd)
cd src/include/fastcfs/
for subdir in api vote; do
link=$(readlink $subdir)
if [ $? -ne 0 ] || [ "$link" != "../../$subdir" -a "$link" != "../../$subdir/" ]; then
ln -sf ../../$subdir $subdir
fi
done
cd $base_path
if [ -z $module ] || [ "$module" = 'auth_server' -o "$module" = 'authserver' ]; then
if [ "x$exclude" != 'xauth_server' -a "x$exclude" != 'xauthserver' ]; then
cd $base_path/src/auth/server
replace_makefile
make $param1 $param2
fi
fi
if [ -z $module ] || [ "$module" = 'auth_client' -o "$module" = 'authclient' ]; then
if [ "x$exclude" != 'xauth_client' -a "x$exclude" != 'xauthclient' ] && [ "x$exclude" != 'xclient' ]; then
cd $base_path/src/auth/client
replace_makefile
make $param1 $param2
cd $base_path/src/auth/client/tools
replace_makefile
make $param1 $param2
fi
fi
if [ -z $module ] || [ "$module" = 'vote_server' -o "$module" = 'voteserver' ]; then
if [ "x$exclude" != 'xvote_server' -a "x$exclude" != 'xvoteserver' ]; then
cd $base_path/src/vote/server
replace_makefile
make $param1 $param2
fi
fi
if [ -z $module ] || [ "$module" = 'vote_client' -o "$module" = 'voteclient' ]; then
if [ "x$exclude" != 'xvote_client' -a "x$exclude" != 'xvoteclient' ] && [ "x$exclude" != 'xclient' ]; then
cd $base_path/src/vote/client
replace_makefile
make $param1 $param2
cd $base_path/src/vote/client/tools
replace_makefile
make $param1 $param2
fi
fi
if [ -z $module ] || [ "$module" = 'api' ] || [ "$module" = 'fuseclient' -o "$module" = 'fuse_client' ]; then
if [ "x$exclude" != 'xapi' ]; then
cd $base_path/src/api
replace_makefile
make $param1 $param2
cd tests || exit
replace_makefile
make $param1 $param2
fi
fi
if [ "$uname" = "Linux" ]; then
if [ -z $module ] || [ "$module" = 'preload' ]; then
if [ "x$exclude" != 'xpreload' ]; then
cd $base_path/src/preload
replace_makefile
make $param1 $param2
fi
fi
fi
if [ -z $module ] || [ "$module" = 'tools' ]; then
if [ "x$exclude" != 'xtools' ]; then
cd $base_path/src/tools
replace_makefile
make $param1 $param2
fi
fi
if [ "$uname" = "Linux" ]; then
if [ -z $module ] || [ "$module" = 'fuse_client' -o "$module" = 'fuseclient' ]; then
if [ "x$exclude" != 'xfuse_client' -a "x$exclude" != 'xfuseclient' ]; then
cd $base_path/src/fuse
replace_makefile
make $param1 $param2
fi
fi
fi
if [ "$module" = 'jni' ]; then
if [ ! -z $JAVA_HOME ]; then
path=$JAVA_HOME
elif [ ! -z $jni_file ]; then
if [ -d $jni_file ]; then
path=$jni_file
else
path=$(dirname $jni_file)
fi
else
if [ -d /Library ]; then
path=/Library
else
path=/usr/lib
fi
fi
files=$(find $path -name jni.h 2>/dev/null | grep '/include/jni.h$')
if [ -z "$files" ]; then
files=$(locate jni.h | grep '/include/jni.h$')
if [ -z "$files" ]; then
echo "can't locate jni.h, please install java SDK first."
exit 2
fi
fi
count=$(echo "$files" | wc -l)
if [ $count -eq 1 ]; then
filename=$files
else
i=0
for file in $files; do
i=$(expr $i + 1)
echo "$i. $file"
done
printf "please input the correct file no.: "
read n
if [ -z "$n" ]; then
echo "invalid file no."
exit 2
fi
filename=$(echo "$files" | head -n $n | tail -n 1)
fi
INCLUDES=
path=$(dirname $filename)
for d in $(find $path -type d); do
INCLUDES="$INCLUDES -I$d"
done
cd $base_path/src/java/jni
replace_makefile
sed_replace "s#\\\$(INCLUDES)#$INCLUDES#g" Makefile
make $param1 $param2
fi
================================================
FILE: mkdocs.yml
================================================
site_name: FastCFS Docs
site_description: 'FastCFS Documents,Version: v3.2.0'
repo_name: GitHub
repo_url: https://github.com/happyfish100/FastCFS/
plugins:
- search
- mike:
version_selector: true
nav:
- Introduction:
- FastCFS Introduction: "index.md"
- Release Notes: "ReleaseNotes.md"
- Benchmarks: "benchmark.md"
- Concepts:
- Architecture:
- FastDir: "concepts/fastDir.md"
- FastStore: "concepts/fast-store.md"
- FastAuth: "concepts/fastDir.md"
- UserGuide:
- Quickstart: "Easy-install-detail-zh_CN.md"
- Install: "INSTALL.md"
markdown_extensions:
- toc:
permalink: True
- footnotes
- tables
- meta # 定义元数据,通过文章上下文控制,如disqus
- pymdownx.caret # 下划线上标
- pymdownx.tilde # 删除线下标
- pymdownx.critic # 增加删除修改高亮注释,可修饰行内或段落
- pymdownx.details # 提示块可折叠
- pymdownx.inlinehilite # 行内代码高亮
- pymdownx.mark # 文本高亮
- pymdownx.smartsymbols # 符号转换
- pymdownx.superfences # 代码嵌套在列表里
- codehilite: # 代码高亮,显示行号
guess_lang: false
linenums: true
- pymdownx.tasklist: # 复选框checklist
custom_checkbox: true
theme:
name: material
logo: img/logo.png
favicon: img/logo.png
palette:
- scheme: default
toggle:
icon: material/toggle-switch-off-outline
name: Switch to dark mode
- scheme: slate
primary: deep orange
accent: deep orange
toggle:
icon: material/toggle-switch
name: Switch to light mode
extra:
version:
provider: mike
alternate:
- name: English
link: /
lang: en
- name: 中文
link: /zh/
lang: zh
================================================
FILE: shell/Dockerfile
================================================
FROM nginx:mainline-alpine
# COPY dependency.2.0.1.settings /usr/share/nginx/html/
COPY conf.2.3.0.tpl.tar.gz /usr/share/nginx/html/
================================================
FILE: shell/conf_tpl_tar.sh
================================================
#!/bin/bash
#
# conf_tpl_tar.sh is a tool for quickly pack FastCFS cluster config files to template tar.
# this is for FastCFS developer.
#
BUILD_PATH="build"
FDIR_LIB="fastDIR"
STORE_LIB="faststore"
shell_name=$0
conf_file_version=$1
update_sources=$2
#---Usage info section begin---#
print_usage() {
# Print usage to console.
echo ""
echo "Usage: $shell_name [update]"
echo ""
echo "A self-sufficient config file templates pack shell for FastCFS cluster"
echo ""
echo "version:"
echo " Version of the tar file, exp: 3.4.0."
echo " Tar file example: conf.3.4.0.tpl.tar.gz"
echo ""
echo "update: Pull source code from remote before execute tar command."
echo ""
}
if [ -z $conf_file_version ]; then
print_usage
exit 1
fi
#---Usage info section end---#
pull_source_code() {
local module_name=$1
local source_path=$2
if ! [ -d $source_path ]; then
echo "ERROR: source code path {$source_path} for $module_name not exist."
exit 1
fi
cd $source_path
echo "INFO: =====Begin to pull $module_name, it will take some time...====="
git checkout master
git pull
cd -
}
pull_source_codes() {
# Update source code from github.com.
echo "INFO: Begin to pull source codes..."
# Pull fastCFS self.
pull_source_code "FastCFS" ../
# Pull fastDIR
pull_source_code fastDIR ../../fastDIR
# Pull faststore
pull_source_code faststore ../../faststore
}
if [ "$update_sources" = "update" ]; then
pull_source_codes
fi
config_file_template_path="conf.$conf_file_version.tpl"
config_file_template_tar="$config_file_template_path.tar.gz"
# Create build path if not exists.
if ! [ -d $config_file_template_path ]; then
mkdir -m 775 $config_file_template_path
echo "INFO: temp tpl path {$config_file_template_path} not exist, created."
else
rm -rf "$config_file_template_path/auth"
rm -rf "$config_file_template_path/fcfs"
rm -rf "$config_file_template_path/fdir"
rm -rf "$config_file_template_path/fstore"
rm -rf "$config_file_template_path/vote"
fi
# Copy config files from source to temp tpl path
mkdir -p "$config_file_template_path/auth/keys"
mkdir "$config_file_template_path/fcfs"
mkdir "$config_file_template_path/fdir"
mkdir "$config_file_template_path/fstore"
mkdir "$config_file_template_path/vote"
`cp ../src/auth/conf/keys/*.key $config_file_template_path/auth/keys/`
`cp ../src/auth/conf/*.conf $config_file_template_path/auth/`
`cp ../src/vote/conf/*.conf $config_file_template_path/vote/`
`cp ../conf/*.conf $config_file_template_path/fcfs/`
`cp ../../fastDIR/conf/*.conf $config_file_template_path/fdir/`
`cp ../../faststore/conf/*.conf $config_file_template_path/fstore/`
`tar -czvf $config_file_template_tar $config_file_template_path`
exit 0
================================================
FILE: shell/fcfs.settings
================================================
# FastCFS cluster ops settings be used with shell fcfs.sh
# This settings file must be placed at same path with fcfs.sh
# You can edit it, or download it from http://www.fastcfs.com/ops.
fastcfs_version=5.3.0
fuseclient_ips=192.168.142.9
================================================
FILE: shell/fcfs.sh
================================================
#!/bin/bash
#
# fcfs.sh is a ops tool for quickly deploy FastCFS clusters.
# It only relying on SSH access to the servers and sudo.
# It runs fully on your workstation, requiring no servers, databases, or anything like that.
#
# If you set up and tear down FastCFS clusters a lot, and want minimal extra repeating works,
# this is for you.
#
#---1. Config path section begin---#
declare -ir MIN_VERSION_OF_Ubuntu=18
declare -ir MIN_VERSION_OF_Debian=10
declare -ir MIN_VERSION_OF_Deepin=20
declare -ir MIN_VERSION_OF_CentOS=7
declare -ir MIN_VERSION_OF_Red=8
declare -ir MIN_VERSION_OF_Rocky=8
declare -ir MIN_VERSION_OF_Oracle=8
declare -ir MIN_VERSION_OF_Fedora=20
declare -ir MIN_VERSION_OF_AlmaLinux=7
declare -ir MIN_VERSION_OF_Alibaba=2
declare -ir MIN_VERSION_OF_Anolis=7
declare -ir MIN_VERSION_OF_Amazon=2
declare -ir MIN_VERSION_OF_openEuler=20
declare -ir MIN_VERSION_OF_UOS=20
declare -ir MIN_VERSION_OF_BigCLoud=21
YUM_OS_ARRAY=(Red Rocky Oracle Fedora CentOS AlmaLinux Alibaba Anolis Amazon openEuler Kylin UOS BigCLoud)
APT_OS_ARRAY=(Ubuntu Debian Deepin)
repo_affix=""
fcfs_settings_file="fcfs.settings"
fcfs_dependency_file_server="http://www.fastken.cn/fastcfs/ops/dependency"
fcfs_cache_path=".fcfs"
fcfs_installed_file="installed.settings"
STORE_CONF_FILES=(client.conf server.conf cluster.conf storage.conf dbstore.conf)
STORE_CONF_PATH="/etc/fastcfs/fstore/"
STORE_LOG_FILE="/opt/fastcfs/fstore/logs/fs_serverd.log"
FDIR_CONF_FILES=(client.conf cluster.conf server.conf dbstore.conf)
FDIR_CONF_PATH="/etc/fastcfs/fdir/"
FDIR_LOG_FILE="/opt/fastcfs/fdir/logs/fdir_serverd.log "
VOTE_CONF_FILES=(client.conf cluster.conf server.conf)
VOTE_CONF_PATH="/etc/fastcfs/vote/"
VOTE_LOG_FILE="/opt/fastcfs/vote/logs/fcfs_voted.log "
AUTH_CONF_FILES=(auth.conf client.conf cluster.conf server.conf session.conf)
AUTH_CONF_PATH="/etc/fastcfs/auth/"
AUTH_KEYS_FILES=(session_validate.key)
AUTH_KEYS_PATH="/etc/fastcfs/auth/keys/"
AUTH_LOG_FILE="/opt/fastcfs/auth/logs/fcfs_authd.log"
FUSE_CONF_FILES=(fuse.conf)
FUSE_CONF_PATH="/etc/fastcfs/fcfs/"
FUSE_LOG_FILE="/opt/fastcfs/fcfs/logs/fcfs_fused.log"
#---1. Config path section end---#
#---2. Get shell and command section begin---#
shell_name=$0
shell_command=$1
local_os_uname=$(uname)
#---2. Get shell and command section end---#
#---3. Usage info section begin---#
print_usage() {
# Print usage to console.
echo ""
echo "Usage: $shell_name [module] [node]"
echo ""
echo "A self-sufficient operation shell for FastCFS cluster"
echo ""
echo "Commands:"
echo " setup Setup FastCFS softwares, a shortcut command combines install, config, and restart"
echo " install Install FastCFS softwares"
echo " reinstall Reinstall FastCFS softwares, only used for yum"
echo " erase Erase FastCFS softwares"
echo " remove Remove FastCFS softwares, same as erase"
echo " config Copy cluster config files to target host path"
echo " start Start all or one module service in cluster"
echo " stop Stop all or one module service in cluster"
echo " restart Restart all or one module service in cluster"
echo " tail Display the last part of the specified module's log"
echo " status Display the service processes status"
echo " help Show the detail of commands and examples"
echo ""
}
print_detail_usage() {
# Print usage to console.
print_usage
echo "Modules:"
echo " fvote FastCFS vote server"
echo " fdir fastDIR server"
echo " fstore faststore server"
echo " fauth FastCFS auth server"
echo " fuseclient FastCFS fuse client"
echo ""
echo "Node:"
echo " You can specify a single cluster IP, or command will be executed on all nodes."
echo ""
echo "Tail command options:"
echo " -n number"
echo " The location is number lines"
echo ""
echo " -number"
echo " The location is number lines"
echo ""
echo "Examples:"
echo " $shell_name setup"
echo " Setup all FastCFS softwares on all nodes, then config and start module services."
echo ""
echo " $shell_name install"
echo " Install all FastCFS softwares on all nodes."
echo ""
echo " $shell_name erase"
echo " Erase all FastCFS softwares on all nodes."
echo ""
echo " $shell_name config fdir 172.16.168.128"
echo " Copy fdir config file to host 172.16.168.128."
echo ""
echo " $shell_name start fdir"
echo " Start all fdir servers."
echo ""
echo " $shell_name start fdir 172.16.168.128"
echo " Start fdir server on host 172.16.168.128."
echo ""
echo " $shell_name tail fdir 172.16.168.128 -n 100"
echo " Display the last 100 lines of fdir server log."
echo ""
echo " $shell_name status"
echo " Display all modules service process status."
echo ""
echo " $shell_name status fdir"
echo " Display all the status of fdir service processes status."
echo ""
echo ""
}
case "$shell_command" in
'setup' | 'install' | 'reinstall' | 'erase' | 'remove' | 'config' | 'start' | 'restart' | 'stop' | 'tail' | 'status')
;;
'help')
print_detail_usage
exit 1
;;
*)
print_usage
exit 1
;;
esac
#---3. Usage info section end---#
#---4. Tool functions section begin---#
sed_replace()
{
local sed_cmd=$1
local file_name=$2
local current_uname=$(uname)
if [ "$current_uname" = "FreeBSD" ] || [ "$current_uname" = "Darwin" ]; then
sed -i "" "$sed_cmd" $file_name
else
sed -i "$sed_cmd" $file_name
fi
}
split_to_array() {
if ! [ -z $2 ]; then
IFS=',' read -ra $2 <<< "$1"
fi
}
# Check preceding version less than or equals following.
function version_le() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" == "$1"; }
# Execute command on a host over SSH
execute_remote_command() {
local remote_host=$1
local remote_command=$2
local result=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 -T $remote_host $remote_command)
echo $result
}
# Execute command on a host over SSH without return
execute_remote_command_no_return() {
local remote_host=$1
local remote_command=$2
ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 -T $remote_host $remote_command
}
# Get remote server's uname
get_remote_uname() {
local remote_host=$1
local remote_uname=$(execute_remote_command $remote_host "uname")
echo $remote_uname
}
# Get remote server's os name
get_remote_osname() {
local remote_host=$1
local osname_command='cat /etc/os-release
| grep -w NAME
| awk -F '\''='\'' '\''{print $2;}'\''
| awk -F '\''"'\'' '\''{if (NF==3) {print $2} else {print $1}}'\''
| awk '\''{print $1}'\'''
local remote_osname=$(execute_remote_command $remote_host "$osname_command")
echo "$remote_osname"
}
# Get remote Ubuntu server's version
get_os_version() {
local remote_host=$1
local os_version_command='cat /etc/os-release
| grep -w VERSION_ID
| awk -F '\''='\'' '\''{print $2;}'\''
| awk -F '\''"'\'' '\''{if (NF==3) {print $2} else {print $1}}'\'''
local remote_os_version=$(execute_remote_command $remote_host "$os_version_command")
echo "$remote_os_version"
}
# Get remote CentOS server's version
get_centos_version() {
local remote_host=$1
local centos_version_command='cat /etc/system-release | awk '\''{print $4}'\'''
local remote_centos_version=$(execute_remote_command $remote_host "$centos_version_command")
echo "$remote_centos_version"
}
#---4. Tool functions section end---#
#---5. Parse cluster servers section begin---#
INT_REGEXP='^[0-9]+$'
RANGE_REGEXP='^\[[0-9]*, *[0-9]*\]$'
parse_value_in_section() {
local conf_file=$1
local section_name=$2
local field_name=$3
local value=$(\
sed -n "/^\\[$section_name\\]/,/^\[/ p" $conf_file | \
sed -n "/^$field_name *=/ p" | \
sed 's/\([^=]*\)=\([^=]\)/\2/g' | \
sed 's/ *^//g' | sed 's/ *$//g')
echo $value
}
parse_fstore_servers() {
local conf_file=$1
if ! [ -f $conf_file ]; then
echo "ERROR: fstore cluster config file $conf_file does not exist."
exit 1
fi
local server_groups=`sed -n '/^\[server-group/ p' $conf_file | sed 's/\[//' | sed 's/\]//'`
for server_group in ${server_groups[@]}; do
let fstore_group_count=$fstore_group_count+1
local fstore_server_hosts=""
local server_ids=$(parse_value_in_section $conf_file $server_group "server_ids")
# echo "server_ids in $server_group is:==$server_ids=="
if [[ $server_ids =~ $INT_REGEXP ]]; then
#单个整数,只有一个节点
# echo "$server_ids is integer"
local server_host=$(parse_value_in_section $conf_file "server-$server_ids" "host")
server_host=${server_host%%:*}
if [ -n server_host ]; then
fstore_server_hosts=$server_host
fi
elif [[ $server_ids =~ $RANGE_REGEXP ]]; then
# echo "[$server_ids] is range"
local src_str=`echo $server_ids | sed 's/\[//' | sed 's/\]//' | sed 's/, */../'`
local dest="echo {$src_str}"
for server_id in $(eval $dest); do
local server_host=$(parse_value_in_section $conf_file "server-$server_id" "host")
server_host=${server_host%%:*}
if [ -n server_host ]; then
fstore_server_hosts="$fstore_server_hosts $server_host"
fi
done
else
echo "ERROR: Invalid server_ids format:[$server_ids] in config file $conf_file"
exit 1
fi
fstore_server_hosts=`echo $fstore_server_hosts | sed 's/ *^//g'`
if [[ -n $fstore_server_hosts ]]; then
local array_str="fstore_group_$fstore_group_count=($fstore_server_hosts)"
eval $array_str
else
echo "ERROR: Parse fstore server hosts failed, $conf_file must conform to format below:"
echo " [server-group-1]"
echo " server_ids = [1, 3]"
echo " # Or server_ids = 1"
echo " [server-1]"
echo " host = 10.0.1.11"
exit 1
fi
done
}
parse_fdir_servers() {
local conf_file=$1
if ! [ -f $conf_file ]; then
echo "ERROR: fdir cluster config file $conf_file does not exist."
exit 1
fi
local fdir_servers=`sed -n '/^\[server-/ p' $conf_file | sed 's/\[//' | sed 's/\]//'`
local fdir_server_hosts=""
for fdir_server in ${fdir_servers[@]}; do
local server_host=$(parse_value_in_section $conf_file $fdir_server "host")
server_host=${server_host%%:*}
if [ -n server_host ]; then
fdir_server_hosts="$fdir_server_hosts $server_host"
fi
done
fdir_server_hosts=`echo $fdir_server_hosts | sed 's/ *^//g'`
if [[ -n $fdir_server_hosts ]]; then
local array_str="fdir_group=($fdir_server_hosts)"
eval $array_str
else
echo "ERROR: Parse fdir server hosts failed, $conf_file must conform to format below:"
echo " [server-1]"
echo " host = 10.0.1.11"
echo " ..."
exit 1
fi
}
parse_fauth_servers() {
local conf_file=$1
if ! [ -f $conf_file ]; then
echo "ERROR: fauth cluster config file $conf_file does not exist."
exit 1
fi
local fauth_servers=`sed -n '/^\[server-/ p' $conf_file | sed 's/\[//' | sed 's/\]//'`
local fauth_server_hosts=""
for fauth_server in ${fauth_servers[@]}; do
local server_host=$(parse_value_in_section $conf_file $fauth_server "host")
server_host=${server_host%%:*}
if [ -n server_host ]; then
fauth_server_hosts="$fauth_server_hosts $server_host"
fi
done
fauth_server_hosts=`echo $fauth_server_hosts | sed 's/ *^//g'`
if [[ -n $fauth_server_hosts ]]; then
local array_str="fauth_group=($fauth_server_hosts)"
eval $array_str
else
echo "ERROR: Parse fauth server hosts failed, $conf_file must conform to format below:"
echo " [server-1]"
echo " host = 10.0.1.11"
echo " ..."
exit 1
fi
}
parse_fvote_servers() {
local conf_file=$1
if ! [ -f $conf_file ]; then
echo "ERROR: fvote cluster config file $conf_file does not exist."
exit 1
fi
local fvote_servers=`sed -n '/^\[server-/ p' $conf_file | sed 's/\[//' | sed 's/\]//'`
local fvote_server_hosts=""
for fvote_server in ${fvote_servers[@]}; do
local server_host=$(parse_value_in_section $conf_file $fvote_server "host")
server_host=${server_host%%:*}
if [ -n server_host ]; then
fvote_server_hosts="$fvote_server_hosts $server_host"
fi
done
fvote_server_hosts=`echo $fvote_server_hosts | sed 's/ *^//g'`
if [[ -n $fvote_server_hosts ]]; then
local array_str="fvote_group=($fvote_server_hosts)"
eval $array_str
else
echo "ERROR: Parse fvote server hosts failed, $conf_file must conform to format below:"
echo " [server-1]"
echo " host = 10.0.1.11"
echo " ..."
exit 1
fi
}
#---5. Parse cluster servers section end---#
#---6. Settings and cluster info section begin---#
check_fcfs_cache_path() {
if ! [ -d $fcfs_cache_path ]; then
if ! mkdir -p $fcfs_cache_path; then
echo "ERROR: Create fcfs cache path failed, $fcfs_cache_path!"
exit 1
else
echo "INFO: Created fcfs cache path successfully, $fcfs_cache_path."
fi
fi
}
# Load cluster settings from file fcfs.settings
load_fcfs_settings() {
if ! [ -f $fcfs_settings_file ]; then
echo "ERROR: File $fcfs_settings_file does not exist"
exit 1
else
fcfs_settings=`sed -e 's/#.*//' -e '/^$/ d' $fcfs_settings_file`
eval $fcfs_settings
split_to_array $fuseclient_ips fuseclient_ip_array
if [ -z $fastcfs_version ]; then
echo "ERROR: param fastcfs_version has no value in $fcfs_settings_file"
exit 1
fi
if [ -z $fuseclient_ips ]; then
echo "ERROR: param fuseclient_ips has no value in $fcfs_settings_file"
exit 1
fi
fi
}
# Load installed settings from file .fcfs/installed.settings
load_installed_settings() {
local installed_mark_file=$fcfs_cache_path/$fcfs_installed_file
if [ -f $installed_mark_file ]; then
local installed_marks=`sed -e 's/#.*//' -e '/^$/ d' $installed_mark_file`
eval $installed_marks
fi
}
# Load cluster dependent lib version settings from file dependency.[FastCFS-version].settings
load_dependency_settings() {
dependency_file_version=$1
if [ -z $dependency_file_version ]; then
echo "ERROR: Dependency file version cannot be empty."
exit 1
fi
dependency_settings_file="$fcfs_cache_path/dependency.$dependency_file_version.settings"
if ! [ -f $dependency_settings_file ]; then
# File not exist in local path, will get it from remote server match the version
echo "WARN: File $dependency_settings_file does not exist, getting it from remote server $fcfs_dependency_file_server."
check_fcfs_cache_path
remote_file_url="$fcfs_dependency_file_server/$dependency_file_version"
download_res=`curl -f -o $dependency_settings_file $remote_file_url`
if ! [ -f $dependency_settings_file ]; then
echo "ERROR: Cannot download file $dependency_settings_file from $remote_file_url."
echo " Please make sure that remote file exists and network is accessible."
exit 1
fi
fi
dependency_settings=`sed -e 's/#.*//' -e '/^$/ d' $dependency_settings_file`
eval $dependency_settings
if [ -z $libfastcommon ]; then
echo "WARN: Dependency libfastcommon has no version value in $dependency_settings_file."
fi
if [ -z $libserverframe ]; then
echo "WARN: Dependency libserverframe has no version value in $dependency_settings_file."
fi
if [ -z $fvote ]; then
echo "WARN: Dependency fvote has no version value in $dependency_settings_file."
fi
if [ -z $fauth ]; then
echo "WARN: Dependency fauth has no version value in $dependency_settings_file."
fi
if [ -z $fdir ]; then
echo "WARN: Dependency fdir has no version value in $dependency_settings_file."
fi
if [ -z $fstore ]; then
echo "WARN: Dependency fstore has no version value in $dependency_settings_file."
fi
}
# Get module name from command args, if not specify, will handle all modules.
fdir_need_execute=0
fstore_need_execute=0
fauth_need_execute=0
fvote_need_execute=0
fuseclient_need_execute=0
has_module_param=1
check_module_param() {
if [ $# -gt 1 ]; then
module_name=$2
case "$module_name" in
'fdir')
fdir_need_execute=1
;;
'fstore')
fstore_need_execute=1
;;
'fauth')
fauth_need_execute=1
;;
'fvote')
fvote_need_execute=1
;;
'fuseclient')
fuseclient_need_execute=1
;;
*)
has_module_param=0
if ! [ $shell_command = 'tail' ] || ! [[ $module_name =~ ^- ]]; then
echo "ERROR: Module name invalid, $module_name."
echo " Allowed module names: fdir, fstore, fauth, fvote, fuseclient."
exit 1
else
fdir_need_execute=1
fstore_need_execute=1
fauth_need_execute=1
fvote_need_execute=1
fuseclient_need_execute=1
fi
;;
esac
else
has_module_param=0
fdir_need_execute=1
fstore_need_execute=1
fauth_need_execute=1
fvote_need_execute=1
fuseclient_need_execute=1
fi
}
# Get node host from command args, if not specify, will handle all nodes.
# It must specify after module name.
has_node_param=0
check_node_param() {
if [ $# -gt 2 ] && ! [[ $3 =~ ^- ]] && [ $has_module_param = 1 ]; then
node_host_need_execute=$3
has_node_param=1
fi
}
# Load cluster groups from cluster config files.
# fdir_group=(172.16.168.128)
# fstore_group_count=1
# fstore_group_1=(172.16.168.128)
# fauth_group=(172.16.168.128)
load_cluster_groups() {
if [ $fdir_need_execute -eq 1 ]; then
parse_fdir_servers "conf/fdir/cluster.conf"
fi
if [ $fstore_need_execute -eq 1 ]; then
parse_fstore_servers "conf/fstore/cluster.conf"
fi
if [ $fauth_need_execute -eq 1 ]; then
parse_fauth_servers "conf/auth/cluster.conf"
fi
if [ $fvote_need_execute -eq 1 ]; then
parse_fvote_servers "conf/vote/cluster.conf"
fi
}
replace_cluster_osname_mark() {
local mark_file=$1
local remote_osname=$2
sed_replace "s#^cluster_host_osname=.*#cluster_host_osname=$remote_osname#g" $mark_file
}
save_cluster_osname_mark() {
check_fcfs_cache_path
local remote_osname=$1
local installed_mark_file=$fcfs_cache_path/$fcfs_installed_file
if [ -f $installed_mark_file ]; then
local cluster_osname_marks=`grep cluster_host_osname $installed_mark_file`
if [ -z $cluster_osname_marks ]; then
echo "cluster_host_osname=$remote_osname" >> $installed_mark_file
else
# replace old value
replace_cluster_osname_mark $installed_mark_file "$remote_osname"
fi
else
echo "cluster_host_osname=$remote_osname" >> $installed_mark_file
fi
}
# Check remote host os and version.
# The whole cluster's host must have same os type.
# The hosts os version must great than or equal xxx_MIN_VERSION
check_remote_os_and_version() {
pkg_manage_tool=""
cluster_host_osname=""
declare -a all_server_ips
all_server_ips+=(${fdir_group[@]})
if [ ! -z $fstore_group_count ]; then
for ((i=1; i <= $fstore_group_count; i++)); do
local fstore_group="fstore_group_$i[@]"
all_server_ips+=(${!fstore_group})
done
fi
all_server_ips+=(${fauth_group[@]})
all_server_ips+=(${fvote_group[@]})
all_server_ips+=(${fuseclient_ip_array[@]})
declare -a distinct_server_ips
for server_ip in ${all_server_ips[@]}; do
if ! [[ ${distinct_server_ips[*]} =~ (^|[[:space:]])"$server_ip"($|[[:space:]]) ]]; then
distinct_server_ips+=("$server_ip")
echo "INFO: Begin check os name and version on server $server_ip"
local remote_uname=$(get_remote_uname $server_ip)
if [ $remote_uname = 'Linux' ]; then
local remote_osname=$(get_remote_osname $server_ip)
if [ "$cluster_host_osname" != '' ]; then
if [ "$cluster_host_osname" != "$remote_osname" ]; then
echo "Error: Cluster's servers must have same OS, $cluster_host_osname and $remote_osname cannot be mixed use"
exit 1
fi
else
cluster_host_osname=$remote_osname
if [[ " ${YUM_OS_ARRAY[@]} " =~ " ${remote_osname} " ]]; then
pkg_manage_tool="yum"
elif [[ " ${APT_OS_ARRAY[@]} " =~ " ${remote_osname} " ]]; then
pkg_manage_tool="apt"
fi
fi
local remote_osversion
if [ $remote_osname = 'CentOS' ]; then
remote_osversion=$(get_centos_version $server_ip)
elif [[ " ${YUM_OS_ARRAY[@]} " =~ " ${remote_osname} " ]] || [[ " ${APT_OS_ARRAY[@]} " =~ " ${remote_osname} " ]]; then
remote_osversion=$(get_os_version $server_ip)
else
echo "Error: Unsupport OS, $remote_osname on server $server_ip"
exit 1
fi
declare -i remote_os_major_version=$(echo $remote_osversion | awk -F '.' '{print $1}')
local min_version_name="MIN_VERSION_OF_$remote_osname"
local min_version=${!min_version_name}
if [ ! -z $min_version ] && [ $remote_os_major_version -lt $min_version ]; then
echo "$remote_osname's version must be great than or equal $min_version, but was $remote_os_major_version on server $server_ip"
exit 1
fi
else
echo "ERROR: Unsupport OS, $remote_uname on server $server_ip"
exit 1
fi
fi
done
if [ "$cluster_host_osname" != '' ]; then
save_cluster_osname_mark "$cluster_host_osname"
else
echo "ERROR: Check remote host os failed."
exit 1
fi
}
fuseclient_share_fdir=0
fuseclient_share_fstore=0
fuseclient_share_fauth=0
fuseclient_share_fvote=0
check_if_client_share_servers() {
if ! [ ${#fuseclient_ip_array[@]} -eq 0 ]; then
for fuseclient_server_ip in ${fuseclient_ip_array[@]}; do
for fdir_server_ip in ${fdir_group[@]}; do
if [ $fdir_server_ip = "$fuseclient_server_ip" ]; then
fuseclient_share_fdir=1
fi
done
if [ ! -z $fstore_group_count ]; then
for ((i=1; i <= $fstore_group_count; i++)); do
local fstore_group="fstore_group_$i[@]"
for fstore_server_ip in ${!fstore_group}; do
if [ $fstore_server_ip = "$fuseclient_server_ip" ]; then
fuseclient_share_fstore=1
fi
done
done
fi
for fauth_server_ip in ${fauth_group[@]}; do
if [ $fauth_server_ip = "$fuseclient_server_ip" ]; then
fuseclient_share_fauth=1
fi
done
for fvote_server_ip in ${fvote_group[@]}; do
if [ $fvote_server_ip = "$fuseclient_server_ip" ]; then
fuseclient_share_fvote=1
fi
done
done
fi
}
#---6. Settings and cluster info section end---#
#---7. Iterate hosts for execute command section begin---#
execute_command_on_fdir_servers() {
local command_name=$1
local function_name=$2
local module_name=$3
if [ $fdir_need_execute -eq 1 ]; then
local fdir_node_match_setting=0
for fdir_server_ip in ${fdir_group[@]}; do
if [ -z $node_host_need_execute ] || [ $fdir_server_ip = "$node_host_need_execute" ]; then
if [ $command_name = 'status' ]; then
echo ""
echo "INFO: Begin display $module_name status on server $fdir_server_ip."
else
echo "INFO: Begin $command_name $module_name on server $fdir_server_ip."
fi
$function_name $fdir_server_ip "$module_name" $command_name
fi
if [ $fdir_server_ip = "$node_host_need_execute" ]; then
fdir_node_match_setting=1
fi
done
if ! [ -z $node_host_need_execute ] && [ $fdir_node_match_setting -eq 0 ]; then
echo "ERROR: The node $node_host_need_execute not match host in fdir cluster.conf."
fi
fi
}
execute_command_on_fstore_servers() {
local command_name=$1
local function_name=$2
local module_name=$3
if [ $fstore_need_execute -eq 1 ]; then
local fstore_node_match_setting=0
for ((i=1; i <= $fstore_group_count; i++)); do
local fstore_group="fstore_group_$i[@]"
for fstore_server_ip in ${!fstore_group}; do
if [ -z $node_host_need_execute ] || [ $fstore_server_ip = "$node_host_need_execute" ]; then
if [ $command_name = 'status' ]; then
echo ""
echo "INFO: Begin display $module_name status on server $fstore_server_ip."
else
echo "INFO: Begin $command_name $module_name on server $fstore_server_ip."
fi
$function_name $fstore_server_ip "$module_name" $command_name
fi
if [ $fstore_server_ip = "$node_host_need_execute" ]; then
fstore_node_match_setting=1
fi
done
done
if ! [ -z $node_host_need_execute ] && [ $fstore_node_match_setting -eq 0 ]; then
echo "ERROR: The node $node_host_need_execute not match host in fstore cluster.conf."
fi
fi
}
execute_command_on_fauth_servers() {
local command_name=$1
local function_name=$2
local module_name=$3
if [ $fauth_need_execute -eq 1 ]; then
local fauth_node_match_setting=0
for fauth_server_ip in ${fauth_group[@]}; do
if [ -z $node_host_need_execute ] || [ $fauth_server_ip = "$node_host_need_execute" ]; then
if [ $command_name = 'status' ]; then
echo ""
echo "INFO: Begin display $module_name status on server $fauth_server_ip."
else
echo "INFO: Begin $command_name $module_name on server $fauth_server_ip."
fi
$function_name $fauth_server_ip "$module_name" $command_name
fi
if [ $fauth_server_ip = "$node_host_need_execute" ]; then
fauth_node_match_setting=1
fi
done
if ! [ -z $node_host_need_execute ] && [ $fauth_node_match_setting -eq 0 ]; then
echo "ERROR: The node $node_host_need_execute not match host in fauth cluster.conf."
fi
fi
}
execute_command_on_fvote_servers() {
local command_name=$1
local function_name=$2
local module_name=$3
if [ $fvote_need_execute -eq 1 ]; then
local fvote_node_match_setting=0
for fvote_server_ip in ${fvote_group[@]}; do
if [ -z $node_host_need_execute ] || [ $fvote_server_ip = "$node_host_need_execute" ]; then
if [ $command_name = 'status' ]; then
echo ""
echo "INFO: Begin display $module_name status on server $fvote_server_ip."
else
echo "INFO: Begin $command_name $module_name on server $fvote_server_ip."
fi
$function_name $fvote_server_ip "$module_name" $command_name
fi
if [ $fvote_server_ip = "$node_host_need_execute" ]; then
fvote_node_match_setting=1
fi
done
if ! [ -z $node_host_need_execute ] && [ $fvote_node_match_setting -eq 0 ]; then
echo "ERROR: The node $node_host_need_execute not match host in fvote cluster.conf."
fi
fi
}
execute_command_on_fuseclient_servers() {
local command_name=$1
local function_name=$2
local module_name=$3
if [ $fuseclient_need_execute -eq 1 ]; then
if [ ${#fuseclient_ip_array[@]} -eq 0 ]; then
echo "ERROR: Param fuseclient_ips has no value in $fcfs_settings_file."
exit 1
else
local fuseclient_node_match_setting=0
for fuseclient_server_ip in ${fuseclient_ip_array[@]}; do
if [ -z $node_host_need_execute ] || [ $fuseclient_server_ip = "$node_host_need_execute" ]; then
if [ $command_name = 'status' ]; then
echo ""
echo "INFO: Begin display $module_name status on server $fuseclient_server_ip."
else
echo "INFO: begin $command_name $module_name on server $fuseclient_server_ip."
fi
$function_name $fuseclient_server_ip "$module_name" $command_name
fi
if [ $fuseclient_server_ip = "$node_host_need_execute" ]; then
fuseclient_node_match_setting=1
fi
done
if ! [ -z $node_host_need_execute ] && [ $fuseclient_node_match_setting -eq 0 ]; then
echo "ERROR: The node $node_host_need_execute not match param fuseclient_ips in $fcfs_settings_file."
exit 1
fi
fi
fi
}
#---7. Iterate hosts for execute command section end---#
#---8. Install section begin---#
check_remote_osname() {
uname=$(uname)
if [ $uname = 'Linux' ]; then
osname=$(cat /etc/os-release | grep -w NAME | awk -F '=' '{print $2;}' | \
awk -F '"' '{if (NF==3) {print $2} else {print $1}}' | awk '{print $1}')
if [ $osname = 'CentOS' ]; then
osversion=$(cat /etc/system-release | awk '{print $4}')
fi
if [ -z $osversion ]; then
osversion=$(cat /etc/os-release | grep -w VERSION_ID | awk -F '=' '{print $2;}' | \
awk -F '"' '{if (NF==3) {print $2} else {print $1}}')
fi
os_major_version=$(echo $osversion | awk -F '.' '{print $1}')
if [ $osname = 'Fedora' ]; then
if [ $os_major_version -lt 20 ]; then
os_major_version=6
elif [ $os_major_version -lt 28 ]; then
os_major_version=7
elif [ $os_major_version -lt 38 ]; then
os_major_version=8
else
os_major_version=9
fi
elif [ $osname = 'Alibaba' ]; then
if [ $os_major_version -lt 3 ]; then
os_major_version=7
elif [ $os_major_version -lt 4 ]; then
os_major_version=8
else
os_major_version=9
fi
elif [ $osname = 'Amazon' ]; then
if [ $os_major_version -lt 3 ]; then
os_major_version=7
elif [ $os_major_version -lt 2023 ]; then
os_major_version=8
else
os_major_version=9
fi
elif [ $osname = 'openEuler' ]; then
if [ $os_major_version -lt 24 ]; then
os_major_version=8
else
os_major_version=9
fi
elif [ $osname = 'Kylin' ]; then
os_major_version=$(echo $os_major_version | awk '{print $1}')
if [ $os_major_version = 'V10' ]; then
os_major_version=8
else
os_major_version=9
fi
elif [ $osname = 'UOS' ] || [ $osname = 'BigCLoud' ]; then
os_major_version=8
fi
else
echo "Error: Unsupport OS, $uname" 1>&2
exit 1
fi
}
check_yum_install_fastos_repo() {
repo=$(rpm -q FastOSrepo 2>/dev/null)
if [ $? -ne 0 ]; then
sudo rpm -ivh http://www.fastken.cn/yumrepo${repo_affix}/el${os_major_version}/noarch/FastOSrepo-1.0.1-1.el${os_major_version}.noarch.rpm
if [ $? -ne 0 ]; then
echo "ERROR: FastOSrepo rpm install failed."
exit 1
fi
fi
}
check_apt_install_fastos_repo() {
if [ ! -f /etc/apt/sources.list.d/fastos.list ]; then
sudo apt-get install curl gpg -y
sudo curl http://www.fastken.cn/aptrepo${repo_affix}/packages.fastos.pub | sudo gpg --dearmor > /tmp/fastos-archive-keyring.gpg
sudo install -D -o root -g root -m 644 /tmp/fastos-archive-keyring.gpg /usr/share/keyrings/fastos-archive-keyring.gpg
sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/fastos-archive-keyring.gpg] http://www.fastken.cn/aptrepo${repo_affix}/fastos/ fastos main" > /etc/apt/sources.list.d/fastos.list'
sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/fastos-archive-keyring.gpg] http://www.fastken.cn/aptrepo${repo_affix}/fastos-debug/ fastos-debug main" > /etc/apt/sources.list.d/fastos-debug.list'
sudo rm -f /tmp/fastos-archive-keyring.gpg
fi
}
execute_yum() {
local yum_command=$1
local program_name=$2
repo_affix=$3
if [ $os_major_version -ge 7 ]; then
check_yum_install_fastos_repo
echo "INFO: yum $yum_command $program_name -y."
sudo yum $yum_command $program_name -y
if [ $? -ne 0 ]; then
echo "ERROR: \"yum $yum_command $program_name -y\" execute failed."
exit 1
fi
else
echo "ERROR: Unsupport OS, $uname" 1>&2
echo " Command setup and install can only be used for CentOS 7 or higher."
exit 1
fi
}
execute_apt() {
local apt_command=$1
local program_name=$2
repo_affix=$3
if [ $apt_command = 'install' ]; then
check_apt_install_fastos_repo
sudo apt-get update
fi
echo "INFO: apt $apt_command $program_name -y."
sudo apt-get $apt_command $program_name -y
if [ $? -ne 0 ]; then
echo "ERROR: \"apt $apt_command $program_name -y\" execute failed."
exit 1
fi
}
execute_yum_on_remote() {
local remote_host=$1
local program_name=$2
local yum_command=$3
execute_remote_command_no_return $remote_host "
$(declare -f check_remote_osname);
check_remote_osname;
$(declare -f check_yum_install_fastos_repo);
$(declare -f execute_yum);
execute_yum $yum_command \"$program_name\" \"$repo_affix\""
if [ $? -ne 0 ]; then
exit 1
fi
}
execute_apt_on_remote() {
local remote_host=$1
local program_name=$2
local apt_command=$3
execute_remote_command_no_return $remote_host "
$(declare -f check_apt_install_fastos_repo);
$(declare -f execute_apt);
execute_apt $apt_command \"$program_name\" \"$repo_affix\""
if [ $? -ne 0 ]; then
exit 1
fi
}
replace_installed_version_mark() {
# Replace host with ip of current host.
local mark_file=$1
local installed_version=$2
sed_replace "s#^fastcfs_version_installed=.*#fastcfs_version_installed=$installed_version#g" $mark_file
}
save_installed_version_mark() {
check_fcfs_cache_path
local installed_mark_file=$fcfs_cache_path/$fcfs_installed_file
if [ -f $installed_mark_file ]; then
local installed_marks=`grep fastcfs_version_installed $installed_mark_file`
if [ -z $installed_marks ]; then
echo "fastcfs_version_installed=$fastcfs_version" >> $installed_mark_file
else
# replace old value
replace_installed_version_mark $installed_mark_file "$fastcfs_version"
fi
else
echo "fastcfs_version_installed=$fastcfs_version" >> $installed_mark_file
fi
}
remove_installed_mark() {
local installed_mark_file=$fcfs_cache_path/$fcfs_installed_file
if [ -f $installed_mark_file ]; then
if ! rm -rf $installed_mark_file; then
echo "ERROR: Delete installed mark file failed, $installed_mark_file!"
exit 1
fi
fi
}
save_installed_mark() {
check_fcfs_cache_path
local installed_mark_file=$fcfs_cache_path/$fcfs_installed_file
if [ -f $installed_mark_file ]; then
local installed_marks=`grep fastcfs_installed $installed_mark_file`
if [ -z $installed_marks ]; then
echo "fastcfs_installed=1" >> $installed_mark_file
fi
else
echo "fastcfs_installed=1" >> $installed_mark_file
fi
}
check_installed_version() {
# First install cannot specify module
if [ -z $fastcfs_version_installed ] && [ $has_module_param = 1 ]; then
echo "ERROR: First execute setup or install cannot specify module."
exit 1
elif ! [ -z $fastcfs_version_installed ] && [ $fastcfs_version_installed = $fastcfs_version ]; then
if [ "$shell_command" = "reinstall" ]; then
# Before reinstall programm, need user to reconfirm
for ((;;)) do
echo -n "WARN: Reinstall the installed program confirm[y/N]"
read var
if ! [ "$var" = "y" ] && ! [ "$var" = "Y" ] && ! [ "$var" = "yes" ] && ! [ "$var" = "YES" ]; then
exit 1
fi
break;
done
else
if ! [ $has_module_param = 1 -a $has_node_param = 1 ]; then
echo "ERROR: FastCFS $fastcfs_version have installed."
exit 1
fi
fi
elif ! [ -z $fastcfs_version_installed ] && ! [ $fastcfs_version_installed = $fastcfs_version ]; then
if version_le $fastcfs_version_installed $fastcfs_version; then
# Upgrade cannot specify module
if [ $has_module_param = 1 ]; then
echo "ERROR: Upgrade cannot specify module."
exit 1
fi
for ((;;)) do
echo -n "WARN: Upgrade installed program confirm, from $fastcfs_version_installed to $fastcfs_version ? [y/N]"
read var
if ! [ "$var" = "y" ] && ! [ "$var" = "Y" ] && ! [ "$var" = "yes" ] && ! [ "$var" = "YES" ]; then
exit 1
fi
break;
done
else
# Downgrade must remove old version first
echo "ERROR: Downgrade install must remove old version first."
exit 1
fi
fi
}
# Install packages to target by yum manage nodes.
install_packages_by_yum() {
check_installed_version
fdir_programs="fastDIR-server-$fdir libfastcommon-$libfastcommon libserverframe-$libserverframe FastCFS-auth-client-$fauth"
execute_command_on_fdir_servers install execute_yum_on_remote "$fdir_programs"
fstore_programs="faststore-server-$fstore libfastcommon-$libfastcommon libserverframe-$libserverframe FastCFS-auth-client-$fauth"
execute_command_on_fstore_servers install execute_yum_on_remote "$fstore_programs"
fauth_programs="FastCFS-auth-server-$fauth libfastcommon-$libfastcommon libserverframe-$libserverframe FastCFS-auth-client-$fauth fastDIR-client-$fdir"
execute_command_on_fauth_servers install execute_yum_on_remote "$fauth_programs"
fvote_programs="FastCFS-vote-server-$fvote libfastcommon-$libfastcommon libserverframe-$libserverframe FastCFS-vote-client-$fvote"
execute_command_on_fvote_servers install execute_yum_on_remote "$fvote_programs"
fuseclient_programs="FastCFS-fused-$fuseclient libfastcommon-$libfastcommon libserverframe-$libserverframe FastCFS-auth-client-$fauth FastCFS-api-libs-$fcfsapi faststore-client-$fstore fastDIR-client-$fdir"
execute_command_on_fuseclient_servers install execute_yum_on_remote "$fuseclient_programs"
save_installed_mark
save_installed_version_mark
}
# Remove packages from target by yum manage nodes.
erase_packages_by_yum() {
# Before remove programm, need user to reconfirm
for ((;;)) do
echo -n "WARN: Delete the installed program confirm[y/N]"
read var
if ! [ "$var" = "y" ] && ! [ "$var" = "Y" ] && ! [ "$var" = "yes" ] && ! [ "$var" = "YES" ]; then
exit 1
fi
break;
done
fdir_programs="fastDIR-server libfastcommon libserverframe FastCFS-auth-client FastOSrepo"
execute_command_on_fdir_servers erase execute_yum_on_remote "$fdir_programs"
fstore_programs="faststore-server libfastcommon libserverframe FastCFS-auth-client FastOSrepo"
execute_command_on_fstore_servers erase execute_yum_on_remote "$fstore_programs"
fauth_programs="FastCFS-auth-server libfastcommon libserverframe FastCFS-auth-client fastDIR-client FastOSrepo"
execute_command_on_fauth_servers erase execute_yum_on_remote "$fauth_programs"
fvote_programs="FastCFS-vote-server libfastcommon libserverframe FastCFS-vote-client FastOSrepo"
execute_command_on_fvote_servers erase execute_yum_on_remote "$fvote_programs"
fuseclient_programs="FastCFS-fused libfastcommon libserverframe FastCFS-auth-client FastCFS-api-libs faststore-client fastDIR-client FastOSrepo"
execute_command_on_fuseclient_servers erase execute_yum_on_remote "$fuseclient_programs"
remove_installed_mark
}
# Reinstall packages to target by yum manage nodes.
reinstall_packages_by_yum() {
check_installed_version
fdir_programs="fastDIR-server-$fdir libfastcommon-$libfastcommon libserverframe-$libserverframe FastCFS-auth-client-$fauth"
execute_command_on_fdir_servers reinstall execute_yum_on_remote "$fdir_programs"
fstore_programs="faststore-server-$fstore libfastcommon-$libfastcommon libserverframe-$libserverframe FastCFS-auth-client-$fauth"
execute_command_on_fstore_servers reinstall execute_yum_on_remote "$fstore_programs"
fauth_programs="FastCFS-auth-server-$fauth libfastcommon-$libfastcommon libserverframe-$libserverframe FastCFS-auth-client-$fauth fastDIR-client-$fdir"
execute_command_on_fauth_servers reinstall execute_yum_on_remote "$fauth_programs"
fvote_programs="FastCFS-vote-server-$fauth libfastcommon-$libfastcommon libserverframe-$libserverframe FastCFS-vote-client-$fauth"
execute_command_on_fvote_servers reinstall execute_yum_on_remote "$fvote_programs"
fuseclient_programs="FastCFS-fused-$fuseclient libfastcommon-$libfastcommon libserverframe-$libserverframe FastCFS-auth-client-$fauth FastCFS-api-libs-$fcfsapi faststore-client-$fstore fastDIR-client-$fdir"
execute_command_on_fuseclient_servers reinstall execute_yum_on_remote "$fuseclient_programs"
save_installed_mark
save_installed_version_mark
}
# Install packages to target by apt manage nodes.
install_packages_by_apt() {
execute_command_on_fdir_servers install execute_apt_on_remote "fastdir-server"
execute_command_on_fstore_servers install execute_apt_on_remote "faststore-server"
execute_command_on_fauth_servers install execute_apt_on_remote "fastcfs-auth-server"
execute_command_on_fvote_servers install execute_apt_on_remote "fastcfs-vote-server"
execute_command_on_fuseclient_servers install execute_apt_on_remote "fastcfs-fused"
save_installed_mark
}
# Remove packages from target by apt manage nodes.
erase_packages_by_apt() {
# Before remove programm, need user to reconfirm
for ((;;)) do
echo -n "WARN: Delete the installed program confirm[y/N]"
read var
if ! [ "$var" = "y" ] && ! [ "$var" = "Y" ] && ! [ "$var" = "yes" ] && ! [ "$var" = "YES" ]; then
exit 1
fi
break;
done
execute_command_on_fdir_servers remove execute_apt_on_remote "fastdir-server"
execute_command_on_fstore_servers remove execute_apt_on_remote "faststore-server"
execute_command_on_fauth_servers remove execute_apt_on_remote "fastcfs-auth-server"
execute_command_on_fvote_servers remove execute_apt_on_remote "fastcfs-vote-server"
execute_command_on_fuseclient_servers remove execute_apt_on_remote "fastcfs-fused"
remove_installed_mark
}
#---8. Install section end---#
#---9. Config section begin---#
check_remote_path() {
dest_path=$1
if ! [ -d $dest_path ]; then
if ! sudo mkdir -p $dest_path; then
echo "ERROR: Create target conf path failed, $dest_path!"
exit 1
fi
fi
}
check_path_on_remote() {
remote_host=$1
remote_target_path=$2
execute_remote_command_no_return $remote_host "
$(declare -f check_remote_path);
check_remote_path $remote_target_path"
}
check_paths_infile_remote() {
# Check all paths in this config file, if not exist, will create it.
check_conf_file=$1
check_result=`sed -n \
-e '/^mountpoint *=/ p' \
-e '/^base_path *=/ p' \
-e '/^path *=/ p' \
$check_conf_file|sed 's/\([^=]*\)=\([^=]\)/\2/g'`
for check_path in ${check_result[@]}; do
if ! [ -d $check_path ]; then
if ! sudo mkdir -p $check_path; then
echo "ERROR: Create target path in file $check_conf_file failed, $check_path!"
exit 1
else
echo "INFO: Created target path in file $check_conf_file successfully, $check_path."
fi
fi
done
}
check_paths_infile() {
remote_host=$1
remote_target_file=$2$3
execute_remote_command_no_return $remote_host "
$(declare -f check_paths_infile_remote);
check_paths_infile_remote $remote_target_file"
}
copy_config_to_remote() {
local target_server_ip=$1
local target_module=$2
local src_path="conf/$target_module"
local config_files=""
local dest_path=""
case "$target_module" in
'fdir')
config_file_array="${FDIR_CONF_FILES[*]}"
dest_path=$FDIR_CONF_PATH
;;
'fstore')
config_file_array="${STORE_CONF_FILES[*]}"
dest_path=$STORE_CONF_PATH
;;
'fauth')
config_file_array="${AUTH_CONF_FILES[*]}"
src_path="conf/auth"
dest_path=$AUTH_CONF_PATH
;;
'keys')
config_file_array="${AUTH_KEYS_FILES[*]}"
src_path="conf/auth/keys"
dest_path=$AUTH_KEYS_PATH
;;
'fvote')
config_file_array="${VOTE_CONF_FILES[*]}"
src_path="conf/vote"
dest_path=$VOTE_CONF_PATH
;;
'fuseclient')
config_file_array="${FUSE_CONF_FILES[*]}"
src_path="conf/fcfs"
dest_path=$FUSE_CONF_PATH
;;
*)
echo "ERROR: Target module name is invalid, $target_module."
exit 1
;;
esac
check_path_on_remote $target_server_ip $dest_path
for CONF_FILE in ${config_file_array[@]}; do
local tmp_src_file=$src_path/$CONF_FILE
if [ -f $tmp_src_file ]; then
echo "INFO: Copy file $tmp_src_file to $dest_path of server $target_server_ip."
scp $tmp_src_file $target_server_ip:/tmp/
execute_remote_command_no_return $target_server_ip "sudo cp /tmp/$CONF_FILE $dest_path"
execute_remote_command_no_return $target_server_ip "sudo rm /tmp/$CONF_FILE"
if [ $? -ne 0 ]; then
exit 1
fi
local file_extension="${CONF_FILE##*.}"
if [ $file_extension = "conf" ]; then
check_paths_infile $target_server_ip $dest_path $CONF_FILE
fi
else
echo "WARN: File $tmp_src_file does not exist."
fi
done
}
save_configed_mark() {
check_fcfs_cache_path
local installed_mark_file=$fcfs_cache_path/$fcfs_installed_file
if [ -f $installed_mark_file ]; then
local configed_marks=`grep fastcfs_configed $installed_mark_file`
if [ -z $configed_marks ]; then
echo "fastcfs_configed=1" >> $installed_mark_file
fi
else
echo "fastcfs_configed=1" >> $installed_mark_file
fi
}
deploy_config_files() {
if [ -z $fastcfs_configed ] && [ $has_module_param = 1 ]; then
echo "ERROR: First execute config cannot specify module."
exit 1
fi
execute_command_on_fvote_servers config copy_config_to_remote fvote
execute_command_on_fdir_servers config copy_config_to_remote fdir
execute_command_on_fstore_servers config copy_config_to_remote fstore
execute_command_on_fauth_servers config copy_config_to_remote fauth
execute_command_on_fauth_servers config copy_config_to_remote keys
execute_command_on_fuseclient_servers config copy_config_to_remote fuseclient
if [ $fuseclient_share_fvote -eq 0 ]; then
execute_command_on_fuseclient_servers config copy_config_to_remote fvote
fi
if [ $fuseclient_share_fdir -eq 0 ]; then
execute_command_on_fuseclient_servers config copy_config_to_remote fdir
fi
if [ $fuseclient_share_fstore -eq 0 ]; then
execute_command_on_fuseclient_servers config copy_config_to_remote fstore
fi
if [ $fuseclient_share_fauth -eq 0 ]; then
execute_command_on_fuseclient_servers config copy_config_to_remote fauth
execute_command_on_fuseclient_servers config copy_config_to_remote keys
fi
# Save configed mark into installed.settings
save_configed_mark
}
#---9. Config section end---#
#---10. Service op section begin---#
service_op_on_remote() {
service_name=$1
operate_mode=$2
conf_file=$3
sudo $service_name $conf_file $operate_mode
if [ $? -ne 0 ] && [ $operate_mode != "stop" ] && [ $operate_mode != "status" ]; then
echo "ERROR: Service $service_name $operate_mode failed."
exit 1
fi
}
service_op() {
target_server_ip=$1
target_module=$2
operate_mode=$3
case "$target_module" in
'fvote')
service_name="fcfs_voted"
conf_file="${VOTE_CONF_PATH}server.conf"
;;
'fdir')
service_name="fdir_serverd"
conf_file="${FDIR_CONF_PATH}server.conf"
;;
'fstore')
service_name="fs_serverd"
conf_file="${STORE_CONF_PATH}server.conf"
;;
'fauth')
service_name="fcfs_authd"
conf_file="${AUTH_CONF_PATH}server.conf"
;;
'fuseclient')
service_name="fcfs_fused"
conf_file="${FUSE_CONF_PATH}fuse.conf"
;;
*)
echo "ERROR: Target module name is invalid, $target_module."
exit 1
;;
esac
execute_remote_command_no_return $target_server_ip "
$(declare -f service_op_on_remote);
service_op_on_remote $service_name $operate_mode $conf_file"
if [ $? -ne 0 ] && [ $operate_mode != "stop" ]; then
exit 1
fi
}
cluster_service_op() {
operate_mode=$1
execute_command_on_fvote_servers $operate_mode service_op fvote
if [ $operate_mode != 'stop' ] && [ $operate_mode != 'status' ]; then
sleep 1
fi
execute_command_on_fdir_servers $operate_mode service_op fdir
execute_command_on_fstore_servers $operate_mode service_op fstore
if [ $operate_mode != 'stop' ] && [ $operate_mode != 'status' ]; then
sleep 3
fi
execute_command_on_fauth_servers $operate_mode service_op fauth
if [ $operate_mode != 'stop' ] && [ $operate_mode != 'status' ]; then
sleep 1
fi
execute_command_on_fuseclient_servers $operate_mode service_op fuseclient
}
#---10. Service op section end---#
#---11. Tail log section begin---#
tail_remote_log() {
local tail_server=$1
local tail_args=$2
execute_remote_command_no_return $tail_server "tail $tail_args"
echo "========================================================"
echo "========Log boundary===================================="
echo "========================================================"
}
# View last N lines log of the cluster with system command tail;
tail_log() {
shift
if [ $has_module_param = 1 ]; then
shift
if [ $has_node_param = 1 ]; then
shift
fi
fi
local tail_args="$*"
execute_command_on_fdir_servers tail tail_remote_log "$tail_args $FDIR_LOG_FILE"
execute_command_on_fstore_servers tail tail_remote_log "$tail_args $STORE_LOG_FILE"
execute_command_on_fauth_servers tail tail_remote_log "$tail_args $AUTH_LOG_FILE"
execute_command_on_fvote_servers tail tail_remote_log "$tail_args $VOTE_LOG_FILE"
execute_command_on_fuseclient_servers tail tail_remote_log "$tail_args $FUSE_LOG_FILE"
}
#---11. Tail log section end---#
#---12. Command execute section begin---#
check_module_param $*
check_node_param $*
load_fcfs_settings
load_cluster_groups
load_installed_settings
case "$shell_command" in
'setup' | 'install' | 'reinstall')
check_remote_os_and_version
if [[ " ${YUM_OS_ARRAY[@]} " =~ " ${cluster_host_osname} " ]]; then
if [ -z $fastcfs_version ]; then
echo "ERROR: Param fastcfs_version in $fcfs_settings_file cannot be empty."
exit 1
fi
load_dependency_settings $fastcfs_version
fi
;;
'erase' | 'remove')
if [[ " ${YUM_OS_ARRAY[@]} " =~ " ${cluster_host_osname} " ]]; then
pkg_manage_tool="yum"
elif [[ " ${APT_OS_ARRAY[@]} " =~ " ${cluster_host_osname} " ]]; then
pkg_manage_tool="apt"
fi
;;
esac
case "$shell_command" in
'setup' | 'config')
check_if_client_share_servers
;;
esac
if [ -z $fastcfs_installed ]; then
case "$shell_command" in
'reinstall' | 'erase' | 'remove' | 'config' | 'start' | 'restart' | 'stop' | 'tail' | 'status')
echo "ERROR: The FastCFS softwares have not been installed, you must execute setup or install first."
exit 1
;;
esac
fi
if [ -z $fastcfs_configed ]; then
case "$shell_command" in
'start' | 'restart' | 'stop' | 'tail' | 'status')
echo "ERROR: The FastCFS softwares have not been configed, you must execute config first."
exit 1
;;
esac
fi
case "$shell_command" in
'setup')
("install_packages_by_$pkg_manage_tool";deploy_config_files;cluster_service_op restart)
;;
'install')
("install_packages_by_$pkg_manage_tool")
;;
'reinstall')
if [ "$pkg_manage_tool" = "yum" ]; then
("reinstall_packages_by_$pkg_manage_tool")
else
echo "ERROR: The reinstall command can only be used for yum."
exit 1
fi
;;
'erase' | 'remove')
("erase_packages_by_$pkg_manage_tool")
;;
'config')
deploy_config_files
;;
'start')
cluster_service_op start
;;
'restart')
cluster_service_op restart
;;
'stop')
cluster_service_op stop
;;
'tail')
tail_log $*
;;
'status')
cluster_service_op status
;;
*)
print_usage
exit 1
;;
esac
exit 0
#---12. Command execute section end---#
================================================
FILE: shell/fcfs_conf.settings
================================================
# FastCFS cluster ops settings be used with shell fcfs_conf.sh
# This settings file must be placed at same path with fcfs_conf.sh
# You can edit it, or download it from http://www.fastcfs.com/ops.
fastcfs_version=5.3.0
vote_ips=10.0.1.11,10.0.1.12,10.0.1.13
auth_ips=10.0.1.11,10.0.1.12,10.0.1.13
fdir_ips=10.0.1.11,10.0.1.12,10.0.1.13
fstore_group_count=1
fstore_group_1=10.0.1.11,10.0.1.12,10.0.1.13
data_group_count=64
================================================
FILE: shell/fcfs_conf.sh
================================================
#!/bin/bash
#
# fcfs_conf.sh is a ops tool for quickly generate FastCFS cluster config files.
# It only relying on bash shell access to the local fcfs_conf.settings file.
# It runs fully on your workstation, requiring no servers, databases, or anything like that.
#
# If you want to generate cluster config files with specify server ips quickly,
# this is for you.
#
fcfs_settings_file="fcfs_conf.settings"
# fcfs_tpl_file_server="http://www.fastken.cn/fastcfs/ops/dependency"
#conf.2.3.0.tpl.tar.gz
fcfs_tpl_file_server="http://www.fastken.cn/fastcfs/ops/config"
fcfs_cache_path=".fcfs"
LOCAL_CONF_PATH="conf"
STORE_CONF_FILES=(client.conf server.conf cluster.conf storage.conf dbstore.conf)
FDIR_CONF_FILES=(client.conf cluster.conf server.conf dbstore.conf)
AUTH_CONF_FILES=(auth.conf client.conf cluster.conf server.conf session.conf)
AUTH_KEYS_FILES=(session_validate.key)
VOTE_CONF_FILES=(cluster.conf server.conf client.conf)
FUSE_CONF_FILES=(fuse.conf)
TRUNCATE_MARK_LINE="## Important:server group mark, don't modify this line."
shell_name=$0
shell_command=$1
uname=$(uname)
#---Usage info section begin---#
print_usage() {
# Print usage to console.
echo ""
echo "Usage: $shell_name [module]"
echo ""
echo "A self-sufficient config file generator shell for FastCFS cluster"
echo ""
echo "Commands:"
echo " create Create config files for FastCFS cluster with specify ips in $fcfs_settings_file"
echo " help Show the detail of commands and examples"
echo ""
}
print_detail_usage() {
# Print usage to console.
print_usage
echo "Modules:"
echo " fvote FastCFS vote server"
echo " fdir fastDIR server"
echo " fstore faststore server"
echo " fauth FastCFS auth server"
echo " fuseclient FastCFS fuse client"
echo ""
echo "Node:"
echo " You can specify a single module, or command will be executed on modules."
echo ""
echo "Examples:"
echo " $shell_name create"
echo " Create config files for all modules."
echo ""
echo " $shell_name create fdir"
echo " Create config files for fastDIR cluster."
echo ""
echo ""
}
case "$shell_command" in
'create')
;;
'help')
print_detail_usage
exit 1
;;
*)
print_usage
exit 1
;;
esac
#---Usage info section end---#
#---Tool functions begin---#
sed_replace()
{
sed_cmd=$1
filename=$2
if [ "$uname" = "FreeBSD" ] || [ "$uname" = "Darwin" ]; then
sed -i "" "$sed_cmd" $filename
else
sed -i "$sed_cmd" $filename
fi
}
split_to_array() {
if ! [ -z $2 ]; then
IFS=',' read -ra $2 <<< "$1"
fi
}
create_path_not_exist() {
local target_path=$1
if ! [ -d $target_path ]; then
if ! mkdir -p $target_path; then
echo "ERROR: Create path failed, $target_path!"
exit 1
else
echo "INFO: Created path successfully, $target_path."
fi
fi
}
#---Tool functions end---#
#---Settings and cluster info section begin---#
# Load cluster settings from file fcfs_conf.settings
load_fcfs_settings() {
if ! [ -f $fcfs_settings_file ]; then
echo "ERROR: File $fcfs_settings_file does not exist"
exit 1
else
fcfs_settings=`sed -e 's/#.*//' -e '/^$/ d' $fcfs_settings_file`
eval $fcfs_settings
split_to_array $auth_ips auth_ip_array
split_to_array $fdir_ips fdir_ip_array
split_to_array $vote_ips vote_ip_array
split_to_array $fstore_groups fstore_group_array
fi
}
# Check config file templates in local cache path.
check_conf_template() {
conf_file_version=$1
if [ -z $conf_file_version ]; then
echo "ERROR: Config file version cannot be empty."
exit 1
fi
local conf_tpl_dir="conf.$conf_file_version.tpl"
config_file_template_path="$fcfs_cache_path/$conf_tpl_dir"
if ! [ -d $config_file_template_path ]; then
# Template path not exist in local cache path,
# will create it and download templates from remote server match the version
echo "WARN: Template path $config_file_template_path does not exist, getting it from remote server $fcfs_tpl_file_server."
create_path_not_exist $fcfs_cache_path
cd $fcfs_cache_path
local template_tar_file="$conf_tpl_dir.tar.gz"
remote_template_url="$fcfs_tpl_file_server/$template_tar_file"
download_res=`curl -f -o $template_tar_file $remote_template_url`
if ! [ -f $template_tar_file ]; then
echo "ERROR: Cannot download file $template_tar_file from $remote_template_url."
echo " Please make sure that remote template file exists and network is accessible."
exit 1
fi
# 解压模版文件
tar -xzvf $template_tar_file
if ! [ -d $conf_tpl_dir ]; then
echo "ERROR: dir $conf_tpl_dir still not exist after unzip file $template_tar_file."
exit 1
fi
cd -
fi
}
# Get module name from command args, if not specify, will handle all modules.
fvote_need_execute=0
fdir_need_execute=0
fstore_need_execute=0
fauth_need_execute=0
fuseclient_need_execute=0
has_module_param=1
check_module_param() {
if [ $# -gt 1 ]; then
module_name=$2
case "$module_name" in
'fvote')
fvote_need_execute=1
;;
'fdir')
fdir_need_execute=1
;;
'fstore')
fstore_need_execute=1
;;
'fauth')
fauth_need_execute=1
;;
'fuseclient')
fuseclient_need_execute=1
;;
*)
has_module_param=0
if ! [[ $module_name =~ ^- ]]; then
echo "ERROR: Module name invalid, $module_name."
echo " Allowed module names: fdir, fstore, fauth, fvote, fuseclient."
exit 1
else
fdir_need_execute=1
fstore_need_execute=1
fauth_need_execute=1
fvote_need_execute=1
fuseclient_need_execute=1
fi
;;
esac
else
has_module_param=0
fdir_need_execute=1
fstore_need_execute=1
fauth_need_execute=1
fvote_need_execute=1
fuseclient_need_execute=1
fi
}
#---Settings and cluster info section end---#
check_module_param $*
load_fcfs_settings
if [ -z $fastcfs_version ]; then
echo "ERROR: Param fastcfs_version in $fcfs_settings_file cannot be empty."
exit 1
fi
# Check local template file, if not exist, download it from server.
check_conf_template $fastcfs_version
copy_config_from_template() {
local config_file_array=$1
local src_path=$2
local dest_path=$3
for CONF_FILE in ${config_file_array[@]}; do
local tmp_src_file=$src_path/$CONF_FILE
if [ -f $tmp_src_file ]; then
echo "INFO: Copy template file $CONF_FILE to $dest_path."
cp $tmp_src_file $dest_path
else
echo "WARN: File $tmp_src_file does not exist."
fi
done
}
create_fdir_conf_files() {
if [ ${#fdir_ip_array[@]} -gt 0 ]; then
echo "INFO: Begin create fdir config files."
local fdir_path="$LOCAL_CONF_PATH/fdir"
local fdir_tpl_path="$config_file_template_path/fdir"
create_path_not_exist $fdir_path
copy_config_from_template "${FDIR_CONF_FILES[*]}" $fdir_tpl_path $fdir_path
local fdir_cluster_file="$fdir_path/cluster.conf"
if ! [ -f $fdir_cluster_file ]; then
echo "ERROR: fdir cluster file not exist, $fdir_cluster_file, can't append server to it"
exit 1
fi
# Trancate cluster.conf with mark line
sed_replace "/$TRUNCATE_MARK_LINE/,$ d" $fdir_cluster_file
# Replace server ip
let server_id=1
for fdir_server_ip in ${fdir_ip_array[@]}; do
echo "[server-$server_id]" >> $fdir_cluster_file
echo "host = $fdir_server_ip" >> $fdir_cluster_file
echo "" >> $fdir_cluster_file
let server_id=$server_id+1
done
else
echo "ERROR: Param fdir_ips in $fcfs_settings_file cannot be empty."
exit 1
fi
}
create_fstore_conf_files() {
if [ -z $data_group_count ]; then
echo "ERROR: Param data_group_count in $fcfs_settings_file must not empty."
exit 1
fi
if [ -z $fstore_group_count ]; then
echo "ERROR: Param fstore_group_count in $fcfs_settings_file must not empty."
exit 1
fi
let data_group_count_int=$data_group_count
let fstore_group_count_int=$fstore_group_count
if [ $fstore_group_count_int -gt 0 ]; then
# Check params setting valid.
if [ $data_group_count_int -lt $fstore_group_count_int ]; then
echo "ERROR: Param data_group_count in $fcfs_settings_file must be great than fstore_group_count."
exit 1
fi
for (( i=1 ; i <= $fstore_group_count_int ; i++ )); do
local fstore_group="fstore_group_$i"
if [ -z ${!fstore_group} ]; then
echo "ERROR: Param $fstore_group in $fcfs_settings_file cannot be empty."
exit 1
fi
done
echo "INFO: Begin create fstore config files."
local fstore_path="$LOCAL_CONF_PATH/fstore"
local fstore_tpl_path="$config_file_template_path/fstore"
create_path_not_exist $fstore_path
copy_config_from_template "${STORE_CONF_FILES[*]}" $fstore_tpl_path $fstore_path
local fstore_cluster_file="$fstore_path/cluster.conf"
if ! [ -f $fstore_cluster_file ]; then
echo "ERROR: fstore cluster file not exist, $fstore_cluster_file, can't append server to it"
exit 1
fi
# Trancate cluster.conf with mark line
sed_replace "/$TRUNCATE_MARK_LINE/,$ d" $fstore_cluster_file
# Replace server_group_count and data_group_count, and append server ips
let data_groups_per_fstore_group=$data_group_count_int/$fstore_group_count_int
let remainder_count=$data_group_count_int-$data_groups_per_fstore_group*$fstore_group_count_int
let data_group_ids_start=1
let data_group_ids_end=$data_groups_per_fstore_group
sed_replace "s#^server_group_count *=.*#server_group_count = $fstore_group_count_int#g" $fstore_cluster_file
sed_replace "s#^data_group_count *=.*#data_group_count = $data_group_count_int#g" $fstore_cluster_file
let server_id_start=1
let store_server_id=1
# for fstore_group in ${fstore_group_array[@]}; do
for (( i=1 ; i <= $fstore_group_count_int ; i++ )); do
local fstore_group="fstore_group_$i"
split_to_array ${!fstore_group} fstore_ips_array
let server_ids=${#fstore_ips_array[@]}
if [ $server_ids -gt 0 ]; then
# Append server group and server ids
echo "[server-group-$i]" >> $fstore_cluster_file
if [ $server_ids -eq 1 ]; then
echo "server_ids = $server_id_start" >> $fstore_cluster_file
else
let server_id_end=$server_id_start+$server_ids-1
echo "server_ids = [$server_id_start, $server_id_end]" >> $fstore_cluster_file
fi
let server_id_start=$server_id_start+$server_ids
let next_start_add_one=0
# Append data group ids
if [ $remainder_count -gt 0 ]; then
let data_group_ids_end=$data_group_ids_end+1
let remainder_count=$remainder_count-1
let next_start_add_one=1
fi
echo "data_group_ids = [$data_group_ids_start, $data_group_ids_end]" >> $fstore_cluster_file
echo "" >> $fstore_cluster_file
let data_group_ids_start=$data_group_ids_end+1
let data_group_ids_end=$data_group_ids_end+$data_groups_per_fstore_group
# Append server hosts
for fstore_server_ip in ${fstore_ips_array[@]}; do
echo "[server-$store_server_id]" >> $fstore_cluster_file
echo "host = $fstore_server_ip" >> $fstore_cluster_file
echo "" >> $fstore_cluster_file
let store_server_id=$store_server_id+1
done
else
echo "ERROR: Param $fstore_group in $fcfs_settings_file cannot be empty."
exit 1
fi
done
else
echo "ERROR: Param fstore_group_count in $fcfs_settings_file must be great than 0."
exit 1
fi
}
create_fauth_conf_files() {
if [ ${#auth_ip_array[@]} -gt 0 ]; then
echo "INFO: Begin create fauth config files."
local auth_path="$LOCAL_CONF_PATH/auth"
local auth_tpl_path="$config_file_template_path/auth"
create_path_not_exist $auth_path
copy_config_from_template "${AUTH_CONF_FILES[*]}" $auth_tpl_path $auth_path
local auth_cluster_file="$auth_path/cluster.conf"
if ! [ -f $auth_cluster_file ]; then
echo "ERROR: auth cluster file not exist, $auth_cluster_file, can't append server to it"
exit 1
fi
# Trancate cluster.conf with mark line
sed_replace "/$TRUNCATE_MARK_LINE/,$ d" $auth_cluster_file
# Replace server ip
let server_id=1
for auth_server_ip in ${auth_ip_array[@]}; do
echo "[server-$server_id]" >> $auth_cluster_file
echo "host = $auth_server_ip" >> $auth_cluster_file
echo "" >> $auth_cluster_file
let server_id=$server_id+1
done
# Copy auth keys
local auth_keys_path="$LOCAL_CONF_PATH/auth/keys"
local auth_keys_tpl_path="$config_file_template_path/auth/keys"
create_path_not_exist $auth_keys_path
copy_config_from_template "${AUTH_KEYS_FILES[*]}" $auth_keys_tpl_path $auth_keys_path
else
echo "ERROR: Param auth_ips in $fcfs_settings_file cannot be empty."
exit 1
fi
}
create_fvote_conf_files() {
if [ ${#vote_ip_array[@]} -gt 0 ]; then
echo "INFO: Begin create vote config files."
local vote_path="$LOCAL_CONF_PATH/vote"
local vote_tpl_path="$config_file_template_path/vote"
create_path_not_exist $vote_path
copy_config_from_template "${VOTE_CONF_FILES[*]}" $vote_tpl_path $vote_path
local vote_cluster_file="$vote_path/cluster.conf"
if ! [ -f $vote_cluster_file ]; then
echo "ERROR: vote cluster file not exist, $vote_cluster_file, can't append server to it"
exit 1
fi
# Trancate cluster.conf with mark line
sed_replace "/$TRUNCATE_MARK_LINE/,$ d" $vote_cluster_file
# Replace server ip
let server_id=1
for vote_server_ip in ${vote_ip_array[@]}; do
echo "[server-$server_id]" >> $vote_cluster_file
echo "host = $vote_server_ip" >> $vote_cluster_file
echo "" >> $vote_cluster_file
let server_id=$server_id+1
done
else
echo "ERROR: Param vote_ips in $fcfs_settings_file cannot be empty."
exit 1
fi
}
create_fuseclient_conf_files() {
echo "INFO: Begin create fuseclient config files."
local fuseclient_path="$LOCAL_CONF_PATH/fcfs"
local fuseclient_tpl_path="$config_file_template_path/fcfs"
create_path_not_exist $fuseclient_path
copy_config_from_template "${FUSE_CONF_FILES[*]}" $fuseclient_tpl_path $fuseclient_path
}
create_config_files() {
if [ -d $LOCAL_CONF_PATH/fdir -a -d $LOCAL_CONF_PATH/fstore ]; then
printf 'config files already exist, make sure to overwrite [y/N]: '
read var
if ! [ "$var" = "y" -o "$var" = "Y" -o "$var" = "yes" -o "$var" = "YES" ]; then
echo -e '\ncreating config files aborted!\n'
exit 1
fi
fi
create_path_not_exist $LOCAL_CONF_PATH
if [ $fdir_need_execute -eq 1 ]; then
create_fdir_conf_files
fi
if [ $fstore_need_execute -eq 1 ]; then
create_fstore_conf_files
fi
if [ $fauth_need_execute -eq 1 ]; then
create_fauth_conf_files
fi
if [ $fvote_need_execute -eq 1 ]; then
create_fvote_conf_files
fi
if [ $fuseclient_need_execute -eq 1 ]; then
create_fuseclient_conf_files
fi
}
case "$shell_command" in
'create')
create_config_files
;;
*)
print_usage
exit 1
;;
esac
exit 0
================================================
FILE: shell/template/dependency.2.0.1.settings
================================================
# FastCFS cluster's dependent libs version settings.
# Ops shell fcfs.sh will use it to install appropriate version libs FastCFS depends.
# This file download from http://www.fastcfs.com/ops/dependency.[FastCFS-version].settings.
# Do not change libs and versions below.
libfastcommon=1.0.50
libserverframe=1.1.7
fauth=2.0.1
fdir=2.0.1
fstore=2.0.1
================================================
FILE: src/api/Makefile.in
================================================
.SUFFIXES: .c .o .lo
COMPILE = $(CC) $(CFLAGS)
INC_PATH = -I../common -I../include
LIB_PATH = $(LIBS) -lfsclient -lfsapi -lfdirclient -lfastcommon -lserverframe -lfcfsauthclient
TARGET_LIB = $(TARGET_PREFIX)/$(LIB_VERSION)
FAST_SHARED_OBJS = ../common/fcfs_global.lo fcfs_api.lo fcfs_api_file.lo \
fcfs_api_util.lo fcfs_api_allocator.lo async_reporter.lo \
inode_htable.lo std/posix_api.lo std/fd_manager.lo \
std/papi.lo std/capi.lo
FAST_STATIC_OBJS = ../common/fcfs_global.o fcfs_api.o fcfs_api_file.o \
fcfs_api_util.o fcfs_api_allocator.o async_reporter.o \
inode_htable.o std/posix_api.o std/fd_manager.o \
std/papi.o std/capi.o
API_HEADER_FILES = ../common/fcfs_global.h fcfs_api.h fcfs_api_types.h \
fcfs_api_file.h fcfs_api_util.h fcfs_api_allocator.h \
async_reporter.h inode_htable.h
STD_HEADER_FILES = std/posix_api.h std/api_types.h std/fd_manager.h \
std/papi.h std/capi.h
ALL_OBJS = $(FAST_STATIC_OBJS) $(FAST_SHARED_OBJS)
ALL_PRGS =
SHARED_LIBS = libfcfsapi.so
STATIC_LIBS = libfcfsapi.a
ALL_LIBS = $(SHARED_LIBS) $(STATIC_LIBS)
all: $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
libfcfsapi.so: $(FAST_SHARED_OBJS)
$(COMPILE) -o $@ -shared $(FAST_SHARED_OBJS) $(LIB_PATH)
libfcfsapi.a: $(FAST_STATIC_OBJS)
ar rcs $@ $(FAST_STATIC_OBJS)
.o:
$(COMPILE) -o $@ $< $(FAST_STATIC_OBJS) $(LIB_PATH) $(INC_PATH)
.c:
$(COMPILE) -o $@ $< $(FAST_STATIC_OBJS) $(LIB_PATH) $(INC_PATH)
.c.o:
$(COMPILE) -c -o $@ $< $(INC_PATH)
.c.lo:
$(COMPILE) -c -fPIC -o $@ $< $(INC_PATH)
install:
mkdir -p $(TARGET_LIB)
mkdir -p $(TARGET_PREFIX)/lib
mkdir -p $(TARGET_PREFIX)/include/fastcfs/api/std
install -m 755 $(SHARED_LIBS) $(TARGET_LIB)
install -m 644 $(API_HEADER_FILES) $(TARGET_PREFIX)/include/fastcfs/api/
install -m 644 $(STD_HEADER_FILES) $(TARGET_PREFIX)/include/fastcfs/api/std/
@BUILDROOT=$$(echo "$(TARGET_PREFIX)" | grep BUILDROOT); \
if [ -z "$$BUILDROOT" ] && [ "$(TARGET_LIB)" != "$(TARGET_PREFIX)/lib" ]; then ln -sf $(TARGET_LIB)/libfcfsapi.so $(TARGET_PREFIX)/lib/libfcfsapi.so; fi
clean:
rm -f $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
================================================
FILE: src/api/async_reporter.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include "fastcommon/shared_func.h"
#include "fastcommon/pthread_func.h"
#include "sf/sf_global.h"
#include "sf/sf_func.h"
#include "async_reporter.h"
AsyncReporterContext g_async_reporter_ctx;
#define FCFS_API_CTX g_async_reporter_ctx.fcfs_api_ctx
#define SORTED_EVENT_PTR_ARRAY g_async_reporter_ctx.event_ptr_arrays.sorted
#define MERGED_EVENT_PTR_ARRAY g_async_reporter_ctx.event_ptr_arrays.merged
#define NOTIFY_EVENT_COUNT g_async_reporter_ctx.event_ptr_arrays.notify_count
static inline int batch_set_dentry_size(const int count)
{
int result;
while (1) {
result = fdir_client_batch_set_dentry_size(FCFS_API_CTX->contexts.
fdir, &FCFS_API_CTX->ns, g_async_reporter_ctx.dsizes, count);
if (result == 0 || result == ENOENT || result == EINVAL) {
break;
}
sleep(1);
}
return result;
}
static int int_event_ptr_array(FCFSAPIAsyncReportEventPtrArray *event_ptr_array)
{
event_ptr_array->alloc = 1024;
event_ptr_array->events = (FCFSAPIAsyncReportEvent **)
fc_malloc(sizeof(FCFSAPIAsyncReportEvent *) * event_ptr_array->alloc);
if (event_ptr_array->events == NULL) {
return ENOMEM;
}
return 0;
}
static FCFSAPIAsyncReportEvent **realloc_event_ptrs(
FCFSAPIAsyncReportEventPtrArray *event_ptr_array, const int count)
{
int alloc;
FCFSAPIAsyncReportEvent **events;
alloc = event_ptr_array->alloc * 2;
events = (FCFSAPIAsyncReportEvent **)fc_malloc(
sizeof(FCFSAPIAsyncReportEvent *) * alloc);
if (events == NULL) {
return NULL;
}
if (count > 0) {
memcpy(events, event_ptr_array->events,
sizeof(FCFSAPIAsyncReportEvent *) * count);
}
free(event_ptr_array->events);
event_ptr_array->alloc = alloc;
event_ptr_array->events = events;
return events + count;
}
static int to_event_ptr_array(FCFSAPIAsyncReportEvent *head,
FCFSAPIAsyncReportEventPtrArray *event_ptr_array)
{
FCFSAPIAsyncReportEvent **event;
int result;
int event_count;
result = 0;
event_count = 0;
event = event_ptr_array->events;
do {
if (event_count >= event_ptr_array->alloc) {
if ((event=realloc_event_ptrs(event_ptr_array,
event_count)) == NULL)
{
result = ENOMEM;
break;
}
}
head->id = ++event_count;
*event++ = head;
head = head->next;
} while (head != NULL);
event_ptr_array->count = event_count;
return result;
}
static int compare_event_ptr(const FCFSAPIAsyncReportEvent **t1,
const FCFSAPIAsyncReportEvent **t2)
{
int sub;
if ((sub=fc_compare_int64((*t1)->dsize.inode, (*t2)->dsize.inode)) != 0) {
return sub;
}
return (int)(*t1)->id - (int)(*t2)->id;
}
static inline void merge_event(FCFSAPIAsyncReportEvent *dest,
const FCFSAPIAsyncReportEvent *src)
{
if ((src->dsize.flags & (FDIR_DENTRY_FIELD_MODIFIED_FLAG_FILE_SIZE |
FDIR_DENTRY_FIELD_MODIFIED_FLAG_SPACE_END)) != 0)
{
if ((dest->dsize.flags & (FDIR_DENTRY_FIELD_MODIFIED_FLAG_FILE_SIZE |
FDIR_DENTRY_FIELD_MODIFIED_FLAG_SPACE_END)) == 0)
{
dest->dsize.file_size = src->dsize.file_size;
} else if (dest->dsize.file_size < src->dsize.file_size) {
dest->dsize.file_size = src->dsize.file_size;
}
}
if ((src->dsize.flags & FDIR_DENTRY_FIELD_MODIFIED_FLAG_INC_ALLOC) != 0) {
dest->dsize.inc_alloc += src->dsize.inc_alloc;
}
dest->dsize.flags |= src->dsize.flags;
}
static int merge_events(FCFSAPIAsyncReportEvent *head)
{
int result;
//int merge_count;
FCFSAPIAsyncReportEvent **ts;
FCFSAPIAsyncReportEvent **send;
FCFSAPIAsyncReportEvent **merge;
FCFSAPIAsyncReportEvent *current;
if ((result=to_event_ptr_array(head, &SORTED_EVENT_PTR_ARRAY)) != 0) {
return result;
}
if (SORTED_EVENT_PTR_ARRAY.count > 1) {
qsort(SORTED_EVENT_PTR_ARRAY.events, SORTED_EVENT_PTR_ARRAY.count,
sizeof(FCFSAPIAsyncReportEvent *), (int (*)(const void *,
const void *))compare_event_ptr);
}
NOTIFY_EVENT_COUNT = 0;
send = SORTED_EVENT_PTR_ARRAY.events + SORTED_EVENT_PTR_ARRAY.count;
ts = SORTED_EVENT_PTR_ARRAY.events;
merge = MERGED_EVENT_PTR_ARRAY.events;
while (ts < send) {
if ((*ts)->type == fcfs_api_event_type_notify) {
NOTIFY_EVENT_COUNT++;
ts++;
continue;
}
if (merge - MERGED_EVENT_PTR_ARRAY.events >=
MERGED_EVENT_PTR_ARRAY.alloc)
{
if ((merge=realloc_event_ptrs(&MERGED_EVENT_PTR_ARRAY,
merge - MERGED_EVENT_PTR_ARRAY.events)) == NULL)
{
result = ENOMEM;
break;
}
}
//merge_count = 1;
current = *ts;
*merge++ = *ts++;
if (current->dsize.force) {
continue;
}
if (ts == send) {
break;
}
while ((ts < send) && (!(*ts)->dsize.force) &&
((*ts)->dsize.inode == current->dsize.inode))
{
if ((*ts)->type == fcfs_api_event_type_notify) {
NOTIFY_EVENT_COUNT++;
} else {
//merge_count++;
merge_event(current, *ts);
}
ts++;
}
/*
logInfo("event oid: %"PRId64", merged count: %d",
current->dsize.inode, merge_count);
*/
}
MERGED_EVENT_PTR_ARRAY.count = merge - MERGED_EVENT_PTR_ARRAY.events;
return 0;
}
static inline void notify_waiting_tasks(FCFSAPIAsyncReportEvent *event)
{
FCFSAPIWaitingTask *task;
if (event->type == fcfs_api_event_type_report) {
PTHREAD_MUTEX_LOCK(&event->inode_hentry->hentry.sharding->lock);
}
while (event->waitings.head != NULL) {
task = event->waitings.head;
event->waitings.head = event->waitings.head->next;
fcfs_api_notify_waiting_task(task);
}
if (event->type == fcfs_api_event_type_report) {
fc_list_del_init(&event->dlink);
PTHREAD_MUTEX_UNLOCK(&event->inode_hentry->hentry.sharding->lock);
}
}
static inline void notify_waiting_tasks_and_free_events(
FCFSAPIAsyncReportEvent *head)
{
FCFSAPIAsyncReportEvent *event;
do {
event = head;
head = head->next;
notify_waiting_tasks(event);
fast_mblock_free_object(event->allocator, event);
} while (head != NULL);
}
static inline int deal_events(FCFSAPIAsyncReportEvent *head)
{
FCFSAPIAsyncReportEvent **event;
FCFSAPIAsyncReportEvent **tend;
FDIRSetDEntrySizeInfo *dsize;
int result;
int current_count;
if ((result=merge_events(head)) != 0) {
notify_waiting_tasks_and_free_events(head);
return result;
}
dsize = g_async_reporter_ctx.dsizes;
tend = MERGED_EVENT_PTR_ARRAY.events + MERGED_EVENT_PTR_ARRAY.count;
for (event=MERGED_EVENT_PTR_ARRAY.events; eventdsize;
if ((current_count=dsize - g_async_reporter_ctx.dsizes) ==
FDIR_BATCH_SET_MAX_DENTRY_COUNT)
{
batch_set_dentry_size(current_count);
dsize = g_async_reporter_ctx.dsizes;
}
}
if ((current_count=dsize - g_async_reporter_ctx.dsizes) > 0) {
batch_set_dentry_size(current_count);
}
__sync_fetch_and_sub(&g_async_reporter_ctx.waiting_count,
SORTED_EVENT_PTR_ARRAY.count - NOTIFY_EVENT_COUNT);
notify_waiting_tasks_and_free_events(head);
/*
logInfo("total (input) event count: %d, report (output) count: %d, "
"notify event count: %d", SORTED_EVENT_PTR_ARRAY.count,
MERGED_EVENT_PTR_ARRAY.count, NOTIFY_EVENT_COUNT);
*/
return 0;
}
void async_reporter_terminate()
{
FCFSAPIAsyncReportEvent *head;
int count;
if (!g_async_reporter_ctx.fcfs_api_ctx->async_report.enabled) {
return;
}
head = (FCFSAPIAsyncReportEvent *)fc_queue_try_pop_all(
&g_async_reporter_ctx.queue);
if (head != NULL) {
count = deal_events(head);
} else {
count = 0;
}
logInfo("file: "__FILE__", line: %d, "
"async_reporter_terminate, remain count: %d",
__LINE__, count);
}
static inline void check_and_set_stage()
{
int old_stage;
if (__sync_bool_compare_and_swap(&g_async_reporter_ctx.stage,
ASYNC_REPORTER_STAGE_DEALING, ASYNC_REPORTER_STAGE_SLEEPING))
{
fc_timedwait_ms(&g_async_reporter_ctx.lcp.lock,
&g_async_reporter_ctx.lcp.cond, g_async_reporter_ctx.
fcfs_api_ctx->async_report.interval_ms);
if (__sync_bool_compare_and_swap(
&g_async_reporter_ctx.stage,
ASYNC_REPORTER_STAGE_SLEEPING,
ASYNC_REPORTER_STAGE_DEALING))
{
return;
}
}
old_stage = __sync_fetch_and_add(&g_async_reporter_ctx.stage, 0);
__sync_bool_compare_and_swap(&g_async_reporter_ctx.stage,
old_stage, ASYNC_REPORTER_STAGE_DEALING);
}
static void *async_reporter_thread_func(void *arg)
{
FCFSAPIAsyncReportEvent *head;
#ifdef OS_LINUX
prctl(PR_SET_NAME, "dir-async-reporter");
#endif
while (SF_G_CONTINUE_FLAG) {
head = (FCFSAPIAsyncReportEvent *)fc_queue_pop_all(
&g_async_reporter_ctx.queue);
if (head != NULL) {
deal_events(head);
}
if (g_async_reporter_ctx.fcfs_api_ctx->async_report.interval_ms > 0) {
check_and_set_stage();
}
}
return NULL;
}
int async_reporter_init(FCFSAPIContext *fcfs_api_ctx)
{
int result;
pthread_t tid;
g_async_reporter_ctx.fcfs_api_ctx = fcfs_api_ctx;
g_async_reporter_ctx.dsizes = (FDIRSetDEntrySizeInfo *)
fc_malloc(sizeof(FDIRSetDEntrySizeInfo) *
FDIR_BATCH_SET_MAX_DENTRY_COUNT);
if (g_async_reporter_ctx.dsizes == NULL) {
return ENOMEM;
}
if ((result=int_event_ptr_array(&SORTED_EVENT_PTR_ARRAY)) != 0) {
return result;
}
if ((result=int_event_ptr_array(&MERGED_EVENT_PTR_ARRAY)) != 0) {
return result;
}
if ((result=init_pthread_lock_cond_pair(&g_async_reporter_ctx.lcp)) != 0) {
return result;
}
if ((result=fc_queue_init(&g_async_reporter_ctx.queue, (long)
(&((FCFSAPIAsyncReportEvent *)NULL)->next))) != 0)
{
return result;
}
g_async_reporter_ctx.stage = ASYNC_REPORTER_STAGE_DEALING;
return fc_create_thread(&tid, async_reporter_thread_func, NULL,
SF_G_THREAD_STACK_SIZE);
}
================================================
FILE: src/api/async_reporter.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_API_ASYNC_REPORTER_H
#define _FCFS_API_ASYNC_REPORTER_H
#include "fastcommon/fc_queue.h"
#include "fastcommon/fc_atomic.h"
#include "fcfs_api_types.h"
#include "fcfs_api_allocator.h"
#include "inode_htable.h"
#define ASYNC_REPORTER_STAGE_DEALING 0
#define ASYNC_REPORTER_STAGE_SLEEPING 1
#define ASYNC_REPORTER_STAGE_KEEPING 2
typedef struct {
FCFSAPIContext *fcfs_api_ctx;
struct fc_queue queue;
volatile int waiting_count;
volatile int stage;
pthread_lock_cond_pair_t lcp; //for timed wait
FDIRSetDEntrySizeInfo *dsizes;
struct {
int notify_count; //notify event count
FCFSAPIAsyncReportEventPtrArray sorted; //for sort
FCFSAPIAsyncReportEventPtrArray merged;
} event_ptr_arrays;
} AsyncReporterContext;
#ifdef __cplusplus
extern "C" {
#endif
extern AsyncReporterContext g_async_reporter_ctx;
int async_reporter_init(FCFSAPIContext *fcfs_api_ctx);
void async_reporter_terminate();
static inline int async_reporter_push(const FDIRSetDEntrySizeInfo *dsize)
{
int result;
FCFSAPIAsyncReportEvent *event;
FCFSAPIAllocatorContext *allocator_ctx;
allocator_ctx = fcfs_api_allocator_get(dsize->inode);
event = (FCFSAPIAsyncReportEvent *)fast_mblock_alloc_object(
&allocator_ctx->async_report_event);
if (event == NULL) {
return ENOMEM;
}
event->type = fcfs_api_event_type_report;
event->dsize = *dsize;
result = inode_htable_insert(event);
__sync_fetch_and_add(&g_async_reporter_ctx.waiting_count, 1);
fc_queue_push(&g_async_reporter_ctx.queue, event);
return result;
}
static inline int async_reporter_push_notify(const uint64_t inode,
FCFSAPIWaitingTask **waiting_task)
{
FCFSAPIAllocatorContext *allocator_ctx;
FCFSAPIAsyncReportEvent *event;
allocator_ctx = fcfs_api_allocator_get(inode);
event = (FCFSAPIAsyncReportEvent *)fast_mblock_alloc_object(
&allocator_ctx->async_report_event);
if (event == NULL) {
return ENOMEM;
}
*waiting_task = (FCFSAPIWaitingTask *)fast_mblock_alloc_object(
&allocator_ctx->waiting_task);
if (*waiting_task == NULL) {
return ENOMEM;
}
(*waiting_task)->next = event->waitings.head;
event->waitings.head = *waiting_task;
event->type = fcfs_api_event_type_notify;
event->dsize.inode = inode;
event->dsize.flags = 0;
event->dsize.force = false;
fc_queue_push(&g_async_reporter_ctx.queue, event);
return 0;
}
static inline void async_reporter_notify()
{
if (g_async_reporter_ctx.fcfs_api_ctx->async_report.interval_ms <= 0) {
return;
}
switch (__sync_fetch_and_add(&g_async_reporter_ctx.stage, 0)) {
case ASYNC_REPORTER_STAGE_DEALING:
__sync_bool_compare_and_swap(
&g_async_reporter_ctx.stage,
ASYNC_REPORTER_STAGE_DEALING,
ASYNC_REPORTER_STAGE_KEEPING);
break;
case ASYNC_REPORTER_STAGE_SLEEPING:
pthread_cond_signal(&g_async_reporter_ctx.lcp.cond);
break;
case ASYNC_REPORTER_STAGE_KEEPING:
//do nothing
break;
default:
break;
}
}
static inline int async_reporter_wait_all(const uint64_t inode)
{
FCFSAPIWaitingTask *waiting_task;
int result;
if (FC_ATOMIC_GET(g_async_reporter_ctx.waiting_count) == 0) {
return 0;
}
if ((result=async_reporter_push_notify(inode, &waiting_task)) != 0) {
return result;
}
async_reporter_notify();
fcfs_api_wait_report_done_and_release(waiting_task);
return 0;
}
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/api/fcfs_api.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include "fastcommon/common_define.h"
#ifdef OS_LINUX
#include
#include
#include
#endif
#include "fastcommon/shared_func.h"
#include "fastcommon/logger.h"
#include "sf/idempotency/client/client_channel.h"
#include "sf/idempotency/client/receipt_handler.h"
#include "async_reporter.h"
#include "fcfs_api.h"
#define FCFS_API_MIN_SHARED_ALLOCATOR_COUNT 1
#define FCFS_API_MAX_SHARED_ALLOCATOR_COUNT 1000
#define FCFS_API_DEFAULT_SHARED_ALLOCATOR_COUNT 11
#define FCFS_API_MIN_HASHTABLE_SHARDING_COUNT 1
#define FCFS_API_MAX_HASHTABLE_SHARDING_COUNT 10000
#define FCFS_API_DEFAULT_HASHTABLE_SHARDING_COUNT 17
#define FCFS_API_MIN_HASHTABLE_TOTAL_CAPACITY 10949
#define FCFS_API_MAX_HASHTABLE_TOTAL_CAPACITY 100000000
#define FCFS_API_DEFAULT_HASHTABLE_TOTAL_CAPACITY 1403641
#define FCFS_API_INI_IDEMPOTENCY_SECTION_NAME "idempotency"
#define FCFS_API_IDEMPOTENCY_DEFAULT_WORK_THREADS 1
#ifndef FUSE_SUPER_MAGIC
#define FUSE_SUPER_MAGIC 0x65735546
#endif
FCFSAPIContext g_fcfs_api_ctx;
static int fcfs_api_load_owner_config(IniFullContext *ini_ctx,
FCFSAPIContext *ctx);
static int opendir_session_alloc_init(void *element, void *args)
{
int result;
FCFSAPIOpendirSession *session;
session = (FCFSAPIOpendirSession *)element;
if ((result=fdir_client_dentry_array_init(&session->array)) != 0) {
return result;
}
if ((result=fast_buffer_init1(&session->buffer, 64 * 1024)) != 0) {
return result;
}
return 0;
}
int fcfs_api_client_session_create(FCFSAPIContext *ctx, const bool publish)
{
FCFSAuthClientFullContext *auth;
if (ctx->contexts.fdir->auth.enabled) {
auth = &ctx->contexts.fdir->auth;
} else if (ctx->contexts.fsapi->fs->auth.enabled) {
auth = &ctx->contexts.fsapi->fs->auth;
} else {
return 0;
}
return fcfs_auth_client_session_create_ex(auth, &ctx->ns, publish);
}
static inline bool fcfs_api_rdma_enabled(FCFSAPIContext *ctx)
{
FCServerGroupInfo *server_group;
server_group = fc_server_get_group_by_index(
&ctx->contexts.fdir->cluster.server_cfg,
ctx->contexts.fdir->cluster.service_group_index);
if (server_group->comm_type != fc_comm_type_sock) {
return true;
}
server_group = fc_server_get_group_by_index(
&FS_CLUSTER_SERVER_CFG(ctx->contexts.fsapi->fs),
FS_CFG_SERVICE_INDEX(ctx->contexts.fsapi->fs));
return (server_group->comm_type != fc_comm_type_sock);
}
static int fcfs_api_common_init(FCFSAPIContext *ctx, FDIRClientContext *fdir,
FSAPIContext *fsapi, const char *ns, IniFullContext *ini_ctx,
const char *fdir_section_name, const char *fs_section_name,
const bool need_lock, const bool persist_additional_gids)
{
int64_t element_limit = 1000 * 1000;
const int64_t min_ttl_sec = 600;
const int64_t max_ttl_sec = 86400;
int result;
ctx->persist_additional_gids = persist_additional_gids;
ctx->use_sys_lock_for_append = iniGetBoolValue(fdir_section_name,
"use_sys_lock_for_append", ini_ctx->context, false);
ctx->async_report.enabled = iniGetBoolValue(fdir_section_name,
"async_report_enabled", ini_ctx->context, true);
ctx->async_report.interval_ms = iniGetIntValue(fdir_section_name,
"async_report_interval_ms", ini_ctx->context, 10);
ini_ctx->section_name = fdir_section_name;
ctx->async_report.shared_allocator_count = iniGetIntCorrectValueEx(
ini_ctx, "shared_allocator_count",
FCFS_API_DEFAULT_SHARED_ALLOCATOR_COUNT,
FCFS_API_MIN_SHARED_ALLOCATOR_COUNT,
FCFS_API_MAX_SHARED_ALLOCATOR_COUNT, true);
ctx->async_report.hashtable_sharding_count = iniGetIntCorrectValue(
ini_ctx, "hashtable_sharding_count",
FCFS_API_DEFAULT_HASHTABLE_SHARDING_COUNT,
FCFS_API_MIN_HASHTABLE_SHARDING_COUNT,
FCFS_API_MAX_HASHTABLE_SHARDING_COUNT);
ctx->async_report.hashtable_total_capacity = iniGetInt64CorrectValue(
ini_ctx, "hashtable_total_capacity",
FCFS_API_DEFAULT_HASHTABLE_TOTAL_CAPACITY,
FCFS_API_MIN_HASHTABLE_TOTAL_CAPACITY,
FCFS_API_MAX_HASHTABLE_TOTAL_CAPACITY);
if (ctx->async_report.enabled) {
if ((result=fcfs_api_allocator_init(ctx)) != 0) {
return result;
}
if ((result=inode_htable_init(ctx->async_report.
hashtable_sharding_count,
ctx->async_report.hashtable_total_capacity,
ctx->async_report.shared_allocator_count,
element_limit, min_ttl_sec, max_ttl_sec)) != 0)
{
return result;
}
}
ini_ctx->section_name = fs_section_name;
if ((result=fs_api_init_ex(fsapi, ini_ctx,
fcfs_api_file_write_done_callback,
sizeof(FCFSAPIWriteDoneCallbackExtraData))) != 0)
{
return result;
}
if ((result=fast_mblock_init_ex1(&ctx->opendir_session_pool,
"opendir_session", sizeof(FCFSAPIOpendirSession), 64,
0, opendir_session_alloc_init, NULL, need_lock)) != 0)
{
return result;
}
fcfs_api_set_contexts_ex1(ctx, fdir, fsapi, ns);
if ((ctx->rdma.enabled=fcfs_api_rdma_enabled(ctx))) {
ctx->rdma.busy_polling = iniGetBoolValue(NULL,
"busy_polling", ini_ctx->context, false);
G_RDMA_CONNECTION_CALLBACKS.set_busy_polling(ctx->rdma.busy_polling);
} else {
ctx->rdma.busy_polling = false;
}
ini_ctx->section_name = fdir_section_name;
return fcfs_api_load_owner_config(ini_ctx, ctx);
}
int fcfs_api_init_ex1(FCFSAPIContext *ctx, FDIRClientContext *fdir,
FSAPIContext *fsapi, const char *ns, IniFullContext *ini_ctx,
const char *fdir_section_name, const char *fs_section_name,
const SFConnectionManager *fdir_conn_manager,
const SFConnectionManager *fs_conn_manager,
const bool need_lock, const bool persist_additional_gids)
{
const bool bg_thread_enabled = true;
int result;
ini_ctx->section_name = fdir_section_name;
if ((result=fdir_client_init_ex1(fdir, &g_fcfs_auth_client_vars.
client_ctx, ini_ctx, fdir_conn_manager)) != 0)
{
return result;
}
ini_ctx->section_name = fs_section_name;
if ((result=fs_client_init_ex1(fsapi->fs, &g_fcfs_auth_client_vars.
client_ctx, ini_ctx, fs_conn_manager,
bg_thread_enabled)) != 0)
{
return result;
}
return fcfs_api_common_init(ctx, fdir, fsapi, ns, ini_ctx,
fdir_section_name, fs_section_name, need_lock,
persist_additional_gids);
}
int fcfs_api_init_ex(FCFSAPIContext *ctx, const char *ns,
const char *config_filename, const char *fdir_section_name,
const char *fs_section_name)
{
int result;
IniContext iniContext;
IniFullContext ini_ctx;
if ((result=iniLoadFromFile(config_filename, &iniContext)) != 0) {
logError("file: "__FILE__", line: %d, "
"load conf file \"%s\" fail, error no: %d",
__LINE__, config_filename, result);
return result;
}
g_fs_api_ctx.fs = &g_fs_client_vars.client_ctx;
FAST_INI_SET_FULL_CTX_EX(ini_ctx, config_filename,
fdir_section_name, &iniContext);
result = fcfs_api_init_ex1(ctx, &g_fdir_client_vars.client_ctx,
&g_fs_api_ctx, ns, &ini_ctx, fdir_section_name,
fs_section_name, NULL, NULL, false, true);
iniFreeContext(&iniContext);
return result;
}
int fcfs_api_pooled_init_ex(FCFSAPIContext *ctx, const char *ns,
const char *config_filename, const char *fdir_section_name,
const char *fs_section_name, const bool need_lock,
const bool persist_additional_gids)
{
int result;
IniContext iniContext;
IniFullContext ini_ctx;
if ((result=iniLoadFromFile(config_filename, &iniContext)) != 0) {
logError("file: "__FILE__", line: %d, "
"load conf file \"%s\" fail, error no: %d",
__LINE__, config_filename, result);
return result;
}
FAST_INI_SET_FULL_CTX_EX(ini_ctx, config_filename,
fdir_section_name, &iniContext);
result = fcfs_api_pooled_init_ex1(ctx, ns, &ini_ctx,
fdir_section_name, fs_section_name, need_lock,
persist_additional_gids);
iniFreeContext(&iniContext);
return result;
}
int fcfs_api_init_ex2(FCFSAPIContext *ctx, FDIRClientContext *fdir,
FSAPIContext *fsapi, const char *ns, IniFullContext *ini_ctx,
const char *fdir_section_name, const char *fs_section_name,
const FDIRClientConnManagerType conn_manager_type,
const SFConnectionManager *fs_conn_manager,
const bool need_lock, const bool persist_additional_gids)
{
const bool bg_thread_enabled = true;
const int max_count_per_entry = 0;
const int max_idle_time = 3600;
int result;
ini_ctx->section_name = fdir_section_name;
if (conn_manager_type == conn_manager_type_simple) {
result = fdir_client_simple_init_ex1(fdir,
&g_fcfs_auth_client_vars.client_ctx, ini_ctx);
} else if (conn_manager_type == conn_manager_type_pooled) {
result = fdir_client_pooled_init_ex1(fdir,
&g_fcfs_auth_client_vars.client_ctx, ini_ctx,
max_count_per_entry, max_idle_time, bg_thread_enabled);
} else {
result = EINVAL;
}
if (result != 0) {
return result;
}
ini_ctx->section_name = fs_section_name;
if ((result=fs_client_init_ex1(fsapi->fs, &g_fcfs_auth_client_vars.
client_ctx, ini_ctx, fs_conn_manager,
bg_thread_enabled)) != 0)
{
return result;
}
return fcfs_api_common_init(ctx, fdir, fsapi, ns, ini_ctx,
fdir_section_name, fs_section_name, need_lock,
persist_additional_gids);
}
void fcfs_api_destroy_ex(FCFSAPIContext *ctx)
{
if (ctx->contexts.fdir != NULL) {
fdir_client_destroy_ex(ctx->contexts.fdir);
ctx->contexts.fdir = NULL;
}
if (ctx->contexts.fsapi != NULL) {
if (ctx->contexts.fsapi->fs != NULL) {
fs_client_destroy_ex(ctx->contexts.fsapi->fs);
ctx->contexts.fsapi->fs = NULL;
}
fs_api_destroy_ex(ctx->contexts.fsapi);
ctx->contexts.fsapi = NULL;
}
}
static int check_create_root_path(FCFSAPIContext *ctx)
{
int result;
int64_t inode;
FDIRClientOperFnamePair fname;
FCFSAPI_SET_PATH_OPER_FNAME(fname, ctx, ctx->owner.oper, "/");
if ((result=fcfs_api_lookup_inode_by_fullname_ex(ctx,
&fname, LOG_DEBUG, &inode)) != 0)
{
if (result == ENOENT) {
FDIRDEntryInfo dentry;
FCFS_API_SET_OPERATOR(fname.oper, ctx->owner,
geteuid(), getegid());
if ((result=fdir_client_create_dentry(ctx->contexts.fdir, &fname,
ACCESSPERMS | S_IFDIR, &dentry)) == EEXIST)
{
/* check again */
result = fcfs_api_lookup_inode_by_fullname_ex(ctx,
&fname, LOG_DEBUG, &inode);
}
}
}
return result;
}
int fcfs_api_start_ex(FCFSAPIContext *ctx)
{
int result;
if ((result=fs_api_start_ex(ctx->contexts.fsapi)) != 0) {
return result;
}
if ((result=sf_connection_manager_start(&ctx->
contexts.fdir->cm)) != 0)
{
return result;
}
if ((result=sf_connection_manager_start(&ctx->
contexts.fsapi->fs->cm)) != 0)
{
return result;
}
if (ctx->contexts.fdir->idempotency_enabled ||
ctx->contexts.fsapi->fs->idempotency_enabled)
{
FCServerGroupInfo *server_group;
FCAddressPtrArray *address_array;
FCServerInfo *first_server;
address_array = NULL;
if (ctx->contexts.fdir->idempotency_enabled) {
server_group = fc_server_get_group_by_index(
&ctx->contexts.fdir->cluster.server_cfg,
ctx->contexts.fdir->cluster.service_group_index);
if (server_group->comm_type != fc_comm_type_sock) {
first_server = FC_SID_SERVERS(ctx->contexts.
fdir->cluster.server_cfg);
address_array = &first_server->group_addrs[ctx->contexts.
fdir->cluster.service_group_index].address_array;
}
}
if (ctx->contexts.fsapi->fs->idempotency_enabled &&
address_array == NULL)
{
server_group = fc_server_get_group_by_index(
&FS_CLUSTER_SERVER_CFG(ctx->contexts.fsapi->fs),
FS_CFG_SERVICE_INDEX(ctx->contexts.fsapi->fs));
if (server_group->comm_type != fc_comm_type_sock) {
first_server = FC_SID_SERVERS(FS_CLUSTER_SERVER_CFG(
ctx->contexts.fsapi->fs));
address_array = &first_server->group_addrs[
FS_CFG_SERVICE_INDEX(ctx->contexts.fsapi->fs)].
address_array;
}
}
if ((result=receipt_handler_init(address_array)) != 0) {
return result;
}
}
if ((result=check_create_root_path(ctx)) != 0) {
return result;
}
if ((result=fdir_client_init_node_id(ctx->contexts.fdir)) != 0) {
return result;
}
if (ctx->async_report.enabled) {
return async_reporter_init(ctx);
} else {
return 0;
}
}
void fcfs_api_terminate_ex(FCFSAPIContext *ctx)
{
fs_api_terminate_ex(ctx->contexts.fsapi);
if (ctx->async_report.enabled) {
async_reporter_terminate();
}
}
void fcfs_api_async_report_config_to_string_ex(FCFSAPIContext *ctx,
char *output, const int size)
{
int len;
len = snprintf(output, size, "use_sys_lock_for_append: %d, "
"async_report { enabled: %d", ctx->use_sys_lock_for_append,
ctx->async_report.enabled);
if (ctx->async_report.enabled) {
len += snprintf(output + len, size - len, ", "
"async_report_interval_ms: %d, "
"shared_allocator_count: %d, "
"hashtable_sharding_count: %d, "
"hashtable_total_capacity: %"PRId64,
ctx->async_report.interval_ms,
ctx->async_report.shared_allocator_count,
ctx->async_report.hashtable_sharding_count,
ctx->async_report.hashtable_total_capacity);
if (len > size) {
len = size;
}
}
snprintf(output + len, size - len, " } ");
}
static int fcfs_api_setgroups(FCFSAPIOwnerInfo *owner_info,
const gid_t *groups, const int count)
{
int index;
const gid_t *group;
const gid_t *end;
char *buff;
if (count == 0 || (count == 1 && groups[0] ==
owner_info->oper.gid))
{
owner_info->oper.additional_gids.count = 0;
owner_info->oper.additional_gids.list = NULL;
return 0;
}
owner_info->oper.additional_gids.count = count;
owner_info->oper.additional_gids.list = fc_malloc(
FDIR_ADDITIONAL_GROUP_BYTES(owner_info->oper));
if (owner_info->oper.additional_gids.list == NULL) {
return ENOMEM;
}
index = 0;
end = groups + count;
for (group=groups; groupoper.gid) {
buff = (char *)(owner_info->oper.additional_gids.
list + 4 * index++);
int2buff(*group, buff);
}
}
owner_info->oper.additional_gids.count = index;
return 0;
}
static int fcfs_api_getgroups(FCFSAPIOwnerInfo *owner_info)
{
int result;
int count;
gid_t groups[FDIR_MAX_USER_GROUP_COUNT];
count = getgroups(FDIR_MAX_USER_GROUP_COUNT, groups);
if (count < 0) {
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, "
"getgroups fail, errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return result;
}
return fcfs_api_setgroups(owner_info, groups, count);
}
static int fcfs_api_getgrouplist(FCFSAPIOwnerInfo *owner_info)
{
int result;
int count;
struct passwd *user;
#ifdef OS_FREEBSD
int i;
int groups[FDIR_MAX_USER_GROUP_COUNT];
gid_t _groups[FDIR_MAX_USER_GROUP_COUNT];
#else
gid_t groups[FDIR_MAX_USER_GROUP_COUNT];
#endif
gid_t *ptr;
errno = ENOENT;
if ((user=getpwuid(owner_info->oper.uid)) == NULL) {
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, "
"getpwuid fail, errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return result;
}
count = FDIR_MAX_USER_GROUP_COUNT;
if (getgrouplist(user->pw_name, owner_info->
oper.gid, groups, &count) < 0)
{
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, "
"getgroups fail, errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return result;
}
#ifdef OS_FREEBSD
for (i=0; iowner.type == fcfs_api_owner_type_fixed) {
return EINVAL;
}
ctx->owner.oper.uid = geteuid();
ctx->owner.oper.gid = getegid();
return fcfs_api_getgroups(&ctx->owner);
}
static int fcfs_api_load_owner_config(IniFullContext *ini_ctx,
FCFSAPIContext *ctx)
{
int result;
char *owner_type;
char *owner_user;
char *owner_group;
struct group *group;
struct passwd *user;
owner_type = iniGetStrValue(ini_ctx->section_name,
"owner_type", ini_ctx->context);
if (owner_type == NULL || *owner_type == '\0') {
ctx->owner.type = fcfs_api_owner_type_caller;
} else if (strcasecmp(owner_type, FCFS_API_OWNER_TYPE_CALLER_STR) == 0) {
ctx->owner.type = fcfs_api_owner_type_caller;
} else if (strcasecmp(owner_type, FCFS_API_OWNER_TYPE_FIXED_STR) == 0) {
ctx->owner.type = fcfs_api_owner_type_fixed;
} else {
ctx->owner.type = fcfs_api_owner_type_caller;
}
if (ctx->owner.type == fcfs_api_owner_type_caller) {
return fcfs_api_set_owner(ctx);
}
owner_user = iniGetStrValue(ini_ctx->section_name,
"owner_user", ini_ctx->context);
if (owner_user == NULL || *owner_user == '\0') {
ctx->owner.oper.uid = geteuid();
} else {
user = getpwnam(owner_user);
if (user == NULL) {
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, "
"getpwnam %s fail, errno: %d, error info: %s",
__LINE__, owner_user, result, STRERROR(result));
return result;
}
ctx->owner.oper.uid = user->pw_uid;
}
owner_group = iniGetStrValue(ini_ctx->section_name,
"owner_group", ini_ctx->context);
if (owner_group == NULL || *owner_group == '\0') {
ctx->owner.oper.gid = getegid();
} else {
group = getgrnam(owner_group);
if (group == NULL) {
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, "
"getgrnam %s fail, errno: %d, error info: %s",
__LINE__, owner_group, result, STRERROR(result));
return result;
}
ctx->owner.oper.gid = group->gr_gid;
}
if (ctx->owner.oper.uid == geteuid() &&
ctx->owner.oper.gid == getegid())
{
return fcfs_api_getgroups(&ctx->owner);
} else {
return fcfs_api_getgrouplist(&ctx->owner);
}
}
int fcfs_api_load_idempotency_config_ex(const char *log_prefix_name,
IniFullContext *ini_ctx, const char *fdir_section_name,
const char *fs_section_name)
{
#define MIN_THREAD_STACK_SIZE (320 * 1024)
const int task_buffer_extra_size = 0;
const bool need_set_run_by = true;
int fixed_buffer_size;
int result;
SFContextIniConfig config;
FCServerGroupInfo *server_group;
FCCommunicationType comm_type;
ini_ctx->section_name = FCFS_API_INI_IDEMPOTENCY_SECTION_NAME;
if ((result=client_channel_init(ini_ctx)) != 0) {
return result;
}
g_sf_context.is_client = true;
g_fdir_client_vars.client_ctx.idempotency_enabled =
iniGetBoolValue(fdir_section_name, "idempotency_enabled",
ini_ctx->context, g_idempotency_client_cfg.enabled);
g_fs_client_vars.client_ctx.idempotency_enabled =
iniGetBoolValue(fs_section_name, "idempotency_enabled",
ini_ctx->context, g_idempotency_client_cfg.enabled);
fixed_buffer_size = 0;
comm_type = fc_comm_type_sock;
if (g_fdir_client_vars.client_ctx.idempotency_enabled) {
server_group = fc_server_get_group_by_index(
&g_fdir_client_vars.client_ctx.cluster.server_cfg,
g_fdir_client_vars.client_ctx.cluster.service_group_index);
if (comm_type != server_group->comm_type) {
comm_type = server_group->comm_type;
fixed_buffer_size = g_fdir_client_vars.client_ctx.
cluster.server_cfg.buffer_size;
}
}
if (g_fs_client_vars.client_ctx.idempotency_enabled) {
server_group = fc_server_get_group_by_index(
&FS_CLUSTER_SERVER_CFG(&g_fs_client_vars.client_ctx),
FS_CFG_SERVICE_INDEX(&g_fs_client_vars.client_ctx));
if (comm_type != server_group->comm_type) {
comm_type = g_fdir_client_vars.client_ctx.idempotency_enabled ?
fc_comm_type_both : server_group->comm_type;
}
if (fixed_buffer_size == 0) {
fixed_buffer_size = FS_CLUSTER_SERVER_CFG(&g_fs_client_vars.
client_ctx).buffer_size;
} else if (FS_CLUSTER_SERVER_CFG(&g_fs_client_vars.
client_ctx).buffer_size > 0)
{
fixed_buffer_size = FC_MIN(fixed_buffer_size,
FS_CLUSTER_SERVER_CFG(&g_fs_client_vars.
client_ctx).buffer_size);
}
}
SF_SET_CONTEXT_INI_CONFIG(config, comm_type, ini_ctx->filename,
ini_ctx->context, FCFS_API_INI_IDEMPOTENCY_SECTION_NAME,
0, 0, FCFS_API_IDEMPOTENCY_DEFAULT_WORK_THREADS);
if ((result=sf_load_config_ex(log_prefix_name, &config,
fixed_buffer_size, task_buffer_extra_size,
need_set_run_by)) != 0)
{
return result;
}
if (SF_G_THREAD_STACK_SIZE < MIN_THREAD_STACK_SIZE) {
logWarning("file: "__FILE__", line: %d, "
"config file: %s, thread_stack_size: %d is too small, "
"set to %d", __LINE__, ini_ctx->filename,
SF_G_THREAD_STACK_SIZE, MIN_THREAD_STACK_SIZE);
SF_G_THREAD_STACK_SIZE = MIN_THREAD_STACK_SIZE;
}
return 0;
}
static int load_mountpoint(IniFullContext *ini_ctx,
string_t *mountpoint, const bool fuse_check)
{
struct statfs buf;
int result;
int ret;
if (mountpoint->str == NULL) {
mountpoint->str = iniGetStrValueEx(ini_ctx->section_name,
"mountpoint", ini_ctx->context, true);
if (mountpoint->str == NULL || *mountpoint->str == '\0') {
logError("file: "__FILE__", line: %d, "
"config file: %s, section: %s, item: mountpoint "
"not exist or is empty", __LINE__, ini_ctx->filename,
ini_ctx->section_name);
return ENOENT;
}
mountpoint->len = strlen(mountpoint->str);
}
if (*mountpoint->str != '/') {
logError("file: "__FILE__", line: %d, "
"config file: %s, mountpoint: %s must start with \"/\"",
__LINE__, ini_ctx->filename, mountpoint->str);
return ENOENT;
}
while (mountpoint->len > 0 && mountpoint->
str[mountpoint->len - 1] == '/')
{
mountpoint->len--;
}
if (fuse_check && !fileExists(mountpoint->str)) {
result = errno != 0 ? errno : ENOENT;
if (result == ENOTCONN) {
#ifdef OS_LINUX
ret = umount2(mountpoint->str, MNT_FORCE);
#else
ret = unmount(mountpoint->str, 0);
#endif
if (ret == 0) {
result = 0;
} else {
result = errno != 0 ? errno : EBUSY;
if (result == EPERM) {
logError("file: "__FILE__", line: %d, "
"unmount %s fail, you should run "
"\"sudo umount -f %s\" manually", __LINE__,
mountpoint->str, mountpoint->str);
} else {
logError("file: "__FILE__", line: %d, "
"unmount %s fail, errno: %d, error info: %s",
__LINE__, mountpoint->str,
result, STRERROR(result));
}
return result;
}
} else if (result != 0) {
logError("file: "__FILE__", line: %d, "
"mountpoint: %s can't be accessed, errno: %d, "
"error info: %s", __LINE__, mountpoint->str,
result, STRERROR(result));
return result;
}
}
if (!isDir(mountpoint->str)) {
logError("file: "__FILE__", line: %d, "
"mountpoint: %s is not a directory!",
__LINE__, mountpoint->str);
return ENOTDIR;
}
if (fuse_check) {
if (statfs(mountpoint->str, &buf) != 0) {
logError("file: "__FILE__", line: %d, "
"statfs mountpoint: %s fail, error info: %s",
__LINE__, mountpoint->str, STRERROR(errno));
return errno != 0 ? errno : ENOENT;
}
if ((buf.f_type & FUSE_SUPER_MAGIC) == FUSE_SUPER_MAGIC) {
logError("file: "__FILE__", line: %d, "
"mountpoint: %s already mounted by FUSE",
__LINE__, mountpoint->str);
return EEXIST;
}
}
return 0;
}
int fcfs_api_check_mountpoint(const char *config_filename,
const string_t *mountpoint)
{
int result;
string_t base_path;
FC_SET_STRING(base_path, SF_G_BASE_PATH_STR);
if (fc_path_contains(&base_path, mountpoint, &result)) {
logError("file: "__FILE__", line: %d, "
"config file: %s, base path: %s contains mountpoint: %.*s, "
"this case is not allowed", __LINE__, config_filename,
SF_G_BASE_PATH_STR, mountpoint->len, mountpoint->str);
return EINVAL;
} else if (result != 0) {
logError("file: "__FILE__", line: %d, "
"config file: %s, base path: %s or mountpoint: %.*s "
"is invalid", __LINE__, config_filename,
SF_G_BASE_PATH_STR, mountpoint->len, mountpoint->str);
}
return result;
}
int fcfs_api_load_ns_mountpoint(IniFullContext *ini_ctx,
const char *fdir_section_name, FCFSAPINSMountpointHolder *nsmp,
string_t *mountpoint, const bool fuse_check)
{
string_t ns;
int result;
if ((result=load_mountpoint(ini_ctx, mountpoint, fuse_check)) != 0) {
return result;
}
if (nsmp->ns == NULL) {
ns.str = iniGetStrValue(fdir_section_name,
"namespace", ini_ctx->context);
if (ns.str == NULL || *ns.str == '\0') {
logError("file: "__FILE__", line: %d, "
"config file: %s, section: %s, item: namespace "
"not exist or is empty", __LINE__, ini_ctx->
filename, fdir_section_name);
return ENOENT;
}
} else {
ns.str = nsmp->ns;
}
ns.len = strlen(ns.str);
nsmp->ns = fc_malloc(ns.len + mountpoint->len + 2);
if (nsmp->ns == NULL) {
return ENOMEM;
}
memcpy(nsmp->ns, ns.str, ns.len + 1);
nsmp->mountpoint = nsmp->ns + ns.len + 1;
memcpy(nsmp->mountpoint, mountpoint->str, mountpoint->len);
*(nsmp->mountpoint + mountpoint->len) = '\0';
mountpoint->str = nsmp->mountpoint;
return 0;
}
void fcfs_api_free_ns_mountpoint(FCFSAPINSMountpointHolder *nsmp)
{
if (nsmp->ns != NULL) {
free(nsmp->ns);
nsmp->ns = NULL;
}
}
void fcfs_api_log_client_common_configs(FCFSAPIContext *ctx,
const char *fdir_section_name, const char *fs_section_name,
BufferInfo *sf_idempotency_config, char *owner_config)
{
char auth_config[512];
char fsapi_config[1024];
char async_report_config[512];
int len;
if (ctx->contexts.fdir->idempotency_enabled ||
ctx->contexts.fsapi->fs->idempotency_enabled)
{
len = snprintf(sf_idempotency_config->buff,
sf_idempotency_config->alloc_size,
"%s idempotency_enabled=%d, "
"%s idempotency_enabled=%d, ",
fdir_section_name, ctx->contexts.
fdir->idempotency_enabled,
fs_section_name, ctx->contexts.
fsapi->fs->idempotency_enabled);
idempotency_client_channel_config_to_string_ex(
sf_idempotency_config->buff + len,
sf_idempotency_config->alloc_size - len, true);
sf_idempotency_config->length = strlen(sf_idempotency_config->buff);
} else {
*sf_idempotency_config->buff = '\0';
sf_idempotency_config->length = 0;
}
len = sprintf(owner_config, "owner_type: %s",
fcfs_api_get_owner_type_caption(ctx->owner.type));
if (ctx->owner.type == fcfs_api_owner_type_fixed) {
struct passwd *user;
struct group *group;
user = getpwuid(ctx->owner.oper.uid);
group = getgrgid(ctx->owner.oper.gid);
sprintf(owner_config + len, ", owner_user: %s, owner_group: %s",
user->pw_name, group->gr_name);
}
fcfs_api_async_report_config_to_string_ex(ctx, async_report_config,
sizeof(async_report_config));
fcfs_auth_config_to_string(&ctx->contexts.fdir->auth,
auth_config, sizeof(auth_config));
snprintf(async_report_config + strlen(async_report_config),
sizeof(async_report_config) - strlen(async_report_config),
", %s", auth_config);
fdir_client_log_config_ex(ctx->contexts.fdir,
async_report_config, false);
fs_api_config_to_string(fsapi_config, sizeof(fsapi_config));
fcfs_auth_config_to_string(&ctx->contexts.fsapi->fs->auth,
auth_config, sizeof(auth_config));
snprintf(fsapi_config + strlen(fsapi_config),
sizeof(fsapi_config) - strlen(fsapi_config),
", %s", auth_config);
fs_client_log_config_ex(ctx->contexts.fsapi->fs,
fsapi_config, false);
}
================================================
FILE: src/api/fcfs_api.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_API_H
#define _FCFS_API_H
#include "fastcommon/shared_func.h"
#include "fcfs_api_types.h"
#include "fcfs_api_file.h"
#include "fcfs_api_util.h"
#define FCFS_API_DEFAULT_FASTDIR_SECTION_NAME "FastDIR"
#define FCFS_API_DEFAULT_FASTSTORE_SECTION_NAME "FastStore"
#define FCFS_API_OWNER_TYPE_CALLER_STR "caller"
#define FCFS_API_OWNER_TYPE_FIXED_STR "fixed"
#define fcfs_api_set_contexts(ns) fcfs_api_set_contexts_ex(&g_fcfs_api_ctx, ns)
#define fcfs_api_init(ns, config_filename) \
fcfs_api_init_ex(&g_fcfs_api_ctx, ns, config_filename, \
FCFS_API_DEFAULT_FASTDIR_SECTION_NAME, \
FCFS_API_DEFAULT_FASTSTORE_SECTION_NAME)
#define fcfs_api_pooled_init(ns, config_filename) \
fcfs_api_pooled_init_ex(&g_fcfs_api_ctx, ns, config_filename, \
FCFS_API_DEFAULT_FASTDIR_SECTION_NAME, \
FCFS_API_DEFAULT_FASTSTORE_SECTION_NAME, \
true, true)
#define fcfs_api_pooled_init1(ns, ini_ctx) \
fcfs_api_pooled_init_ex1(&g_fcfs_api_ctx, ns, ini_ctx, \
FCFS_API_DEFAULT_FASTDIR_SECTION_NAME, \
FCFS_API_DEFAULT_FASTSTORE_SECTION_NAME, \
true, true)
#define fcfs_api_destroy() fcfs_api_destroy_ex(&g_fcfs_api_ctx)
#define fcfs_api_start() fcfs_api_start_ex(&g_fcfs_api_ctx)
#define fcfs_api_terminate() fcfs_api_terminate_ex(&g_fcfs_api_ctx)
#define fcfs_api_async_report_config_to_string(output, size) \
fcfs_api_async_report_config_to_string_ex(&g_fcfs_api_ctx, output, size)
#ifdef __cplusplus
extern "C" {
#endif
static inline void fcfs_api_set_contexts_ex1(FCFSAPIContext *ctx,
FDIRClientContext *fdir, FSAPIContext *fsapi, const char *ns)
{
ctx->contexts.fdir = fdir;
ctx->contexts.fsapi = fsapi;
ctx->ns.str = ctx->ns_holder;
ctx->ns.len = fc_safe_strcpy(ctx->ns_holder, ns);
}
static inline void fcfs_api_set_contexts_ex(FCFSAPIContext *ctx,
const char *ns)
{
g_fs_api_ctx.fs = &g_fs_client_vars.client_ctx;
return fcfs_api_set_contexts_ex1(ctx, &g_fdir_client_vars.
client_ctx, &g_fs_api_ctx, ns);
}
int fcfs_api_init_ex1(FCFSAPIContext *ctx, FDIRClientContext *fdir,
FSAPIContext *fsapi, const char *ns, IniFullContext *ini_ctx,
const char *fdir_section_name, const char *fs_section_name,
const SFConnectionManager *fdir_conn_manager,
const SFConnectionManager *fs_conn_manager,
const bool need_lock, const bool persist_additional_gids);
int fcfs_api_init_ex(FCFSAPIContext *ctx, const char *ns,
const char *config_filename, const char *fdir_section_name,
const char *fs_section_name);
int fcfs_api_init_ex2(FCFSAPIContext *ctx, FDIRClientContext *fdir,
FSAPIContext *fsapi, const char *ns, IniFullContext *ini_ctx,
const char *fdir_section_name, const char *fs_section_name,
const FDIRClientConnManagerType conn_manager_type,
const SFConnectionManager *fs_conn_manager,
const bool need_lock, const bool persist_additional_gids);
static inline int fcfs_api_pooled_init_ex1(FCFSAPIContext *ctx,
const char *ns, IniFullContext *ini_ctx, const char *
fdir_section_name, const char *fs_section_name,
const bool need_lock, const bool persist_additional_gids)
{
g_fs_api_ctx.fs = &g_fs_client_vars.client_ctx;
return fcfs_api_init_ex2(ctx, &g_fdir_client_vars.client_ctx,
&g_fs_api_ctx, ns, ini_ctx, fdir_section_name,
fs_section_name, conn_manager_type_pooled,
NULL, need_lock, persist_additional_gids);
}
int fcfs_api_pooled_init_ex(FCFSAPIContext *ctx, const char *ns,
const char *config_filename, const char *fdir_section_name,
const char *fs_section_name, const bool need_lock,
const bool persist_additional_gids);
void fcfs_api_destroy_ex(FCFSAPIContext *ctx);
int fcfs_api_start_ex(FCFSAPIContext *ctx);
void fcfs_api_terminate_ex(FCFSAPIContext *ctx);
int fcfs_api_client_session_create(FCFSAPIContext *ctx, const bool publish);
static inline int fcfs_api_init_with_auth(const char *ns,
const char *config_filename, const bool publish)
{
int result;
if ((result=fcfs_api_init(ns, config_filename)) != 0) {
return result;
}
return fcfs_api_client_session_create(&g_fcfs_api_ctx, publish);
}
static inline int fcfs_api_pooled_init_with_auth(const char *ns,
const char *config_filename, const bool publish)
{
int result;
if ((result=fcfs_api_pooled_init(ns, config_filename)) != 0) {
return result;
}
return fcfs_api_client_session_create(&g_fcfs_api_ctx, publish);
}
static inline int fcfs_api_pooled_init1_with_auth(const char *ns,
IniFullContext *ini_ctx, const bool publish)
{
int result;
if ((result=fcfs_api_pooled_init1(ns, ini_ctx)) != 0) {
return result;
}
return fcfs_api_client_session_create(&g_fcfs_api_ctx, publish);
}
int fcfs_api_load_idempotency_config_ex(const char *log_prefix_name,
IniFullContext *ini_ctx, const char *fdir_section_name,
const char *fs_section_name);
static inline int fcfs_api_load_idempotency_config(const char
*log_prefix_name, IniFullContext *ini_ctx)
{
return fcfs_api_load_idempotency_config_ex(log_prefix_name,
ini_ctx, FCFS_API_DEFAULT_FASTDIR_SECTION_NAME,
FCFS_API_DEFAULT_FASTSTORE_SECTION_NAME);
}
int fcfs_api_load_ns_mountpoint(IniFullContext *ini_ctx,
const char *fdir_section_name, FCFSAPINSMountpointHolder *nsmp,
string_t *mountpoint, const bool fuse_check);
void fcfs_api_free_ns_mountpoint(FCFSAPINSMountpointHolder *nsmp);
int fcfs_api_check_mountpoint(const char *config_filename,
const string_t *mountpoint);
static inline int fcfs_api_check_mountpoint1(const char
*config_filename, const char *mpoint)
{
string_t mountpoint;
FC_SET_STRING(mountpoint, (char *)mpoint);
return fcfs_api_check_mountpoint(config_filename, &mountpoint);
}
void fcfs_api_async_report_config_to_string_ex(FCFSAPIContext *ctx,
char *output, const int size);
void fcfs_api_log_client_common_configs(FCFSAPIContext *ctx,
const char *fdir_section_name, const char *fs_section_name,
BufferInfo *sf_idempotency_config, char *owner_config);
int fcfs_api_set_owner(FCFSAPIContext *ctx);
static inline const char *fcfs_api_get_owner_type_caption(
const FCFSAPIOwnerType owner_type)
{
switch (owner_type) {
case fcfs_api_owner_type_caller:
return FCFS_API_OWNER_TYPE_CALLER_STR;
case fcfs_api_owner_type_fixed:
return FCFS_API_OWNER_TYPE_FIXED_STR;
default:
return "";
}
}
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/api/fcfs_api_allocator.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include "fcfs_api_allocator.h"
FCFSAPIAllocatorCtxArray g_fcfs_api_allocator_array;
static int async_report_event_alloc_init(FCFSAPIAsyncReportEvent *event,
struct fast_mblock_man *allocator)
{
event->allocator = allocator;
return 0;
}
static int waiting_task_alloc_init(FCFSAPIWaitingTask *task,
struct fast_mblock_man *allocator)
{
int result;
if ((result=init_pthread_lock_cond_pair(&task->lcp)) != 0) {
return result;
}
task->allocator = allocator;
return 0;
}
static int init_allocator_context(FCFSAPIAllocatorContext *ctx)
{
int result;
if ((result=fast_mblock_init_ex1(&ctx->async_report_event,
"async_report_event", sizeof(FCFSAPIAsyncReportEvent),
4096, 0, (fast_mblock_object_init_func)
async_report_event_alloc_init,
&ctx->async_report_event, true)) != 0)
{
return result;
}
if ((result=fast_mblock_init_ex1(&ctx->waiting_task,
"waiting_task", sizeof(FCFSAPIWaitingTask), 1024, 0,
(fast_mblock_object_init_func)waiting_task_alloc_init,
&ctx->waiting_task, true)) != 0)
{
return result;
}
return 0;
}
int fcfs_api_allocator_init(FCFSAPIContext *api_ctx)
{
int result;
int bytes;
FCFSAPIAllocatorContext *ctx;
FCFSAPIAllocatorContext *end;
g_fcfs_api_allocator_array.count = api_ctx->
async_report.shared_allocator_count;
bytes = sizeof(FCFSAPIAllocatorContext) * g_fcfs_api_allocator_array.count;
g_fcfs_api_allocator_array.allocators = (FCFSAPIAllocatorContext *)
fc_malloc(bytes);
if (g_fcfs_api_allocator_array.allocators == NULL) {
return ENOMEM;
}
end = g_fcfs_api_allocator_array.allocators +
g_fcfs_api_allocator_array.count;
for (ctx=g_fcfs_api_allocator_array.allocators; ctx
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_API_ALLOCATOR_H
#define _FCFS_API_ALLOCATOR_H
#include "fastcommon/pthread_func.h"
#include "fcfs_api_types.h"
typedef struct fcfs_api_allocator_context {
struct fast_mblock_man async_report_event; //element: FCFSAPIAsyncReportEvent
struct fast_mblock_man waiting_task; //element: FCFSAPIWaitingTask
} FCFSAPIAllocatorContext;
typedef struct fcfs_api_allocator_ctx_array {
int count;
FCFSAPIAllocatorContext *allocators;
} FCFSAPIAllocatorCtxArray;
#ifdef __cplusplus
extern "C" {
#endif
extern FCFSAPIAllocatorCtxArray g_fcfs_api_allocator_array;
int fcfs_api_allocator_init(FCFSAPIContext *api_ctx);
static inline FCFSAPIAllocatorContext *fcfs_api_allocator_get(
const uint64_t id)
{
return g_fcfs_api_allocator_array.allocators +
id % g_fcfs_api_allocator_array.count;
}
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/api/fcfs_api_file.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include "fastcommon/shared_func.h"
#include "fastcommon/logger.h"
#include "fastcommon/sockopt.h"
#include "fastcommon/sched_thread.h"
#include "sf/sf_iov.h"
#include "fcfs_api_util.h"
#include "async_reporter.h"
#include "fcfs_api_file.h"
#define FCFS_API_MAGIC_NUMBER 1588076578
static int file_truncate(FCFSAPIContext *ctx, const int64_t oid,
const int64_t new_size, const FDIRDentryOperator *oper,
const int64_t tid);
static int deal_open_flags(FCFSAPIFileInfo *fi, FDIRClientOperFnamePair *path,
const FDIRDentryOperator *oper, const mode_t mode,
const int64_t tid, int result)
{
int bytes;
fi->tid = tid;
fi->oper = *oper;
if (fi->ctx->persist_additional_gids) {
/* persist fi->oper.additional_gids.list for future usage */
if (oper->additional_gids.count > 0) {
bytes = FDIR_ADDITIONAL_GROUP_BYTES(*oper);
if (bytes <= sizeof(fi->fixed_groups_buff)) {
fi->oper.additional_gids.list = fi->fixed_groups_buff;
} else {
fi->oper.additional_gids.list = fc_malloc(bytes);
if (fi->oper.additional_gids.list == NULL) {
return ENOMEM;
}
}
memcpy((void *)fi->oper.additional_gids.list,
oper->additional_gids.list, bytes);
} else {
fi->oper.additional_gids.list = fi->fixed_groups_buff;
}
}
if (!((fi->flags & O_WRONLY) || (fi->flags & O_RDWR))) {
fi->offset = 0;
return (fi->flags & O_TRUNC) ? EACCES : result;
}
if ((fi->flags & O_CREAT)) {
if (result == 0) {
if ((fi->flags & O_EXCL)) {
return EEXIST;
}
} else if (result == ENOENT) {
if ((result=fdir_client_create_dentry(fi->ctx->contexts.fdir,
path, mode, &fi->dentry)) != 0)
{
if (result == EEXIST) {
if ((fi->flags & O_EXCL)) {
return EEXIST;
}
if ((result=fcfs_api_access_dentry_by_path_ex(fi->ctx,
path, FCFS_API_GET_ACCESS_MASK(fi->flags),
FCFS_API_GET_ACCESS_FLAGS(fi->flags),
&fi->dentry)) != 0)
{
return result;
}
} else {
return result;
}
}
} else {
return result;
}
} else if (result != 0) {
return result;
}
if (S_ISDIR(fi->dentry.stat.mode)) {
return EISDIR; //flags O_WRONLY or O_RDWR are forbidden for directory
}
if ((fi->flags & O_NOFOLLOW) && S_ISLNK(fi->dentry.stat.mode)) {
return ELOOP;
}
fi->write_notify.last_modified_time = fi->dentry.stat.mtime;
if ((fi->flags & O_TRUNC)) {
if (fi->dentry.stat.size > 0) {
if (S_ISLNK(fi->dentry.stat.mode)) {
return EPERM;
}
if ((result=file_truncate(fi->ctx, fi->dentry.
inode, 0, &fi->oper, tid)) != 0)
{
return result;
}
fi->dentry.stat.size = 0;
fi->dentry.stat.space_end = 0;
}
}
if ((fi->flags & O_APPEND)) {
fi->offset = fi->dentry.stat.size;
} else {
fi->offset = 0;
}
return 0;
}
#define SET_FILE_COMMON_FIELDS(fi, _ctx, _flags) \
fi->ctx = _ctx; \
fi->flags = _flags; \
fi->sessions.flock.mconn = NULL
int fcfs_api_open_ex(FCFSAPIContext *ctx, FCFSAPIFileInfo *fi,
const char *path, const int flags,
const FCFSAPIFileContext *fctx)
{
FDIRClientOperFnamePair fname;
mode_t mode;
int result;
if ((fctx->mode & S_IFMT)) {
mode = (fctx->mode & (~S_IFMT)) | S_IFREG;
} else {
mode = fctx->mode | S_IFREG;
}
SET_FILE_COMMON_FIELDS(fi, ctx, flags);
FCFSAPI_SET_PATH_OPER_FNAME(fname, ctx, fctx->oper, path);
result = fcfs_api_access_dentry_by_path_ex(ctx,
&fname, FCFS_API_GET_ACCESS_MASK(flags),
FCFS_API_GET_ACCESS_FLAGS(flags), &fi->dentry);
if ((result=deal_open_flags(fi, &fname, &fctx->oper,
mode, fctx->tid, result)) != 0)
{
return result;
}
fi->magic = FCFS_API_MAGIC_NUMBER;
return 0;
}
int fcfs_api_open_by_dentry_ex(FCFSAPIContext *ctx, FCFSAPIFileInfo *fi,
const FDIRDEntryInfo *dentry, const int flags,
const FCFSAPIFileContext *fctx)
{
int result;
SET_FILE_COMMON_FIELDS(fi, ctx, flags);
fi->dentry = *dentry;
result = 0;
if ((result=deal_open_flags(fi, NULL, &fctx->oper,
fctx->mode, fctx->tid, result)) != 0)
{
return result;
}
fi->magic = FCFS_API_MAGIC_NUMBER;
return 0;
}
int fcfs_api_open_by_inode_ex(FCFSAPIContext *ctx, FCFSAPIFileInfo *fi,
const int64_t inode, const int flags, const FCFSAPIFileContext *fctx)
{
FDIRClientOperInodePair oino;
int result;
FCFSAPI_SET_OPER_INODE_PAIR(oino, fctx->oper, inode);
if ((result=fcfs_api_access_dentry_by_inode_ex(ctx, &oino,
FCFS_API_GET_ACCESS_MASK(flags),
FCFS_API_GET_ACCESS_FLAGS(flags),
&fi->dentry)) != 0)
{
return result;
}
SET_FILE_COMMON_FIELDS(fi, ctx, flags);
if ((result=deal_open_flags(fi, NULL, &fctx->oper,
fctx->mode, fctx->tid, result)) != 0)
{
return result;
}
fi->magic = FCFS_API_MAGIC_NUMBER;
return 0;
}
int fcfs_api_close(FCFSAPIFileInfo *fi)
{
if (fi->magic != FCFS_API_MAGIC_NUMBER) {
return EBADF;
}
if (fi->sessions.flock.mconn != NULL) {
/* force close connection to unlock */
fdir_client_close_session(&fi->sessions.flock, true);
}
if (fi->ctx->persist_additional_gids) {
if (fi->oper.additional_gids.list != fi->fixed_groups_buff) {
free((void *)fi->oper.additional_gids.list);
fi->oper.additional_gids.list = NULL;
}
}
fi->ctx = NULL;
fi->magic = 0;
return 0;
}
static int report_size_and_time(FCFSAPIContext *ctx,
const FDIRSetDEntrySizeInfo *dsize, FDIRDEntryInfo *dentry)
{
if (ctx->async_report.enabled) {
if (dentry != NULL) {
if ((dsize->flags & FDIR_DENTRY_FIELD_MODIFIED_FLAG_FILE_SIZE)) {
dentry->stat.size = dsize->file_size;
}
if ((dsize->flags & FDIR_DENTRY_FIELD_MODIFIED_FLAG_SPACE_END)) {
dentry->stat.space_end = dsize->file_size;
}
if ((dsize->flags & FDIR_DENTRY_FIELD_MODIFIED_FLAG_MTIME)) {
dentry->stat.mtime = get_current_time();
}
}
return async_reporter_push(dsize);
} else {
FDIRDEntryInfo tmp;
if (dentry == NULL) {
dentry = &tmp;
}
return fdir_client_set_dentry_size(ctx->contexts.fdir,
&ctx->ns, dsize, dentry);
}
}
static int fcfs_api_file_report_size_and_time(
FCFSAPIWriteDoneCallbackArg *callback_arg, int *flags,
FDIRDEntryInfo *dentry)
{
FDIRSetDEntrySizeInfo dsize;
int current_time;
dsize.file_size = callback_arg->arg.bs_key->block.offset +
callback_arg->arg.bs_key->slice.offset +
callback_arg->arg.write_bytes;
if (dsize.file_size > callback_arg->extra.file_size) {
*flags = FDIR_DENTRY_FIELD_MODIFIED_FLAG_FILE_SIZE |
FDIR_DENTRY_FIELD_MODIFIED_FLAG_SPACE_END;
} else {
if (dsize.file_size > callback_arg->extra.space_end) {
*flags = FDIR_DENTRY_FIELD_MODIFIED_FLAG_SPACE_END;
} else {
*flags = 0;
}
current_time = get_current_time();
if (current_time > callback_arg->extra.last_modified_time) {
*flags |= FDIR_DENTRY_FIELD_MODIFIED_FLAG_MTIME;
}
}
if (callback_arg->arg.inc_alloc != 0) {
if (!(*flags & (FDIR_DENTRY_FIELD_MODIFIED_FLAG_FILE_SIZE |
FDIR_DENTRY_FIELD_MODIFIED_FLAG_SPACE_END)))
{
*flags = FDIR_DENTRY_FIELD_MODIFIED_FLAG_FILE_SIZE |
FDIR_DENTRY_FIELD_MODIFIED_FLAG_SPACE_END |
FDIR_DENTRY_FIELD_MODIFIED_FLAG_INC_ALLOC;
} else {
*flags |= FDIR_DENTRY_FIELD_MODIFIED_FLAG_INC_ALLOC;
}
}
if (*flags == 0) {
return 0;
} else {
dsize.inode = callback_arg->arg.bs_key->block.oid;
dsize.inc_alloc = callback_arg->arg.inc_alloc;
dsize.force = false;
dsize.flags = *flags;
return report_size_and_time(callback_arg->extra.ctx, &dsize, dentry);
}
}
void fcfs_api_file_write_done_callback(FSAPIWriteDoneCallbackArg *callback_arg)
{
int flags;
fcfs_api_file_report_size_and_time((FCFSAPIWriteDoneCallbackArg *)
callback_arg, &flags, NULL);
}
/*
static inline void print_block_slice_key(FSBlockSliceKeyInfo *bs_key)
{
logInfo("block {oid: %"PRId64", offset: %"PRId64"}, "
"slice {offset: %d, length: %d}", bs_key->block.oid,
bs_key->block.offset, bs_key->slice.offset, bs_key->slice.length);
}
*/
static int do_pwrite(FCFSAPIFileInfo *fi, FSAPIWriteBuffer *wbuffer,
const int size, const int64_t offset, int *written_bytes,
int *total_inc_alloc, const bool need_report_modified,
const int64_t tid)
{
FSAPIOperationContext op_ctx;
FCFSAPIWriteDoneCallbackArg callback_arg;
SFDynamicIOVArray iova;
int64_t new_offset;
int loop_flags;
int result;
int remain;
FS_API_SET_CTX_AND_TID_EX(op_ctx, fi->ctx->contexts.fsapi, tid);
wbuffer->extra_data = &callback_arg.extra;
callback_arg.extra.ctx = fi->ctx;
*total_inc_alloc = *written_bytes = 0;
new_offset = offset;
fs_set_block_slice(&op_ctx.bs_key, fi->dentry.inode, offset, size);
loop_flags = 1;
if (wbuffer->is_writev) {
sf_iova_init(iova, wbuffer->iov, wbuffer->iovcnt);
if (op_ctx.bs_key.slice.length < size) {
if ((result=sf_iova_first_slice(&iova, op_ctx.
bs_key.slice.length)) != 0)
{
loop_flags = 0;
}
}
}
while (loop_flags) {
//print_block_slice_key(&op_ctx.bs_key);
callback_arg.arg.bs_key = &op_ctx.bs_key;
callback_arg.extra.file_size = fi->dentry.stat.size;
callback_arg.extra.space_end = fi->dentry.stat.space_end;
callback_arg.extra.last_modified_time = fi->write_notify.last_modified_time;
if ((result=fs_api_slice_write(&op_ctx, wbuffer, &callback_arg.
arg.write_bytes, &callback_arg.arg.inc_alloc)) != 0)
{
if (callback_arg.arg.write_bytes == 0) {
break;
}
}
new_offset += callback_arg.arg.write_bytes;
*written_bytes += callback_arg.arg.write_bytes;
*total_inc_alloc += callback_arg.arg.inc_alloc;
if (need_report_modified) {
int flags;
fcfs_api_file_report_size_and_time(&callback_arg,
&flags, &fi->dentry);
if ((flags & FDIR_DENTRY_FIELD_MODIFIED_FLAG_MTIME) != 0) {
fi->write_notify.last_modified_time = get_current_time();
}
}
remain = size - *written_bytes;
if (remain <= 0) {
break;
}
if (callback_arg.arg.write_bytes == op_ctx.bs_key.slice.length) {
/* fully completed */
fs_next_block_slice_key(&op_ctx.bs_key, remain);
} else { //partially completed, try again the remain part
fs_set_slice_size(&op_ctx.bs_key, new_offset, remain);
}
if (wbuffer->is_writev) {
if ((result=sf_iova_next_slice(&iova, *written_bytes,
op_ctx.bs_key.slice.length)) != 0)
{
break;
}
} else {
wbuffer->buff += *written_bytes;
}
}
if (wbuffer->is_writev) {
sf_iova_destroy(iova);
}
return (*written_bytes > 0) ? 0 : EIO;
}
static inline int check_writable(FCFSAPIFileInfo *fi)
{
if (fi->magic != FCFS_API_MAGIC_NUMBER || !((fi->flags & O_WRONLY) ||
(fi->flags & O_RDWR)))
{
return EBADF;
}
if (S_ISDIR(fi->dentry.stat.mode)) {
return EISDIR;
}
return (S_ISREG(fi->dentry.stat.mode) ? 0 : EPERM);
}
static inline int check_readable(FCFSAPIFileInfo *fi)
{
if (fi->magic != FCFS_API_MAGIC_NUMBER || (fi->flags & O_WRONLY)) {
return EBADF;
}
if (S_ISDIR(fi->dentry.stat.mode)) {
return EISDIR;
}
return (S_ISREG(fi->dentry.stat.mode) ? 0 : EPERM);
}
static int pwrite_wrapper(FCFSAPIFileInfo *fi, FSAPIWriteBuffer *wbuffer,
const int size, const int64_t offset, int *written_bytes,
const int64_t tid)
{
int total_inc_alloc;
int result;
if (size == 0) {
return 0;
} else if (size < 0) {
return EINVAL;
}
if ((result=check_writable(fi)) != 0) {
return result;
}
return do_pwrite(fi, wbuffer, size, offset, written_bytes,
&total_inc_alloc, true, tid);
}
int fcfs_api_pwrite_ex(FCFSAPIFileInfo *fi, const char *buff,
const int size, const int64_t offset, int *written_bytes,
const int64_t tid)
{
FSAPIWriteBuffer wbuffer;
FS_API_SET_WBUFFER_BUFF(wbuffer, buff);
return pwrite_wrapper(fi, &wbuffer, size, offset, written_bytes, tid);
}
static int do_write(FCFSAPIFileInfo *fi, FSAPIWriteBuffer *wbuffer,
const int size, int *written_bytes, const int64_t tid)
{
FDIRClientSession session;
FDIRSetDEntrySizeInfo dsize;
bool use_sys_lock;
int result;
int total_inc_alloc;
int64_t old_size;
int64_t space_end;
if (size == 0) {
return 0;
} else if (size < 0) {
return EINVAL;
}
if ((result=check_writable(fi)) != 0) {
return result;
}
use_sys_lock = fi->ctx->use_sys_lock_for_append &&
!fi->ctx->async_report.enabled && (fi->flags & O_APPEND);
if (use_sys_lock) {
if ((result=fcfs_api_dentry_sys_lock(&session, fi->dentry.inode,
0, &old_size, &space_end)) != 0)
{
return result;
}
fi->offset = old_size;
} else {
old_size = fi->dentry.stat.size;
}
if ((result=do_pwrite(fi, wbuffer, size, fi->offset, written_bytes,
&total_inc_alloc, !use_sys_lock, tid)) == 0)
{
fi->offset += *written_bytes;
}
if (use_sys_lock) {
string_t *ns;
if (fi->offset > old_size) {
ns = &fi->ctx->ns; //set ns for update file_size, space_end etc.
} else {
ns = NULL; //do NOT update
}
dsize.inode = fi->dentry.inode;
dsize.file_size = fi->offset;
dsize.inc_alloc = total_inc_alloc;
dsize.force = false;
dsize.flags = FDIR_DENTRY_FIELD_MODIFIED_FLAG_FILE_SIZE |
FDIR_DENTRY_FIELD_MODIFIED_FLAG_SPACE_END;
fcfs_api_dentry_sys_unlock(&session, ns, old_size, &dsize);
}
return result;
}
int fcfs_api_write_ex(FCFSAPIFileInfo *fi, const char *buff,
const int size, int *written_bytes, const int64_t tid)
{
FSAPIWriteBuffer wbuffer;
FS_API_SET_WBUFFER_BUFF(wbuffer, buff);
return do_write(fi, &wbuffer, size, written_bytes, tid);
}
int fcfs_api_pwritev_ex(FCFSAPIFileInfo *fi, const struct iovec *iov,
const int iovcnt, const int64_t offset, int *written_bytes,
const int64_t tid)
{
FSAPIWriteBuffer wbuffer;
FS_API_SET_WBUFFER_IOV(wbuffer, iov, iovcnt);
return pwrite_wrapper(fi, &wbuffer, fc_iov_get_bytes(iov, iovcnt),
offset, written_bytes, tid);
}
int fcfs_api_writev_ex(FCFSAPIFileInfo *fi, const struct iovec *iov,
const int iovcnt, int *written_bytes, const int64_t tid)
{
FSAPIWriteBuffer wbuffer;
FS_API_SET_WBUFFER_IOV(wbuffer, iov, iovcnt);
return do_write(fi, &wbuffer, fc_iov_get_bytes(iov, iovcnt),
written_bytes, tid);
}
static int do_pread(FCFSAPIFileInfo *fi, const bool is_readv,
const void *data, const int iovcnt, const int size,
const int64_t offset, int *read_bytes, const int64_t tid)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
FSAPIOperationContext op_ctx;
SFDynamicIOVArray iova;
FDIRClientOperInodePair oino;
int result;
int current_read;
int remain;
int64_t current_offset;
int64_t hole_bytes;
int fill_bytes;
*read_bytes = 0;
if (size == 0) {
return 0;
} else if (size < 0) {
return EINVAL;
}
if ((result=check_readable(fi)) != 0) {
return result;
}
FS_API_SET_CTX_AND_TID_EX(op_ctx, fi->ctx->contexts.fsapi, tid);
fs_set_block_slice(&op_ctx.bs_key, fi->dentry.inode, offset, size);
if (is_readv) {
sf_iova_init(iova, (struct iovec *)data, iovcnt);
}
while (1) {
//print_block_slice_key(&op_ctx.bs_key);
if (is_readv) {
result = fs_api_slice_readv(&op_ctx, iova.iov,
iova.cnt, ¤t_read);
} else {
result = fs_api_slice_read(&op_ctx, (char *)data +
(*read_bytes), ¤t_read);
}
if (result != 0) {
if (result == ENODATA) {
result = 0;
} else {
break;
}
}
while (current_read < op_ctx.bs_key.slice.length) {
/* deal file hole caused by ftruncate and lseek */
current_offset = offset + *read_bytes + current_read;
if (current_offset == fi->dentry.stat.size) {
break;
}
if (current_offset > fi->dentry.stat.size) {
FCFSAPI_SET_OPER_INODE_PAIR(oino, fi->oper, fi->dentry.inode);
if ((result=fcfs_api_stat_dentry_by_inode_ex(fi->ctx,
&oino, flags, &fi->dentry)) != 0)
{
break;
}
}
hole_bytes = fi->dentry.stat.size - current_offset;
if (hole_bytes > 0) {
if ((int64_t)current_read + hole_bytes > (int64_t)
op_ctx.bs_key.slice.length)
{
fill_bytes = op_ctx.bs_key.slice.length - current_read;
} else {
fill_bytes = hole_bytes;
}
/*
logInfo("=====offset: %"PRId64", current_read: %d, "
"hole_bytes: %"PRId64", fill_bytes: %d, "
"buff offset: %d =====", offset, current_read,
hole_bytes, fill_bytes, *read_bytes + current_read);
*/
if (is_readv) {
if ((result=sf_iova_memset(iova, 0, current_read,
fill_bytes)) != 0)
{
break;
}
} else {
memset((char *)data + (*read_bytes) +
current_read, 0, fill_bytes);
}
current_read += fill_bytes;
}
break;
}
/*
logInfo("current read: %d, total read: %d, slice length: %d",
current_read, *read_bytes, op_ctx.bs_key.slice.length);
*/
*read_bytes += current_read;
remain = size - *read_bytes;
if (remain <= 0 || current_read < op_ctx.bs_key.slice.length) {
break;
}
if (is_readv) {
if ((result=sf_iova_consume(&iova, current_read)) != 0) {
break;
}
}
fs_next_block_slice_key(&op_ctx.bs_key, remain);
}
if (is_readv) {
sf_iova_destroy(iova);
}
return result;
}
int fcfs_api_pread_ex(FCFSAPIFileInfo *fi, char *buff, const int size,
const int64_t offset, int *read_bytes, const int64_t tid)
{
const bool is_readv = false;
const int iovcnt = 0;
return do_pread(fi, is_readv, buff, iovcnt,
size, offset, read_bytes, tid);
}
int fcfs_api_read_ex(FCFSAPIFileInfo *fi, char *buff, const int size,
int *read_bytes, const int64_t tid)
{
const bool is_readv = false;
const int iovcnt = 0;
int result;
if ((result=do_pread(fi, is_readv, buff, iovcnt, size,
fi->offset, read_bytes, tid)) != 0)
{
return result;
}
fi->offset += *read_bytes;
return 0;
}
int fcfs_api_preadv_ex(FCFSAPIFileInfo *fi, const struct iovec *iov,
const int iovcnt, const int64_t offset, int *read_bytes,
const int64_t tid)
{
const bool is_readv = true;
return do_pread(fi, is_readv, iov, iovcnt,
fc_iov_get_bytes(iov, iovcnt),
offset, read_bytes, tid);
}
int fcfs_api_readv_ex(FCFSAPIFileInfo *fi, const struct iovec *iov,
const int iovcnt, int *read_bytes, const int64_t tid)
{
const bool is_readv = true;
int result;
if ((result=do_pread(fi, is_readv, iov, iovcnt,
fc_iov_get_bytes(iov, iovcnt),
fi->offset, read_bytes, tid)) != 0)
{
return result;
}
fi->offset += *read_bytes;
return 0;
}
static int do_truncate(FCFSAPIContext *ctx, const int64_t oid,
const int64_t old_space_end, const int64_t offset,
const int64_t length, int64_t *total_dec_alloc, const int64_t tid)
{
FSAPIOperationContext op_ctx;
int64_t remain;
int dec_alloc;
int result;
*total_dec_alloc = 0;
if (offset >= old_space_end) {
return 0;
}
if (offset + length > old_space_end) {
remain = old_space_end - offset;
} else {
remain = length;
}
FS_API_SET_CTX_AND_TID_EX(op_ctx, ctx->contexts.fsapi, tid);
fs_set_block_slice(&op_ctx.bs_key, oid, offset, remain);
while (1) {
//print_block_slice_key(&op_ctx.bs_key);
if (op_ctx.bs_key.slice.length == FS_FILE_BLOCK_SIZE) {
result = fs_api_block_delete(&op_ctx,
&dec_alloc);
} else {
result = fs_api_slice_delete(&op_ctx,
&dec_alloc);
}
if (result == 0) {
*total_dec_alloc -= dec_alloc;
} else if (result == ENOENT) {
result = 0;
} else if (result != 0) {
break;
}
remain -= op_ctx.bs_key.slice.length;
if (remain <= 0) {
break;
}
fs_next_block_slice_key(&op_ctx.bs_key, remain);
}
return result;
}
static int do_allocate(FCFSAPIContext *ctx, const int64_t oid,
const int64_t offset, const int64_t length,
int64_t *total_inc_alloc, const int64_t tid)
{
FSAPIOperationContext op_ctx;
int64_t remain;
int inc_alloc;
int result;
*total_inc_alloc = 0;
if (length <= 0) {
return 0;
}
FS_API_SET_CTX_AND_TID_EX(op_ctx, ctx->contexts.fsapi, tid);
remain = length;
fs_set_block_slice(&op_ctx.bs_key, oid, offset, remain);
while (1) {
//print_block_slice_key(&op_ctx.bs_key);
if ((result=fs_api_slice_allocate(&op_ctx, &inc_alloc)) != 0) {
break;
}
*total_inc_alloc += inc_alloc;
remain -= op_ctx.bs_key.slice.length;
if (remain <= 0) {
break;
}
fs_next_block_slice_key(&op_ctx.bs_key, remain);
}
return result;
}
static inline int check_and_sys_lock(FCFSAPIContext *ctx,
FDIRClientSession *session, const int64_t oid,
const FDIRDentryOperator *oper,
int64_t *old_size, int64_t *space_end)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
FDIRClientOperInodePair oino;
FDIRDEntryInfo dentry;
int result;
if (ctx->use_sys_lock_for_append && !ctx->async_report.enabled) {
result = fcfs_api_dentry_sys_lock(session,
oid, 0, old_size, space_end);
} else {
FCFSAPI_SET_OPER_INODE_PAIR(oino, *oper, oid);
if ((result=fcfs_api_stat_dentry_by_inode_ex(ctx,
&oino, flags, &dentry)) == 0)
{
*old_size = dentry.stat.size;
*space_end = dentry.stat.space_end;
}
}
return result;
}
static inline int check_and_sys_unlock(FCFSAPIContext *ctx,
FDIRClientSession *session, const int64_t old_size,
const FDIRSetDEntrySizeInfo *dsize, const int result)
{
if (ctx->use_sys_lock_for_append && !ctx->async_report.enabled) {
string_t *ns;
int unlock_res;
if (result == 0) {
ns = &ctx->ns; //set ns for update file_size, space_end etc.
} else {
ns = NULL; //do NOT update
}
unlock_res = fcfs_api_dentry_sys_unlock(session, ns, old_size, dsize);
return result == 0 ? unlock_res : result;
} else {
if (result == 0) {
return report_size_and_time(ctx, dsize, NULL);
} else {
return result;
}
}
}
static int file_truncate(FCFSAPIContext *ctx, const int64_t oid,
const int64_t new_size, const FDIRDentryOperator *oper,
const int64_t tid)
{
FDIRClientSession session;
FDIRSetDEntrySizeInfo dsize;
int64_t old_size;
int64_t space_end;
int result;
if (new_size < 0) {
return EINVAL;
}
if ((result=check_and_sys_lock(ctx, &session, oid,
oper, &old_size, &space_end)) != 0)
{
return result;
}
dsize.inode = oid;
dsize.file_size = new_size;
dsize.force = true;
if (new_size >= old_size) {
result = 0;
dsize.inc_alloc = 0;
if (new_size == old_size) {
dsize.flags = 0;
} else {
dsize.flags = FDIR_DENTRY_FIELD_MODIFIED_FLAG_FILE_SIZE;
}
} else {
result = do_truncate(ctx, oid, space_end, new_size,
old_size - new_size, &dsize.inc_alloc, tid);
dsize.flags = FDIR_DENTRY_FIELD_MODIFIED_FLAG_FILE_SIZE;
if (new_size < space_end) {
dsize.flags |= FDIR_DENTRY_FIELD_MODIFIED_FLAG_SPACE_END;
}
if (dsize.inc_alloc != 0) {
dsize.flags |= FDIR_DENTRY_FIELD_MODIFIED_FLAG_INC_ALLOC;
}
}
return check_and_sys_unlock(ctx, &session, old_size, &dsize, result);
}
int fcfs_api_ftruncate_ex(FCFSAPIFileInfo *fi, const int64_t new_size,
const int64_t tid)
{
int result;
if ((result=check_writable(fi)) != 0) {
return result;
}
return file_truncate(fi->ctx, fi->dentry.inode, new_size,
&fi->oper, tid);
}
static int get_regular_file_inode(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *fname, int64_t *inode)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
FDIRDEntryInfo dentry;
int result;
if ((result=fcfs_api_stat_dentry_by_fullname_ex(ctx, fname,
flags, LOG_DEBUG, &dentry)) != 0)
{
return result;
}
if (S_ISDIR(dentry.stat.mode)) {
return EISDIR;
}
*inode = dentry.inode;
return 0;
}
int fcfs_api_truncate_ex(FCFSAPIContext *ctx, const char *path,
const int64_t new_size, const FCFSAPIFileContext *fctx)
{
int result;
FDIRClientOperFnamePair fname;
int64_t inode;
FCFSAPI_SET_PATH_OPER_FNAME(fname, ctx, fctx->oper, path);
if ((result=get_regular_file_inode(ctx, &fname, &inode)) != 0) {
return result;
}
return file_truncate(ctx, inode, new_size, &fname.oper, fctx->tid);
}
int fcfs_api_file_truncate_ex(FCFSAPIContext *ctx,
const FDIRClientOperInodePair *oino,
const int64_t new_size, const int64_t tid,
FDIRDEntryInfo *dentry)
{
const int flags = FDIR_FLAGS_OUTPUT_DENTRY;
int result;
if ((result=fcfs_api_access_dentry_by_inode_ex(ctx,
oino, W_OK, flags, dentry)) != 0)
{
return result;
}
if (S_ISDIR(dentry->stat.mode)) {
return EISDIR;
}
return file_truncate(ctx, oino->inode, new_size, &oino->oper, tid);
}
#define calc_file_offset(fi, offset, whence, new_offset) \
calc_file_offset_ex(fi, offset, whence, false, new_offset)
static inline int calc_file_offset_ex(FCFSAPIFileInfo *fi,
const int64_t offset, const int whence,
const bool refresh_fsize, int64_t *new_offset)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
int result;
FDIRClientOperInodePair oino;
switch (whence) {
case SEEK_SET:
if (offset < 0) {
return EINVAL;
}
*new_offset = offset;
break;
case SEEK_CUR:
*new_offset = fi->offset + offset;
if (*new_offset < 0) {
return EINVAL;
}
break;
case SEEK_END:
if (refresh_fsize) {
FCFSAPI_SET_OPER_INODE_PAIR(oino, fi->oper, fi->dentry.inode);
if ((result=fcfs_api_stat_dentry_by_inode_ex(fi->ctx,
&oino, flags, &fi->dentry)) != 0)
{
return result;
}
}
*new_offset = fi->dentry.stat.size + offset;
if (*new_offset < 0) {
return EINVAL;
}
break;
default:
logError("file: "__FILE__", line: %d, "
"invalid whence: %d", __LINE__, whence);
return EINVAL;
}
return 0;
}
int fcfs_api_lseek(FCFSAPIFileInfo *fi, const int64_t offset, const int whence)
{
int64_t new_offset;
int result;
if (fi->magic != FCFS_API_MAGIC_NUMBER) {
return EBADF;
}
if ((result=calc_file_offset_ex(fi, offset, whence,
true, &new_offset)) != 0)
{
return result;
}
fi->offset = new_offset;
return 0;
}
void fcfs_api_fill_stat(const FDIRDEntryInfo *dentry, struct stat *stat)
{
stat->st_ino = dentry->inode;
stat->st_rdev = dentry->stat.rdev;
stat->st_mode = dentry->stat.mode;
stat->st_size = dentry->stat.size;
stat->st_atime = (uint32_t)dentry->stat.atime;
stat->st_mtime = (uint32_t)dentry->stat.mtime;
stat->st_ctime = (uint32_t)dentry->stat.ctime;
stat->st_uid = dentry->stat.uid;
stat->st_gid = dentry->stat.gid;
stat->st_nlink = dentry->stat.nlink;
stat->st_blksize = 512;
if (dentry->stat.alloc > 0) {
stat->st_blocks = (dentry->stat.alloc + stat->st_blksize - 1) /
stat->st_blksize;
}
}
int fcfs_api_fstat(FCFSAPIFileInfo *fi, struct stat *buf)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
int result;
FDIRClientOperInodePair oino;
if (fi->magic != FCFS_API_MAGIC_NUMBER) {
return EBADF;
}
FCFSAPI_SET_OPER_INODE_PAIR(oino, fi->oper, fi->dentry.inode);
if ((result=fcfs_api_stat_dentry_by_inode_ex(fi->ctx,
&oino, flags, &fi->dentry)) != 0)
{
return result;
}
memset(buf, 0, sizeof(struct stat));
fcfs_api_fill_stat(&fi->dentry, buf);
return 0;
}
static inline int fapi_stat(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path,
struct stat *buf, const int flags)
{
int result;
FDIRDEntryInfo dentry;
if ((result=fcfs_api_stat_dentry_by_fullname_ex(ctx,
path, flags, LOG_DEBUG, &dentry)) != 0)
{
return result;
}
memset(buf, 0, sizeof(struct stat));
fcfs_api_fill_stat(&dentry, buf);
return 0;
}
int fcfs_api_lstat_ex(FCFSAPIContext *ctx, const char *path,
const FDIRDentryOperator *oper, struct stat *buf)
{
const int flags = 0;
FDIRClientOperFnamePair fname;
FCFSAPI_SET_PATH_OPER_FNAME(fname, ctx, *oper, path);
return fapi_stat(ctx, &fname, buf, flags);
}
int fcfs_api_stat_ex(FCFSAPIContext *ctx, const char *path,
const FDIRDentryOperator *oper, struct stat *buf,
const int flags)
{
FDIRClientOperFnamePair fname;
FCFSAPI_SET_PATH_OPER_FNAME(fname, ctx, *oper, path);
return fapi_stat(ctx, &fname, buf, flags);
}
static inline int fcntl_lock(FCFSAPIFileInfo *fi, const int operation,
const int64_t offset, const int64_t length,
const int64_t owner_id, const pid_t pid)
{
int result;
FDIRFlockOwner owner;
FDIRClientOperInodePair oino;
if (fi->sessions.flock.mconn == NULL) {
if ((result=fdir_client_init_session(fi->ctx->contexts.
fdir, &fi->sessions.flock)) != 0)
{
return result;
}
}
FCFSAPI_SET_OPER_INODE_PAIR(oino, fi->oper, fi->dentry.inode);
owner.id = owner_id;
owner.pid = pid;
if ((result=fdir_client_flock_dentry_ex(&fi->sessions.flock,
&fi->ctx->ns, &oino, operation,
offset, length, &owner)) != 0)
{
return result;
}
return 0;
}
static inline int fcntl_unlock(FCFSAPIFileInfo *fi, const int operation,
const int64_t offset, const int64_t length,
const int64_t owner_id, const pid_t pid)
{
int result;
FDIRFlockOwner owner;
FDIRClientOperInodePair oino;
if (fi->sessions.flock.mconn == NULL) {
return 0;
}
FCFSAPI_SET_OPER_INODE_PAIR(oino, fi->oper, fi->dentry.inode);
owner.id = owner_id;
owner.pid = pid;
if ((result=fdir_client_flock_dentry_ex(&fi->sessions.flock,
&fi->ctx->ns, &oino, operation,
offset, length, &owner)) != 0)
{
return (result == ENOENT ? 0 : result);
}
return 0;
}
int fcfs_api_flock_ex2(FCFSAPIFileInfo *fi, const int operation,
const int64_t owner_id, const pid_t pid)
{
const int64_t offset = 0;
const int64_t length = 0;
if (fi->magic != FCFS_API_MAGIC_NUMBER) {
return EBADF;
}
if ((operation & LOCK_UN)) {
return fcntl_unlock(fi, operation, offset, length, owner_id, pid);
} else if ((operation & LOCK_SH) || (operation & LOCK_EX)) {
return fcntl_lock(fi, operation, offset, length, owner_id, pid);
} else {
return EINVAL;
}
}
static inline int fcntl_type_to_flock_op(const short type, int *operation)
{
switch (type) {
case F_RDLCK:
*operation = LOCK_SH;
break;
case F_WRLCK:
*operation = LOCK_EX;
break;
case F_UNLCK:
*operation = LOCK_UN;
break;
default:
return EINVAL;
}
return 0;
}
static inline int flock_op_to_fcntl_type(const int operation, short *type)
{
switch (operation) {
case LOCK_SH:
*type = F_RDLCK;
break;
case LOCK_EX:
*type = F_WRLCK;
break;
case LOCK_UN:
*type = F_UNLCK;
break;
default:
return EINVAL;
}
return 0;
}
int fcfs_api_setlk_ex(FCFSAPIFileInfo *fi, const struct flock *lock,
const int64_t owner_id, const bool blocked)
{
int operation;
int result;
int64_t offset;
if (fi->magic != FCFS_API_MAGIC_NUMBER) {
return EBADF;
}
if ((result=fcntl_type_to_flock_op(lock->l_type, &operation)) != 0) {
return result;
}
if ((result=calc_file_offset(fi, lock->l_start,
lock->l_whence, &offset)) != 0)
{
return result;
}
if (operation == LOCK_UN) {
return fcntl_unlock(fi, operation, offset,
lock->l_len, owner_id, lock->l_pid);
} else {
if (!blocked) {
operation |= LOCK_NB;
}
return fcntl_lock(fi, operation, offset, lock->l_len,
owner_id, lock->l_pid);
}
}
int fcfs_api_getlk_ex(FCFSAPIFileInfo *fi,
struct flock *lock, int64_t *owner_id)
{
int operation;
int result;
int64_t offset;
int64_t length;
FDIRClientOperInodePair oino;
FDIRFlockOwner owner;
if (fi->magic != FCFS_API_MAGIC_NUMBER) {
return EBADF;
}
if ((result=fcntl_type_to_flock_op(lock->l_type, &operation)) != 0) {
return result;
}
if (operation == LOCK_UN) {
return EINVAL;
}
if ((result=calc_file_offset(fi, lock->l_start,
lock->l_whence, &offset)) != 0)
{
return result;
}
FCFSAPI_SET_OPER_INODE_PAIR(oino, fi->oper, fi->dentry.inode);
length = lock->l_len;
owner.id = *owner_id;
owner.pid = lock->l_pid;
if ((result=fdir_client_getlk_dentry(fi->ctx->contexts.fdir,
&fi->ctx->ns, &oino, &operation,
&offset, &length, &owner)) == 0)
{
flock_op_to_fcntl_type(operation, &lock->l_type);
lock->l_whence = SEEK_SET;
lock->l_start = offset;
lock->l_len = length;
}
return result;
}
int fcfs_api_fallocate_ex(FCFSAPIFileInfo *fi, const int mode,
const int64_t offset, const int64_t length, const int64_t tid)
{
FDIRClientSession session;
FDIRSetDEntrySizeInfo dsize;
int64_t old_size;
int64_t space_end;
int op;
int result;
if (offset < 0 || length < 0) {
return EINVAL;
}
if ((result=check_writable(fi)) != 0) {
return result;
}
op = mode & (~FALLOC_FL_KEEP_SIZE);
if (!(op == 0 || op == FALLOC_FL_PUNCH_HOLE)) {
return EOPNOTSUPP;
}
if (length == 0) {
return 0;
}
if (fi->ctx->use_sys_lock_for_append && !fi->ctx->async_report.enabled) {
if ((result=fcfs_api_dentry_sys_lock(&session, fi->dentry.
inode, 0, &old_size, &space_end)) != 0)
{
return result;
}
} else {
old_size = fi->dentry.stat.size;
space_end = fi->dentry.stat.space_end;
}
dsize.inode = fi->dentry.inode;
dsize.force = true;
dsize.flags = 0;
if (op == 0) { //allocate space
result = do_allocate(fi->ctx, fi->dentry.inode,
offset, length, &dsize.inc_alloc, tid);
dsize.file_size = offset + length;
if (dsize.file_size > space_end) {
dsize.flags |= FDIR_DENTRY_FIELD_MODIFIED_FLAG_SPACE_END;
}
if (dsize.file_size > old_size) {
dsize.flags |= (mode & FALLOC_FL_KEEP_SIZE) ? 0 :
FDIR_DENTRY_FIELD_MODIFIED_FLAG_FILE_SIZE;
}
} else { //deallocate space
result = do_truncate(fi->ctx, fi->dentry.inode, space_end,
offset, length, &dsize.inc_alloc, tid);
if (offset + length >= old_size) {
dsize.file_size = offset;
dsize.flags |= (mode & FALLOC_FL_KEEP_SIZE) ? 0 :
FDIR_DENTRY_FIELD_MODIFIED_FLAG_FILE_SIZE;
if (dsize.file_size < space_end) {
dsize.flags |= FDIR_DENTRY_FIELD_MODIFIED_FLAG_SPACE_END;
}
} else {
if (offset < space_end && offset + length >= space_end) {
dsize.file_size = offset;
dsize.flags |= FDIR_DENTRY_FIELD_MODIFIED_FLAG_SPACE_END;
} else {
dsize.file_size = old_size;
}
}
}
if (dsize.inc_alloc != 0) {
dsize.flags |= FDIR_DENTRY_FIELD_MODIFIED_FLAG_INC_ALLOC;
}
return check_and_sys_unlock(fi->ctx, &session, old_size, &dsize, result);
}
int fcfs_api_rename_ex(FCFSAPIContext *ctx, const char *old_path,
const char *new_path, const int flags,
const FCFSAPIFileContext *fctx)
{
FDIRDEntryFullName src_fullname;
FDIRDEntryFullName dest_fullname;
FDIRDEntryInfo dentry;
FDIRDEntryInfo *pe;
int result;
src_fullname.ns = ctx->ns;
FC_SET_STRING(src_fullname.path, (char *)old_path);
dest_fullname.ns = ctx->ns;
FC_SET_STRING(dest_fullname.path, (char *)new_path);
pe = &dentry;
if ((result=fdir_client_rename_dentry_ex(ctx->contexts.fdir,
&src_fullname, &dest_fullname, &fctx->oper,
flags, &pe)) != 0)
{
return result;
}
if (pe != NULL && S_ISREG(pe->stat.mode) && pe->stat.nlink == 0
&& !ctx->contexts.fdir->trash_bin_enabled)
{
fs_api_unlink_file(ctx->contexts.fsapi, pe->inode,
pe->stat.space_end, fctx->tid);
}
return result;
}
int fcfs_api_symlink_ex(FCFSAPIContext *ctx, const char *target,
const char *path, const FDIRDentryOperator *oper,
const mode_t mode)
{
FDIRClientOperFnamePair fname;
string_t link;
FDIRDEntryInfo dentry;
FCFSAPI_SET_PATH_OPER_FNAME(fname, ctx, *oper, path);
FC_SET_STRING(link, (char *)target);
return fdir_client_symlink_dentry(ctx->contexts.fdir,
&link, &fname, mode, &dentry);
}
int fcfs_api_readlink(FCFSAPIContext *ctx, const char *path,
const FDIRDentryOperator *oper, char *buff, const int size)
{
FDIRClientOperFnamePair fname;
string_t link;
FCFSAPI_SET_PATH_OPER_FNAME(fname, ctx, *oper, path);
link.str = buff;
return fdir_client_readlink_by_path(ctx->contexts.fdir,
&fname, &link, size);
}
int fcfs_api_link_ex(FCFSAPIContext *ctx, const char *old_path,
const char *new_path, const FDIRDentryOperator *oper,
const mode_t mode, const int flags)
{
FDIRDEntryFullName src_fullname;
FDIRDEntryFullName dest_fullname;
FDIRDEntryInfo dentry;
src_fullname.ns = ctx->ns;
FC_SET_STRING(src_fullname.path, (char *)old_path);
dest_fullname.ns = ctx->ns;
FC_SET_STRING(dest_fullname.path, (char *)new_path);
return fdir_client_link_dentry(ctx->contexts.fdir, &src_fullname,
&dest_fullname, oper, mode, flags, &dentry);
}
int fcfs_api_mknod_ex(FCFSAPIContext *ctx, const char *path,
const FDIRDentryOperator *oper, const mode_t mode,
const dev_t dev)
{
FDIRClientOperFnamePair fname;
FDIRDEntryInfo dentry;
if (!(S_ISCHR(mode) || S_ISBLK(mode))) {
return EINVAL;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, ctx, *oper, path);
return fdir_client_create_dentry_ex(ctx->contexts.fdir,
&fname, mode, dev, &dentry);
}
static inline int do_make_dentry(FCFSAPIContext *ctx, const char *path,
FDIRDentryOperator *oper, const mode_t mode, const int mtype)
{
FDIRClientOperFnamePair fname;
FDIRDEntryInfo dentry;
FCFSAPI_SET_PATH_OPER_FNAME(fname, ctx, *oper, path);
return fdir_client_create_dentry(ctx->contexts.fdir,
&fname, ((mode & (~S_IFMT)) | mtype), &dentry);
}
int fcfs_api_mkfifo_ex(FCFSAPIContext *ctx, const char *path,
FDIRDentryOperator *oper, const mode_t mode)
{
return do_make_dentry(ctx, path, oper, mode, S_IFIFO);
}
int fcfs_api_mkdir_ex(FCFSAPIContext *ctx, const char *path,
FDIRDentryOperator *oper, const mode_t mode)
{
return do_make_dentry(ctx, path, oper, mode, S_IFDIR);
}
int fcfs_api_statvfs_ex(FCFSAPIContext *ctx, const char *path,
struct statvfs *stbuf)
{
int result;
FCFSAuthClientFullContext *auth;
int64_t quota;
int64_t total;
int64_t avail;
FDIRClientNamespaceStat nstat;
if (ctx->contexts.fdir->auth.enabled) {
auth = &ctx->contexts.fdir->auth;
} else if (ctx->contexts.fsapi->fs->auth.enabled) {
auth = &ctx->contexts.fsapi->fs->auth;
} else {
auth = NULL;
}
if (auth != NULL) {
if ((result=fcfs_auth_client_spool_get_quota(
auth->ctx, &ctx->ns, "a)) != 0)
{
return result;
}
} else {
quota = FCFS_AUTH_UNLIMITED_QUOTA_VAL;
}
if ((result=fdir_client_namespace_stat(ctx->contexts.
fdir, &ctx->ns, &nstat)) != 0)
{
return result;
}
if (quota == FCFS_AUTH_UNLIMITED_QUOTA_VAL) {
FSClusterSpaceStat sstat;
if ((result=fs_api_cluster_space_stat(ctx->
contexts.fsapi, &sstat)) != 0)
{
return result;
}
total = sstat.total;
avail = total - sstat.used;
} else {
total = quota;
avail = total - nstat.space.used;
}
if (avail < 0) {
avail = 0;
}
stbuf->f_bsize = stbuf->f_frsize = 512;
stbuf->f_blocks = total / stbuf->f_frsize;
stbuf->f_bavail = stbuf->f_bfree = avail / stbuf->f_frsize;
stbuf->f_files = nstat.inode.total;
stbuf->f_ffree = nstat.inode.total - nstat.inode.used;
stbuf->f_favail = nstat.inode.avail;
stbuf->f_namemax = NAME_MAX;
stbuf->f_fsid = 0;
stbuf->f_flag = 0;
return 0;
}
int fcfs_api_access_ex(FCFSAPIContext *ctx, const char *path,
const int mask, const FDIRDentryOperator *oper,
const int flags)
{
FDIRClientOperFnamePair fname;
FDIRDEntryInfo dentry;
FCFSAPI_SET_PATH_OPER_FNAME(fname, ctx, *oper, path);
return fcfs_api_access_dentry_by_path_ex(ctx,
&fname, mask, flags, &dentry);
}
int fcfs_api_euidaccess_ex(FCFSAPIContext *ctx, const char *path,
const int mask, const FDIRDentryOperator *oper,
const int flags)
{
FDIRClientOperFnamePair fname;
FDIRDEntryInfo dentry;
FCFSAPI_SET_PATH_OPER_FNAME(fname, ctx, *oper, path);
return fcfs_api_access_dentry_by_path_ex(ctx,
&fname, mask, flags, &dentry);
}
int fcfs_api_set_file_flags(FCFSAPIFileInfo *fi, const int flags)
{
/*
if (flags & (O_ASYNC | O_DIRECT | O_NOATIME | O_NONBLOCK)) {
logInfo("set flags: %d, is O_DIRECT: %d, is O_NOATIME: %d, "
"is O_NONBLOCK: %d", flags, (flags & O_DIRECT),
(flags & O_NOATIME), (flags & O_NONBLOCK));
}
*/
if ((flags & O_APPEND) == 0) {
return 0;
}
if (!((fi->flags & O_WRONLY) || (fi->flags & O_RDWR))) {
return EBADF;
}
fi->flags |= O_APPEND;
fi->offset = fi->dentry.stat.size;
return 0;
}
================================================
FILE: src/api/fcfs_api_file.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_API_FILE_H
#define _FCFS_API_FILE_H
#include
#include
#include
#include
#include
#include
#include "fcfs_api_types.h"
#include "fcfs_api_util.h"
#ifndef FALLOC_FL_KEEP_SIZE
#define FALLOC_FL_KEEP_SIZE 0x01
#endif
#ifndef FALLOC_FL_PUNCH_HOLE
#define FALLOC_FL_PUNCH_HOLE 0x02
#endif
#ifdef O_SYMLINK
#define FCFS_API_NOFOLLOW_SYMLINK_FLAGS (O_NOFOLLOW | O_SYMLINK)
#else
#define FCFS_API_NOFOLLOW_SYMLINK_FLAGS (O_NOFOLLOW)
#endif
#define FCFS_API_GET_ACCESS_FLAGS(open_flags) \
((((open_flags) & FCFS_API_NOFOLLOW_SYMLINK_FLAGS) != 0) ? \
FDIR_FLAGS_OUTPUT_DENTRY : (FDIR_FLAGS_FOLLOW_SYMLINK | \
FDIR_FLAGS_OUTPUT_DENTRY))
#define FCFS_API_GET_ACCESS_MASK(open_flags) \
(((open_flags) & O_WRONLY) ? W_OK : (((open_flags) & O_RDWR) ? \
(R_OK | W_OK) : R_OK))
#ifdef __cplusplus
extern "C" {
#endif
#define fcfs_api_create(fi, path, fctx) \
fcfs_api_create_ex(&g_fcfs_api_ctx, fi, path, fctx)
#define fcfs_api_open(fi, path, flags, fctx) \
fcfs_api_open_ex(&g_fcfs_api_ctx, fi, path, flags, fctx)
#define fcfs_api_open_by_inode(fi, inode, flags, fctx) \
fcfs_api_open_by_inode_ex(&g_fcfs_api_ctx, fi, inode, flags, fctx)
#define fcfs_api_open_by_dentry(fi, dentry, flags, fctx) \
fcfs_api_open_by_dentry_ex(&g_fcfs_api_ctx, fi, dentry, flags, fctx)
#define fcfs_api_write(fi, buff, size, written_bytes) \
fcfs_api_write_ex(fi, buff, size, written_bytes, (fi)->tid)
#define fcfs_api_pwrite(fi, buff, size, offset, written_bytes) \
fcfs_api_pwrite_ex(fi, buff, size, offset, written_bytes, (fi)->tid)
#define fcfs_api_read(fi, buff, size, read_bytes) \
fcfs_api_read_ex(fi, buff, size, read_bytes, (fi)->tid)
#define fcfs_api_pread(fi, buff, size, offset, read_bytes) \
fcfs_api_pread_ex(fi, buff, size, offset, read_bytes, (fi)->tid)
#define fcfs_api_writev(fi, iov, iovcnt, written_bytes) \
fcfs_api_writev_ex(fi, iov, iovcnt, written_bytes, (fi)->tid)
#define fcfs_api_pwritev(fi, iov, iovcnt, offset, written_bytes) \
fcfs_api_pwritev_ex(fi, iov, iovcnt, offset, written_bytes, (fi)->tid)
#define fcfs_api_readv(fi, iov, iovcnt, read_bytes) \
fcfs_api_readv_ex(fi, iov, iovcnt, read_bytes, (fi)->tid)
#define fcfs_api_preadv(fi, iov, iovcnt, offset, read_bytes) \
fcfs_api_preadv_ex(fi, iov, iovcnt, offset, read_bytes, (fi)->tid)
#define fcfs_api_ftruncate(fi, new_size) \
fcfs_api_ftruncate_ex(fi, new_size, getpid())
#define fcfs_api_truncate(path, new_size, fctx) \
fcfs_api_truncate_ex(&g_fcfs_api_ctx, path, new_size, fctx)
#define fcfs_api_file_truncate(oino, new_size, tid, dentry) \
fcfs_api_file_truncate_ex(&g_fcfs_api_ctx, oino, new_size, tid, dentry)
#define fcfs_api_unlink(path, tid) \
fcfs_api_unlink_ex(&g_fcfs_api_ctx, path, tid)
#define fcfs_api_stat(path, oper, buf, flags) \
fcfs_api_stat_ex(&g_fcfs_api_ctx, path, oper, buf, flags)
#define fcfs_api_lstat(path, oper, buf) \
fcfs_api_lstat_ex(&g_fcfs_api_ctx, path, oper, buf)
#define fcfs_api_rename(old_path, new_path, fctx) \
fcfs_api_rename_ex(&g_fcfs_api_ctx, old_path, new_path, 0, fctx)
#define fcfs_api_statvfs(path, stbuf) \
fcfs_api_statvfs_ex(&g_fcfs_api_ctx, path, stbuf)
int fcfs_api_open_ex(FCFSAPIContext *ctx, FCFSAPIFileInfo *fi,
const char *path, const int flags,
const FCFSAPIFileContext *fctx);
int fcfs_api_open_by_inode_ex(FCFSAPIContext *ctx, FCFSAPIFileInfo *fi,
const int64_t inode, const int flags,
const FCFSAPIFileContext *fctx);
int fcfs_api_open_by_dentry_ex(FCFSAPIContext *ctx, FCFSAPIFileInfo *fi,
const FDIRDEntryInfo *dentry, const int flags,
const FCFSAPIFileContext *fctx);
static inline int fcfs_api_create_ex(FCFSAPIContext *ctx,
FCFSAPIFileInfo *fi, const char *path,
const FCFSAPIFileContext *fctx)
{
const int flags = O_CREAT | O_TRUNC | O_WRONLY;
return fcfs_api_open_ex(ctx, fi, path, flags, fctx);
}
int fcfs_api_close(FCFSAPIFileInfo *fi);
void fcfs_api_file_write_done_callback(
FSAPIWriteDoneCallbackArg *callback_arg);
int fcfs_api_pwrite_ex(FCFSAPIFileInfo *fi, const char *buff,
const int size, const int64_t offset, int *written_bytes,
const int64_t tid);
int fcfs_api_write_ex(FCFSAPIFileInfo *fi, const char *buff,
const int size, int *written_bytes, const int64_t tid);
int fcfs_api_pread_ex(FCFSAPIFileInfo *fi, char *buff, const int size,
const int64_t offset, int *read_bytes, const int64_t tid);
int fcfs_api_read_ex(FCFSAPIFileInfo *fi, char *buff,
const int size, int *read_bytes, const int64_t tid);
int fcfs_api_pwritev_ex(FCFSAPIFileInfo *fi, const struct iovec *iov,
const int iovcnt, const int64_t offset, int *written_bytes,
const int64_t tid);
int fcfs_api_writev_ex(FCFSAPIFileInfo *fi, const struct iovec *iov,
const int iovcnt, int *written_bytes, const int64_t tid);
int fcfs_api_preadv_ex(FCFSAPIFileInfo *fi, const struct iovec *iov,
const int iovcnt, const int64_t offset, int *read_bytes,
const int64_t tid);
int fcfs_api_readv_ex(FCFSAPIFileInfo *fi, const struct iovec *iov,
const int iovcnt, int *read_bytes, const int64_t tid);
int fcfs_api_file_truncate_ex(FCFSAPIContext *ctx,
const FDIRClientOperInodePair *oino,
const int64_t new_size, const int64_t tid,
FDIRDEntryInfo *dentry);
int fcfs_api_ftruncate_ex(FCFSAPIFileInfo *fi, const int64_t new_size,
const int64_t tid);
int fcfs_api_truncate_ex(FCFSAPIContext *ctx, const char *path,
const int64_t new_size, const FCFSAPIFileContext *fctx);
int fcfs_api_fallocate_ex(FCFSAPIFileInfo *fi, const int mode,
const int64_t offset, const int64_t len, const int64_t tid);
static inline int fcfs_api_unlink_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path, const int64_t tid)
{
const int flags = FDIR_UNLINK_FLAGS_MATCH_FILE;
return fcfs_api_remove_dentry_ex(ctx, path, flags, tid);
}
int fcfs_api_lseek(FCFSAPIFileInfo *fi, const int64_t offset,
const int whence);
void fcfs_api_fill_stat(const FDIRDEntryInfo *dentry, struct stat *stat);
int fcfs_api_fstat(FCFSAPIFileInfo *fi, struct stat *buf);
int fcfs_api_lstat_ex(FCFSAPIContext *ctx, const char *path,
const FDIRDentryOperator *oper, struct stat *buf);
int fcfs_api_stat_ex(FCFSAPIContext *ctx, const char *path,
const FDIRDentryOperator *oper, struct stat *buf,
const int flags);
int fcfs_api_flock_ex2(FCFSAPIFileInfo *fi, const int operation,
const int64_t owner_id, const pid_t pid);
static inline int fcfs_api_flock_ex(FCFSAPIFileInfo *fi,
const int operation, const int64_t owner_id)
{
return fcfs_api_flock_ex2(fi, operation, owner_id, getpid());
}
static inline int fcfs_api_flock(FCFSAPIFileInfo *fi, const int operation)
{
return fcfs_api_flock_ex2(fi, operation,
(long)pthread_self(), getpid());
}
int fcfs_api_getlk_ex(FCFSAPIFileInfo *fi, struct flock *lock,
int64_t *owner_id);
static inline int fcfs_api_getlk(FCFSAPIFileInfo *fi, struct flock *lock)
{
int64_t owner_id;
return fcfs_api_getlk_ex(fi, lock, &owner_id);
}
int fcfs_api_setlk_ex(FCFSAPIFileInfo *fi, const struct flock *lock,
const int64_t owner_id, const bool blocked);
static inline int fcfs_api_setlk(FCFSAPIFileInfo *fi,
const struct flock *lock)
{
const bool blocked = false;
int64_t owner_id;
owner_id = fc_gettid();
return fcfs_api_setlk_ex(fi, lock, owner_id, blocked);
}
static inline int fcfs_api_setlkw(FCFSAPIFileInfo *fi,
const struct flock *lock)
{
const bool blocked = true;
int64_t owner_id;
owner_id = fc_gettid();
return fcfs_api_setlk_ex(fi, lock, owner_id, blocked);
}
int fcfs_api_rename_ex(FCFSAPIContext *ctx, const char *old_path,
const char *new_path, const int flags,
const FCFSAPIFileContext *fctx);
int fcfs_api_symlink_ex(FCFSAPIContext *ctx, const char *target,
const char *path, const FDIRDentryOperator *oper,
const mode_t mode);
int fcfs_api_readlink(FCFSAPIContext *ctx, const char *path,
const FDIRDentryOperator *oper, char *buff, const int size);
int fcfs_api_link_ex(FCFSAPIContext *ctx, const char *old_path,
const char *new_path, const FDIRDentryOperator *oper,
const mode_t mode, const int flags);
int fcfs_api_mknod_ex(FCFSAPIContext *ctx, const char *path,
const FDIRDentryOperator *oper, const mode_t mode,
const dev_t dev);
int fcfs_api_mkfifo_ex(FCFSAPIContext *ctx, const char *path,
FDIRDentryOperator *oper, const mode_t mode);
int fcfs_api_mkdir_ex(FCFSAPIContext *ctx, const char *path,
FDIRDentryOperator *oper, const mode_t mode);
int fcfs_api_access_ex(FCFSAPIContext *ctx, const char *path,
const int mask, const FDIRDentryOperator *oper,
const int flags);
int fcfs_api_euidaccess_ex(FCFSAPIContext *ctx, const char *path,
const int mask, const FDIRDentryOperator *oper,
const int flags);
static inline int fcfs_api_eaccess_ex(FCFSAPIContext *ctx,
const char *path, const int mask,
const FDIRDentryOperator *oper,
const int flags)
{
return fcfs_api_euidaccess_ex(ctx, path, mask, oper, flags);
}
int fcfs_api_statvfs_ex(FCFSAPIContext *ctx, const char *path,
struct statvfs *stbuf);
int fcfs_api_set_file_flags(FCFSAPIFileInfo *fi, const int flags);
static inline int fcfs_api_fdatasync(FCFSAPIFileInfo *fi,
const int64_t tid)
{
fs_api_datasync(fi->ctx->contexts.fsapi, fi->dentry.inode, tid);
return 0;
}
static inline int fcfs_api_fsync(FCFSAPIFileInfo *fi, const int64_t tid)
{
fs_api_datasync(fi->ctx->contexts.fsapi, fi->dentry.inode, tid);
if (fi->ctx->async_report.enabled) {
inode_htable_check_conflict_and_wait(fi->dentry.inode);
}
return 0;
}
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/api/fcfs_api_types.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_API_TYPES_H
#define _FCFS_API_TYPES_H
#include
#include
#include
#include "fastcommon/fast_mblock.h"
#include "fastcommon/fast_buffer.h"
#include "fastdir/client/fdir_client.h"
#include "fastsore/api/fs_api.h"
#define FCFS_FUSE_DEFAULT_CONFIG_FILENAME "/etc/fastcfs/fcfs/fuse.conf"
typedef enum {
fcfs_api_owner_type_caller,
fcfs_api_owner_type_fixed
} FCFSAPIOwnerType;
typedef struct fcfs_api_owner_info {
FCFSAPIOwnerType type;
FDIRDentryOperator oper;
} FCFSAPIOwnerInfo;
typedef struct fcfs_api_ns_mountpoint_holder {
char *ns;
char *mountpoint;
} FCFSAPINSMountpointHolder;
typedef struct fcfs_api_opendir_session {
FDIRClientDentryArray array;
int btype; //buffer type
FastBuffer buffer;
} FCFSAPIOpendirSession;
typedef struct fcfs_api_context {
/* whether FCFSAPIFileInfo object persist additional gids */
bool persist_additional_gids;
bool use_sys_lock_for_append;
struct {
bool enabled;
bool busy_polling; //for RDMA
} rdma;
struct {
bool enabled;
int interval_ms;
int shared_allocator_count;
int hashtable_sharding_count;
int64_t hashtable_total_capacity;
} async_report;
string_t ns; //namespace
char ns_holder[NAME_MAX];
FCFSAPIOwnerInfo owner;
struct {
FDIRClientContext *fdir;
FSAPIContext *fsapi;
} contexts;
struct fast_mblock_man opendir_session_pool;
} FCFSAPIContext;
typedef struct fcfs_api_file_info {
FCFSAPIContext *ctx;
FDIRDentryOperator oper;
int64_t tid;
struct {
FDIRClientSession flock;
FCFSAPIOpendirSession *opendir;
} sessions;
FDIRDEntryInfo dentry;
int flags;
int magic;
struct {
int last_modified_time;
} write_notify;
int64_t offset; //current offset
char fixed_groups_buff[256]; //for additional gids
} FCFSAPIFileInfo;
typedef struct fcfs_api_file_context {
FDIRDentryOperator oper;
mode_t mode;
int64_t tid;
} FCFSAPIFileContext;
typedef struct fcfs_api_write_done_callback_extra_data {
FCFSAPIContext *ctx;
int64_t file_size;
int64_t space_end;
int last_modified_time;
} FCFSAPIWriteDoneCallbackExtraData;
typedef struct fcfs_api_write_done_callback_arg {
FSAPIWriteDoneCallbackArg arg; //must be the first
FCFSAPIWriteDoneCallbackExtraData extra;
} FCFSAPIWriteDoneCallbackArg;
struct fcfs_api_inode_hentry;
struct fcfs_api_insert_event_context;
typedef struct fcfs_api_waiting_task {
pthread_lock_cond_pair_t lcp; //for notify
bool finished;
struct fast_mblock_man *allocator; //for free
struct fcfs_api_waiting_task *next; //for event waitings queue
} FCFSAPIWaitingTask;
typedef enum {
fcfs_api_event_type_report,
fcfs_api_event_type_notify
} FCFSAPIEventType;
typedef struct fcfs_api_async_report_event {
FCFSAPIEventType type;
int id; //used by async_reporter for stable sort
FDIRSetDEntrySizeInfo dsize;
struct fcfs_api_inode_hentry *inode_hentry;
struct {
FCFSAPIWaitingTask *head; //use lock of inode sharding
} waitings;
struct fc_list_head dlink; //for inode sharding htable
struct fast_mblock_man *allocator; //for free
struct fcfs_api_async_report_event *next; //for async_reporter's queue
} FCFSAPIAsyncReportEvent;
typedef struct fcfs_api_async_report_event_ptr_array {
int alloc;
int count;
FCFSAPIAsyncReportEvent **events;
} FCFSAPIAsyncReportEventPtrArray;
#define FCFS_API_SET_OPERATOR(_oper, _owner, _uid, _gid) \
do { \
if ((_owner).type == fcfs_api_owner_type_fixed) { \
_oper = (_owner).oper; \
} else { \
FDIR_SET_OPERATOR(_oper, _uid, _gid, 0, NULL); \
} \
} while (0)
#define FCFS_API_SET_FCTX(fctx, _oper, _mode, _tid) \
fctx.oper = _oper; \
fctx.mode = _mode; \
fctx.tid = _tid
#ifdef __cplusplus
extern "C" {
#endif
extern FCFSAPIContext g_fcfs_api_ctx;
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/api/fcfs_api_util.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include "fastcommon/shared_func.h"
#include "fastcommon/logger.h"
#include "fastcommon/sockopt.h"
#include "fastcommon/sched_thread.h"
#include "fcfs_api_util.h"
int fcfs_api_remove_dentry_by_pname_ex(FCFSAPIContext *ctx,
const FDIRClientOperPnamePair *opname,
const int flags, const int64_t tid)
{
FDIRDEntryInfo dentry;
int result;
if ((result=fdir_client_remove_dentry_by_pname_ex(
ctx->contexts.fdir, &ctx->ns, opname,
flags, &dentry)) != 0)
{
return result;
}
if (S_ISREG(dentry.stat.mode) && dentry.stat.nlink == 0
&& !ctx->contexts.fdir->trash_bin_enabled)
{
result = fs_api_unlink_file(ctx->contexts.fsapi,
dentry.inode, dentry.stat.space_end, tid);
}
return result;
}
int fcfs_api_remove_dentry_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path,
const int flags, const int64_t tid)
{
FDIRDEntryInfo dentry;
int result;
if ((result=fdir_client_remove_dentry_ex(ctx->contexts.fdir,
path, flags, &dentry)) != 0)
{
return result;
}
if (S_ISREG(dentry.stat.mode) && dentry.stat.nlink == 0
&& !ctx->contexts.fdir->trash_bin_enabled)
{
result = fs_api_unlink_file(ctx->contexts.fsapi,
dentry.inode, dentry.stat.space_end, tid);
}
return result;
}
int fcfs_api_rename_dentry_by_pname_ex(FCFSAPIContext *ctx,
const int64_t src_parent_inode, const string_t *src_name,
const int64_t dest_parent_inode, const string_t *dest_name,
const FDIRDentryOperator *oper, const int flags, const int64_t tid)
{
FDIRDEntryPName src_pname;
FDIRDEntryPName dest_pname;
FDIRDEntryInfo dentry;
FDIRDEntryInfo *pe;
int result;
FDIR_SET_DENTRY_PNAME_PTR(&src_pname, src_parent_inode, src_name);
FDIR_SET_DENTRY_PNAME_PTR(&dest_pname, dest_parent_inode, dest_name);
pe = &dentry;
if ((result=fdir_client_rename_dentry_by_pname_ex(ctx->contexts.fdir,
&ctx->ns, &src_pname, &ctx->ns, &dest_pname, oper,
flags, &pe)) != 0)
{
return result;
}
if (pe != NULL && S_ISREG(pe->stat.mode) && pe->stat.nlink == 0
&& !ctx->contexts.fdir->trash_bin_enabled)
{
fs_api_unlink_file(ctx->contexts.fsapi, pe->inode,
pe->stat.space_end, tid);
}
return result;
}
int fcfs_api_rename_dentry_ex(FCFSAPIContext *ctx, const char *path1,
const char *path2, const FDIRDentryOperator *oper,
const int flags, const int64_t tid)
{
FDIRDEntryFullName src;
FDIRDEntryFullName dest;
FDIRDEntryInfo dentry;
FDIRDEntryInfo *pe;
int result;
FCFSAPI_SET_PATH_FULLNAME(src, ctx, path1);
FCFSAPI_SET_PATH_FULLNAME(dest, ctx, path2);
pe = &dentry;
if ((result=fdir_client_rename_dentry_ex(ctx->contexts.fdir,
&src, &dest, oper, flags, &pe)) != 0)
{
return result;
}
if (pe != NULL && S_ISREG(pe->stat.mode) && pe->stat.nlink == 0
&& !ctx->contexts.fdir->trash_bin_enabled)
{
fs_api_unlink_file(ctx->contexts.fsapi, pe->inode,
pe->stat.space_end, tid);
}
return result;
}
================================================
FILE: src/api/fcfs_api_util.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_API_UTIL_H
#define _FCFS_API_UTIL_H
#include
#include
#include "fastcommon/logger.h"
#include "fcfs_api_types.h"
#include "inode_htable.h"
#include "async_reporter.h"
#ifdef __cplusplus
extern "C" {
#endif
#define FCFSAPI_SET_PATH_FULLNAME(fullname, ctx, path_str) \
fullname.ns = (ctx)->ns; \
FC_SET_STRING(fullname.path, (char *)path_str)
#define FCFSAPI_SET_PATH_OPER_FNAME_EX(fname, ctx, \
_uid, _gid, _gcount, _glist, path_str) \
FDIR_SET_OPERATOR(fname.oper, _uid, _gid, _gcount, _glist); \
FCFSAPI_SET_PATH_FULLNAME(fname.fullname, ctx, path_str)
#define FCFSAPI_SET_PATH_OPER_FNAME(fname, ctx, _oper, path_str) \
fname.oper = _oper; \
FCFSAPI_SET_PATH_FULLNAME(fname.fullname, ctx, path_str)
#define FCFSAPI_SET_PATH_OPER_PNAME_EX(opname, _uid, _gid, \
_gcount, _glist, parent_inode, name) \
FDIR_SET_OPERATOR(opname.oper, _uid, _gid, _gcount, _glist); \
FDIR_SET_DENTRY_PNAME_PTR(&opname.pname, parent_inode, name)
#define FCFSAPI_SET_PATH_OPER_PNAME(opname, _oper, parent_inode, name) \
opname.oper = _oper; \
FDIR_SET_DENTRY_PNAME_PTR(&opname.pname, parent_inode, name)
#define FCFSAPI_SET_PATH_OPER_PNAME1(opname, _uid, _gid, \
_gcount, _glist, parent_inode, name) \
FDIR_SET_OPERATOR(opname.oper, _uid, _gid, _gcount, _glist); \
FDIR_SET_DENTRY_PNAME_STR(&opname.pname, parent_inode, name)
#define FCFSAPI_SET_OPER_INODE_PAIR_EX(oino, \
_uid, _gid, _gcount, _glist, _inode) \
FDIR_SET_OPERATOR(fname.oper, _uid, _gid, _gcount, _glist); \
oino.inode = _inode
#define FCFSAPI_SET_OPER_INODE_PAIR(oino, _oper, _inode) \
oino.oper = _oper; \
oino.inode = _inode
#define fcfs_api_lookup_inode_by_path(path, oper, inode) \
fcfs_api_lookup_inode_by_path_ex(&g_fcfs_api_ctx, path, \
oper, LOG_DEBUG, inode)
#define fcfs_api_stat_dentry_by_path(path, flags, dentry) \
fcfs_api_stat_dentry_by_path_ex(&g_fcfs_api_ctx, \
path, flags, LOG_DEBUG, dentry)
#define fcfs_api_stat_dentry_by_fullname(fullname, flags, dentry) \
fcfs_api_stat_dentry_by_fullname_ex(&g_fcfs_api_ctx, \
fullname, flags, LOG_DEBUG, dentry)
#define fcfs_api_stat_dentry_by_inode(inode, flags, dentry) \
fcfs_api_stat_dentry_by_inode_ex(&g_fcfs_api_ctx, inode, flags, dentry)
#define fcfs_api_stat_dentry_by_pname(opname, flags, dentry) \
fcfs_api_stat_dentry_by_pname_ex(&g_fcfs_api_ctx, opname, \
flags, LOG_DEBUG, dentry)
#define fcfs_api_access_dentry_by_path(path, mask, flags, dentry) \
fcfs_api_access_dentry_by_path_ex(&g_fcfs_api_ctx, \
path, mask, flags, dentry)
#define fcfs_api_access_dentry_by_inode(oino, mask, flags, dentry) \
fcfs_api_access_dentry_by_inode_ex(&g_fcfs_api_ctx, \
oino, mask, flags, dentry)
#define fcfs_api_access_dentry_by_pname(opname, mask, flags, dentry) \
fcfs_api_access_dentry_by_pname_ex(&g_fcfs_api_ctx, \
opname, mask, flags, dentry)
#define fcfs_api_create_dentry_by_pname(parent_inode, name, oper, rdev, dentry) \
fcfs_api_create_dentry_by_pname_ex(&g_fcfs_api_ctx, \
parent_inode, name, oper, rdev, dentry)
#define fcfs_api_symlink_dentry_by_pname(link, parent_inode, name, oper, dentry)\
fcfs_api_symlink_dentry_by_pname_ex(&g_fcfs_api_ctx, link, \
parent_inode, name, oper, dentry)
#define fcfs_api_readlink_by_pname(parent_inode, name, link, size) \
fcfs_api_readlink_by_pname_ex(&g_fcfs_api_ctx, parent_inode, \
name, link, size)
#define fcfs_api_readlink_by_inode(inode, link, size) \
fcfs_api_readlink_by_inode_ex(&g_fcfs_api_ctx, inode, link, size)
#define fcfs_api_link_dentry_by_pname(src_inode, dest_parent_inode, \
dest_name, oper, flags, dentry) \
fcfs_api_link_dentry_by_pname_ex(&g_fcfs_api_ctx, src_inode, \
dest_parent_inode, dest_name, oper, flags, dentry)
#define fcfs_api_remove_dentry_by_pname(opname, flags, tid) \
fcfs_api_remove_dentry_by_pname_ex(&g_fcfs_api_ctx, \
opname, flags, tid)
#define fcfs_api_remove_dentry(path, flags, tid) \
fcfs_api_remove_dentry_ex(&g_fcfs_api_ctx, path, flags, tid)
#define fcfs_api_rename_dentry_by_pname(src_parent_inode, src_name, \
dest_parent_inode, dest_name, oper, flags, tid) \
fcfs_api_rename_dentry_by_pname_ex(&g_fcfs_api_ctx, src_parent_inode, \
src_name, dest_parent_inode, dest_name, oper, flags, tid)
#define fcfs_api_rename_dentry(path1, path2, flags, tid) \
fcfs_api_rename_dentry_ex(&g_fcfs_api_ctx, \
path1, path2, flags, tid)
#define fcfs_api_modify_stat_by_inode(oino, attr, mflags, flags, dentry) \
fcfs_api_modify_stat_by_inode_ex(&g_fcfs_api_ctx, \
oino, attr, mflags, flags, dentry)
#define fcfs_api_set_xattr_by_inode(inode, xattr, flags) \
fcfs_api_set_xattr_by_inode_ex(&g_fcfs_api_ctx, inode, xattr, flags)
#define fcfs_api_set_xattr_by_path(path, xattr, flags) \
fcfs_api_set_xattr_by_path_ex(&g_fcfs_api_ctx, path, xattr, flags)
#define fcfs_api_remove_xattr_by_inode(inode, name, flags) \
fcfs_api_remove_xattr_by_inode_ex(&g_fcfs_api_ctx, inode, name, flags)
#define fcfs_api_remove_xattr_by_path(path, name, flags) \
fcfs_api_remove_xattr_by_path_ex(&g_fcfs_api_ctx, path, name, flags)
#define fcfs_api_get_xattr_by_inode(inode, name, value, size, flags) \
fcfs_api_get_xattr_by_inode_ex(&g_fcfs_api_ctx, inode, \
name, LOG_DEBUG, value, size, flags)
#define fcfs_api_get_xattr_by_path(path, name, value, size, flags) \
fcfs_api_get_xattr_by_path_ex(&g_fcfs_api_ctx, path, \
name, LOG_DEBUG, value, size, flags)
#define fcfs_api_list_xattr_by_inode(inode, list, size, flags) \
fcfs_api_list_xattr_by_inode_ex(&g_fcfs_api_ctx, inode, list, size, flags)
#define fcfs_api_list_xattr_by_path(path, list, size, flags) \
fcfs_api_list_xattr_by_path_ex(&g_fcfs_api_ctx, path, list, size, flags)
#define fcfs_api_list_dentry_by_inode(inode, array) \
fcfs_api_list_dentry_by_inode_ex(&g_fcfs_api_ctx, inode, array)
#define fcfs_api_list_compact_dentry_by_path(path, array) \
fcfs_api_list_compact_dentry_by_path_ex(&g_fcfs_api_ctx, path, array)
#define fcfs_api_list_compact_dentry_by_inode(inode, array) \
fcfs_api_list_compact_dentry_by_inode_ex(&g_fcfs_api_ctx, inode, array)
#define fcfs_api_alloc_opendir_session() \
fcfs_api_alloc_opendir_session_ex(&g_fcfs_api_ctx)
#define fcfs_api_free_opendir_session(session) \
fcfs_api_free_opendir_session_ex(&g_fcfs_api_ctx, session)
#define fcfs_api_dentry_sys_lock(session, inode, flags, file_size, space_end) \
fcfs_api_dentry_sys_lock_ex(&g_fcfs_api_ctx, session, inode, \
flags, file_size, space_end)
static inline int fcfs_api_lookup_inode_by_fullname_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path, const int enoent_log_level,
int64_t *inode)
{
return fdir_client_lookup_inode_by_path_ex(ctx->contexts.fdir,
path, enoent_log_level, inode);
}
static inline int fcfs_api_lookup_inode_by_path_ex(FCFSAPIContext *ctx,
const char *path, const FDIRDentryOperator *oper,
const int enoent_log_level, int64_t *inode)
{
FDIRClientOperFnamePair fname;
FCFSAPI_SET_PATH_OPER_FNAME(fname, ctx, *oper, path);
return fdir_client_lookup_inode_by_path_ex(ctx->contexts.fdir,
&fname, enoent_log_level, inode);
}
static inline int fcfs_api_stat_dentry_by_inode_ex(FCFSAPIContext *ctx,
const FDIRClientOperInodePair *oino, const int flags,
FDIRDEntryInfo *dentry)
{
if (ctx->async_report.enabled) {
inode_htable_check_conflict_and_wait(oino->inode);
}
return fdir_client_stat_dentry_by_inode(ctx->contexts.fdir,
&ctx->ns, oino, flags, dentry);
}
static inline int fcfs_api_stat_dentry_by_fullname_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path, const int flags,
const int enoent_log_level, FDIRDEntryInfo *dentry)
{
if (ctx->async_report.enabled) {
int result;
FDIRClientOperInodePair oino;
if ((result=fcfs_api_lookup_inode_by_fullname_ex(ctx,
path, enoent_log_level, &oino.inode)) != 0)
{
return result;
}
oino.oper = path->oper;
return fcfs_api_stat_dentry_by_inode_ex(ctx, &oino, flags, dentry);
} else {
return fdir_client_stat_dentry_by_path_ex(ctx->contexts.fdir,
path, flags, enoent_log_level, dentry);
}
}
static inline int fcfs_api_stat_dentry_by_path_ex(FCFSAPIContext *ctx,
const char *path, const FDIRDentryOperator *oper, const int flags,
const int enoent_log_level, FDIRDEntryInfo *dentry)
{
FDIRClientOperFnamePair fname;
FCFSAPI_SET_PATH_OPER_FNAME(fname, ctx, *oper, path);
return fcfs_api_stat_dentry_by_fullname_ex(ctx, &fname,
flags, enoent_log_level, dentry);
}
static inline int fcfs_api_stat_dentry_by_pname_ex(FCFSAPIContext *ctx,
const FDIRClientOperPnamePair *opname, const int flags,
const int enoent_log_level, FDIRDEntryInfo *dentry)
{
if (ctx->async_report.enabled) {
int result;
FDIRClientOperInodePair oino;
if ((result=fdir_client_lookup_inode_by_pname_ex(ctx->contexts.fdir,
&ctx->ns, opname, enoent_log_level, &oino.inode)) != 0)
{
return result;
}
oino.oper = opname->oper;
return fcfs_api_stat_dentry_by_inode_ex(ctx, &oino, flags, dentry);
} else {
return fdir_client_stat_dentry_by_pname_ex(ctx->contexts.fdir,
&ctx->ns, opname, flags, enoent_log_level, dentry);
}
}
static inline int fcfs_api_access_dentry_by_inode_ex(FCFSAPIContext *ctx,
const FDIRClientOperInodePair *oino, const char mask,
const int flags, FDIRDEntryInfo *dentry)
{
if (ctx->async_report.enabled && (flags & FDIR_FLAGS_OUTPUT_DENTRY)) {
inode_htable_check_conflict_and_wait(oino->inode);
}
return fdir_client_access_dentry_by_inode(ctx->contexts.fdir,
&ctx->ns, oino, mask, flags, dentry);
}
static inline int fcfs_api_access_dentry_by_path_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path, const char mask,
const int flags, FDIRDEntryInfo *dentry)
{
if (ctx->async_report.enabled && (flags & FDIR_FLAGS_OUTPUT_DENTRY)) {
int result;
FDIRClientOperInodePair oino;
if ((result=fcfs_api_lookup_inode_by_fullname_ex(ctx,
path, LOG_NOTHING, &oino.inode)) != 0)
{
return result;
}
oino.oper = path->oper;
return fcfs_api_access_dentry_by_inode_ex(
ctx, &oino, mask, flags, dentry);
}
return fdir_client_access_dentry_by_path(ctx->
contexts.fdir, path, mask, flags, dentry);
}
static inline int fcfs_api_access_dentry_by_pname_ex(FCFSAPIContext *ctx,
const FDIRClientOperPnamePair *opname, const char mask,
const int flags, FDIRDEntryInfo *dentry)
{
if (ctx->async_report.enabled && (flags & FDIR_FLAGS_OUTPUT_DENTRY)) {
int result;
FDIRClientOperInodePair oino;
if ((result=fdir_client_lookup_inode_by_pname_ex(ctx->contexts.fdir,
&ctx->ns, opname, LOG_NOTHING, &oino.inode)) != 0)
{
return result;
}
oino.oper = opname->oper;
return fcfs_api_access_dentry_by_inode_ex(
ctx, &oino, mask, flags, dentry);
}
return fdir_client_access_dentry_by_pname(ctx->contexts.fdir,
&ctx->ns, opname, mask, flags, dentry);
}
static inline int fcfs_api_create_dentry_by_pname_ex(FCFSAPIContext *ctx,
const int64_t parent_inode, const string_t *name,
const FDIRDentryOperator *oper, const mode_t mode,
const dev_t rdev, FDIRDEntryInfo *dentry)
{
FDIRClientOperPnamePair opname;
FCFSAPI_SET_PATH_OPER_PNAME(opname, *oper, parent_inode, name);
return fdir_client_create_dentry_by_pname_ex(ctx->contexts.fdir,
&ctx->ns, &opname, mode, rdev, dentry);
}
static inline int fcfs_api_symlink_dentry_by_pname_ex(FCFSAPIContext *ctx,
const string_t *link, const int64_t parent_inode,
const string_t *name, const FDIRDentryOperator *oper,
const mode_t mode, FDIRDEntryInfo *dentry)
{
FDIRClientOperPnamePair opname;
FCFSAPI_SET_PATH_OPER_PNAME(opname, *oper, parent_inode, name);
return fdir_client_symlink_dentry_by_pname(ctx->contexts.fdir,
link, &ctx->ns, &opname, mode, dentry);
}
static inline int fcfs_api_readlink_by_pname_ex(FCFSAPIContext *ctx,
const FDIRClientOperPnamePair *opname,
string_t *link, const int size)
{
return fdir_client_readlink_by_pname(ctx->contexts.fdir,
&ctx->ns, opname, link, size);
}
static inline int fcfs_api_readlink_by_inode_ex(FCFSAPIContext *ctx,
const FDIRClientOperInodePair *oino, string_t *link, const int size)
{
return fdir_client_readlink_by_inode(ctx->contexts.fdir,
&ctx->ns, oino, link, size);
}
int fcfs_api_remove_dentry_by_pname_ex(FCFSAPIContext *ctx,
const FDIRClientOperPnamePair *opname,
const int flags, const int64_t tid);
int fcfs_api_remove_dentry_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path,
const int flags, const int64_t tid);
int fcfs_api_rename_dentry_by_pname_ex(FCFSAPIContext *ctx,
const int64_t src_parent_inode, const string_t *src_name,
const int64_t dest_parent_inode, const string_t *dest_name,
const FDIRDentryOperator *oper, const int flags,
const int64_t tid);
int fcfs_api_rename_dentry_ex(FCFSAPIContext *ctx, const char *path1,
const char *path2, const FDIRDentryOperator *oper,
const int flags, const int64_t tid);
static inline int fcfs_api_modify_stat_by_inode_ex(FCFSAPIContext *ctx,
const FDIRClientOperInodePair *oino, const struct stat *attr,
const int64_t mflags, const int flags, FDIRDEntryInfo *dentry)
{
FDIRDEntryStat stat;
if (ctx->async_report.enabled) {
inode_htable_check_conflict_and_wait(oino->inode);
}
stat.mode = attr->st_mode;
stat.gid = attr->st_gid;
stat.uid = attr->st_uid;
stat.atime = attr->st_atime;
stat.ctime = attr->st_ctime;
stat.mtime = attr->st_mtime;
stat.size = attr->st_size;
return fdir_client_modify_stat_by_inode(ctx->contexts.fdir,
&ctx->ns, oino, mflags, &stat, flags, dentry);
}
#define FCFS_API_SET_UTIMES(stat, options, times) \
do { \
options.flags = 0; \
options.atime = options.mtime = 1; \
memset(&stat, 0, sizeof(stat)); \
if (times == NULL) { \
stat.atime = stat.mtime = get_current_time(); \
} else { \
stat.atime = times[0].tv_sec; \
stat.mtime = times[1].tv_sec; \
} \
} while (0)
#define SET_ONE_UTIMENS(var, option_flag, option_now, tp) \
do { \
if (tp.tv_nsec == UTIME_NOW) { \
var = get_current_time(); \
option_flag = 1; \
option_now = 1; \
} else if (tp.tv_nsec == UTIME_OMIT) { \
option_flag = 0; \
} else { \
var = tp.tv_sec; \
option_flag = 1; \
} \
} while (0)
#define FCFS_API_SET_UTIMENS(stat, options, times) \
do { \
options.flags = 0; \
memset(&stat, 0, sizeof(stat)); \
if (times == NULL) { \
stat.atime = stat.mtime = get_current_time(); \
} else { \
SET_ONE_UTIMENS(stat.atime, options.atime, \
options.atime_now, times[0]); \
SET_ONE_UTIMENS(stat.mtime, options.mtime, \
options.mtime_now, times[1]); \
} \
} while (0)
static inline int fcfs_api_utimes_by_inode_ex(FCFSAPIContext *ctx,
const FDIRClientOperInodePair *oino, const struct timeval times[2],
const int flags)
{
FDIRStatModifyFlags options;
FDIRDEntryStat stat;
FDIRDEntryInfo dentry;
if (ctx->async_report.enabled) {
inode_htable_check_conflict_and_wait(oino->inode);
}
FCFS_API_SET_UTIMES(stat, options, times);
return fdir_client_modify_stat_by_inode(ctx->contexts.fdir,
&ctx->ns, oino, options.flags, &stat, flags, &dentry);
}
static inline int fcfs_api_utimes_by_path_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path,
const struct timeval times[2], const int flags)
{
FDIRStatModifyFlags options;
FDIRDEntryStat stat;
FDIRDEntryInfo dentry;
FCFS_API_SET_UTIMES(stat, options, times);
return fdir_client_modify_stat_by_path(ctx->contexts.fdir,
path, options.flags, &stat, flags, &dentry);
}
static inline int fcfs_api_utimens_by_inode_ex(FCFSAPIContext *ctx,
const FDIRClientOperInodePair *oino, const struct timespec times[2],
const int flags)
{
FDIRStatModifyFlags options;
FDIRDEntryStat stat;
FDIRDEntryInfo dentry;
if (ctx->async_report.enabled) {
inode_htable_check_conflict_and_wait(oino->inode);
}
FCFS_API_SET_UTIMENS(stat, options, times);
if (options.flags == 0) {
return 0;
} else {
return fdir_client_modify_stat_by_inode(ctx->contexts.fdir,
&ctx->ns, oino, options.flags, &stat, flags, &dentry);
}
}
static inline int fcfs_api_utimens_by_path_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path,
const struct timespec times[2], const int flags)
{
FDIRStatModifyFlags options;
FDIRDEntryStat stat;
FDIRDEntryInfo dentry;
FCFS_API_SET_UTIMENS(stat, options, times);
if (options.flags == 0) {
return 0;
} else {
return fdir_client_modify_stat_by_path(ctx->contexts.fdir,
path, options.flags, &stat, flags, &dentry);
}
}
static inline int fcfs_api_utime_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path,
const struct utimbuf *times)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
FDIRStatModifyFlags options;
FDIRDEntryStat stat;
FDIRDEntryInfo dentry;
options.flags = 0;
options.atime = options.mtime = 1;
memset(&stat, 0, sizeof(stat));
if (times == NULL) {
stat.atime = stat.mtime = get_current_time();
} else {
stat.atime = times->actime;
stat.mtime = times->modtime;
}
return fdir_client_modify_stat_by_path(ctx->contexts.fdir,
path, options.flags, &stat, flags, &dentry);
}
static inline int fcfs_api_chown_by_inode_ex(FCFSAPIContext *ctx,
const FDIRClientOperInodePair *oino, const uid_t uid,
const gid_t gid, const int flags)
{
FDIRStatModifyFlags options;
FDIRDEntryStat stat;
FDIRDEntryInfo dentry;
options.flags = 0;
options.uid = options.gid = 1;
memset(&stat, 0, sizeof(stat));
stat.uid = uid;
stat.gid = gid;
return fdir_client_modify_stat_by_inode(ctx->contexts.fdir,
&ctx->ns, oino, options.flags, &stat, flags, &dentry);
}
static inline int fcfs_api_chown_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path, const uid_t uid,
const gid_t gid, const int flags)
{
FDIRStatModifyFlags options;
FDIRDEntryStat stat;
FDIRDEntryInfo dentry;
options.flags = 0;
options.uid = options.gid = 1;
memset(&stat, 0, sizeof(stat));
stat.uid = uid;
stat.gid = gid;
return fdir_client_modify_stat_by_path(ctx->contexts.fdir,
path, options.flags, &stat, flags, &dentry);
}
static inline int fcfs_api_chmod_by_inode_ex(FCFSAPIContext *ctx,
const FDIRClientOperInodePair *oino, const mode_t mode,
const int flags)
{
FDIRStatModifyFlags options;
FDIRDEntryStat stat;
FDIRDEntryInfo dentry;
options.flags = 0;
options.mode = 1;
memset(&stat, 0, sizeof(stat));
stat.mode = (mode & ALLPERMS);
return fdir_client_modify_stat_by_inode(ctx->contexts.fdir,
&ctx->ns, oino, options.flags, &stat, flags, &dentry);
}
static inline int fcfs_api_chmod_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path,
const mode_t mode, const int flags)
{
FDIRStatModifyFlags options;
FDIRDEntryStat stat;
FDIRDEntryInfo dentry;
options.flags = 0;
options.mode = 1;
memset(&stat, 0, sizeof(stat));
stat.mode = (mode & ALLPERMS);
return fdir_client_modify_stat_by_path(ctx->contexts.fdir,
path, options.flags, &stat, flags, &dentry);
}
static inline int convert_xattr_flags(const int flags)
{
int new_flags;
if (flags == 0) {
return 0;
}
new_flags = (flags & FDIR_FLAGS_FOLLOW_SYMLINK);
if ((flags & XATTR_CREATE) != 0) {
return (new_flags | FDIR_FLAGS_XATTR_CREATE);
} else if ((flags & XATTR_REPLACE) != 0) {
return (new_flags | FDIR_FLAGS_XATTR_REPLACE);
} else {
return new_flags;
}
}
static inline int fcfs_api_set_xattr_by_inode_ex(FCFSAPIContext *ctx,
const FDIRClientOperInodePair *oino, const key_value_pair_t *xattr,
const int flags)
{
return fdir_client_set_xattr_by_inode(ctx->contexts.fdir,
&ctx->ns, oino, xattr, convert_xattr_flags(flags));
}
static inline int fcfs_api_set_xattr_by_path_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path,
const key_value_pair_t *xattr, const int flags)
{
return fdir_client_set_xattr_by_path(ctx->contexts.fdir,
path, xattr, convert_xattr_flags(flags));
}
static inline int fcfs_api_remove_xattr_by_inode_ex(FCFSAPIContext *ctx,
const FDIRClientOperInodePair *oino,
const string_t *name, const int flags)
{
return fdir_client_remove_xattr_by_inode_ex(ctx->contexts.fdir,
&ctx->ns, oino, name, flags, LOG_DEBUG);
}
static inline int fcfs_api_remove_xattr_by_path_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path,
const string_t *name, const int flags)
{
return fdir_client_remove_xattr_by_path_ex(ctx->contexts.fdir,
path, name, flags, LOG_DEBUG);
}
static inline int fcfs_api_get_xattr_by_inode_ex(FCFSAPIContext *ctx,
const FDIRClientOperInodePair *oino, const string_t *name,
const int enoattr_log_level, string_t *value, const int size,
const int flags)
{
return fdir_client_get_xattr_by_inode_ex(ctx->contexts.fdir, &ctx->ns,
oino, name, enoattr_log_level, value, size, flags);
}
static inline int fcfs_api_get_xattr_by_path_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path, const string_t *name,
const int enoattr_log_level, string_t *value,
const int size, const int flags)
{
return fdir_client_get_xattr_by_path_ex(ctx->contexts.fdir,
path, name, enoattr_log_level, value, size, flags);
}
static inline int fcfs_api_list_xattr_by_inode_ex(FCFSAPIContext *ctx,
const FDIRClientOperInodePair *oino, string_t *list,
const int size, const int flags)
{
return fdir_client_list_xattr_by_inode(ctx->contexts.fdir,
&ctx->ns, oino, list, size, flags);
}
static inline int fcfs_api_list_xattr_by_path_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path, string_t *list,
const int size, const int flags)
{
return fdir_client_list_xattr_by_path(ctx->contexts.fdir,
path, list, size, flags);
}
static inline int fcfs_api_list_dentry_by_inode_ex(FCFSAPIContext *ctx,
const FDIRClientOperInodePair *oino, FDIRClientDentryArray *array)
{
const int flags = FDIR_LIST_DENTRY_FLAGS_OUTPUT_SPECIAL;
if (ctx->async_report.enabled) {
async_reporter_wait_all(oino->inode);
}
return fdir_client_list_dentry_by_inode(ctx->contexts.fdir,
&ctx->ns, oino, array, flags);
}
static inline int fcfs_api_list_compact_dentry_by_path_ex(FCFSAPIContext *ctx,
const FDIRClientOperFnamePair *path,
FDIRClientCompactDentryArray *array)
{
return fdir_client_list_compact_dentry_by_path(
ctx->contexts.fdir, path, array);
}
static inline int fcfs_api_list_compact_dentry_by_inode_ex(
FCFSAPIContext *ctx, const FDIRClientOperInodePair *oino,
FDIRClientCompactDentryArray *array)
{
return fdir_client_list_compact_dentry_by_inode(
ctx->contexts.fdir, &ctx->ns, oino, array);
}
static inline FCFSAPIOpendirSession *fcfs_api_alloc_opendir_session_ex(
FCFSAPIContext *ctx)
{
return (FCFSAPIOpendirSession *)fast_mblock_alloc_object(
&ctx->opendir_session_pool);
}
static inline void fcfs_api_free_opendir_session_ex(
FCFSAPIContext *ctx, FCFSAPIOpendirSession *session)
{
fast_mblock_free_object(&ctx->opendir_session_pool, session);
}
static inline int fcfs_api_dentry_sys_lock_ex(FCFSAPIContext *ctx,
FDIRClientSession *session, const int64_t inode, const int flags,
int64_t *file_size, int64_t *space_end)
{
int result;
if ((result=fdir_client_init_session(ctx->contexts.fdir, session)) != 0) {
return result;
}
return fdir_client_dentry_sys_lock(session, &ctx->ns,
inode, flags, file_size, space_end);
}
static inline int fcfs_api_dentry_sys_unlock(FDIRClientSession *session,
const string_t *ns, const int64_t old_size,
const FDIRSetDEntrySizeInfo *dsize)
{
int result;
result = fdir_client_dentry_sys_unlock_ex(session, ns, old_size, dsize);
fdir_client_close_session(session, result != 0);
return result;
}
static inline int fcfs_api_link_dentry_by_pname_ex(FCFSAPIContext *ctx,
const int64_t src_inode, const int64_t dest_parent_inode,
const string_t *dest_name, const FDIRDentryOperator *oper,
const mode_t mode, const int flags, FDIRDEntryInfo *dentry)
{
FDIRClientOperPnamePair dest_opname;
FCFSAPI_SET_PATH_OPER_PNAME(dest_opname, *oper,
dest_parent_inode, dest_name);
return fdir_client_link_dentry_by_pname(ctx->contexts.fdir,
src_inode, &ctx->ns, &dest_opname, mode, flags, dentry);
}
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/api/inode_htable.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include "fcfs_api_allocator.h"
#include "async_reporter.h"
#include "inode_htable.h"
static SFHtableShardingContext inode_sharding_ctx;
typedef struct fcfs_api_insert_event_context {
FCFSAPIAsyncReportEvent *event;
} FCFSAPIInsertEventContext;
typedef struct fcfs_api_find_callback_arg {
FCFSAPIAllocatorContext *allocator_ctx;
FCFSAPIWaitingTask *waiting_task;
} FCFSAPIFindCallbackArg;
static int inode_htable_insert_callback(SFShardingHashEntry *he,
void *arg, const bool new_create)
{
FCFSAPIInodeHEntry *inode;
FCFSAPIInsertEventContext *ictx;
inode = (FCFSAPIInodeHEntry *)he;
ictx = (FCFSAPIInsertEventContext *)arg;
if (new_create) {
FC_INIT_LIST_HEAD(&inode->head);
}
ictx->event->inode_hentry = inode;
fc_list_add(&ictx->event->dlink, &inode->head);
return 0;
}
static void *inode_htable_find_callback(SFShardingHashEntry *he, void *arg)
{
FCFSAPIInodeHEntry *inode;
FCFSAPIFindCallbackArg *farg;
FCFSAPIAsyncReportEvent *event;
inode = (FCFSAPIInodeHEntry *)he;
event = fc_list_first_entry(&inode->head, FCFSAPIAsyncReportEvent, dlink);
if (event == NULL) {
return NULL;
}
farg = (FCFSAPIFindCallbackArg *)arg;
farg->waiting_task = (FCFSAPIWaitingTask *)fast_mblock_alloc_object(
&farg->allocator_ctx->waiting_task);
if (farg->waiting_task == NULL) {
return NULL;
}
//add to event waiting queue
farg->waiting_task->next = event->waitings.head;
event->waitings.head = farg->waiting_task;
return event;
}
static bool inode_htable_accept_reclaim_callback(SFShardingHashEntry *he)
{
return fc_list_empty(&((FCFSAPIInodeHEntry *)he)->head);
}
int inode_htable_init(const int sharding_count,
const int64_t htable_capacity,
const int allocator_count, int64_t element_limit,
const int64_t min_ttl_sec, const int64_t max_ttl_sec)
{
return sf_sharding_htable_init(&inode_sharding_ctx,
sf_sharding_htable_key_ids_one, inode_htable_insert_callback,
inode_htable_find_callback, NULL,
inode_htable_accept_reclaim_callback, sharding_count,
htable_capacity, allocator_count, sizeof(FCFSAPIInodeHEntry),
element_limit, min_ttl_sec, max_ttl_sec);
}
int inode_htable_insert(FCFSAPIAsyncReportEvent *event)
{
SFTwoIdsHashKey key;
FCFSAPIInsertEventContext ictx;
key.oid = event->dsize.inode;
ictx.event = event;
return sf_sharding_htable_insert(&inode_sharding_ctx,
&key, &ictx);
}
int inode_htable_check_conflict_and_wait(const uint64_t inode)
{
SFTwoIdsHashKey key;
FCFSAPIFindCallbackArg callback_arg;
key.oid = inode;
callback_arg.allocator_ctx = fcfs_api_allocator_get(inode);
callback_arg.waiting_task = NULL;
if (sf_sharding_htable_find(&inode_sharding_ctx,
&key, &callback_arg) == NULL)
{
return 0;
}
if (callback_arg.waiting_task != NULL) {
async_reporter_notify();
//logInfo("oid: %"PRId64", wait_report_done_and_release", inode);
fcfs_api_wait_report_done_and_release(callback_arg.waiting_task);
}
return 0;
}
================================================
FILE: src/api/inode_htable.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _INODE_HTABLE_H
#define _INODE_HTABLE_H
#include "fcfs_api_types.h"
#include "sf/sf_sharding_htable.h"
typedef struct fcfs_api_inode_hentry {
SFShardingHashEntry hentry; //must be the first
struct fc_list_head head; //element: FCFSAPIAsyncReportEvent
} FCFSAPIInodeHEntry;
#ifdef __cplusplus
extern "C" {
#endif
int inode_htable_init(const int sharding_count,
const int64_t htable_capacity,
const int allocator_count, int64_t element_limit,
const int64_t min_ttl_sec, const int64_t max_ttl_sec);
int inode_htable_insert(FCFSAPIAsyncReportEvent *event);
int inode_htable_check_conflict_and_wait(const uint64_t inode);
static inline void fcfs_api_notify_waiting_task(FCFSAPIWaitingTask *task)
{
PTHREAD_MUTEX_LOCK(&task->lcp.lock);
task->finished = true;
pthread_cond_signal(&task->lcp.cond);
PTHREAD_MUTEX_UNLOCK(&task->lcp.lock);
}
static inline void fcfs_api_wait_report_done_and_release(
FCFSAPIWaitingTask *waiting_task)
{
PTHREAD_MUTEX_LOCK(&waiting_task->lcp.lock);
while (!waiting_task->finished) {
pthread_cond_wait(&waiting_task->lcp.cond,
&waiting_task->lcp.lock);
}
waiting_task->finished = false; //reset for next use
PTHREAD_MUTEX_UNLOCK(&waiting_task->lcp.lock);
fast_mblock_free_object(waiting_task->allocator, waiting_task);
}
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/api/std/api_types.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_POSIX_API_TYPES_H
#define _FCFS_POSIX_API_TYPES_H
#include "fastcommon/fc_list.h"
#include "fastcommon/pthread_func.h"
#include "../fcfs_api.h"
#ifndef OS_LINUX
typedef off_t off64_t;
#endif
#define FCFS_POSIX_API_FD_BASE (2 << 28)
struct dirent;
typedef int (*fcfs_dir_filter_func)(const struct dirent *ent);
typedef int (*fcfs_dir_compare_func)(const struct dirent **ent1,
const struct dirent **ent2);
typedef struct fcfs_posix_api_context {
FCFSAPINSMountpointHolder nsmp;
string_t mountpoint;
FCFSAPIContext api_ctx;
} FCFSPosixAPIContext;
typedef enum {
fcfs_papi_tpid_type_tid,
fcfs_papi_tpid_type_pid
} FCFSPosixAPITPIDType;
typedef struct fcfs_posix_api_file_info {
string_t filename;
int fd;
FCFSPosixAPITPIDType tpid_type; //use pid or tid
FCFSAPIFileInfo fi;
} FCFSPosixAPIFileInfo;
typedef struct fcfs_posix_file_ptr_array {
volatile FCFSPosixAPIFileInfo **files;
volatile int count;
} FCFSPosixFilePtrArray;
typedef struct fcfs_posix_api_dir {
FCFSPosixAPIFileInfo *file;
FDIRClientCompactDentryArray darray;
int magic;
int offset;
} FCFSPosixAPIDIR;
typedef struct fcfs_posix_capi_file {
int magic;
int fd;
int error_no;
int eof;
pthread_mutex_t lock;
struct fc_list_head dlink; //for opened files chain
} FCFSPosixCAPIFILE;
typedef struct fcfs_posix_api_global_vars {
FCFSPosixAPIContext ctx;
string_t *cwd;
} FCFSPosixAPIGlobalVars;
#define FCFS_PAPI_IS_MY_FD(fd) \
(fd > FCFS_POSIX_API_FD_BASE)
#endif
================================================
FILE: src/api/std/capi.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include "fastcommon/shared_func.h"
#include "fastcommon/logger.h"
#include "fastcommon/locked_list.h"
#include "papi.h"
#include "capi.h"
static FCLockedList capi_opend_files;
#define FCFS_CAPI_MAGIC_NUMBER 1645431088
#ifdef OS_LINUX
#define FCFS_POS_OFFSET(pos) (pos)->__pos
#else
#define FCFS_POS_OFFSET(pos) *(pos)
#endif
#define FCFS_CAPI_CONVERT_FP_EX(fp, ...) \
FCFSPosixCAPIFILE *file; \
file = (FCFSPosixCAPIFILE *)fp; \
if (file->magic != FCFS_CAPI_MAGIC_NUMBER) { \
errno = EBADF; \
return __VA_ARGS__; \
}
#define FCFS_CAPI_CONVERT_FP(fp) \
FCFS_CAPI_CONVERT_FP_EX(fp, -1)
#define FCFS_CAPI_CONVERT_FP_VOID(fp) \
FCFS_CAPI_CONVERT_FP_EX(fp)
int fcfs_capi_init()
{
return locked_list_init(&capi_opend_files);
}
void fcfs_capi_destroy()
{
fcfs_fcloseall();
locked_list_destroy(&capi_opend_files);
}
static FILE *alloc_file_handle(int fd)
{
FCFSPosixCAPIFILE *file;
int result;
if ((file=fc_malloc(sizeof(FCFSPosixCAPIFILE))) == NULL) {
errno = ENOMEM;
return NULL;
}
if ((result=init_pthread_lock(&file->lock)) != 0) {
free(file);
errno = result;
return NULL;
}
file->fd = fd;
file->magic = FCFS_CAPI_MAGIC_NUMBER;
file->error_no = 0;
file->eof = 0;
locked_list_add_tail(&file->dlink, &capi_opend_files);
return (FILE *)file;
}
static inline int free_file_handle(FCFSPosixCAPIFILE *file)
{
int result;
locked_list_del(&file->dlink, &capi_opend_files);
if (fcfs_close(file->fd) == 0) {
result = 0;
} else {
result = EOF;
}
file->magic = 0;
free(file);
return result;
}
static int mode_to_flags(const char *mode, int *flags)
{
const char *p;
const char *end;
int len;
len = strlen(mode);
if (len == 0) {
return EINVAL;
}
p = mode;
switch (*p++) {
case 'r':
if (*p == '+') {
*flags = O_RDWR;
p++;
} else {
*flags = O_RDONLY;
}
break;
case 'w':
if (*p == '+') {
*flags = O_RDWR | O_CREAT | O_TRUNC;
p++;
} else {
*flags = O_WRONLY | O_CREAT | O_TRUNC;
}
break;
case 'a':
if (*p == '+') {
*flags = O_RDWR | O_CREAT | O_APPEND;
p++;
} else {
*flags = O_WRONLY | O_CREAT | O_APPEND;
}
break;
default:
return EINVAL;
}
end = mode + len;
while (p < end) {
switch (*p) {
case 'e':
*flags |= O_CLOEXEC;
break;
case'x':
*flags |= O_EXCL;
break;
default:
break;
}
++p;
}
return 0;
}
static int check_flags(const char *mode, const int flags, int *adding_flags)
{
const char *p;
const char *end;
int rwflags;
int len;
len = strlen(mode);
if (len == 0) {
return EINVAL;
}
*adding_flags = 0;
p = mode;
switch (*p++) {
case 'r':
if (*p == '+') {
rwflags = O_RDWR;
p++;
} else {
rwflags = O_RDONLY;
}
break;
case 'a':
*adding_flags = O_APPEND;
case 'w':
if (*p == '+') {
rwflags = O_RDWR;
p++;
} else {
rwflags = O_WRONLY;
}
break;
default:
return EINVAL;
}
if ((flags & rwflags) != rwflags) {
return EINVAL;
}
end = mode + len;
while (p < end) {
switch (*p) {
case 'e':
*adding_flags |= O_CLOEXEC;
break;
case'x':
//just ignore
break;
default:
break;
}
++p;
}
return 0;
}
static inline int do_fdopen(FCFSPosixAPIContext *ctx,
const char *path, const char *mode)
{
int flags;
int result;
if ((result=mode_to_flags(mode, &flags)) != 0) {
errno = result;
return -1;
}
return fcfs_file_open(ctx, path, flags, 0666, fcfs_papi_tpid_type_pid);
}
void fcfs_flockfile(FILE *fp)
{
FCFS_CAPI_CONVERT_FP_VOID(fp);
PTHREAD_MUTEX_LOCK(&file->lock);
}
int fcfs_ftrylockfile(FILE *fp)
{
int result;
FCFS_CAPI_CONVERT_FP_EX(fp, -1);
if ((result=pthread_mutex_trylock(&file->lock)) != 0) {
errno = result;
return -1;
}
return 0;
}
void fcfs_funlockfile(FILE *fp)
{
FCFS_CAPI_CONVERT_FP_VOID(fp);
PTHREAD_MUTEX_UNLOCK(&file->lock);
}
FILE *fcfs_fopen_ex(FCFSPosixAPIContext *ctx,
const char *path, const char *mode)
{
int fd;
if ((fd=do_fdopen(ctx, path, mode)) < 0) {
return NULL;
}
return alloc_file_handle(fd);
}
FILE *fcfs_fdopen_ex(FCFSPosixAPIContext *ctx, int fd, const char *mode)
{
int flags;
int adding_flags;
int result;
if ((flags=fcfs_fcntl(fd, F_GETFL)) < 0) {
return NULL;
}
if ((result=check_flags(mode, flags, &adding_flags)) != 0) {
errno = result;
return NULL;
}
if (adding_flags != 0 && (flags & adding_flags) != adding_flags) {
if (fcfs_fcntl(fd, F_SETFL, (flags | adding_flags)) != 0) {
return NULL;
}
}
return alloc_file_handle(fd);
}
FILE *fcfs_freopen_ex(FCFSPosixAPIContext *ctx,
const char *path, const char *mode, FILE *fp)
{
int fd;
FCFSPosixAPIFileInfo *finfo;
FCFS_CAPI_CONVERT_FP_EX(fp, NULL);
if (path == NULL) {
if ((finfo=fcfs_get_file_handle(file->fd)) == NULL) {
errno = EBADF;
return NULL;
}
path = finfo->filename.str;
}
if ((fd=do_fdopen(ctx, path, mode)) < 0) {
return NULL;
}
fcfs_close(file->fd);
file->fd = fd;
file->eof = 0;
file->error_no = 0;
return (FILE *)file;
}
int fcfs_fclose(FILE *fp)
{
FCFS_CAPI_CONVERT_FP_EX(fp, EOF);
return free_file_handle(file);
}
int fcfs_fcloseall()
{
int result;
int r;
FCFSPosixCAPIFILE *file;
result = 0;
while (1) {
locked_list_first_entry(&capi_opend_files,
FCFSPosixCAPIFILE, dlink, file);
if (file == NULL) {
break;
}
if ((r=free_file_handle(file)) != 0) {
result = r;
}
}
return result;
}
int fcfs_setvbuf(FILE *fp, char *buf, int mode, size_t size)
{
switch (mode) {
case _IOFBF:
break;
case _IOLBF:
break;
case _IONBF:
break;
default:
break;
}
//alloc_file_buffer(FCFSPosixCAPIFILE *file, const int size);
return 0;
}
int fcfs_fseek(FILE *fp, long offset, int whence)
{
FCFS_CAPI_CONVERT_FP(fp);
return fcfs_lseek(file->fd, offset, whence) >= 0 ? 0 : -1;
}
int fcfs_fseeko(FILE *fp, off_t offset, int whence)
{
FCFS_CAPI_CONVERT_FP(fp);
return fcfs_lseek(file->fd, offset, whence) >= 0 ? 0 : -1;
}
long fcfs_ftell(FILE *fp)
{
FCFS_CAPI_CONVERT_FP(fp);
return fcfs_ltell(file->fd);
}
off_t fcfs_ftello(FILE *fp)
{
FCFS_CAPI_CONVERT_FP(fp);
return fcfs_ltell(file->fd);
}
void fcfs_rewind(FILE *fp)
{
FCFS_CAPI_CONVERT_FP_VOID(fp);
fcfs_lseek(file->fd, 0L, SEEK_SET);
}
int fcfs_fgetpos(FILE *fp, fpos_t *pos)
{
FCFS_CAPI_CONVERT_FP(fp);
FCFS_POS_OFFSET(pos) = fcfs_ltell(file->fd);
return FCFS_POS_OFFSET(pos) >= 0 ? 0 : -1;
}
int fcfs_fsetpos(FILE *fp, const fpos_t *pos)
{
FCFS_CAPI_CONVERT_FP(fp);
return fcfs_lseek(file->fd, FCFS_POS_OFFSET(pos), SEEK_SET) >= 0 ? 0 : -1;
}
#define SET_FILE_ERROR(file, bytes) \
do { \
if (bytes < 0) { \
file->error_no = (errno != 0 ? errno : EIO); \
} else { \
file->eof = 1; \
} \
} while (0)
static inline int do_fgetc(FILE *fp, const bool need_lock)
{
int bytes;
int c;
unsigned char buff[8];
FCFS_CAPI_CONVERT_FP_EX(fp, EOF);
if (need_lock) {
PTHREAD_MUTEX_LOCK(&file->lock);
}
bytes = fcfs_read(file->fd, buff, 1);
if (bytes > 0) {
c = *buff;
} else {
SET_FILE_ERROR(file, bytes);
c = EOF;
}
if (need_lock) {
PTHREAD_MUTEX_UNLOCK(&file->lock);
}
return c;
}
static inline int do_fputc(int c, FILE *fp, const bool need_lock)
{
int bytes;
char ch;
FCFS_CAPI_CONVERT_FP_EX(fp, EOF);
if (need_lock) {
PTHREAD_MUTEX_LOCK(&file->lock);
}
ch = c;
bytes = fcfs_write(file->fd, &ch, 1);
if (bytes <= 0) {
file->error_no = (errno != 0 ? errno : EIO);
ch = EOF;
}
if (need_lock) {
PTHREAD_MUTEX_UNLOCK(&file->lock);
}
return ch;
}
static inline void do_clearerr(FILE *fp, const bool need_lock)
{
FCFS_CAPI_CONVERT_FP_VOID(fp);
if (need_lock) {
PTHREAD_MUTEX_LOCK(&file->lock);
}
file->error_no = 0;
file->eof = 0;
if (need_lock) {
PTHREAD_MUTEX_UNLOCK(&file->lock);
}
}
static inline int do_feof(FILE *fp, const bool need_lock)
{
int eof;
FCFS_CAPI_CONVERT_FP(fp);
if (need_lock) {
PTHREAD_MUTEX_LOCK(&file->lock);
}
eof = file->eof;
if (need_lock) {
PTHREAD_MUTEX_UNLOCK(&file->lock);
}
return eof;
}
static inline int do_ferror(FILE *fp, const bool need_lock)
{
int error_no;
FCFS_CAPI_CONVERT_FP(fp);
if (need_lock) {
PTHREAD_MUTEX_LOCK(&file->lock);
}
error_no = file->error_no;
if (need_lock) {
PTHREAD_MUTEX_UNLOCK(&file->lock);
}
return error_no;
}
static inline int do_fileno(FILE *fp, const bool need_lock)
{
int fd;
FCFS_CAPI_CONVERT_FP(fp);
if (need_lock) {
PTHREAD_MUTEX_LOCK(&file->lock);
}
fd = file->fd;
if (need_lock) {
PTHREAD_MUTEX_UNLOCK(&file->lock);
}
return fd;
}
static inline int do_fflush(FILE *fp, const bool need_lock)
{
FCFS_CAPI_CONVERT_FP_EX(fp, EOF);
return 0;
}
static inline size_t do_fread(void *buff, size_t size,
size_t n, FILE *fp, const bool need_lock)
{
size_t count;
FCFS_CAPI_CONVERT_FP_EX(fp, EOF);
if (need_lock) {
PTHREAD_MUTEX_LOCK(&file->lock);
}
count = fcfs_file_read(file->fd, buff, size, n);
if (count != n) {
if (count < 0) {
file->error_no = (errno != 0 ? errno : EIO);
count = 0;
} else if (count == 0) {
file->eof = 1;
}
}
if (need_lock) {
PTHREAD_MUTEX_UNLOCK(&file->lock);
}
return count;
}
static inline size_t do_fwrite(const void *buff, size_t size,
size_t n, FILE *fp, const bool need_lock)
{
size_t count;
FCFS_CAPI_CONVERT_FP_EX(fp, EOF);
if (need_lock) {
PTHREAD_MUTEX_LOCK(&file->lock);
}
count = fcfs_file_write(file->fd, buff, size, n);
if (count != n) {
if (count < 0) {
file->error_no = (errno != 0 ? errno : EIO);
count = 0;
} else if (count == 0) {
file->error_no = (errno != 0 ? errno : EIO);
}
}
if (need_lock) {
PTHREAD_MUTEX_UNLOCK(&file->lock);
}
return count;
}
static inline int do_fputs(const char *s, FILE *fp, const bool need_lock)
{
int len;
int bytes;
FCFS_CAPI_CONVERT_FP_EX(fp, EOF);
if (need_lock) {
PTHREAD_MUTEX_LOCK(&file->lock);
}
len = strlen(s);
if (len == 0) {
bytes = 0;
} else {
bytes = fcfs_write(file->fd, s, len);
if (bytes <= 0) {
file->error_no = (errno != 0 ? errno : EIO);
bytes = EOF;
}
}
if (need_lock) {
PTHREAD_MUTEX_UNLOCK(&file->lock);
}
return bytes;
}
static inline char *do_fgets(char *s, int size,
FILE *fp, const bool need_lock)
{
size_t bytes;
FCFS_CAPI_CONVERT_FP_EX(fp, NULL);
if (need_lock) {
PTHREAD_MUTEX_LOCK(&file->lock);
}
bytes = fcfs_file_gets(file->fd, s, size);
if (bytes < 0) {
file->error_no = (errno != 0 ? errno : EIO);
} else if (bytes == 0) {
file->eof = 1;
}
if (need_lock) {
PTHREAD_MUTEX_UNLOCK(&file->lock);
}
return (bytes > 0 ? s : NULL);
}
int fcfs_fgetc_unlocked(FILE *fp)
{
const bool need_lock = false;
return do_fgetc(fp, need_lock);
}
int fcfs_fputc_unlocked(int c, FILE *fp)
{
const bool need_lock = false;
return do_fputc(c, fp, need_lock);
}
void fcfs_clearerr_unlocked(FILE *fp)
{
const bool need_lock = false;
return do_clearerr(fp, need_lock);
}
int fcfs_feof_unlocked(FILE *fp)
{
const bool need_lock = false;
return do_feof(fp, need_lock);
}
int fcfs_ferror_unlocked(FILE *fp)
{
const bool need_lock = false;
return do_ferror(fp, need_lock);
}
int fcfs_fileno_unlocked(FILE *fp)
{
const bool need_lock = false;
return do_fileno(fp, need_lock);
}
int fcfs_fflush_unlocked(FILE *fp)
{
const bool need_lock = false;
return do_fflush(fp, need_lock);
}
size_t fcfs_fread_unlocked(void *buff,
size_t size, size_t n, FILE *fp)
{
const bool need_lock = false;
return do_fread(buff, size, n, fp, need_lock);
}
size_t fcfs_fwrite_unlocked(const void *buff,
size_t size, size_t n, FILE *fp)
{
const bool need_lock = false;
return do_fwrite(buff, size, n, fp, need_lock);
}
int fcfs_fputs_unlocked(const char *s, FILE *fp)
{
const bool need_lock = false;
return do_fputs(s, fp, need_lock);
}
char *fcfs_fgets_unlocked(char *s, int size, FILE *fp)
{
const bool need_lock = false;
return do_fgets(s, size, fp, need_lock);
}
int fcfs_fgetc(FILE *fp)
{
const bool need_lock = true;
return do_fgetc(fp, need_lock);
}
int fcfs_fputc(int c, FILE *fp)
{
const bool need_lock = true;
return do_fputc(c, fp, need_lock);
}
void fcfs_clearerr(FILE *fp)
{
const bool need_lock = true;
return do_clearerr(fp, need_lock);
}
int fcfs_feof(FILE *fp)
{
const bool need_lock = true;
return do_feof(fp, need_lock);
}
int fcfs_ferror(FILE *fp)
{
const bool need_lock = true;
return do_ferror(fp, need_lock);
}
int fcfs_fileno(FILE *fp)
{
const bool need_lock = true;
return do_fileno(fp, need_lock);
}
int fcfs_fflush(FILE *fp)
{
const bool need_lock = true;
return do_fflush(fp, need_lock);
}
size_t fcfs_fread(void *buff,
size_t size, size_t n, FILE *fp)
{
const bool need_lock = true;
return do_fread(buff, size, n, fp, need_lock);
}
size_t fcfs_fwrite(const void *buff,
size_t size, size_t n, FILE *fp)
{
const bool need_lock = true;
return do_fwrite(buff, size, n, fp, need_lock);
}
int fcfs_fputs(const char *s, FILE *fp)
{
const bool need_lock = true;
return do_fputs(s, fp, need_lock);
}
char *fcfs_fgets(char *s, int size, FILE *fp)
{
const bool need_lock = true;
return do_fgets(s, size, fp, need_lock);
}
int fcfs_ungetc(int c, FILE *fp)
{
FCFS_CAPI_CONVERT_FP_EX(fp, EOF);
PTHREAD_MUTEX_LOCK(&file->lock);
if (c == EOF) {
file->error_no = EINVAL;
} else {
if (fcfs_lseek(file->fd, -1, SEEK_CUR) < 0) {
file->error_no = (errno != 0 ? errno : EIO);
c = EOF;
}
}
PTHREAD_MUTEX_UNLOCK(&file->lock);
return c;
}
int fcfs_fprintf(FILE *fp, const char *format, ...)
{
va_list ap;
int bytes;
FCFS_CAPI_CONVERT_FP(fp);
va_start(ap, format);
bytes = fcfs_vdprintf(file->fd, format, ap);
va_end(ap);
return bytes;
}
int fcfs_vfprintf(FILE *fp, const char *format, va_list ap)
{
FCFS_CAPI_CONVERT_FP(fp);
return fcfs_vdprintf(file->fd, format, ap);
}
ssize_t fcfs_getdelim(char **line, size_t *size, int delim, FILE *fp)
{
FCFS_CAPI_CONVERT_FP(fp);
return fcfs_file_getdelim(file->fd, line, size, delim);
}
static inline ssize_t do_readline(FILE *fp, char *buff,
size_t size, const bool need_lock)
{
size_t bytes;
FCFS_CAPI_CONVERT_FP(fp);
if (need_lock) {
PTHREAD_MUTEX_LOCK(&file->lock);
}
bytes = fcfs_file_readline(file->fd, buff, size);
if (bytes < 0) {
file->error_no = (errno != 0 ? errno : EIO);
} else if (bytes == 0) {
file->eof = 1;
}
if (need_lock) {
PTHREAD_MUTEX_UNLOCK(&file->lock);
}
return bytes;
}
ssize_t fcfs_readline(FILE *fp, char *buff, size_t size)
{
const bool need_lock = true;
return do_readline(fp, buff, size, need_lock);
}
ssize_t fcfs_readline_unlocked(FILE *fp, char *buff, size_t size)
{
const bool need_lock = false;
return do_readline(fp, buff, size, need_lock);
}
================================================
FILE: src/api/std/capi.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_CAPI_H
#define _FCFS_CAPI_H
#include "api_types.h"
#define fcfs_fopen(path, mode) \
fcfs_fopen_ex(&G_FCFS_PAPI_CTX, path, mode)
#define fcfs_fdopen(fd, mode) \
fcfs_fdopen_ex(&G_FCFS_PAPI_CTX, fd, mode)
#define fcfs_freopen(path, mode, fp) \
fcfs_freopen_ex(&G_FCFS_PAPI_CTX, path, mode, fp)
#ifdef __cplusplus
extern "C" {
#endif
int fcfs_capi_init();
void fcfs_capi_destroy();
FILE *fcfs_fopen_ex(FCFSPosixAPIContext *ctx,
const char *path, const char *mode);
FILE *fcfs_fdopen_ex(FCFSPosixAPIContext *ctx, int fd, const char *mode);
FILE *fcfs_freopen_ex(FCFSPosixAPIContext *ctx,
const char *path, const char *mode, FILE *fp);
int fcfs_fclose(FILE *fp);
int fcfs_fcloseall();
void fcfs_flockfile(FILE *fp);
int fcfs_ftrylockfile(FILE *fp);
void fcfs_funlockfile(FILE *fp);
int fcfs_fseek(FILE *fp, long offset, int whence);
int fcfs_fseeko(FILE *fp, off_t offset, int whence);
long fcfs_ftell(FILE *fp);
off_t fcfs_ftello(FILE *fp);
void fcfs_rewind(FILE *fp);
int fcfs_fgetpos(FILE *fp, fpos_t *pos);
int fcfs_fsetpos(FILE *fp, const fpos_t *pos);
int fcfs_fgetc_unlocked(FILE *fp);
int fcfs_fputc_unlocked(int c, FILE *fp);
static inline int fcfs_getc_unlocked(FILE *fp)
{
return fcfs_fgetc_unlocked(fp);
}
static inline int fcfs_putc_unlocked(int c, FILE *fp)
{
return fcfs_fputc_unlocked(c, fp);
}
void fcfs_clearerr_unlocked(FILE *fp);
int fcfs_feof_unlocked(FILE *fp);
int fcfs_ferror_unlocked(FILE *fp);
int fcfs_fileno_unlocked(FILE *fp);
int fcfs_fflush_unlocked(FILE *fp);
size_t fcfs_fread_unlocked(void *buff,
size_t size, size_t n, FILE *fp);
size_t fcfs_fwrite_unlocked(const void *buff,
size_t size, size_t n, FILE *fp);
//with terminating null byte ('\0')
char *fcfs_fgets_unlocked(char *s, int size, FILE *fp);
int fcfs_fputs_unlocked(const char *s, FILE *fp);
void fcfs_clearerr(FILE *fp);
int fcfs_feof(FILE *fp);
int fcfs_ferror(FILE *fp);
int fcfs_fileno(FILE *fp);
int fcfs_fgetc(FILE *fp);
//with terminating null byte ('\0')
char *fcfs_fgets(char *s, int size, FILE *fp);
int fcfs_getc(FILE *fp);
int fcfs_ungetc(int c, FILE *fp);
int fcfs_fputc(int c, FILE *fp);
int fcfs_fputs(const char *s, FILE *fp);
int fcfs_putc(int c, FILE *fp);
size_t fcfs_fread(void *buff, size_t size, size_t nmemb, FILE *fp);
size_t fcfs_fwrite(const void *buff, size_t size, size_t nmemb, FILE *fp);
int fcfs_fprintf(FILE *fp, const char *format, ...)
__gcc_attribute__ ((format (printf, 2, 3)));
int fcfs_vfprintf(FILE *fp, const char *format, va_list ap);
ssize_t fcfs_getdelim(char **line, size_t *size, int delim, FILE *fp);
static inline ssize_t fcfs_getline(char **line, size_t *size, FILE *fp)
{
return fcfs_getdelim(line, size, '\n', fp);
}
//without terminating null byte ('\0')
ssize_t fcfs_readline(FILE *fp, char *buff, size_t size);
//without terminating null byte ('\0')
ssize_t fcfs_readline_unlocked(FILE *fp, char *buff, size_t size);
//TODO
/*
int fcfs_fscanf(FILE *fp, const char *format, ...)
__gcc_attribute__ ((format (scanf, 2, 3)));
int fcfs_vfscanf(FILE *fp, const char *format, va_list ap);
*/
int fcfs_setvbuf(FILE *fp, char *buf, int mode, size_t size);
static inline void fcfs_setbuf(FILE *fp, char *buf)
{
fcfs_setvbuf(fp, buf, (buf != NULL ? _IOFBF : _IONBF), BUFSIZ);
}
static inline void fcfs_setbuffer(FILE *fp, char *buf, size_t size)
{
fcfs_setvbuf(fp, buf, (buf != NULL ? _IOFBF : _IONBF), size);
}
static inline void fcfs_setlinebuf(FILE *fp)
{
fcfs_setvbuf(fp, NULL, _IOLBF, 0);
}
int fcfs_fflush(FILE *fp);
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/api/std/fd_manager.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include "fastcommon/fast_mblock.h"
#include "fastcommon/shared_func.h"
#include "fastcommon/logger.h"
#include "fd_manager.h"
#define FILE_INFO_ALLOC_ONCE 1024
typedef struct fcfs_fd_manager_context {
volatile int generation;
volatile int in_realloc;
volatile int next_fd;
struct fast_mblock_man file_info_allocator; //element: FCFSPosixAPIFileInfo
FCFSPosixFilePtrArray file_parray;
} FCFSFDManagerContext;
static FCFSFDManagerContext fd_manager_ctx;
#define PARRAY_IN_REALLOC fd_manager_ctx.in_realloc
#define PARRAY_GENERATION fd_manager_ctx.generation
#define FINFO_ALLOCATOR fd_manager_ctx.file_info_allocator
#define PAPI_NEXT_FD fd_manager_ctx.next_fd
#define FILE_PARRAY fd_manager_ctx.file_parray
static int file_parray_realloc()
{
FCFSPosixAPIFileInfo **new_files;
volatile FCFSPosixAPIFileInfo **old_files;
int new_count;
int old_count;
int bytes;
if (!__sync_bool_compare_and_swap(&PARRAY_IN_REALLOC, 0, 1)) {
return 0;
}
old_count = FC_ATOMIC_GET(FILE_PARRAY.count);
new_count = old_count + FILE_INFO_ALLOC_ONCE;
bytes = sizeof(FCFSPosixAPIFileInfo *) * new_count;
new_files = (FCFSPosixAPIFileInfo **)fc_malloc(bytes);
if (new_files == NULL) {
__sync_bool_compare_and_swap(&PARRAY_IN_REALLOC, 1, 0);
return ENOMEM;
}
memset(new_files, 0, bytes);
old_files = FC_ATOMIC_GET(FILE_PARRAY.files);
if (old_count > 0) {
memcpy(new_files, old_files, old_count *
sizeof(FCFSPosixAPIFileInfo *));
}
__sync_bool_compare_and_swap(&FILE_PARRAY.files, old_files,
(volatile FCFSPosixAPIFileInfo **)new_files);
__sync_bool_compare_and_swap(&FILE_PARRAY.count,
old_count, new_count);
FC_ATOMIC_INC(PARRAY_GENERATION);
__sync_bool_compare_and_swap(&PARRAY_IN_REALLOC, 1, 0);
if (old_files != NULL) {
usleep(100000); //delay free
free(old_files);
}
return 0;
}
static int finfo_init_func(FCFSPosixAPIFileInfo *finfo, void *args)
{
int elt_count;
finfo->fd = __sync_add_and_fetch(&PAPI_NEXT_FD, 1);
elt_count = finfo->fd - FCFS_POSIX_API_FD_BASE;
if (elt_count <= FILE_PARRAY.count) {
return 0;
} else {
return file_parray_realloc();
}
}
int fcfs_fd_manager_init()
{
int result;
__sync_add_and_fetch(&PAPI_NEXT_FD, FCFS_POSIX_API_FD_BASE);
if ((result=fast_mblock_init_ex1(&FINFO_ALLOCATOR, "papi_file_info",
sizeof(FCFSPosixAPIFileInfo), FILE_INFO_ALLOC_ONCE, 0,
(fast_mblock_object_init_func)finfo_init_func,
NULL, true)) != 0)
{
return result;
}
return 0;
}
void fcfs_fd_manager_destroy()
{
fast_mblock_destroy(&FINFO_ALLOCATOR);
free(FILE_PARRAY.files);
FILE_PARRAY.count = 0;
}
#define FCFS_FD_TO_INDEX(fd) ((fd - FCFS_POSIX_API_FD_BASE) - 1)
static inline int set_file_info(const int index,
FCFSPosixAPIFileInfo *old_finfo,
FCFSPosixAPIFileInfo *new_finfo)
{
int old_generation;
do {
old_generation = FC_ATOMIC_GET(PARRAY_GENERATION);
if (!__sync_bool_compare_and_swap(&FILE_PARRAY.
files[index], old_finfo, new_finfo))
{
return EBUSY;
}
} while (FC_ATOMIC_GET(PARRAY_IN_REALLOC) || old_generation !=
FC_ATOMIC_GET(PARRAY_GENERATION));
return 0;
}
FCFSPosixAPIFileInfo *fcfs_fd_manager_alloc(const char *filename)
{
FCFSPosixAPIFileInfo *finfo;
if ((finfo=fast_mblock_alloc_object(&FINFO_ALLOCATOR)) == NULL) {
return finfo;
}
finfo->filename.len = strlen(filename);
finfo->filename.str = (char *)fc_malloc(finfo->filename.len + 2);
if (finfo->filename.str == NULL) {
fast_mblock_free_object(&FINFO_ALLOCATOR, finfo);
return NULL;
}
memcpy(finfo->filename.str, filename, finfo->filename.len + 1);
if (set_file_info(FCFS_FD_TO_INDEX(finfo->fd), NULL, finfo) == 0) {
return finfo;
} else {
logError("file: "__FILE__", line: %d, "
"set file info fail, filename: %s, fd: %d",
__LINE__, filename, finfo->fd);
free(finfo->filename.str);
FC_SET_STRING_NULL(finfo->filename);
fast_mblock_free_object(&FINFO_ALLOCATOR, finfo);
return NULL;
}
}
FCFSPosixAPIFileInfo *fcfs_fd_manager_get(const int fd)
{
int result;
int index;
FCFSPosixAPIFileInfo *finfo;
index = FCFS_FD_TO_INDEX(fd);
if (index >= 0 && index < FC_ATOMIC_GET(FILE_PARRAY.count)) {
finfo = (FCFSPosixAPIFileInfo *)FC_ATOMIC_GET(
FILE_PARRAY.files[index]);
result = finfo != NULL ? 0 : ENOENT;
} else {
finfo = NULL;
result = EOVERFLOW;
}
if (result != 0) {
logError("file: "__FILE__", line: %d, "
"get file info fail, fd: %d, errno: %d, error info: %s",
__LINE__, fd, result, STRERROR(result));
}
return finfo;
}
int fcfs_fd_manager_free(FCFSPosixAPIFileInfo *finfo)
{
int result;
int index;
index = FCFS_FD_TO_INDEX(finfo->fd);
if (index >= 0 && index < FC_ATOMIC_GET(FILE_PARRAY.count)) {
if (finfo == FC_ATOMIC_GET(FILE_PARRAY.files[index])) {
result = set_file_info(index, finfo, NULL);
} else {
result = ENOENT;
}
} else {
result = EOVERFLOW;
}
if (result == 0) {
free(finfo->filename.str);
FC_SET_STRING_NULL(finfo->filename);
fast_mblock_free_object(&FINFO_ALLOCATOR, finfo);
} else {
logError("file: "__FILE__", line: %d, "
"free file info fail, fd: %d, errno: %d, error info: %s",
__LINE__, finfo->fd, result, STRERROR(result));
}
return result;
}
================================================
FILE: src/api/std/fd_manager.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_FD_MANAGER_H
#define _FCFS_FD_MANAGER_H
#include "api_types.h"
#ifdef __cplusplus
extern "C" {
#endif
int fcfs_fd_manager_init();
void fcfs_fd_manager_destroy();
FCFSPosixAPIFileInfo *fcfs_fd_manager_alloc(const char *filename);
FCFSPosixAPIFileInfo *fcfs_fd_manager_get(const int fd);
static inline void fcfs_fd_manager_normalize_path(
FCFSPosixAPIFileInfo *finfo)
{
if (!(finfo->filename.len > 0 && finfo->filename.str
[finfo->filename.len - 1] == '/'))
{
*(finfo->filename.str + finfo->filename.len++) = '/';
*(finfo->filename.str + finfo->filename.len) = '\0';
}
}
int fcfs_fd_manager_free(FCFSPosixAPIFileInfo *finfo);
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/api/std/papi.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include "fastcommon/shared_func.h"
#include "fastcommon/logger.h"
#include "posix_api.h"
#include "papi.h"
#define FCFS_PAPI_MAGIC_NUMBER 1644551636
static FCFSPosixAPIFileInfo *do_open_ex(FCFSPosixAPIContext *ctx,
const char *path, const int flags, const int mode,
const FCFSPosixAPITPIDType tpid_type)
{
FCFSPosixAPIFileInfo *file;
FCFSAPIFileContext fctx;
int result;
if ((file=fcfs_fd_manager_alloc(path)) == NULL) {
errno = ENOMEM;
return NULL;
}
fcfs_posix_api_set_fctx(&fctx, ctx, mode, tpid_type);
if ((result=fcfs_api_open_ex(&ctx->api_ctx, &file->fi,
path, flags, &fctx)) != 0)
{
fcfs_fd_manager_free(file);
errno = result;
return NULL;
}
if (S_ISDIR(file->fi.dentry.stat.mode)) {
fcfs_fd_manager_normalize_path(file);
}
return file;
}
static inline int do_open(FCFSPosixAPIContext *ctx, const char *path,
const int flags, const int mode, const FCFSPosixAPITPIDType tpid_type)
{
FCFSPosixAPIFileInfo *file;
file = do_open_ex(ctx, path, flags, mode, tpid_type);
if (file != NULL) {
file->tpid_type = tpid_type;
return file->fd;
} else {
return -1;
}
}
static inline char *do_getcwd(FCFSPosixAPIContext *ctx,
string_t *cwd, size_t size, const int overflow_errno)
{
if (G_FCFS_PAPI_CWD == NULL) {
if (ctx->mountpoint.len >= size) {
errno = overflow_errno;
cwd->len = 0;
return NULL;
}
cwd->len = ctx->mountpoint.len;
memcpy(cwd->str, ctx->mountpoint.str, ctx->mountpoint.len);
*(cwd->str + cwd->len) = '\0';
return cwd->str;
}
if (ctx->mountpoint.len + G_FCFS_PAPI_CWD->len >= size) {
errno = overflow_errno;
cwd->len = 0;
return NULL;
}
cwd->len = ctx->mountpoint.len + G_FCFS_PAPI_CWD->len;
memcpy(cwd->str, ctx->mountpoint.str, ctx->mountpoint.len);
memcpy(cwd->str + ctx->mountpoint.len, G_FCFS_PAPI_CWD->str,
G_FCFS_PAPI_CWD->len);
*(cwd->str + cwd->len) = '\0';
return cwd->str;
}
static inline int do_getcwd1(FCFSPosixAPIContext *ctx,
string_t *cwd, size_t size)
{
if (do_getcwd(ctx, cwd, size, EOVERFLOW) == NULL) {
return -1;
}
if (cwd->len == 0 || cwd->str[cwd->len - 1] != '/') {
cwd->str[cwd->len++] = '/';
}
return 0;
}
static inline int papi_resolve_path(FCFSPosixAPIContext *ctx,
const char *func, const char **path,
char *full_filename, const int size)
{
char cwd[PATH_MAX];
string_t from_string;
string_t path_string;
if (**path != '/') {
from_string.str = cwd;
if (do_getcwd1(ctx, &from_string, sizeof(cwd)) != 0) {
return -1;
}
FC_SET_STRING(path_string, (char *)*path);
normalize_path(&from_string, &path_string, full_filename, size);
*path = full_filename;
}
FCFS_API_CHECK_PATH_MOUNTPOINT(ctx, *path, func);
*path += ctx->mountpoint.len;
return 0;
}
static int papi_resolve_pathat(FCFSPosixAPIContext *ctx, const char *func,
int fd, const char **path, char *full_filename, const int size)
{
FCFSPosixAPIFileInfo *file;
char cwd[PATH_MAX];
string_t from_string;
string_t path_string;
if (fd == AT_FDCWD) {
from_string.str = cwd;
if (do_getcwd1(ctx, &from_string, sizeof(cwd)) != 0) {
return -1;
}
FC_SET_STRING(path_string, (char *)*path);
normalize_path(&from_string, &path_string, full_filename, size);
FCFS_API_CHECK_PATH_MOUNTPOINT(ctx, full_filename, func);
*path = full_filename + ctx->mountpoint.len;
return 0;
}
if (**path == '/') {
FCFS_API_CHECK_PATH_MOUNTPOINT(ctx, *path, func);
*path += ctx->mountpoint.len;
return 0;
}
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
normalize_path1(file->filename.str, *path, full_filename, size);
*path = full_filename;
return 0;
}
int fcfs_open_ex(FCFSPosixAPIContext *ctx, const char *path, int flags, ...)
{
char full_fname[PATH_MAX];
va_list ap;
int fd;
int mode;
int result;
if ((result=papi_resolve_path(ctx, "open", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
va_start(ap, flags);
mode = va_arg(ap, int);
fd = do_open(ctx, path, flags, mode, fcfs_papi_tpid_type_tid);
va_end(ap);
return fd;
}
int fcfs_file_open(FCFSPosixAPIContext *ctx, const char *path,
const int flags, const int mode, const
FCFSPosixAPITPIDType tpid_type)
{
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_path(ctx, "open", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
return do_open(ctx, path, flags, mode, tpid_type);
}
int fcfs_openat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, int flags, ...)
{
char full_fname[PATH_MAX];
va_list ap;
int mode;
int new_fd;
int result;
if ((result=papi_resolve_pathat(ctx, "openat", fd, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
va_start(ap, flags);
mode = va_arg(ap, int);
new_fd = do_open(ctx, path, flags, mode, fcfs_papi_tpid_type_tid);
va_end(ap);
return new_fd;
}
int fcfs_creat_ex(FCFSPosixAPIContext *ctx, const char *path, mode_t mode)
{
return fcfs_open_ex(ctx, path, O_CREAT | O_TRUNC | O_WRONLY, mode);
}
int fcfs_close(int fd)
{
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
fcfs_api_close(&file->fi);
fcfs_fd_manager_free(file);
return 0;
}
int fcfs_fsync(int fd)
{
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
return fcfs_api_fsync(&file->fi,
fcfs_posix_api_gettid(
file->tpid_type));
}
int fcfs_fdatasync(int fd)
{
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
return fcfs_api_fdatasync(&file->fi,
fcfs_posix_api_gettid(
file->tpid_type));
}
static inline ssize_t do_write(FCFSPosixAPIFileInfo *file,
const void *buff, size_t count)
{
int result;
int write_bytes;
if ((result=fcfs_api_write_ex(&file->fi, buff, count, &write_bytes,
fcfs_posix_api_gettid(file->tpid_type))) != 0)
{
errno = result;
return -1;
} else {
return write_bytes;
}
}
ssize_t fcfs_write(int fd, const void *buff, size_t count)
{
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
return do_write(file, buff, count);
}
ssize_t fcfs_file_write(int fd, const void *buff, size_t size, size_t n)
{
FCFSPosixAPIFileInfo *file;
size_t expect;
size_t bytes;
size_t count;
size_t remain;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
expect = size * n;
bytes = do_write(file, buff, expect);
if (bytes == expect) {
count = n;
} else if (bytes > 0) {
count = bytes / size;
remain = bytes - (size * count);
fcfs_api_lseek(&file->fi, -1 * remain, SEEK_CUR);
} else {
count = 0;
}
return count;
}
ssize_t fcfs_pwrite(int fd, const void *buff, size_t count, off_t offset)
{
int result;
int write_bytes;
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
if ((result=fcfs_api_pwrite_ex(&file->fi, buff, count, offset,
&write_bytes, fcfs_posix_api_gettid(
file->tpid_type))) != 0)
{
errno = result;
return -1;
} else {
return write_bytes;
}
}
ssize_t fcfs_writev(int fd, const struct iovec *iov, int iovcnt)
{
int result;
int write_bytes;
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
if ((result=fcfs_api_writev_ex(&file->fi, iov, iovcnt, &write_bytes,
fcfs_posix_api_gettid(file->tpid_type))) != 0)
{
errno = result;
return -1;
} else {
return write_bytes;
}
}
ssize_t fcfs_pwritev(int fd, const struct iovec *iov,
int iovcnt, off_t offset)
{
int result;
int write_bytes;
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
if ((result=fcfs_api_pwritev_ex(&file->fi, iov, iovcnt, offset,
&write_bytes, fcfs_posix_api_gettid(
file->tpid_type))) != 0)
{
errno = result;
return -1;
} else {
return write_bytes;
}
}
static inline ssize_t do_read(FCFSPosixAPIFileInfo *file,
void *buff, size_t count)
{
int result;
int read_bytes;
if ((result=fcfs_api_read_ex(&file->fi, buff, count, &read_bytes,
fcfs_posix_api_gettid(file->tpid_type))) != 0)
{
errno = result;
return -1;
} else {
return read_bytes;
}
}
ssize_t fcfs_read(int fd, void *buff, size_t count)
{
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
return do_read(file, buff, count);
}
ssize_t fcfs_readahead(int fd, off64_t offset, size_t count)
{
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
return 0;
}
ssize_t fcfs_file_read(int fd, void *buff, size_t size, size_t n)
{
FCFSPosixAPIFileInfo *file;
size_t expect;
size_t bytes;
size_t count;
size_t remain;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
expect = size * n;
bytes = do_read(file, buff, expect);
if (bytes == expect) {
count = n;
} else if (bytes > 0) {
count = bytes / size;
remain = bytes - (size * count);
fcfs_api_lseek(&file->fi, -1 * remain, SEEK_CUR);
} else {
count = 0;
}
return count;
}
ssize_t fcfs_file_readline(int fd, char *s, size_t size)
{
FCFSPosixAPIFileInfo *file;
char *p;
char *end;
char *ch;
int read_bytes_once;
int current;
int bytes;
int remain;
if (size <= 0) {
errno = EINVAL;
return -1;
}
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
read_bytes_once = 64;
remain = size;
p = s;
while (1) {
current = FC_MIN(remain, read_bytes_once);
bytes = do_read(file, p, current);
if (bytes < 0) {
return -1;
} else if (bytes == 0) {
break;
}
end = p + bytes;
ch = p;
while (ch < end && *ch != '\n') {
++ch;
}
if (ch < end) { //found
p = ++ch; //skip the new line
remain = end - p;
if (remain > 0) {
fcfs_api_lseek(&file->fi, -1 * remain, SEEK_CUR);
}
break;
}
p = end;
if (bytes < current) { //end of file
break;
}
remain -= bytes;
if (remain == 0) {
break;
}
read_bytes_once *= 2;
}
return (p - s);
}
ssize_t fcfs_file_gets(int fd, char *s, size_t size)
{
ssize_t bytes;
if ((bytes=fcfs_file_readline(fd, s, size - 1)) >= 0) {
*(s + bytes) = '\0';
}
return bytes;
}
ssize_t fcfs_file_getdelim(int fd, char **line, size_t *size, int delim)
{
FCFSPosixAPIFileInfo *file;
char *buff;
char *p;
char *end;
char *ch;
ssize_t alloc;
ssize_t bytes;
ssize_t len;
ssize_t remain;
if (*line != NULL && *size < 0) {
errno = EINVAL;
return -1;
}
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
if (*size < 128) {
*size = 128;
buff = fc_malloc(*size);
if (buff == NULL) {
errno = ENOMEM;
return -1;
}
if (*line != NULL) {
free(*line);
}
*line = buff;
} else {
buff = *line;
}
remain = *size - 1;
p = buff;
while (1) {
bytes = do_read(file, p, remain);
if (bytes < 0) {
return -1;
} else if (bytes == 0) {
break;
}
end = p + bytes;
ch = p;
while (ch < end && *ch != delim) {
++ch;
}
if (ch < end) { //found
p = ++ch; //skip the new line
remain = end - p;
if (remain > 0) {
fcfs_api_lseek(&file->fi, -1 * remain, SEEK_CUR);
}
break;
}
if (bytes < remain) { //end of file
p = end;
break;
}
len = end - buff;
alloc = (*size) * 2;
buff = fc_malloc(alloc);
if (buff == NULL) {
errno = ENOMEM;
return -1;
}
memcpy(buff, *line, len);
free(*line);
*line = buff;
*size = alloc;
p = buff + len;
remain = (*size) - len;
}
*p = '\0';
return (p - buff);
}
ssize_t fcfs_pread(int fd, void *buff, size_t count, off_t offset)
{
int result;
int read_bytes;
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
if ((result=fcfs_api_pread_ex(&file->fi, buff, count, offset,
&read_bytes, fcfs_posix_api_gettid(
file->tpid_type))) != 0)
{
errno = result;
return -1;
} else {
return read_bytes;
}
}
ssize_t fcfs_readv(int fd, const struct iovec *iov, int iovcnt)
{
int result;
int read_bytes;
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
if ((result=fcfs_api_readv_ex(&file->fi, iov, iovcnt, &read_bytes,
fcfs_posix_api_gettid(file->tpid_type))) != 0)
{
errno = result;
return -1;
} else {
return read_bytes;
}
}
ssize_t fcfs_preadv(int fd, const struct iovec *iov,
int iovcnt, off_t offset)
{
int result;
int read_bytes;
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
if ((result=fcfs_api_preadv_ex(&file->fi, iov, iovcnt, offset,
&read_bytes, fcfs_posix_api_gettid(
file->tpid_type))) != 0)
{
errno = result;
return -1;
} else {
return read_bytes;
}
}
off_t fcfs_lseek(int fd, off_t offset, int whence)
{
int result;
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
if ((result=fcfs_api_lseek(&file->fi, offset, whence)) != 0) {
errno = result;
return -1;
} else {
return file->fi.offset;
}
}
off_t fcfs_ltell(int fd)
{
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
return file->fi.offset;
}
int fcfs_fallocate(int fd, int mode, off_t offset, off_t length)
{
int result;
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
if ((result=fcfs_api_fallocate_ex(&file->fi, mode, offset, length,
fcfs_posix_api_gettid(file->tpid_type))) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_truncate_ex(FCFSPosixAPIContext *ctx,
const char *path, off_t length)
{
FCFSAPIFileContext fctx;
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_path(ctx, "truncate", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
fcfs_posix_api_set_fctx(&fctx, ctx, ACCESSPERMS,
fcfs_papi_tpid_type_tid);
if ((result=fcfs_api_truncate_ex(&ctx->api_ctx,
path, length, &fctx)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_ftruncate(int fd, off_t length)
{
int result;
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
if ((result=fcfs_api_ftruncate_ex(&file->fi, length,
fcfs_posix_api_gettid(file->tpid_type))) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_lstat_ex(FCFSPosixAPIContext *ctx,
const char *path, struct stat *buf)
{
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_path(ctx, "lstat", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_lstat_ex(&ctx->api_ctx, path,
&ctx->api_ctx.owner.oper, buf)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_stat_ex(FCFSPosixAPIContext *ctx,
const char *path, struct stat *buf)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_path(ctx, "stat", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_stat_ex(&ctx->api_ctx, path, &ctx->
api_ctx.owner.oper, buf, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_fstat(int fd, struct stat *buf)
{
int result;
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
if ((result=fcfs_api_fstat(&file->fi, buf)) != 0) {
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_fstatat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, struct stat *buf, int flags)
{
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_pathat(ctx, "fstatat", fd, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_stat_ex(&ctx->api_ctx, path, &ctx->api_ctx.owner.
oper, buf, ((flags & AT_SYMLINK_NOFOLLOW) != 0 ? 0 :
FDIR_FLAGS_FOLLOW_SYMLINK))) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_flock(int fd, int operation)
{
FCFSPosixAPIFileInfo *file;
int result;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
if ((result=fcfs_api_flock(&file->fi, operation)) != 0) {
errno = result;
return -1;
} else {
return 0;
}
}
static int do_fcntl(FCFSPosixAPIFileInfo *file, int cmd, void *arg)
{
int64_t owner_id;
struct flock *lock;
int flags;
int result;
switch (cmd) {
/*
case F_DUPFD:
errno = EOPNOTSUPP;
return -1;
*/
case F_GETFD:
case F_SETFD:
return 0;
case F_GETFL:
return file->fi.flags;
case F_SETFL:
flags = (long)arg;
result = fcfs_api_set_file_flags(&file->fi, flags);
break;
case F_GETLK:
case F_SETLK:
case F_SETLKW:
lock = (struct flock *)arg;
if (cmd == F_GETLK) {
result = fcfs_api_getlk_ex(&file->fi, lock, &owner_id);
} else {
owner_id = fc_gettid();
result = fcfs_api_setlk_ex(&file->fi, lock,
owner_id, (cmd == F_SETLKW));
}
break;
default:
logError("file: "__FILE__", line: %d, "
"unsupport fcntl cmd: %d", __LINE__, cmd);
errno = EOPNOTSUPP;
return -1;
}
if (result != 0) {
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_fcntl(int fd, int cmd, ...)
{
FCFSPosixAPIFileInfo *file;
va_list ap;
void *arg;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
va_start(ap, cmd);
arg = va_arg(ap, void *);
va_end(ap);
return do_fcntl(file, cmd, arg);
}
int fcfs_symlink_ex(FCFSPosixAPIContext *ctx,
const char *link, const char *path)
{
char full_fname[PATH_MAX];
int result;
if (*link == '/') {
FCFS_API_CHECK_PATH_MOUNTPOINT(ctx, link, "symlink");
link += ctx->mountpoint.len;
}
if ((result=papi_resolve_path(ctx, "symlink", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_symlink_ex(&ctx->api_ctx, link, path,
&ctx->api_ctx.owner.oper, ACCESSPERMS)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_symlinkat_ex(FCFSPosixAPIContext *ctx, const char *link,
int fd, const char *path)
{
char full_fname[PATH_MAX];
int result;
if (*link == '/') {
FCFS_API_CHECK_PATH_MOUNTPOINT(ctx, link, "symlinkat");
link += ctx->mountpoint.len;
}
if ((result=papi_resolve_pathat(ctx, "symlinkat", fd, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_symlink_ex(&ctx->api_ctx, link, path,
&ctx->api_ctx.owner.oper, ACCESSPERMS)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_link_ex(FCFSPosixAPIContext *ctx,
const char *path1, const char *path2)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
char full_fname1[PATH_MAX];
char full_fname2[PATH_MAX];
int result;
if ((result=papi_resolve_path(ctx, "linkat", &path1,
full_fname1, sizeof(full_fname1))) != 0)
{
return result;
}
if ((result=papi_resolve_path(ctx, "linkat", &path2,
full_fname2, sizeof(full_fname2))) != 0)
{
return result;
}
if ((result=fcfs_api_link_ex(&ctx->api_ctx, path1, path2, &ctx->
api_ctx.owner.oper, ACCESSPERMS, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_linkat_ex(FCFSPosixAPIContext *ctx, int fd1,
const char *path1, int fd2, const char *path2, int flags)
{
char full_fname1[PATH_MAX];
char full_fname2[PATH_MAX];
int result;
if ((result=papi_resolve_pathat(ctx, "linkat", fd1, &path1,
full_fname1, sizeof(full_fname1))) != 0)
{
return result;
}
if ((result=papi_resolve_pathat(ctx, "linkat", fd2, &path2,
full_fname2, sizeof(full_fname2))) != 0)
{
return result;
}
if ((result=fcfs_api_link_ex(&ctx->api_ctx, path1, path2,
&ctx->api_ctx.owner.oper, ACCESSPERMS,
((flags & AT_SYMLINK_FOLLOW) != 0) ?
FDIR_FLAGS_FOLLOW_SYMLINK : 0)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
ssize_t fcfs_readlink_ex(FCFSPosixAPIContext *ctx,
const char *path, char *buff, size_t size)
{
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_path(ctx, "readlink", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_readlink(&ctx->api_ctx, path, &ctx->
api_ctx.owner.oper, buff, size)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
ssize_t fcfs_readlinkat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, char *buff, size_t size)
{
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_pathat(ctx, "readlinkat", fd, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_readlink(&ctx->api_ctx, path, &ctx->
api_ctx.owner.oper, buff, size)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_mknod_ex(FCFSPosixAPIContext *ctx,
const char *path, mode_t mode, dev_t dev)
{
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_path(ctx, "mknod", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_mknod_ex(&ctx->api_ctx, path, &ctx->
api_ctx.owner.oper, mode, dev)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_mknodat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, mode_t mode, dev_t dev)
{
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_pathat(ctx, "mknodat", fd, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_mknod_ex(&ctx->api_ctx, path, &ctx->
api_ctx.owner.oper, mode, dev)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_mkfifo_ex(FCFSPosixAPIContext *ctx,
const char *path, mode_t mode)
{
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_path(ctx, "mkfifo", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_mkfifo_ex(&ctx->api_ctx, path,
&ctx->api_ctx.owner.oper, mode)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_mkfifoat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, mode_t mode)
{
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_pathat(ctx, "mkfifoat", fd, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_mkfifo_ex(&ctx->api_ctx, path,
&ctx->api_ctx.owner.oper, mode)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_access_ex(FCFSPosixAPIContext *ctx,
const char *path, int mode)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_path(ctx, "access", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_access_ex(&ctx->api_ctx, path, mode,
&ctx->api_ctx.owner.oper, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_faccessat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, int mode, int flags)
{
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_pathat(ctx, "faccessat", fd, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_access_ex(&ctx->api_ctx, path,
mode, &ctx->api_ctx.owner.oper,
(flags & AT_SYMLINK_NOFOLLOW) ? 0 :
FDIR_FLAGS_FOLLOW_SYMLINK)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_euidaccess_ex(FCFSPosixAPIContext *ctx,
const char *path, int mode)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_path(ctx, "euidaccess", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_euidaccess_ex(&ctx->api_ctx, path, mode,
&ctx->api_ctx.owner.oper, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_utime_ex(FCFSPosixAPIContext *ctx, const char *path,
const struct utimbuf *times)
{
char full_fname[PATH_MAX];
int result;
FDIRClientOperFnamePair fname;
if ((result=papi_resolve_path(ctx, "utime", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
if ((result=fcfs_api_utime_ex(&ctx->api_ctx, &fname, times)) != 0) {
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_utimes_ex(FCFSPosixAPIContext *ctx, const char *path,
const struct timeval times[2])
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
char full_fname[PATH_MAX];
int result;
FDIRClientOperFnamePair fname;
if ((result=papi_resolve_path(ctx, "utimes", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
if ((result=fcfs_api_utimes_by_path_ex(&ctx->api_ctx,
&fname, times, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_futimes_ex(FCFSPosixAPIContext *ctx,
int fd, const struct timeval times[2])
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
FCFSPosixAPIFileInfo *file;
FDIRClientOperInodePair oino;
int result;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
FCFSAPI_SET_OPER_INODE_PAIR(oino, ctx->api_ctx.
owner.oper, file->fi.dentry.inode);
if ((result=fcfs_api_utimes_by_inode_ex(&ctx->api_ctx,
&oino, times, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_futimesat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, const struct timeval times[2])
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
char full_fname[PATH_MAX];
int result;
FDIRClientOperFnamePair fname;
if ((result=papi_resolve_pathat(ctx, "futimesat", fd, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
if ((result=fcfs_api_utimes_by_path_ex(&ctx->api_ctx,
&fname, times, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_futimens_ex(FCFSPosixAPIContext *ctx, int fd,
const struct timespec times[2])
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
FCFSPosixAPIFileInfo *file;
int result;
FDIRClientOperInodePair oino;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
FCFSAPI_SET_OPER_INODE_PAIR(oino, ctx->api_ctx.
owner.oper, file->fi.dentry.inode);
if ((result=fcfs_api_utimens_by_inode_ex(&ctx->api_ctx,
&oino, times, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_utimensat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, const struct timespec times[2], int flags)
{
char full_fname[PATH_MAX];
int result;
FDIRClientOperFnamePair fname;
if ((result=papi_resolve_pathat(ctx, "futimensat", fd, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
if ((result=fcfs_api_utimens_by_path_ex(&ctx->api_ctx, &fname,
times, (flags & AT_SYMLINK_NOFOLLOW) ?
0 : FDIR_FLAGS_FOLLOW_SYMLINK)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_unlink_ex(FCFSPosixAPIContext *ctx, const char *path)
{
char full_fname[PATH_MAX];
int result;
FDIRClientOperFnamePair fname;
if ((result=papi_resolve_path(ctx, "unlink", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
if ((result=fcfs_api_unlink_ex(&ctx->api_ctx, &fname,
fcfs_posix_api_gettid(fcfs_papi_tpid_type_tid))) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_unlinkat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, int flags)
{
char full_fname[PATH_MAX];
int result;
FDIRClientOperFnamePair fname;
if ((result=papi_resolve_pathat(ctx, "unlinkat", fd, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
if ((result=fcfs_api_remove_dentry_ex(&ctx->api_ctx, &fname,
((flags & AT_REMOVEDIR) ? FDIR_UNLINK_FLAGS_MATCH_DIR :
FDIR_UNLINK_FLAGS_MATCH_FILE), fcfs_posix_api_gettid(
fcfs_papi_tpid_type_tid))) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_rename_ex(FCFSPosixAPIContext *ctx,
const char *path1, const char *path2)
{
const int flags = 0;
int result;
char full_fname1[PATH_MAX];
char full_fname2[PATH_MAX];
if ((result=papi_resolve_path(ctx, "rename", &path1,
full_fname1, sizeof(full_fname1))) != 0)
{
return result;
}
if ((result=papi_resolve_path(ctx, "rename", &path2,
full_fname2, sizeof(full_fname2))) != 0)
{
return result;
}
if ((result=fcfs_api_rename_dentry_ex(&ctx->api_ctx, path1,
path2, &ctx->api_ctx.owner.oper, flags,
fcfs_posix_api_gettid(fcfs_papi_tpid_type_tid))) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
static inline int do_renameat(FCFSPosixAPIContext *ctx,
const char *func_name, int fd1, const char *path1,
int fd2, const char *path2, const int flags)
{
int result;
char full_fname1[PATH_MAX];
char full_fname2[PATH_MAX];
if ((result=papi_resolve_pathat(ctx, func_name, fd1, &path1,
full_fname1, sizeof(full_fname1))) != 0)
{
return result;
}
if ((result=papi_resolve_pathat(ctx, func_name, fd2, &path2,
full_fname2, sizeof(full_fname2))) != 0)
{
return result;
}
if ((result=fcfs_api_rename_dentry_ex(&ctx->api_ctx, path1,
path2, &ctx->api_ctx.owner.oper, flags,
fcfs_posix_api_gettid(fcfs_papi_tpid_type_tid))) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_renameat_ex(FCFSPosixAPIContext *ctx, int fd1,
const char *path1, int fd2, const char *path2)
{
const int flags = 0;
return do_renameat(ctx, "renameat", fd1, path1, fd2, path2, flags);
}
int fcfs_renameat2_ex(FCFSPosixAPIContext *ctx, int fd1,
const char *path1, int fd2, const char *path2,
unsigned int flags)
{
/* flags convert from FreeBSD to Linux */
#if defined(RENAME_SWAP) && defined(RENAME_EXCL)
if ((flags & RENAME_SWAP)) {
flags = ((flags & (~RENAME_SWAP)) | RENAME_EXCHANGE);
} else if ((flags & RENAME_EXCL)) {
flags = ((flags & (~RENAME_EXCL)) | RENAME_NOREPLACE);
}
#endif
return do_renameat(ctx, "renameat2", fd1, path1, fd2, path2, flags);
}
int fcfs_mkdir_ex(FCFSPosixAPIContext *ctx,
const char *path, mode_t mode)
{
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_path(ctx, "mkdir", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_mkdir_ex(&ctx->api_ctx, path,
&ctx->api_ctx.owner.oper, mode)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_mkdirat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, mode_t mode)
{
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_pathat(ctx, "mkdirat", fd, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_mkdir_ex(&ctx->api_ctx, path,
&ctx->api_ctx.owner.oper, mode)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_rmdir_ex(FCFSPosixAPIContext *ctx, const char *path)
{
const int flags = FDIR_UNLINK_FLAGS_MATCH_DIR;
int result;
char full_fname[PATH_MAX];
FDIRClientOperFnamePair fname;
if ((result=papi_resolve_path(ctx, "rmdir", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
if ((result=fcfs_api_remove_dentry_ex(&ctx->api_ctx, &fname, flags,
fcfs_posix_api_gettid(fcfs_papi_tpid_type_tid))) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_chown_ex(FCFSPosixAPIContext *ctx, const char *path,
uid_t owner, gid_t group)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
int result;
char full_fname[PATH_MAX];
FDIRClientOperFnamePair fname;
if ((result=papi_resolve_path(ctx, "chown", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
if ((result=fcfs_api_chown_ex(&ctx->api_ctx, &fname,
owner, group, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_lchown_ex(FCFSPosixAPIContext *ctx, const char *path,
uid_t owner, gid_t group)
{
const int flags = 0;
int result;
char full_fname[PATH_MAX];
FDIRClientOperFnamePair fname;
if ((result=papi_resolve_path(ctx, "lchown", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
if ((result=fcfs_api_chown_ex(&ctx->api_ctx, &fname,
owner, group, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_fchown(int fd, uid_t owner, gid_t group)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
int result;
FCFSPosixAPIFileInfo *file;
FDIRClientOperInodePair oino;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
FCFSAPI_SET_OPER_INODE_PAIR(oino, file->fi.ctx->
owner.oper, file->fi.dentry.inode);
if ((result=fcfs_api_chown_by_inode_ex(file->fi.ctx,
&oino, owner, group, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_fchownat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, uid_t owner, gid_t group, int flags)
{
int result;
char full_fname[PATH_MAX];
FDIRClientOperFnamePair fname;
if ((result=papi_resolve_pathat(ctx, "fchownat", fd, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
if ((result=fcfs_api_chown_ex(&ctx->api_ctx, &fname, owner,
group, (flags & AT_SYMLINK_NOFOLLOW) ?
0 : FDIR_FLAGS_FOLLOW_SYMLINK)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_chmod_ex(FCFSPosixAPIContext *ctx,
const char *path, mode_t mode)
{
const int flags = 0;
int result;
char full_fname[PATH_MAX];
FDIRClientOperFnamePair fname;
if ((result=papi_resolve_path(ctx, "chmod", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
if ((result=fcfs_api_chmod_ex(&ctx->api_ctx,
&fname, mode, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_fchmod(int fd, mode_t mode)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
int result;
FCFSPosixAPIFileInfo *file;
FDIRClientOperInodePair oino;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
FCFSAPI_SET_OPER_INODE_PAIR(oino, file->fi.ctx->
owner.oper, file->fi.dentry.inode);
if ((result=fcfs_api_chmod_by_inode_ex(file->fi.ctx,
&oino, mode, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_fchmodat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, mode_t mode, int flags)
{
int result;
char full_fname[PATH_MAX];
FDIRClientOperFnamePair fname;
if ((result=papi_resolve_pathat(ctx, "fchmodat", fd, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
if ((result=fcfs_api_chmod_ex(&ctx->api_ctx, &fname,
mode, (flags & AT_SYMLINK_NOFOLLOW) ?
0 : FDIR_FLAGS_FOLLOW_SYMLINK)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_statvfs_ex(FCFSPosixAPIContext *ctx,
const char *path, struct statvfs *buf)
{
char full_fname[PATH_MAX];
int result;
if ((result=papi_resolve_path(ctx, "chmod", &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
if ((result=fcfs_api_statvfs_ex(&ctx->api_ctx, path, buf)) != 0) {
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_fstatvfs(int fd, struct statvfs *buf)
{
FCFSPosixAPIFileInfo *file;
int result;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
if ((result=fcfs_api_statvfs_ex(file->fi.ctx,
file->filename.str, buf)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
static inline int do_setxattr(FCFSPosixAPIContext *ctx, const char *func,
const char *path, const char *name, const void *value,
size_t size, int flags)
{
FDIRClientOperFnamePair fname;
char full_fname[PATH_MAX];
key_value_pair_t xattr;
int result;
if ((result=papi_resolve_path(ctx, func, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
FC_SET_STRING(xattr.key, (char *)name);
FC_SET_STRING_EX(xattr.value, (char *)value, size);
if ((result=fcfs_api_set_xattr_by_path_ex(&ctx->api_ctx,
&fname, &xattr, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_setxattr_ex(FCFSPosixAPIContext *ctx, const char *path,
const char *name, const void *value, size_t size, int flags)
{
return do_setxattr(ctx, "setxattr", path, name, value, size,
(flags | FDIR_FLAGS_FOLLOW_SYMLINK));
}
int fcfs_lsetxattr_ex(FCFSPosixAPIContext *ctx, const char *path,
const char *name, const void *value, size_t size, int flags)
{
return do_setxattr(ctx, "lsetxattr", path, name, value, size,
(flags & (~FDIR_FLAGS_FOLLOW_SYMLINK)));
}
int fcfs_fsetxattr(int fd, const char *name, const void *value,
size_t size, int flags)
{
FDIRClientOperInodePair oino;
key_value_pair_t xattr;
FCFSPosixAPIFileInfo *file;
int result;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
FCFSAPI_SET_OPER_INODE_PAIR(oino, file->fi.ctx->
owner.oper, file->fi.dentry.inode);
FC_SET_STRING(xattr.key, (char *)name);
FC_SET_STRING_EX(xattr.value, (char *)value, size);
if ((result=fcfs_api_set_xattr_by_inode_ex(file->fi.ctx, &oino,
&xattr, (flags | FDIR_FLAGS_FOLLOW_SYMLINK))) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
#define GET_XATTR_FLAGS_BY_VSIZE(size, flags) \
((size == 0) ? (flags | FDIR_FLAGS_XATTR_GET_SIZE) : flags)
static inline ssize_t do_getxattr(FCFSPosixAPIContext *ctx,
const char *func, const char *path, const char *name,
void *value, size_t size, int flags)
{
FDIRClientOperFnamePair fname;
char full_fname[PATH_MAX];
string_t nm;
string_t vl;
int result;
if ((result=papi_resolve_path(ctx, func, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
FC_SET_STRING(nm, (char *)name);
FC_SET_STRING_EX(vl, (char *)value, 0);
if ((result=fcfs_api_get_xattr_by_path_ex(&ctx->api_ctx,
&fname, &nm, LOG_DEBUG, &vl, size,
GET_XATTR_FLAGS_BY_VSIZE(size, flags))) != 0)
{
errno = result;
return -1;
} else {
return vl.len;
}
}
ssize_t fcfs_getxattr_ex(FCFSPosixAPIContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
return do_getxattr(ctx, "getxattr", path, name, value, size, flags);
}
ssize_t fcfs_lgetxattr_ex(FCFSPosixAPIContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
const int flags = 0;
return do_getxattr(ctx, "lgetxattr", path, name, value, size, flags);
}
ssize_t fcfs_fgetxattr(int fd, const char *name,
void *value, size_t size)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
int result;
FCFSPosixAPIFileInfo *file;
string_t nm;
string_t vl;
FDIRClientOperInodePair oino;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
FCFSAPI_SET_OPER_INODE_PAIR(oino, file->fi.ctx->
owner.oper, file->fi.dentry.inode);
FC_SET_STRING(nm, (char *)name);
FC_SET_STRING_EX(vl, (char *)value, 0);
if ((result=fcfs_api_get_xattr_by_inode_ex(file->fi.ctx,
&oino, &nm, LOG_DEBUG, &vl, size,
GET_XATTR_FLAGS_BY_VSIZE(size, flags))) != 0)
{
errno = result;
return -1;
} else {
return vl.len;
}
}
static inline ssize_t do_listxattr(FCFSPosixAPIContext *ctx,
const char *func, const char *path, char *list,
size_t size, int flags)
{
FDIRClientOperFnamePair fname;
char full_fname[PATH_MAX];
string_t ls;
int result;
if ((result=papi_resolve_path(ctx, func, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
ls.str = list;
if ((result=fcfs_api_list_xattr_by_path_ex(&ctx->api_ctx, &fname, &ls,
size, GET_XATTR_FLAGS_BY_VSIZE(size, flags))) != 0)
{
errno = result;
return -1;
} else {
return ls.len;
}
}
ssize_t fcfs_listxattr_ex(FCFSPosixAPIContext *ctx,
const char *path, char *list, size_t size)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
return do_listxattr(ctx, "listattr", path, list, size, flags);
}
ssize_t fcfs_llistxattr_ex(FCFSPosixAPIContext *ctx,
const char *path, char *list, size_t size)
{
const int flags = 0;
return do_listxattr(ctx, "llistattr", path, list, size, flags);
}
ssize_t fcfs_flistxattr(int fd, char *list, size_t size)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
int result;
FCFSPosixAPIFileInfo *file;
string_t ls;
FDIRClientOperInodePair oino;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
FCFSAPI_SET_OPER_INODE_PAIR(oino, file->fi.ctx->
owner.oper, file->fi.dentry.inode);
ls.str = list;
if ((result=fcfs_api_list_xattr_by_inode_ex(file->fi.ctx, &oino, &ls,
size, GET_XATTR_FLAGS_BY_VSIZE(size, flags))) != 0)
{
errno = result;
return -1;
} else {
return ls.len;
}
}
static inline int do_removexattr(FCFSPosixAPIContext *ctx, const char *func,
const char *path, const char *name, int flags)
{
FDIRClientOperFnamePair fname;
char full_fname[PATH_MAX];
string_t nm;
int result;
if ((result=papi_resolve_path(ctx, func, &path,
full_fname, sizeof(full_fname))) != 0)
{
return result;
}
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
FC_SET_STRING(nm, (char *)name);
if ((result=fcfs_api_remove_xattr_by_path_ex(&ctx->api_ctx,
&fname, &nm, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_removexattr_ex(FCFSPosixAPIContext *ctx,
const char *path, const char *name)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
return do_removexattr(ctx, "removexattr", path, name, flags);
}
int fcfs_lremovexattr_ex(FCFSPosixAPIContext *ctx,
const char *path, const char *name)
{
const int flags = 0;
return do_removexattr(ctx, "lremovexattr", path, name, flags);
}
int fcfs_fremovexattr(int fd, const char *name)
{
const int flags = FDIR_FLAGS_FOLLOW_SYMLINK;
int result;
FCFSPosixAPIFileInfo *file;
string_t nm;
FDIRClientOperInodePair oino;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
FCFSAPI_SET_OPER_INODE_PAIR(oino, file->fi.ctx->
owner.oper, file->fi.dentry.inode);
FC_SET_STRING(nm, (char *)name);
if ((result=fcfs_api_remove_xattr_by_inode_ex(file->fi.ctx,
&oino, &nm, flags)) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
static FCFSPosixAPIDIR *do_opendir(FCFSPosixAPIContext *ctx,
FCFSPosixAPIFileInfo *file)
{
FDIRClientOperInodePair oino;
FCFSPosixAPIDIR *dir;
int result;
dir = (FCFSPosixAPIDIR *)fc_malloc(sizeof(FCFSPosixAPIDIR));
if (dir == NULL) {
errno = ENOMEM;
return NULL;
}
FCFSAPI_SET_OPER_INODE_PAIR(oino, file->fi.ctx->
owner.oper, file->fi.dentry.inode);
dir->file = file;
dir->magic = FCFS_PAPI_MAGIC_NUMBER;
dir->offset = 0;
fdir_client_compact_dentry_array_init(&dir->darray);
if ((result=fcfs_api_list_compact_dentry_by_inode_ex(
&ctx->api_ctx, &oino, &dir->darray)) != 0)
{
free(dir);
errno = result;
return NULL;
}
return dir;
}
DIR *fcfs_opendir_ex(FCFSPosixAPIContext *ctx, const char *path)
{
const int flags = O_RDONLY;
const mode_t mode = ACCESSPERMS | S_IFDIR;
FCFSPosixAPIFileInfo *file;
FCFSPosixAPIDIR *dir;
char full_fname[PATH_MAX];
if (papi_resolve_path(ctx, "opendir", &path,
full_fname, sizeof(full_fname)) != 0)
{
return NULL;
}
if ((file=do_open_ex(ctx, path, flags, mode,
fcfs_papi_tpid_type_tid)) == NULL)
{
return NULL;
}
if ((dir=do_opendir(ctx, file)) == NULL) {
fcfs_api_close(&file->fi);
fcfs_fd_manager_free(file);
}
return (DIR *)dir;
}
DIR *fcfs_fdopendir_ex(FCFSPosixAPIContext *ctx, int fd)
{
FCFSPosixAPIFileInfo *file;
FCFSPosixAPIDIR *dir;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return NULL;
}
if ((dir=do_opendir(ctx, file)) == NULL) {
fcfs_api_close(&file->fi);
fcfs_fd_manager_free(file);
}
return (DIR *)dir;
}
#define FCFS_CONVERT_DIRP_EX(dirp, ...) \
FCFSPosixAPIDIR *dir; \
dir = (FCFSPosixAPIDIR *)dirp; \
if (dir->magic != FCFS_PAPI_MAGIC_NUMBER) { \
errno = EBADF; \
return __VA_ARGS__; \
}
#define FCFS_CONVERT_DIRP(dirp) \
FCFS_CONVERT_DIRP_EX(dirp, -1)
#define FCFS_CONVERT_DIRP_VOID(dirp) \
FCFS_CONVERT_DIRP_EX(dirp)
int fcfs_closedir_ex(FCFSPosixAPIContext *ctx, DIR *dirp)
{
FCFS_CONVERT_DIRP(dirp);
fdir_client_compact_dentry_array_free(&dir->darray);
fcfs_api_close(&dir->file->fi);
fcfs_fd_manager_free(dir->file);
dir->magic = 0;
free(dir);
return 0;
}
static inline struct dirent *do_readdir(FCFSPosixAPIDIR *dir)
{
if (dir->offset < 0 || dir->offset >= dir->darray.count) {
return NULL;
}
return dir->darray.entries + dir->offset++;
}
struct dirent *fcfs_readdir_ex(FCFSPosixAPIContext *ctx, DIR *dirp)
{
FCFS_CONVERT_DIRP_EX(dirp, NULL);
return do_readdir(dir);
}
int fcfs_readdir_r_ex(FCFSPosixAPIContext *ctx, DIR *dirp,
struct dirent *entry, struct dirent **result)
{
struct dirent *current;
FCFS_CONVERT_DIRP(dirp);
if ((current=do_readdir(dir)) != NULL) {
memcpy(entry, current, sizeof(FDIRDirent));
*result = entry;
} else {
*result = NULL;
}
return 0;
}
void fcfs_seekdir_ex(FCFSPosixAPIContext *ctx, DIR *dirp, long loc)
{
FCFS_CONVERT_DIRP_VOID(dirp);
dir->offset = loc;
}
long fcfs_telldir_ex(FCFSPosixAPIContext *ctx, DIR *dirp)
{
FCFS_CONVERT_DIRP(dirp);
return dir->offset;
}
void fcfs_rewinddir_ex(FCFSPosixAPIContext *ctx, DIR *dirp)
{
FCFS_CONVERT_DIRP_VOID(dirp);
dir->offset = 0;
}
int fcfs_dirfd_ex(FCFSPosixAPIContext *ctx, DIR *dirp)
{
FCFS_CONVERT_DIRP(dirp);
if (fcfs_fd_manager_get(dir->file->fd) != dir->file) {
errno = EBADF;
return -1;
}
return dir->file->fd;
}
static int do_scandir(FCFSPosixAPIContext *ctx, const char *path,
struct dirent ***namelist, int (*filter)(const struct dirent *),
int (*compar)(const struct dirent **, const struct dirent **))
{
FDIRClientOperFnamePair fname;
FCFSPosixAPIDIR dir;
FDIRDirent *ent;
FDIRDirent *end;
FDIRDirent **cur;
int result;
int count;
fdir_client_compact_dentry_array_init(&dir.darray);
FCFSAPI_SET_PATH_OPER_FNAME(fname, &ctx->api_ctx,
ctx->api_ctx.owner.oper, path);
if ((result=fcfs_api_list_compact_dentry_by_path_ex(&ctx->
api_ctx, &fname, &dir.darray)) != 0)
{
errno = result;
return -1;
}
do {
if ((*namelist=fc_malloc(sizeof(FDIRDirent *) *
dir.darray.count)) == NULL)
{
errno = ENOMEM;
count = -1;
break;
}
count = 0;
if (dir.darray.count == 0) {
break;
}
cur = (FDIRDirent **)*namelist;
end = dir.darray.entries + dir.darray.count;
for (ent=dir.darray.entries; ent 1) {
qsort(*namelist, count, sizeof(struct dirent *),
(int (*)(const void *, const void *))compar);
}
}
} while (0);
fdir_client_compact_dentry_array_free(&dir.darray);
return count;
}
int fcfs_scandir_ex(FCFSPosixAPIContext *ctx, const char *path,
struct dirent ***namelist, int (*filter)(const struct dirent *),
int (*compar)(const struct dirent **, const struct dirent **))
{
char full_fname[PATH_MAX];
if (papi_resolve_path(ctx, "scandir", &path,
full_fname, sizeof(full_fname)) != 0)
{
return -1;
}
return do_scandir(ctx, path, namelist, filter, compar);
}
int fcfs_scandirat_ex(FCFSPosixAPIContext *ctx, int fd, const char *path,
struct dirent ***namelist, int (*filter)(const struct dirent *),
int (*compar)(const struct dirent **, const struct dirent **))
{
char full_fname[PATH_MAX];
if (papi_resolve_pathat(ctx, "scandirat", fd, &path,
full_fname, sizeof(full_fname)) != 0)
{
return -1;
}
return do_scandir(ctx, path, namelist, filter, compar);
}
static int do_chdir(const string_t *path)
{
string_t *cwd;
char *old_cwd;
if ((cwd=fc_malloc(sizeof(string_t) + path->len + 1)) == NULL) {
errno = ENOMEM;
return -1;
}
cwd->str = (char *)(cwd + 1);
memcpy(cwd->str, path->str, path->len + 1);
cwd->len = path->len;
old_cwd = (G_FCFS_PAPI_CWD != NULL ? G_FCFS_PAPI_CWD->str : NULL);
G_FCFS_PAPI_CWD = cwd;
if (old_cwd != NULL) {
free(old_cwd);
}
return 0;
}
int fcfs_chdir_ex(FCFSPosixAPIContext *ctx, const char *path)
{
char full_fname[PATH_MAX];
string_t cwd;
if (papi_resolve_path(ctx, "chdir", &path,
full_fname, sizeof(full_fname)) != 0)
{
return -1;
}
FC_SET_STRING(cwd, (char *)path);
return do_chdir(&cwd);
}
int fcfs_fchdir(int fd)
{
FCFSPosixAPIFileInfo *file;
char full_path[PATH_MAX];
string_t cwd;
char *p;
int len;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
p = strrchr(file->filename.str, '/');
if (p == NULL) {
errno = EBUSY;
return -1;
}
len = (p - file->filename.str) + 1;
if (len >= sizeof(full_path)) {
snprintf(full_path, sizeof(full_path), "%.*s",
len, file->filename.str);
} else {
memcpy(full_path, file->filename.str, len);
*(full_path + len) = '\0';
}
FC_SET_STRING_EX(cwd, full_path, len);
return do_chdir(&cwd);
}
char *fcfs_getcwd_ex(FCFSPosixAPIContext *ctx, char *buf, size_t size)
{
string_t cwd;
cwd.str = buf;
return do_getcwd(ctx, &cwd, size, ERANGE);
}
char *fcfs_getwd_ex(FCFSPosixAPIContext *ctx, char *buf)
{
string_t cwd;
cwd.str = buf;
return do_getcwd(ctx, &cwd, PATH_MAX, ENAMETOOLONG);
}
#define FCFS_API_NOT_IMPLEMENTED(api_name, retval) \
logError("file: "__FILE__", line: %d, " \
"function \"%s\" not implemented!", \
__LINE__, api_name); \
errno = EOPNOTSUPP; \
return retval
int fcfs_chroot_ex(FCFSPosixAPIContext *ctx, const char *path)
{
FCFS_API_NOT_IMPLEMENTED("chroot", -1);
}
int fcfs_dup_ex(FCFSPosixAPIContext *ctx, int fd)
{
logInfo("file: "__FILE__", line: %d, func: %s, "
"fd: %d", __LINE__, __FUNCTION__, fd);
FCFS_API_NOT_IMPLEMENTED("dup", -1);
}
int fcfs_dup2_ex(FCFSPosixAPIContext *ctx, int fd1, int fd2)
{
logInfo("file: "__FILE__", line: %d, func: %s, "
"fd1: %d, fd2: %d", __LINE__, __FUNCTION__, fd1, fd2);
FCFS_API_NOT_IMPLEMENTED("dup2", -1);
}
void *fcfs_mmap_ex(FCFSPosixAPIContext *ctx, void *addr, size_t length,
int prot, int flags, int fd, off_t offset)
{
FCFS_API_NOT_IMPLEMENTED("mmap", NULL);
}
int fcfs_munmap_ex(FCFSPosixAPIContext *ctx, void *addr, size_t length)
{
FCFS_API_NOT_IMPLEMENTED("munmap", -1);
}
int fcfs_lockf_ex(FCFSPosixAPIContext *ctx, int fd, int cmd, off_t len)
{
FCFSPosixAPIFileInfo *file;
struct flock lock;
int fcntl_cmd;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
switch (cmd) {
case F_LOCK:
fcntl_cmd = F_SETLKW;
lock.l_type = F_WRLCK;
break;
case F_TLOCK:
fcntl_cmd = F_SETLK;
lock.l_type = F_WRLCK;
break;
case F_ULOCK:
fcntl_cmd = F_SETLK;
lock.l_type = F_UNLCK;
break;
case F_TEST:
fcntl_cmd = F_GETLK;
lock.l_type = F_UNLCK;
break;
default:
errno = EOPNOTSUPP;
return -1;
}
lock.l_whence = SEEK_SET;
lock.l_start = file->fi.offset;
lock.l_len = len;
lock.l_pid = fcfs_posix_api_getpid();
return do_fcntl(file, fcntl_cmd, &lock);
}
int fcfs_posix_fallocate_ex(FCFSPosixAPIContext *ctx,
int fd, off_t offset, off_t len)
{
const int mode = 0;
int result;
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
if ((result=fcfs_api_fallocate_ex(&file->fi, mode, offset, len,
fcfs_posix_api_gettid(file->tpid_type))) != 0)
{
errno = result;
return -1;
} else {
return 0;
}
}
int fcfs_posix_fadvise_ex(FCFSPosixAPIContext *ctx, int fd,
off_t offset, off_t len, int advice)
{
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
return 0;
}
static int do_vdprintf(FCFSPosixAPIFileInfo *file,
const char *format, va_list ap)
{
#define FIXED_BUFFUER_SIZE (4 * 1024)
char fixed[FIXED_BUFFUER_SIZE];
char *buff;
int length;
int result;
va_list new_ap;
va_copy(new_ap, ap);
buff = fixed;
length = vsnprintf(buff, FIXED_BUFFUER_SIZE, format, ap);
if (length > FIXED_BUFFUER_SIZE - 1) { //overflow
buff = (char *)fc_malloc(length + 1);
if (buff == NULL) {
errno = ENOMEM;
return -1;
}
length = vsprintf(buff, format, new_ap);
}
va_end(new_ap);
result = do_write(file, buff, length);
if (buff != fixed) {
free(buff);
}
if (result != 0) {
errno = result;
return -1;
} else {
return length;
}
}
int fcfs_dprintf(int fd, const char *format, ...)
{
FCFSPosixAPIFileInfo *file;
va_list ap;
int bytes;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
va_start(ap, format);
bytes = do_vdprintf(file, format, ap);
va_end(ap);
return bytes;
}
int fcfs_vdprintf(int fd, const char *format, va_list ap)
{
FCFSPosixAPIFileInfo *file;
if ((file=fcfs_fd_manager_get(fd)) == NULL) {
errno = EBADF;
return -1;
}
return do_vdprintf(file, format, ap);
}
================================================
FILE: src/api/std/papi.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_PAPI_H
#define _FCFS_PAPI_H
#include
#include
#include "api_types.h"
#include "fd_manager.h"
#define G_FCFS_PAPI_CTX g_fcfs_papi_global_vars.ctx
#define G_FCFS_PAPI_CWD g_fcfs_papi_global_vars.cwd
#define fcfs_open(path, flags, ...) \
fcfs_open_ex(&G_FCFS_PAPI_CTX, path, flags, ##__VA_ARGS__)
#define fcfs_openat(fd, path, flags, ...) \
fcfs_openat_ex(&G_FCFS_PAPI_CTX, fd, path, flags, ##__VA_ARGS__)
#define fcfs_creat(path, mode) \
fcfs_creat_ex(&G_FCFS_PAPI_CTX, path, mode)
#define fcfs_truncate(path, length) \
fcfs_truncate_ex(&G_FCFS_PAPI_CTX, path, length)
#define fcfs_lstat(path, buf) \
fcfs_lstat_ex(&G_FCFS_PAPI_CTX, path, buf)
#define fcfs_stat(path, buf) \
fcfs_stat_ex(&G_FCFS_PAPI_CTX, path, buf)
#define fcfs_fstatat(fd, path, buf, flags) \
fcfs_fstatat_ex(&G_FCFS_PAPI_CTX, fd, path, buf, flags)
#define fcfs_symlink(link, path) \
fcfs_symlink_ex(&G_FCFS_PAPI_CTX, link, path)
#define fcfs_symlinkat(link, fd, path) \
fcfs_symlinkat_ex(&G_FCFS_PAPI_CTX, link, fd, path)
#define fcfs_link(path1, path2) \
fcfs_link_ex(&G_FCFS_PAPI_CTX, path1, path2)
#define fcfs_linkat(fd1, path1, fd2, path2, flags) \
fcfs_linkat_ex(&G_FCFS_PAPI_CTX, fd1, path1, fd2, path2, flags)
#define fcfs_readlink(path, buff, size) \
fcfs_readlink_ex(&G_FCFS_PAPI_CTX, path, buff, size)
#define fcfs_readlinkat(fd, path, buff, size) \
fcfs_readlinkat_ex(&G_FCFS_PAPI_CTX, fd, path, buff, size)
#define fcfs_mknod(path, mode, dev) \
fcfs_mknod_ex(&G_FCFS_PAPI_CTX, path, mode, dev)
#define fcfs_mknodat(fd, path, mode, dev) \
fcfs_mknodat_ex(&G_FCFS_PAPI_CTX, fd, path, mode, dev)
#define fcfs_mkfifo(path, mode) \
fcfs_mkfifo_ex(&G_FCFS_PAPI_CTX, path, mode)
#define fcfs_mkfifoat(fd, path, mode) \
fcfs_mkfifoat_ex(&G_FCFS_PAPI_CTX, fd, path, mode)
#define fcfs_access(path, mode) \
fcfs_access_ex(&G_FCFS_PAPI_CTX, path, mode)
#define fcfs_faccessat(fd, path, mode, flags) \
fcfs_faccessat_ex(&G_FCFS_PAPI_CTX, fd, path, mode, flags)
#define fcfs_euidaccess(path, mode) \
fcfs_euidaccess_ex(&G_FCFS_PAPI_CTX, path, mode)
#define fcfs_eaccess(path, mode) \
fcfs_eaccess_ex(&G_FCFS_PAPI_CTX, path, mode)
#define fcfs_utime(path, times) \
fcfs_utime_ex(&G_FCFS_PAPI_CTX, path, times)
#define fcfs_utimes(path, times) \
fcfs_utimes_ex(&G_FCFS_PAPI_CTX, path, times)
#define fcfs_futimes(fd, times) \
fcfs_futimes_ex(&G_FCFS_PAPI_CTX, fd, times)
#define fcfs_futimesat(fd, path, times) \
fcfs_futimesat_ex(&G_FCFS_PAPI_CTX, fd, path, times)
#define fcfs_futimens(fd, times) \
fcfs_futimens_ex(&G_FCFS_PAPI_CTX, fd, times)
#define fcfs_utimensat(fd, path, times, flags) \
fcfs_utimensat_ex(&G_FCFS_PAPI_CTX, fd, path, times, flags)
#define fcfs_unlink(path) \
fcfs_unlink_ex(&G_FCFS_PAPI_CTX, path)
#define fcfs_unlinkat(fd, path, flags) \
fcfs_unlinkat_ex(&G_FCFS_PAPI_CTX, fd, path, flags)
#define fcfs_rename(path1, path2) \
fcfs_rename_ex(&G_FCFS_PAPI_CTX, path1, path2)
#define fcfs_renameat(fd1, path1, fd2, path2) \
fcfs_renameat_ex(&G_FCFS_PAPI_CTX, fd1, path1, fd2, path2)
#define fcfs_renameat2(fd1, path1, fd2, path2, flags) \
fcfs_renameat2_ex(&G_FCFS_PAPI_CTX, fd1, path1, fd2, path2, flags)
#define fcfs_mkdir(path, mode) \
fcfs_mkdir_ex(&G_FCFS_PAPI_CTX, path, mode)
#define fcfs_mkdirat(fd, path, mode) \
fcfs_mkdirat_ex(&G_FCFS_PAPI_CTX, fd, path, mode)
#define fcfs_rmdir(path) \
fcfs_rmdir_ex(&G_FCFS_PAPI_CTX, path)
#define fcfs_chown(path, owner, group) \
fcfs_chown_ex(&G_FCFS_PAPI_CTX, path, owner, group)
#define fcfs_lchown(path, owner, group) \
fcfs_lchown_ex(&G_FCFS_PAPI_CTX, path, owner, group)
#define fcfs_fchownat(fd, path, owner, group, flags) \
fcfs_fchownat_ex(&G_FCFS_PAPI_CTX, fd, path, owner, group, flags)
#define fcfs_chmod(path, mode) \
fcfs_chmod_ex(&G_FCFS_PAPI_CTX, path, mode)
#define fcfs_fchmodat(fd, path, mode, flags) \
fcfs_fchmodat_ex(&G_FCFS_PAPI_CTX, fd, path, mode, flags)
#define fcfs_statvfs(path, buf) \
fcfs_statvfs_ex(&G_FCFS_PAPI_CTX, path, buf)
#define fcfs_setxattr(path, name, value, size, flags) \
fcfs_setxattr_ex(&G_FCFS_PAPI_CTX, path, name, value, size, flags)
#define fcfs_lsetxattr(path, name, value, size, flags) \
fcfs_lsetxattr_ex(&G_FCFS_PAPI_CTX, path, name, value, size, flags)
#define fcfs_getxattr(path, name, value, size) \
fcfs_getxattr_ex(&G_FCFS_PAPI_CTX, path, name, value, size)
#define fcfs_lgetxattr(path, name, value, size) \
fcfs_lgetxattr_ex(&G_FCFS_PAPI_CTX, path, name, value, size)
#define fcfs_listxattr(path, list, size) \
fcfs_listxattr_ex(&G_FCFS_PAPI_CTX, path, list, size)
#define fcfs_llistxattr(path, list, size) \
fcfs_llistxattr_ex(&G_FCFS_PAPI_CTX, path, list, size)
#define fcfs_removexattr(path, name) \
fcfs_removexattr_ex(&G_FCFS_PAPI_CTX, path, name)
#define fcfs_lremovexattr(path, name) \
fcfs_lremovexattr_ex(&G_FCFS_PAPI_CTX, path, name)
#define fcfs_opendir(path) \
fcfs_opendir_ex(&G_FCFS_PAPI_CTX, path)
#define fcfs_fdopendir(fd) \
fcfs_fdopendir_ex(&G_FCFS_PAPI_CTX, fd)
#define fcfs_closedir(dirp) \
fcfs_closedir_ex(&G_FCFS_PAPI_CTX, dirp)
#define fcfs_readdir(dirp) \
fcfs_readdir_ex(&G_FCFS_PAPI_CTX, dirp)
#define fcfs_readdir_r(dirp, entry, result) \
fcfs_readdir_r_ex(&G_FCFS_PAPI_CTX, dirp, entry, result)
#define fcfs_seekdir(dirp, loc) \
fcfs_seekdir_ex(&G_FCFS_PAPI_CTX, dirp, loc)
#define fcfs_telldir(dirp) \
fcfs_telldir_ex(&G_FCFS_PAPI_CTX, dirp)
#define fcfs_rewinddir(dirp) \
fcfs_rewinddir_ex(&G_FCFS_PAPI_CTX, dirp)
#define fcfs_dirfd(dirp) \
fcfs_dirfd_ex(&G_FCFS_PAPI_CTX, dirp)
#define fcfs_scandir(path, namelist, filter, compar) \
fcfs_scandir_ex(&G_FCFS_PAPI_CTX, path, namelist, filter, compar)
#define fcfs_scandirat(fd, path, namelist, filter, compar) \
fcfs_scandirat_ex(&G_FCFS_PAPI_CTX, fd, path, namelist, filter, compar)
#define fcfs_lockf(fd, cmd, len) \
fcfs_lockf_ex(&G_FCFS_PAPI_CTX, fd, cmd, len)
#define fcfs_posix_fallocate(fd, offset, len) \
fcfs_posix_fallocate_ex(&G_FCFS_PAPI_CTX, fd, offset, len)
#define fcfs_posix_fadvise(fd, offset, len, advice) \
fcfs_posix_fadvise_ex(&G_FCFS_PAPI_CTX, fd, offset, len, advice)
#define fcfs_chdir(path) \
fcfs_chdir_ex(&G_FCFS_PAPI_CTX, path)
#define fcfs_getcwd(buf, size) \
fcfs_getcwd_ex(&G_FCFS_PAPI_CTX, buf, size)
#define fcfs_getwd(buf) \
fcfs_getwd_ex(&G_FCFS_PAPI_CTX, buf)
#define fcfs_chroot(path) \
fcfs_chroot_ex(&G_FCFS_PAPI_CTX, path)
#define fcfs_dup(fd) \
fcfs_dup_ex(&G_FCFS_PAPI_CTX, fd)
#define fcfs_dup2(fd1, fd2) \
fcfs_dup2_ex(&G_FCFS_PAPI_CTX, fd1, fd2)
#define fcfs_mmap(addr, length, prot, flags, fd, offset) \
fcfs_mmap_ex(&G_FCFS_PAPI_CTX, addr, length, prot, flags, fd, offset)
#define fcfs_munmap(addr, length) \
fcfs_munmap_ex(&G_FCFS_PAPI_CTX, addr, length)
#ifdef __cplusplus
extern "C" {
#endif
int fcfs_open_ex(FCFSPosixAPIContext *ctx,
const char *path, int flags, ...);
int fcfs_openat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, int flags, ...);
int fcfs_creat_ex(FCFSPosixAPIContext *ctx,
const char *path, mode_t mode);
int fcfs_close(int fd);
int fcfs_fsync(int fd);
int fcfs_fdatasync(int fd);
ssize_t fcfs_write(int fd, const void *buff, size_t count);
ssize_t fcfs_pwrite(int fd, const void *buff,
size_t count, off_t offset);
ssize_t fcfs_writev(int fd, const struct iovec *iov, int iovcnt);
ssize_t fcfs_pwritev(int fd, const struct iovec *iov,
int iovcnt, off_t offset);
ssize_t fcfs_read(int fd, void *buff, size_t count);
ssize_t fcfs_pread(int fd, void *buff, size_t count, off_t offset);
ssize_t fcfs_readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t fcfs_preadv(int fd, const struct iovec *iov,
int iovcnt, off_t offset);
ssize_t fcfs_readahead(int fd, off64_t offset, size_t count);
off_t fcfs_lseek(int fd, off_t offset, int whence);
off_t fcfs_ltell(int fd);
int fcfs_fallocate(int fd, int mode, off_t offset, off_t length);
int fcfs_truncate_ex(FCFSPosixAPIContext *ctx,
const char *path, off_t length);
int fcfs_ftruncate(int fd, off_t length);
int fcfs_lstat_ex(FCFSPosixAPIContext *ctx,
const char *path, struct stat *buf);
int fcfs_stat_ex(FCFSPosixAPIContext *ctx,
const char *path, struct stat *buf);
int fcfs_fstat(int fd, struct stat *buf);
int fcfs_fstatat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, struct stat *buf, int flags);
int fcfs_flock(int fd, int operation);
int fcfs_fcntl(int fd, int cmd, ...);
int fcfs_symlink_ex(FCFSPosixAPIContext *ctx,
const char *link, const char *path);
int fcfs_symlinkat_ex(FCFSPosixAPIContext *ctx,
const char *link, int fd, const char *path);
int fcfs_link_ex(FCFSPosixAPIContext *ctx,
const char *path1, const char *path2);
int fcfs_linkat_ex(FCFSPosixAPIContext *ctx, int fd1,
const char *path1, int fd2, const char *path2,
int flags);
ssize_t fcfs_readlink_ex(FCFSPosixAPIContext *ctx,
const char *path, char *buff, size_t size);
ssize_t fcfs_readlinkat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, char *buff, size_t size);
int fcfs_mknod_ex(FCFSPosixAPIContext *ctx,
const char *path, mode_t mode, dev_t dev);
int fcfs_mknodat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, mode_t mode, dev_t dev);
int fcfs_mkfifo_ex(FCFSPosixAPIContext *ctx,
const char *path, mode_t mode);
int fcfs_mkfifoat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, mode_t mode);
int fcfs_access_ex(FCFSPosixAPIContext *ctx,
const char *path, int mode);
int fcfs_faccessat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, int mode, int flags);
int fcfs_euidaccess_ex(FCFSPosixAPIContext *ctx,
const char *path, int mode);
static inline int fcfs_eaccess_ex(FCFSPosixAPIContext *ctx,
const char *path, int mode)
{
return fcfs_euidaccess_ex(ctx, path, mode);
}
int fcfs_utime_ex(FCFSPosixAPIContext *ctx, const char *path,
const struct utimbuf *times);
int fcfs_utimes_ex(FCFSPosixAPIContext *ctx, const char *path,
const struct timeval times[2]);
int fcfs_futimes_ex(FCFSPosixAPIContext *ctx,
int fd, const struct timeval times[2]);
int fcfs_futimesat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, const struct timeval times[2]);
int fcfs_futimens_ex(FCFSPosixAPIContext *ctx, int fd,
const struct timespec times[2]);
int fcfs_utimensat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, const struct timespec times[2], int flags);
int fcfs_unlink_ex(FCFSPosixAPIContext *ctx, const char *path);
int fcfs_unlinkat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, int flags);
int fcfs_rename_ex(FCFSPosixAPIContext *ctx,
const char *path1, const char *path2);
int fcfs_renameat_ex(FCFSPosixAPIContext *ctx, int fd1,
const char *path1, int fd2, const char *path2);
//renameatx_np for FreeBSD
int fcfs_renameat2_ex(FCFSPosixAPIContext *ctx, int fd1,
const char *path1, int fd2, const char *path2,
unsigned int flags);
int fcfs_mkdir_ex(FCFSPosixAPIContext *ctx,
const char *path, mode_t mode);
int fcfs_mkdirat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, mode_t mode);
int fcfs_rmdir_ex(FCFSPosixAPIContext *ctx, const char *path);
int fcfs_chown_ex(FCFSPosixAPIContext *ctx, const char *path,
uid_t owner, gid_t group);
int fcfs_lchown_ex(FCFSPosixAPIContext *ctx, const char *path,
uid_t owner, gid_t group);
int fcfs_fchown(int fd, uid_t owner, gid_t group);
int fcfs_fchownat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, uid_t owner, gid_t group, int flags);
int fcfs_chmod_ex(FCFSPosixAPIContext *ctx,
const char *path, mode_t mode);
int fcfs_fchmod(int fd, mode_t mode);
int fcfs_fchmodat_ex(FCFSPosixAPIContext *ctx, int fd,
const char *path, mode_t mode, int flags);
int fcfs_statvfs_ex(FCFSPosixAPIContext *ctx,
const char *path, struct statvfs *buf);
int fcfs_fstatvfs(int fd, struct statvfs *buf);
int fcfs_setxattr_ex(FCFSPosixAPIContext *ctx, const char *path,
const char *name, const void *value, size_t size, int flags);
int fcfs_lsetxattr_ex(FCFSPosixAPIContext *ctx, const char *path,
const char *name, const void *value, size_t size, int flags);
int fcfs_fsetxattr(int fd, const char *name, const void *value,
size_t size, int flags);
ssize_t fcfs_getxattr_ex(FCFSPosixAPIContext *ctx, const char *path,
const char *name, void *value, size_t size);
ssize_t fcfs_lgetxattr_ex(FCFSPosixAPIContext *ctx, const char *path,
const char *name, void *value, size_t size);
ssize_t fcfs_fgetxattr(int fd, const char *name,
void *value, size_t size);
ssize_t fcfs_listxattr_ex(FCFSPosixAPIContext *ctx,
const char *path, char *list, size_t size);
ssize_t fcfs_llistxattr_ex(FCFSPosixAPIContext *ctx,
const char *path, char *list, size_t size);
ssize_t fcfs_flistxattr(int fd, char *list, size_t size);
int fcfs_removexattr_ex(FCFSPosixAPIContext *ctx,
const char *path, const char *name);
int fcfs_lremovexattr_ex(FCFSPosixAPIContext *ctx,
const char *path, const char *name);
int fcfs_fremovexattr(int fd, const char *name);
DIR *fcfs_opendir_ex(FCFSPosixAPIContext *ctx, const char *path);
DIR *fcfs_fdopendir_ex(FCFSPosixAPIContext *ctx, int fd);
int fcfs_closedir_ex(FCFSPosixAPIContext *ctx, DIR *dirp);
struct dirent *fcfs_readdir_ex(FCFSPosixAPIContext *ctx, DIR *dirp);
int fcfs_readdir_r_ex(FCFSPosixAPIContext *ctx, DIR *dirp,
struct dirent *entry, struct dirent **result);
void fcfs_seekdir_ex(FCFSPosixAPIContext *ctx, DIR *dirp, long loc);
long fcfs_telldir_ex(FCFSPosixAPIContext *ctx, DIR *dirp);
void fcfs_rewinddir_ex(FCFSPosixAPIContext *ctx, DIR *dirp);
int fcfs_dirfd_ex(FCFSPosixAPIContext *ctx, DIR *dirp);
int fcfs_scandir_ex(FCFSPosixAPIContext *ctx, const char *path,
struct dirent ***namelist, int (*filter)(const struct dirent *),
int (*compar)(const struct dirent **, const struct dirent **));
int fcfs_scandirat_ex(FCFSPosixAPIContext *ctx, int fd, const char *path,
struct dirent ***namelist, int (*filter)(const struct dirent *),
int (*compar)(const struct dirent **, const struct dirent **));
int fcfs_lockf_ex(FCFSPosixAPIContext *ctx, int fd, int cmd, off_t len);
int fcfs_posix_fallocate_ex(FCFSPosixAPIContext *ctx,
int fd, off_t offset, off_t len);
int fcfs_posix_fadvise_ex(FCFSPosixAPIContext *ctx, int fd,
off_t offset, off_t len, int advice);
int fcfs_dprintf(int fd, const char *format, ...)
__gcc_attribute__ ((format (printf, 2, 3)));
int fcfs_vdprintf(int fd, const char *format, va_list ap);
int fcfs_chdir_ex(FCFSPosixAPIContext *ctx, const char *path);
int fcfs_fchdir(int fd);
char *fcfs_getcwd_ex(FCFSPosixAPIContext *ctx, char *buf, size_t size);
char *fcfs_getwd_ex(FCFSPosixAPIContext *ctx, char *buf);
int fcfs_chroot_ex(FCFSPosixAPIContext *ctx, const char *path);
int fcfs_dup_ex(FCFSPosixAPIContext *ctx, int fd);
int fcfs_dup2_ex(FCFSPosixAPIContext *ctx, int fd1, int fd2);
void *fcfs_mmap_ex(FCFSPosixAPIContext *ctx, void *addr, size_t length,
int prot, int flags, int fd, off_t offset);
int fcfs_munmap_ex(FCFSPosixAPIContext *ctx, void *addr, size_t length);
/* following functions for internal use only */
static inline FCFSPosixAPIFileInfo *fcfs_get_file_handle(int fd)
{
return fcfs_fd_manager_get(fd);
}
int fcfs_file_open(FCFSPosixAPIContext *ctx, const char *path,
const int flags, const int mode, const
FCFSPosixAPITPIDType tpid_type);
//for fread
ssize_t fcfs_file_read(int fd, void *buff, size_t size, size_t n);
//for fwrite
ssize_t fcfs_file_write(int fd, const void *buff, size_t size, size_t n);
ssize_t fcfs_file_readline(int fd, char *s, size_t size);
//for fgets
ssize_t fcfs_file_gets(int fd, char *s, size_t size);
//for getdelim
ssize_t fcfs_file_getdelim(int fd, char **line, size_t *size, int delim);
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/api/std/posix_api.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include "fastcommon/logger.h"
#include "sf/idempotency/client/client_channel.h"
#include "posix_api.h"
#define DUMMY_MOUNTPOINT_STR "/fastcfs/dummy/"
#define DUMMY_MOUNTPOINT_LEN (sizeof(DUMMY_MOUNTPOINT_STR) - 1)
FCFSPosixAPIGlobalVars g_fcfs_papi_global_vars = {
{{NULL, NULL}, {DUMMY_MOUNTPOINT_STR, DUMMY_MOUNTPOINT_LEN}}
};
static int load_posix_api_config(FCFSPosixAPIContext *ctx,
const char *ns, IniFullContext *ini_ctx,
const char *fdir_section_name)
{
int result;
ctx->nsmp.ns = (char *)ns;
FC_SET_STRING_NULL(ctx->mountpoint);
if ((result=fcfs_api_load_ns_mountpoint(ini_ctx,
fdir_section_name, &ctx->nsmp,
&ctx->mountpoint, false)) != 0)
{
return result;
}
return 0;
}
int fcfs_posix_api_init_ex1(FCFSPosixAPIContext *ctx, const char
*log_prefix_name, const char *ns, const char *config_filename,
const char *fdir_section_name, const char *fs_section_name,
const bool publish)
{
const bool need_lock = true;
const bool persist_additional_gids = false;
int result;
IniContext iniContext;
IniFullContext ini_ctx;
log_try_init();
if ((result=iniLoadFromFile(config_filename, &iniContext)) != 0) {
logError("file: "__FILE__", line: %d, "
"load conf file \"%s\" fail, ret code: %d",
__LINE__, config_filename, result);
return result;
}
FAST_INI_SET_FULL_CTX_EX(ini_ctx, config_filename,
NULL, &iniContext);
do {
if ((result=load_posix_api_config(ctx, ns, &ini_ctx,
fdir_section_name)) != 0)
{
break;
}
if ((result=fcfs_api_pooled_init_ex1(&ctx->api_ctx,
ns, &ini_ctx, fdir_section_name,
fs_section_name, need_lock,
persist_additional_gids)) != 0)
{
break;
}
if ((result=fcfs_api_check_mountpoint(config_filename,
&ctx->mountpoint)) != 0)
{
break;
}
if ((result=fcfs_api_load_idempotency_config_ex(log_prefix_name,
&ini_ctx, fdir_section_name, fs_section_name)) != 0)
{
break;
}
} while (0);
iniFreeContext(&iniContext);
if (result != 0) {
return result;
}
if ((result=fcfs_api_client_session_create(
&ctx->api_ctx, publish)) != 0)
{
return result;
}
return fcfs_fd_manager_init();
}
void fcfs_posix_api_log_configs_ex(FCFSPosixAPIContext *ctx,
const char *fdir_section_name, const char *fs_section_name)
{
BufferInfo sf_idempotency_config;
char buff[256];
char rdma_busy_polling[128];
char owner_config[2 * NAME_MAX + 64];
sf_idempotency_config.buff = buff;
sf_idempotency_config.alloc_size = sizeof(buff);
fcfs_api_log_client_common_configs(&ctx->api_ctx,
fdir_section_name, fs_section_name,
&sf_idempotency_config, owner_config);
if (ctx->api_ctx.rdma.enabled) {
sprintf(rdma_busy_polling, "rdma busy polling: %s, ",
ctx->api_ctx.rdma.busy_polling ? "true" : "false");
} else {
*rdma_busy_polling = '\0';
}
logInfo("%sFastDIR namespace: %s, %smountpoint: %s, %s",
rdma_busy_polling, ctx->nsmp.ns,
sf_idempotency_config.buff,
ctx->nsmp.mountpoint, owner_config);
}
void fcfs_posix_api_destroy_ex(FCFSPosixAPIContext *ctx)
{
if (ctx->mountpoint.str != NULL) {
fcfs_api_free_ns_mountpoint(&ctx->nsmp);
ctx->mountpoint.str = NULL;
fcfs_api_destroy_ex(&ctx->api_ctx);
}
}
================================================
FILE: src/api/std/posix_api.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_POSIX_API_H
#define _FCFS_POSIX_API_H
#include
#include
#include "fastcommon/shared_func.h"
#include "api_types.h"
#include "fd_manager.h"
#include "papi.h"
#include "capi.h"
#ifdef __cplusplus
extern "C" {
#endif
extern FCFSPosixAPIGlobalVars g_fcfs_papi_global_vars;
/** FastCFS POSIX API init
* parameters:
* ctx: the POSIX API context
* log_prefix_name: the prefix name for log filename, NULL for stderr
* ns: the namespace/poolname of FastDIR
* config_filename: the config filename, eg. /etc/fastcfs/fcfs/fuse.conf
* fdir_section_name: the section name of FastDIR
* fs_section_name: the section name of FastStore
* publish: if publish the session, this parameter is valid when auth enabled
* return: error no, 0 for success, != 0 fail
*/
int fcfs_posix_api_init_ex1(FCFSPosixAPIContext *ctx,
const char *log_prefix_name, const char *ns,
const char *config_filename, const char *fdir_section_name,
const char *fs_section_name, const bool publish);
/** FastCFS POSIX API init with default section names
* parameters:
* ctx: the POSIX API context
* log_prefix_name: the prefix name for log filename, NULL for stderr
* ns: the namespace/poolname of FastDIR
* config_filename: the config filename, eg. /etc/fastcfs/fcfs/fuse.conf
* return: error no, 0 for success, != 0 fail
*/
static inline int fcfs_posix_api_init_ex(FCFSPosixAPIContext *ctx,
const char *log_prefix_name, const char *ns,
const char *config_filename)
{
const bool publish = true;
return fcfs_posix_api_init_ex1(ctx, log_prefix_name, ns,
config_filename, FCFS_API_DEFAULT_FASTDIR_SECTION_NAME,
FCFS_API_DEFAULT_FASTSTORE_SECTION_NAME, publish);
}
/** FastCFS POSIX API init with the global context
* parameters:
* log_prefix_name: the prefix name for log filename, NULL for stderr
* ns: the namespace/poolname of FastDIR
* config_filename: the config filename, eg. /etc/fastcfs/fcfs/fuse.conf
* return: error no, 0 for success, != 0 fail
*/
static inline int fcfs_posix_api_init(const char *log_prefix_name,
const char *ns, const char *config_filename)
{
return fcfs_posix_api_init_ex(&g_fcfs_papi_global_vars.ctx,
log_prefix_name, ns, config_filename);
}
/** log configs of FastCFS POSIX API
* parameters:
* ctx: the POSIX API context
* fdir_section_name: the section name of FastDIR
* fs_section_name: the section name of FastStore
* return: none
*/
void fcfs_posix_api_log_configs_ex(FCFSPosixAPIContext *ctx,
const char *fdir_section_name, const char *fs_section_name);
/** log configs of FastCFS POSIX API with the global context
* and default section names
*
* return: none
*/
static inline void fcfs_posix_api_log_configs()
{
fcfs_posix_api_log_configs_ex(&g_fcfs_papi_global_vars.ctx,
FCFS_API_DEFAULT_FASTDIR_SECTION_NAME,
FCFS_API_DEFAULT_FASTSTORE_SECTION_NAME);
}
/** FastCFS POSIX API start (create the background threads)
* parameters:
* ctx: the POSIX API context
* return: error no, 0 for success, != 0 fail
*/
static inline int fcfs_posix_api_start_ex(FCFSPosixAPIContext *ctx)
{
return fcfs_api_start_ex(&ctx->api_ctx);
}
/** FastCFS POSIX API init and start
* parameters:
* ctx: the POSIX API context
* log_prefix_name: the prefix name for log filename, NULL for stderr
* ns: the namespace/poolname of FastDIR
* config_filename: the config filename, eg. /etc/fastcfs/fcfs/fuse.conf
* return: error no, 0 for success, != 0 fail
*/
static inline int fcfs_posix_api_init_start_ex(
FCFSPosixAPIContext *ctx, const char *log_prefix_name,
const char *ns, const char *config_filename)
{
int result;
if ((result=fcfs_posix_api_init_ex(ctx, log_prefix_name,
ns, config_filename)) != 0)
{
return result;
}
return fcfs_api_start_ex(&ctx->api_ctx);
}
/** FastCFS POSIX API stop the background threads
* parameters:
* ctx: the POSIX API context
* return: none
*/
static inline void fcfs_posix_api_stop_ex(FCFSPosixAPIContext *ctx)
{
fcfs_api_terminate_ex(&ctx->api_ctx);
}
/** FastCFS POSIX API destroy
* parameters:
* ctx: the POSIX API context
* return: none
*/
void fcfs_posix_api_destroy_ex(FCFSPosixAPIContext *ctx);
/** FastCFS POSIX API start (create the background threads)
*
* return: error no, 0 for success, != 0 fail
*/
static inline int fcfs_posix_api_start()
{
return fcfs_posix_api_start_ex(&g_fcfs_papi_global_vars.ctx);
}
/** FastCFS POSIX API init and start with the global context
* parameters:
* log_prefix_name: the prefix name for log filename, NULL for stderr
* ns: the namespace/poolname of FastDIR
* config_filename: the config filename, eg. /etc/fastcfs/fcfs/fuse.conf
* return: error no, 0 for success, != 0 fail
*/
static inline int fcfs_posix_api_init_start(const char *log_prefix_name,
const char *ns, const char *config_filename)
{
return fcfs_posix_api_init_start_ex(&g_fcfs_papi_global_vars.ctx,
log_prefix_name, ns, config_filename);
}
/** FastCFS POSIX API stop the background threads with the global context
*
* return: none
*/
static inline void fcfs_posix_api_stop()
{
fcfs_posix_api_stop_ex(&g_fcfs_papi_global_vars.ctx);
}
/** FastCFS POSIX API destroy with the global context
*
* return: none
*/
static inline void fcfs_posix_api_destroy()
{
fcfs_posix_api_destroy_ex(&g_fcfs_papi_global_vars.ctx);
}
static inline pid_t fcfs_posix_api_getpid()
{
return getpid();
}
static inline pid_t fcfs_posix_api_gettid(
const FCFSPosixAPITPIDType tpid_type)
{
if (tpid_type == fcfs_papi_tpid_type_pid) {
return getpid();
} else {
return fc_gettid();
}
}
static inline int fcfs_posix_api_set_owner_ex(
FCFSPosixAPIContext *pctx)
{
return fcfs_api_set_owner(&pctx->api_ctx);
}
static inline int fcfs_posix_api_set_owner()
{
return fcfs_posix_api_set_owner_ex(&g_fcfs_papi_global_vars.ctx);
}
static inline void fcfs_posix_api_set_fctx(FCFSAPIFileContext *fctx,
const FCFSPosixAPIContext *pctx, const mode_t mode,
const FCFSPosixAPITPIDType tpid_type)
{
fctx->mode = (mode & (~fc_get_umask()));
fctx->oper = pctx->api_ctx.owner.oper;
fctx->tid = fcfs_posix_api_gettid(tpid_type);
}
#define FCFS_API_IS_MY_MOUNTPOINT_EX(ctx, path) \
(strlen(path) > (ctx)->mountpoint.len && \
((ctx)->mountpoint.len == 0 || \
memcmp(path, (ctx)->mountpoint.str, \
(ctx)->mountpoint.len) == 0))
#define FCFS_API_IS_MY_MOUNTPOINT(path) \
FCFS_API_IS_MY_MOUNTPOINT_EX(&g_fcfs_papi_global_vars.ctx, path)
#define FCFS_API_CHECK_PATH_MOUNTPOINT_EX(file, line, ctx, path, func, retval) \
do { \
if (!FCFS_API_IS_MY_MOUNTPOINT_EX(ctx, path)) \
{ \
logError("file: %s, line: %d, " \
"%s path: %s is not the FastCFS mountpoint!", \
file, line, func, path); \
errno = EOPNOTSUPP; \
return retval; \
} \
} while (0)
#define FCFS_API_CHECK_PATH_MOUNTPOINT(ctx, path, func) \
FCFS_API_CHECK_PATH_MOUNTPOINT_EX(__FILE__, __LINE__, ctx, path, func, -1)
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/api/tests/Makefile.in
================================================
.SUFFIXES: .c .o .lo
COMPILE = $(CC) $(CFLAGS)
INC_PATH = -I../../include
LIB_PATH = -L.. $(LIBS) -lfcfsapi -lfsapi -lfdirclient -lfsclient -lfastcommon -lserverframe
TARGET_PATH = $(TARGET_PREFIX)/bin
STATIC_OBJS =
ALL_PRGS = fcfs_test_file_op fcfs_test_file_copy fcfs_test_papi_copy \
fcfs_test_read_ahead fcfs_beachmark
all: $(STATIC_OBJS) $(ALL_PRGS)
.o:
$(COMPILE) -o $@ $< $(STATIC_OBJS) $(LIB_PATH) $(INC_PATH)
.c:
$(COMPILE) -o $@ $< $(STATIC_OBJS) $(LIB_PATH) $(INC_PATH)
.c.o:
$(COMPILE) -c -o $@ $< $(INC_PATH)
install:
mkdir -p $(TARGET_PATH)
cp -f $(ALL_PRGS) $(TARGET_PATH)
clean:
rm -f $(STATIC_OBJS) $(ALL_PRGS)
================================================
FILE: src/api/tests/fcfs_beachmark.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "fastcommon/logger.h"
#include "fastcommon/fc_atomic.h"
#include "fastcfs/api/std/posix_api.h"
typedef enum {
fcfs_beachmark_mode_read,
fcfs_beachmark_mode_write,
fcfs_beachmark_mode_randread,
fcfs_beachmark_mode_randwrite
} BeachmarkMode;
typedef struct {
int index;
volatile int64_t success_count;
} BeachmarkThreadInfo;
static struct {
const char *config_filename;
char *ns;
int64_t file_size;
struct {
BeachmarkMode val;
const char *str;
} mode;
int buffer_size;
int thread_count;
int runtime;
string_t filename_prefix;
bool is_fcfs_input;
} cfg = {FCFS_FUSE_DEFAULT_CONFIG_FILENAME,
"fs", 1 * 1024 * 1024 * 1024, {fcfs_beachmark_mode_read,
"read"}, 4 * 1024, 1, 60, {NULL, 0}, false};
static struct {
volatile int ready_count;
volatile int running_count;
volatile char ready_flag;
volatile char continue_flag;
time_t start_time;
struct {
int cur;
int avg;
int max;
} iops;
struct {
char cur[32];
char avg[32];
char max[32];
} iops_buff;
BeachmarkThreadInfo *threads;
BeachmarkThreadInfo *tend;
} st = {0, 0, 0, 1};
static inline void usage(char *argv[])
{
fprintf(stderr, "Usage: %s [-c config_filename=%s] "
"[-n namespace=fs] [-b buffer_size=4KB] "
"[-s file_size=1G] [-m mode=read] "
"[-T threads=1] [-t runtime=60] <-f filename_prefix>\n"
"\t mode value list: read, write, randrand, randwrite\n\n"
"for example: \n"
"\tfcfs_beachmark -m randread -s 256M -T 4 -t 300 "
"-f /opt/fastcfs/fuse/test_file\n\n",
argv[0], FCFS_FUSE_DEFAULT_CONFIG_FILENAME);
}
static inline int open_file(const char *filename, int flags)
{
if (cfg.is_fcfs_input) {
return fcfs_open(filename, flags);
} else {
return open(filename, flags);
}
}
static inline void close_file(int fd)
{
if (cfg.is_fcfs_input) {
fcfs_close(fd);
} else {
close(fd);
}
}
static int create_file(const char *filename, const int64_t start_offset)
{
#define BUFFER_SIZE (4 * 1024 * 1024)
const int flags = O_WRONLY | O_CREAT;
int result;
int bytes;
int fd;
int len;
int64_t start_time_us;
char *buff;
char time_buff[32];
unsigned char *p;
unsigned char *end;
int64_t remain;
if (cfg.is_fcfs_input) {
fd = fcfs_open(filename, flags, 0755);
} else {
fd = open(filename, flags, 0755);
}
if (fd < 0) {
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, "
"open file %s to write fail, errno: %d, error info: %s",
__LINE__, filename, result, strerror(result));
return result;
}
if (start_offset > 0) {
if (cfg.is_fcfs_input) {
bytes = fcfs_lseek(fd, start_offset, SEEK_SET);
} else {
bytes = lseek(fd, start_offset, SEEK_SET);
}
if (bytes < 0) {
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, "
"lseek file %s fail, errno: %d, error info: %s",
__LINE__, filename, result, strerror(result));
return result;
}
}
start_time_us = get_current_time_us();
printf("creating file: %s ...\n", filename);
if ((buff=fc_malloc(BUFFER_SIZE)) == NULL) {
close_file(fd);
return ENOMEM;
}
end = (unsigned char *)buff + BUFFER_SIZE;
for (p=(unsigned char *)buff; p 0) {
len = remain > BUFFER_SIZE ? BUFFER_SIZE : remain;
if (cfg.is_fcfs_input) {
bytes = fcfs_write(fd, buff, len);
} else {
bytes = write(fd, buff, len);
}
if (bytes != len) {
result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, "
"write to file %s fail, errno: %d, error info: %s",
__LINE__, filename, result, strerror(result));
break;
}
remain -= len;
}
if (result == 0) {
long_to_comma_str((get_current_time_us() -
start_time_us) / 1000, time_buff);
printf("create file: %s successfully, time used: %s ms\n",
filename, time_buff);
}
free(buff);
close_file(fd);
return result;
}
static int check_create_file(const char *filename)
{
struct stat stbuf;
int ret;
int result;
if (cfg.is_fcfs_input) {
ret = fcfs_stat(filename, &stbuf);
} else {
ret = stat(filename, &stbuf);
}
if (ret != 0) {
result = errno != 0 ? errno : EIO;
if (result == ENOENT) {
stbuf.st_size = 0;
} else {
logError("file: "__FILE__", line: %d, "
"stat file %s fail, errno: %d, error info: %s",
__LINE__, filename, result, strerror(result));
return result;
}
}
if (stbuf.st_size == cfg.file_size) {
return 0;
} else if (stbuf.st_size > cfg.file_size) {
if (cfg.is_fcfs_input) {
ret = fcfs_truncate(filename, cfg.file_size);
} else {
ret = truncate(filename, cfg.file_size);
}
if (ret == 0) {
return 0;
} else {
result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, "
"truncate file %s fail, errno: %d, error info: %s",
__LINE__, filename, result, strerror(result));
return result;
}
}
return create_file(filename, stbuf.st_size);
}
static int thread_run(BeachmarkThreadInfo *thread)
{
int result;
int flags;
int fd;
bool is_read;
bool is_sequence;
char *buff;
int64_t blocks;
int64_t offset;
int size;
int bytes;
char *filename;
char *p;
buff = (char *)fc_malloc(cfg.buffer_size);
if (buff == NULL) {
return ENOMEM;
}
filename = fc_malloc(cfg.filename_prefix.len + 8);
if (filename == NULL) {
return ENOMEM;
}
p = filename;
memcpy(p, cfg.filename_prefix.str, cfg.filename_prefix.len);
p += cfg.filename_prefix.len;
*p++ = '.';
p += fc_itoa(thread->index, p);
*p = '\0';
if ((result=check_create_file(filename)) != 0) {
return result;
}
switch (cfg.mode.val) {
case fcfs_beachmark_mode_read:
case fcfs_beachmark_mode_randread:
is_read = true;
flags = O_RDONLY;
break;
case fcfs_beachmark_mode_write:
case fcfs_beachmark_mode_randwrite:
is_read = false;
flags = O_WRONLY;
break;
default:
return EINVAL;
}
is_sequence = (cfg.mode.val == fcfs_beachmark_mode_read ||
cfg.mode.val == fcfs_beachmark_mode_write);
if ((fd=open_file(filename, flags)) < 0) {
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, "
"open file %s to read fail, errno: %d, error info: %s",
__LINE__, filename, result, strerror(result));
return result;
}
__sync_add_and_fetch(&st.ready_count, 1);
while (FC_ATOMIC_GET(st.continue_flag) &&
!FC_ATOMIC_GET(st.ready_flag))
{
fc_sleep_ms(10);
}
offset = 0;
size = cfg.buffer_size;
blocks = cfg.file_size / cfg.buffer_size;
while (FC_ATOMIC_GET(st.continue_flag)) {
switch (cfg.mode.val) {
case fcfs_beachmark_mode_read:
case fcfs_beachmark_mode_write:
size = cfg.file_size - offset;
if (size <= 0) {
offset = 0;
size = cfg.buffer_size;
} else if (size > cfg.buffer_size) {
size = cfg.buffer_size;
}
break;
case fcfs_beachmark_mode_randread:
case fcfs_beachmark_mode_randwrite:
offset = (((int64_t)rand() * blocks) / (int64_t)RAND_MAX)
* cfg.buffer_size;
break;
default:
break;
}
if (is_read) {
if (cfg.is_fcfs_input) {
bytes = fcfs_pread(fd, buff, size, offset);
} else {
bytes = pread(fd, buff, size, offset);
}
} else {
if (cfg.is_fcfs_input) {
bytes = fcfs_pwrite(fd, buff, size, offset);
} else {
bytes = pwrite(fd, buff, size, offset);
}
}
if (bytes != size) {
result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, "
"read from file %s fail, errno: %d, error info: %s",
__LINE__, filename, result, strerror(result));
return result;
}
FC_ATOMIC_INC(thread->success_count);
if (is_sequence) {
offset += bytes;
}
}
close_file(fd);
return 0;
}
static void *thread_entrance(void *arg)
{
BeachmarkThreadInfo *thread;
thread = arg;
__sync_add_and_fetch(&st.running_count, 1);
thread_run(thread);
__sync_sub_and_fetch(&st.running_count, 1);
return NULL;
}
static void output(const time_t current_time)
{
BeachmarkThreadInfo *thread;
static time_t last_time = 0;
static int64_t last_count = 0;
int64_t total_count;
int time_distance;
if (last_time == 0) {
last_time = st.start_time;
printf("\n");
}
total_count = 0;
for (thread=st.threads; threadsuccess_count);
}
time_distance = current_time - last_time;
if (time_distance > 0) {
st.iops.cur = (total_count - last_count) / time_distance;
if (st.iops.cur > st.iops.max) {
st.iops.max = st.iops.cur;
}
st.iops.avg = total_count / (current_time - st.start_time);
long_to_comma_str(st.iops.cur, st.iops_buff.cur);
long_to_comma_str(st.iops.avg, st.iops_buff.avg);
printf("running time: %4d seconds, %s IOPS {current: %s, avg: %s}\n",
(int)(current_time - st.start_time), cfg.mode.str,
st.iops_buff.cur, st.iops_buff.avg);
last_time = current_time;
last_count = total_count;
}
}
static void sigQuitHandler(int sig)
{
if (FC_ATOMIC_GET(st.continue_flag)) {
FC_ATOMIC_SET(st.continue_flag, 0);
printf("file: "__FILE__", line: %d, "
"catch signal %d, program exiting...\n",
__LINE__, sig);
}
}
static int setup_signal_handler()
{
struct sigaction act;
memset(&act, 0, sizeof(act));
sigemptyset(&act.sa_mask);
act.sa_handler = sigQuitHandler;
if(sigaction(SIGINT, &act, NULL) < 0 ||
sigaction(SIGTERM, &act, NULL) < 0 ||
sigaction(SIGQUIT, &act, NULL) < 0)
{
fprintf(stderr, "file: "__FILE__", line: %d, "
"call sigaction fail, errno: %d, error info: %s\n",
__LINE__, errno, strerror(errno));
return errno != 0 ? errno : EBUSY;
}
return 0;
}
static int beachmark()
{
const char *log_prefix_name = NULL;
int result;
int count;
int bytes;
long i;
time_t current_time;
time_t end_time;
pthread_t *tids;
void **args;
char buffer_size_prompt[32];
BeachmarkThreadInfo *thread;
if ((result=fcfs_posix_api_init(log_prefix_name,
cfg.ns, cfg.config_filename)) != 0)
{
return result;
}
if ((result=fcfs_posix_api_start()) != 0) {
return result;
}
if ((result=setup_signal_handler()) != 0) {
return result;
}
fcfs_posix_api_log_configs();
cfg.is_fcfs_input = FCFS_API_IS_MY_MOUNTPOINT(cfg.filename_prefix.str);
bytes = sizeof(BeachmarkThreadInfo) * cfg.thread_count;
st.threads = fc_malloc(bytes);
if (st.threads == NULL) {
return ENOMEM;
}
memset(st.threads, 0, bytes);
st.tend = st.threads + cfg.thread_count;
tids = fc_malloc(sizeof(pthread_t) * cfg.thread_count);
if (tids == NULL) {
return ENOMEM;
}
args = fc_malloc(sizeof(void *) * cfg.thread_count);
if (args == NULL) {
return ENOMEM;
}
for (i=0, thread=st.threads; iindex = i;
args[i] = thread;
}
count = cfg.thread_count;
if ((result=create_work_threads(&count, thread_entrance,
args, tids, 256 * 1024)) != 0)
{
return result;
}
if (cfg.buffer_size % 1024 != 0) {
long_to_comma_str(cfg.buffer_size, buffer_size_prompt);
} else {
sprintf(buffer_size_prompt, "%d KB", cfg.buffer_size / 1024);
}
printf("\nthreads: %d, mode: %s, file size: %"PRId64" MB, "
"buffer size: %s\n\n", cfg.thread_count, cfg.mode.str,
cfg.file_size / (1024 * 1024), buffer_size_prompt);
fc_sleep_ms(100);
while (FC_ATOMIC_GET(st.continue_flag) &&
FC_ATOMIC_GET(st.ready_count) <
FC_ATOMIC_GET(st.running_count))
{
fc_sleep_ms(10);
}
FC_ATOMIC_SET(st.ready_flag, 1);
st.start_time = time(NULL);
end_time = st.start_time + cfg.runtime;
do {
sleep(1);
current_time = time(NULL);
output(current_time);
} while (FC_ATOMIC_GET(st.continue_flag) &&
FC_ATOMIC_GET(st.running_count) > 0 &&
current_time < end_time);
long_to_comma_str(st.iops.avg, st.iops_buff.avg);
long_to_comma_str(st.iops.max, st.iops_buff.max);
printf("\nrunning time: %4d seconds, %s IOPS {avg: %s, max: %s}\n",
(int)(current_time - st.start_time), cfg.mode.str,
st.iops_buff.avg, st.iops_buff.max);
FC_ATOMIC_SET(st.continue_flag, 0);
while (FC_ATOMIC_GET(st.running_count) > 0) {
sleep(1);
}
fcfs_posix_api_stop();
return 0;
}
int main(int argc, char *argv[])
{
int result;
int ch;
int64_t bytes;
if (argc < 3) {
usage(argv);
return 1;
}
log_try_init();
while ((ch=getopt(argc, argv, "hc:m:n:b:T:t:f:s:")) != -1) {
switch (ch) {
case 'h':
usage(argv);
return 0;
case 'c':
cfg.config_filename = optarg;
break;
case 'm':
if (strcasecmp(optarg, "read") == 0) {
cfg.mode.val = fcfs_beachmark_mode_read;
cfg.mode.str = "read";
} else if (strcasecmp(optarg, "write") == 0) {
cfg.mode.val = fcfs_beachmark_mode_write;
cfg.mode.str = "write";
} else if (strcasecmp(optarg, "randread") == 0) {
cfg.mode.val = fcfs_beachmark_mode_randread;
cfg.mode.str = "randread";
} else if (strcasecmp(optarg, "randwrite") == 0) {
cfg.mode.val = fcfs_beachmark_mode_randwrite;
cfg.mode.str = "randwrite";
} else {
logError("file: "__FILE__", line: %d, "
"invalid mode: %s!", __LINE__, optarg);
usage(argv);
return EINVAL;
}
break;
case 'n':
cfg.ns = optarg;
break;
case 's':
if ((result=parse_bytes(optarg, 1, &cfg.file_size)) != 0) {
usage(argv);
return result;
}
break;
case 'T':
cfg.thread_count = strtol(optarg, NULL, 10);
if (cfg.thread_count <= 0) {
logError("file: "__FILE__", line: %d, "
"invalid thread count: %d which <= 0",
__LINE__, cfg.thread_count);
return EINVAL;
}
break;
case 't':
cfg.runtime = strtol(optarg, NULL, 10);
if (cfg.runtime <= 0) {
logError("file: "__FILE__", line: %d, "
"invalid runtime: %d which <= 0",
__LINE__, cfg.runtime);
return EINVAL;
}
break;
case 'b':
if ((result=parse_bytes(optarg, 1, &bytes)) != 0) {
usage(argv);
return result;
}
if (bytes <= 0) {
logError("file: "__FILE__", line: %d, "
"invalid buffer size: %"PRId64" which <= 0",
__LINE__, bytes);
return EINVAL;
}
cfg.buffer_size = bytes;
break;
case 'f':
FC_SET_STRING(cfg.filename_prefix, optarg);
break;
default:
usage(argv);
return 1;
}
}
if (cfg.filename_prefix.str == NULL) {
fprintf(stderr, "expect parameter -f filename_prefix\n\n");
usage(argv);
return EINVAL;
}
if (cfg.file_size < cfg.buffer_size) {
logError("file: "__FILE__", line: %d, "
"invalid file size: %"PRId64" which < buffer size: %d",
__LINE__, cfg.file_size, cfg.buffer_size);
return EINVAL;
}
srand(time(NULL));
return beachmark();
}
================================================
FILE: src/api/tests/fcfs_test_file_copy.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "fastcommon/logger.h"
#include "fastcfs/api/fcfs_api.h"
const char *config_filename = FCFS_FUSE_DEFAULT_CONFIG_FILENAME;
static char *ns = "fs";
static int buffer_size = 128 * 1024;
static char *input_filename;
static char *fs_filename;
static void usage(char *argv[])
{
fprintf(stderr, "Usage: %s [-c config_filename=%s] "
"[-n namespace=fs] [-b buffer_size=128KB] "
" \n\n",
argv[0], FCFS_FUSE_DEFAULT_CONFIG_FILENAME);
}
static int copy_file()
{
const bool publish = false;
#define FIXED_BUFFEER_SIZE (128 * 1024)
FCFSAPIFileContext fctx;
int result;
int fd;
FCFSAPIFileInfo fi;
char fixed_buff[FIXED_BUFFEER_SIZE];
char async_report_config[256];
char write_combine_config[512];
char *buff;
char new_fs_filename[PATH_MAX];
int read_bytes;
int write_bytes;
int current_write;
if ((fd=open(input_filename, O_RDONLY)) < 0) {
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, "
"open file %s to read fail, "
"errno: %d, error info: %s",
__LINE__, input_filename,
result, strerror(result));
return result;
}
if ((result=fcfs_api_pooled_init_with_auth(ns,
config_filename, publish)) != 0)
{
return result;
}
if ((result=fcfs_api_start()) != 0) {
return result;
}
fcfs_api_async_report_config_to_string_ex(&g_fcfs_api_ctx,
async_report_config, sizeof(async_report_config));
fdir_client_log_config_ex(g_fcfs_api_ctx.contexts.fdir,
async_report_config, true);
fs_api_config_to_string(write_combine_config,
sizeof(write_combine_config));
fs_client_log_config_ex(g_fcfs_api_ctx.contexts.fsapi->fs,
write_combine_config, true);
if (fs_filename[strlen(fs_filename) - 1] == '/') {
const char *filename;
filename = strrchr(input_filename, '/');
if (filename != NULL) {
filename++; //skip "/"
} else {
filename = input_filename;
}
snprintf(new_fs_filename, sizeof(new_fs_filename),
"%s%s", fs_filename, filename);
} else {
snprintf(new_fs_filename, sizeof(new_fs_filename),
"%s", fs_filename);
}
fctx.tid = getpid();
fctx.mode = 0755;
FDIR_SET_OPERATOR(fctx.oper, geteuid(), getegid(), 0, NULL);
if ((result=fcfs_api_open(&fi, new_fs_filename,
O_CREAT | O_WRONLY, &fctx)) != 0)
{
return result;
}
if (buffer_size <= FIXED_BUFFEER_SIZE) {
buff = fixed_buff;
} else {
buff = (char *)fc_malloc(buffer_size);
if (buff == NULL) {
return ENOMEM;
}
}
write_bytes = 0;
while (1) {
read_bytes = read(fd, buff, buffer_size);
if (read_bytes == 0) {
break;
} else if (read_bytes < 0) {
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, "
"read from file %s fail, "
"errno: %d, error info: %s",
__LINE__, input_filename,
result, strerror(result));
return result;
}
result = fcfs_api_write(&fi, buff, read_bytes, ¤t_write);
if (result != 0) {
logError("file: "__FILE__", line: %d, "
"write to file %s fail, "
"errno: %d, error info: %s",
__LINE__, fs_filename,
result, STRERROR(result));
return result;
}
write_bytes += current_write;
}
fcfs_api_close(&fi);
fcfs_api_terminate();
return 0;
}
int main(int argc, char *argv[])
{
int result;
int ch;
int64_t bytes;
if (argc < 3) {
usage(argv);
return 1;
}
while ((ch=getopt(argc, argv, "hc:n:b:")) != -1) {
switch (ch) {
case 'h':
usage(argv);
break;
case 'c':
config_filename = optarg;
break;
case 'n':
ns = optarg;
break;
case 'b':
if ((result=parse_bytes(optarg, 1, &bytes)) != 0) {
usage(argv);
return result;
}
buffer_size = bytes;
break;
default:
usage(argv);
return 1;
}
}
if (optind + 1 >= argc) {
usage(argv);
return 1;
}
log_init();
//g_log_context.log_level = LOG_DEBUG;
input_filename = argv[optind];
fs_filename = argv[optind + 1];
if (strlen(fs_filename) == 0) {
usage(argv);
return EINVAL;
}
return copy_file();
}
================================================
FILE: src/api/tests/fcfs_test_file_op.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "fastcommon/logger.h"
#include "fastcfs/api/fcfs_api.h"
static void usage(char *argv[])
{
fprintf(stderr, "Usage: %s [-c config_filename=%s] "
"-n [namespace=fs] \n\t[-o offset=0] [-l length=0 for auto] "
"[-A append mode] \n\t[-T truncate mode] [-S set file size = -1] "
"-i \n\n", argv[0],
FCFS_FUSE_DEFAULT_CONFIG_FILENAME);
}
int main(int argc, char *argv[])
{
const bool publish = false;
const char *config_filename = FCFS_FUSE_DEFAULT_CONFIG_FILENAME;
FCFSAPIFileContext fctx;
int ch;
int result;
int open_flags;
int64_t offset = 0;
int64_t file_size;
int64_t file_size_to_set;
int length = 0;
FCFSAPIFileInfo fi;
char *ns = "fs";
char *input_filename = NULL;
char *filename;
char *endptr;
char *out_buff;
char *in_buff;
int write_bytes;
int read_bytes;
if (argc < 2) {
usage(argv);
return 1;
}
fctx.tid = getpid();
fctx.mode = 0755;
FDIR_SET_OPERATOR(fctx.oper, geteuid(), getegid(), 0, NULL);
open_flags = 0;
file_size_to_set = -1;
while ((ch=getopt(argc, argv, "hc:o:n:i:l:S:AT")) != -1) {
switch (ch) {
case 'h':
usage(argv);
break;
case 'c':
config_filename = optarg;
break;
case 'i':
input_filename = optarg;
break;
case 'n':
ns = optarg;
break;
case 'o':
offset = strtol(optarg, &endptr, 10);
break;
case 'l':
length = strtol(optarg, &endptr, 10);
break;
case 'S':
file_size_to_set = strtol(optarg, &endptr, 10);
break;
case 'A':
open_flags |= O_APPEND;
break;
case 'T':
open_flags |= O_TRUNC;
break;
default:
usage(argv);
return 1;
}
}
if (input_filename == NULL) {
fprintf(stderr, "expect input filename\n");
usage(argv);
return 1;
}
if (optind >= argc) {
fprintf(stderr, "expect filename\n");
usage(argv);
return 1;
}
log_init();
//g_log_context.log_level = LOG_DEBUG;
filename = argv[optind];
if ((result=getFileContent(input_filename, &out_buff, &file_size)) != 0) {
return result;
}
if (file_size == 0) {
logError("file: "__FILE__", line: %d, "
"empty file: %s", __LINE__, input_filename);
return ENOENT;
}
if (length == 0 || length > file_size) {
length = file_size;
}
if ((result=fcfs_api_pooled_init_with_auth(ns,
config_filename, publish)) != 0)
{
return result;
}
/*
{
struct statvfs stbuf;
if (fcfs_api_statvfs(filename, &stbuf) == 0) {
printf("%s fs id: %ld, total: %"PRId64" MB, free: %"PRId64" MB, "
"avail: %"PRId64" MB, f_namemax: %ld, f_flag: %ld\n", filename,
stbuf.f_fsid, (int64_t)(stbuf.f_blocks * stbuf.f_frsize) / (1024 * 1024),
(int64_t)(stbuf.f_bfree * stbuf.f_frsize) / (1024 * 1024),
(int64_t)(stbuf.f_bavail * stbuf.f_frsize) / (1024 * 1024),
stbuf.f_namemax, stbuf.f_flag);
}
}
*/
if ((result=fcfs_api_start()) != 0) {
return result;
}
if ((result=fcfs_api_open(&fi, filename, O_CREAT |
O_WRONLY | open_flags, &fctx)) != 0)
{
return result;
}
if (file_size_to_set >= 0) {
if ((result=fcfs_api_ftruncate_ex(&fi, file_size_to_set,
fctx.tid)) != 0)
{
return result;
}
}
if (offset == 0) {
result = fcfs_api_write(&fi, out_buff, length, &write_bytes);
} else {
result = fcfs_api_pwrite(&fi, out_buff, length, offset, &write_bytes);
}
if (result != 0) {
logError("file: "__FILE__", line: %d, "
"write to file %s fail, offset: %"PRId64", length: %d, "
"write_bytes: %d, errno: %d, error info: %s",
__LINE__, filename, offset, length, write_bytes,
result, STRERROR(result));
return result;
}
fcfs_api_close(&fi);
if ((result=fcfs_api_open(&fi, filename, O_RDONLY, &fctx)) != 0) {
return result;
}
in_buff = (char *)malloc(length);
if (in_buff == NULL) {
logError("file: "__FILE__", line: %d, "
"malloc %d bytes fail", __LINE__, length);
return ENOMEM;
}
if ((result=fcfs_api_lseek(&fi, offset, SEEK_SET)) != 0) {
return result;
}
if (offset == 0) {
result = fcfs_api_read(&fi, in_buff, length, &read_bytes);
} else {
//result = fcfs_api_pread(&fi, in_buff, length, offset, &read_bytes);
result = fcfs_api_read(&fi, in_buff, length, &read_bytes);
}
if (result != 0) {
logError("file: "__FILE__", line: %d, "
"read from file %s fail, offset: %"PRId64", length: %d, "
"read_bytes: %d, errno: %d, error info: %s",
__LINE__, filename, offset, length, read_bytes,
result, STRERROR(result));
return result;
}
if (read_bytes != length) {
logError("file: "__FILE__", line: %d, "
"read bytes: %d != slice length: %d",
__LINE__, read_bytes, length);
return EINVAL;
}
result = memcmp(in_buff, out_buff, length);
if (result != 0) {
printf("read and write buffer compare result: %d != 0\n", result);
return EINVAL;
}
fcfs_api_close(&fi);
fcfs_api_terminate();
return 0;
}
================================================
FILE: src/api/tests/fcfs_test_papi_copy.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "fastcommon/logger.h"
#include "fastcfs/api/std/posix_api.h"
const char *config_filename = FCFS_FUSE_DEFAULT_CONFIG_FILENAME;
static char *ns = "fs";
static int buffer_size = 128 * 1024;
static int slice_size = 4 * 1024;
static char *input_filename;
static char *fs_filename;
static bool use_iov = false; //use readv & writev
static void usage(char *argv[])
{
fprintf(stderr, "Usage: %s [-c config_filename=%s] "
"[-n namespace=fs] [-b buffer_size=128KB] "
"[-V use readv & writev] [-s slice_size=4K] "
" \n\n",
argv[0], FCFS_FUSE_DEFAULT_CONFIG_FILENAME);
}
static int alloc_iovec_array(iovec_array_t *array, char *buff)
{
struct iovec *iob;
struct iovec *last;
char *p;
array->count = array->alloc = (buffer_size +
(slice_size - 1)) / slice_size;
array->iovs = fc_malloc(sizeof(struct iovec) * array->alloc);
if (array->iovs == NULL) {
return ENOMEM;
}
p = buff;
last = array->iovs + (array->alloc - 1);
for (iob=array->iovs; iobiov_base = p;
iob->iov_len = slice_size;
p += iob->iov_len;
}
last->iov_base = p;
last->iov_len = (buff + buffer_size) - p;
return 0;
}
static int copy_file()
{
#define FIXED_BUFFEER_SIZE (128 * 1024)
const char *log_prefix_name = NULL;
int result;
int src_fd;
int dst_fd;
bool is_fcfs_input;
char fixed_buff[FIXED_BUFFEER_SIZE];
iovec_array_t src_buffers;
iovec_array_t dst_buffers;
char *buff;
char new_filename[PATH_MAX];
char new_fs_filename[PATH_MAX];
int filename_len;
int read_bytes;
int write_bytes;
int current_write;
int count;
if ((result=fcfs_posix_api_init(log_prefix_name,
ns, config_filename)) != 0)
{
return result;
}
if ((result=fcfs_posix_api_start()) != 0) {
return result;
}
fcfs_posix_api_log_configs();
is_fcfs_input = FCFS_API_IS_MY_MOUNTPOINT(input_filename);
if (is_fcfs_input) {
src_fd = fcfs_open(input_filename, O_RDONLY);
} else {
src_fd = open(input_filename, O_RDONLY);
}
if (src_fd < 0) {
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, "
"open file %s to read fail, "
"errno: %d, error info: %s",
__LINE__, input_filename,
result, strerror(result));
return result;
}
if (fs_filename[strlen(fs_filename) - 1] == '/') {
const char *filename;
filename = strrchr(input_filename, '/');
if (filename != NULL) {
filename++; //skip "/"
} else {
filename = input_filename;
}
filename_len = snprintf(new_filename, sizeof(new_filename),
"%s%s", fs_filename, filename);
} else {
filename_len = snprintf(new_filename, sizeof(new_filename),
"%s%s", (*fs_filename != '/' ? "/" : ""), fs_filename);
}
if (!(filename_len > g_fcfs_papi_global_vars.ctx.mountpoint.len &&
memcmp(new_filename, g_fcfs_papi_global_vars.ctx.mountpoint.str,
g_fcfs_papi_global_vars.ctx.mountpoint.len) == 0))
{
snprintf(new_fs_filename, sizeof(new_fs_filename), "%s%s",
g_fcfs_papi_global_vars.ctx.mountpoint.str, new_filename);
} else {
snprintf(new_fs_filename, sizeof(new_fs_filename), "%s", new_filename);
}
if ((dst_fd=fcfs_open(new_fs_filename, O_CREAT | O_WRONLY, 0755)) < 0) {
result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, "
"open file %s fail, errno: %d, error info: %s",
__LINE__, fs_filename, result, STRERROR(result));
return result;
}
logInfo("is_fcfs_input: %d, input fd: %d, output fd: %d",
is_fcfs_input, src_fd, dst_fd);
if (buffer_size <= FIXED_BUFFEER_SIZE) {
buff = fixed_buff;
} else {
buff = (char *)fc_malloc(buffer_size);
if (buff == NULL) {
return ENOMEM;
}
}
if (use_iov) {
if ((result=alloc_iovec_array(&src_buffers, buff)) != 0) {
return result;
}
if ((result=alloc_iovec_array(&dst_buffers, buff)) != 0) {
return result;
}
}
count = 0;
write_bytes = 0;
while (1) {
if (is_fcfs_input) {
if (use_iov) {
read_bytes = fcfs_readv(src_fd, src_buffers.iovs,
src_buffers.count);
} else {
read_bytes = fcfs_read(src_fd, buff, buffer_size);
}
} else {
if (use_iov) {
read_bytes = readv(src_fd, src_buffers.iovs,
src_buffers.count);
} else {
read_bytes = read(src_fd, buff, buffer_size);
}
}
if (read_bytes == 0) {
break;
} else if (read_bytes < 0) {
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, "
"read from file %s fail, "
"errno: %d, error info: %s",
__LINE__, input_filename,
result, strerror(result));
return result;
}
if (use_iov) {
int bytes;
int remain;
struct iovec *iob;
struct iovec *last;
if (read_bytes == buffer_size) {
dst_buffers.count = src_buffers.count;
} else {
iob = src_buffers.iovs;
bytes = iob->iov_len;
while (bytes < read_bytes) {
++iob;
bytes += iob->iov_len;
}
dst_buffers.count = (iob - src_buffers.iovs + 1);
last = dst_buffers.iovs + (dst_buffers.count - 1);
remain = bytes - read_bytes;
last->iov_len -= remain;
logInfo("read_bytes: %d, bytes: %d, count: %d, last length: %d",
read_bytes, bytes, dst_buffers.count, (int)last->iov_len);
}
current_write = fcfs_writev(dst_fd, dst_buffers.iovs,
dst_buffers.count);
if (read_bytes < buffer_size) {
/* restore the last iov */
(dst_buffers.iovs + (dst_buffers.count - 1))->iov_len =
(src_buffers.iovs + (dst_buffers.count - 1))->iov_len;
}
} else {
current_write = fcfs_write(dst_fd, buff, read_bytes);
}
if (current_write != read_bytes) {
result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, "
"write to file %s fail, "
"errno: %d, error info: %s",
__LINE__, fs_filename,
result, STRERROR(result));
return result;
}
if (++count % 10 == 0) {
fcfs_fsync(dst_fd);
}
write_bytes += current_write;
}
if (is_fcfs_input) {
fcfs_close(src_fd);
} else {
close(src_fd);
}
fcfs_fsync(dst_fd);
fcfs_close(dst_fd);
fcfs_posix_api_stop();
return 0;
}
int main(int argc, char *argv[])
{
int result;
int ch;
int64_t bytes;
if (argc < 3) {
usage(argv);
return 1;
}
while ((ch=getopt(argc, argv, "hc:n:b:s:V")) != -1) {
switch (ch) {
case 'h':
usage(argv);
return 0;
case 'c':
config_filename = optarg;
break;
case 'n':
ns = optarg;
break;
case 'b':
if ((result=parse_bytes(optarg, 1, &bytes)) != 0) {
usage(argv);
return result;
}
if (bytes < 4 * 1024) {
buffer_size = 4 * 1024;
} else {
buffer_size = bytes;
}
break;
case 's':
if ((result=parse_bytes(optarg, 1, &bytes)) != 0) {
usage(argv);
return result;
}
if (bytes < 1 * 1024) {
slice_size = 1 * 1024;
} else {
slice_size = bytes;
}
break;
case 'V':
use_iov = true;
break;
default:
usage(argv);
return 1;
}
}
if (optind + 1 >= argc) {
usage(argv);
return 1;
}
log_try_init();
//g_log_context.log_level = LOG_DEBUG;
if (use_iov) {
logInfo("use writev & readv, slice size: %d", slice_size);
}
input_filename = argv[optind];
fs_filename = argv[optind + 1];
if (strlen(fs_filename) == 0) {
usage(argv);
return EINVAL;
}
return copy_file();
}
================================================
FILE: src/api/tests/fcfs_test_read_ahead.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "fastcommon/logger.h"
#include "sf/sf_global.h"
#include "fastcfs/api/fcfs_api.h"
#define FCFS_BLOCK_SIZE 512
typedef struct {
int count;
char **blocks;
} BlockArray;
static char *ns = "test";
static int64_t file_size;
static int64_t write_buffer_size;
static int64_t read_buffer_size;
static int read_thread_count;
static int read_loop_count;
static bool is_random_read;
static bool is_random_write;
static volatile int running_read_threads;
static volatile int can_read = 0;
static BlockArray barray;
const char *filename = "/test.dat";
static void usage(char *argv[])
{
fprintf(stderr, "Usage: %s [-c config_filename=%s] "
"-n [namespace=test]\n\t[-s file_size=64MB] "
"[-r read_buffer_size=4KB] [-w write_buffer_size=4KB]\n"
"\t[-t read_thread_count=1]\n\t[-R random read] "
"[-W random write] [-l read_loop_count=1]\n\n", argv[0],
FCFS_FUSE_DEFAULT_CONFIG_FILENAME);
}
static int check_create_root_path()
{
FDIRClientOperFnamePair path;
FDIRDEntryInfo dentry;
int64_t inode;
int result;
FC_SET_STRING(path.fullname.ns, ns);
FC_SET_STRING(path.fullname.path, "/");
FDIR_SET_OPERATOR(path.oper, geteuid(), getegid(), 0, NULL);
if ((result=fdir_client_lookup_inode_by_path_ex(g_fcfs_api_ctx.
contexts.fdir, &path, LOG_DEBUG, &inode)) != 0)
{
if (result == ENOENT) {
result = fdir_client_create_dentry(g_fcfs_api_ctx.
contexts.fdir, &path, 0777 | S_IFDIR, &dentry);
}
}
return result;
}
static int init()
{
char *buff;
char *p;
char **pp;
char **end;
int count;
int bytes;
srand(time(NULL));
count = (int64_t)rand() * 256LL / RAND_MAX;
barray.count = 2;
while (barray.count < count) {
barray.count *= 2;
}
bytes = FCFS_BLOCK_SIZE * barray.count;
buff = (char *)fc_malloc(bytes);
if (buff == NULL) {
return ENOMEM;
}
barray.blocks = (char **)fc_malloc(sizeof(char *) * barray.count);
if (barray.blocks == NULL) {
return ENOMEM;
}
p = buff;
end = barray.blocks + barray.count;
for (pp=barray.blocks; pp 0 && SF_G_CONTINUE_FLAG) {
fill_buffer(out_buff, write_buffer_size, file_size - remain);
length = FC_MIN(remain, write_buffer_size);
result = fcfs_api_write(fi, out_buff, length, &write_bytes);
if (result != 0) {
logError("file: "__FILE__", line: %d, "
"write to file %s fail, offset: %"PRId64", length: %d, "
"write_bytes: %d, errno: %d, error info: %s",
__LINE__, filename, file_size - remain, length,
write_bytes, result, STRERROR(result));
return result;
}
remain -= write_bytes;
}
return 0;
}
static int random_write(FCFSAPIFileInfo *fi, char *out_buff)
{
int result;
int write_bytes;
int i;
int64_t loop_count;
int64_t offset;
i = 0;
loop_count = (file_size / write_buffer_size) - 1;
while (i <= loop_count && SF_G_CONTINUE_FLAG) {
offset = ((int64_t)rand() * loop_count / RAND_MAX) *
write_buffer_size;
fill_buffer(out_buff, write_buffer_size, offset);
result = fcfs_api_pwrite(fi, out_buff, write_buffer_size,
offset, &write_bytes);
if (result != 0) {
logError("file: "__FILE__", line: %d, "
"write to file %s fail, offset: %"PRId64", "
"length: %"PRId64", write_bytes: %d, "
"errno: %d, error info: %s", __LINE__,
filename, offset, write_buffer_size,
write_bytes, result, STRERROR(result));
return result;
}
++i;
}
return 0;
}
static inline int do_write(FCFSAPIFileInfo *fi, char *out_buff)
{
if (is_random_write) {
return random_write(fi, out_buff);
} else {
return sequential_write(fi, out_buff);
}
}
static void *write_thread(void *arg)
{
FCFSAPIFileContext fctx;
FCFSAPIFileInfo fi;
char *out_buff;
long thread_index;
int result;
thread_index = (long)arg;
fctx.tid = getpid() + thread_index;
fctx.mode = 0755;
FDIR_SET_OPERATOR(fctx.oper, geteuid(), getegid(), 0, NULL);
if ((result=fcfs_api_open(&fi, filename, O_CREAT |
O_WRONLY | O_TRUNC, &fctx)) != 0)
{
__sync_bool_compare_and_swap(&can_read, 0, -1);
return NULL;
}
out_buff = (char *)fc_malloc(write_buffer_size);
if (out_buff == NULL) {
__sync_bool_compare_and_swap(&can_read, 0, -1);
fcfs_api_close(&fi);
return NULL;
}
do {
if (is_random_read || is_random_write) {
logInfo("file: "__FILE__", line: %d, "
"prepare file for read ...", __LINE__);
if (sequential_write(&fi, out_buff) != 0) {
__sync_bool_compare_and_swap(&can_read, 0, -1);
break;
}
logInfo("file: "__FILE__", line: %d, "
"file ready for read.", __LINE__);
}
__sync_bool_compare_and_swap(&can_read, 0, 1);
while (SF_G_CONTINUE_FLAG) {
if (do_write(&fi, out_buff) != 0) {
break;
}
}
} while (0);
fcfs_api_close(&fi);
free(out_buff);
return NULL;
}
static int do_read(const int thread_index, FCFSAPIFileInfo *fi,
char *in_buff, char *expect_buff, int *wait_count, int *retry_count)
{
int length;
int read_bytes;
int result;
int fail_count;
int64_t loop_count;
int64_t i;
int64_t offset;
int64_t remain;
length = read_buffer_size;
loop_count = (file_size / read_buffer_size) - 1;
i = 0;
fail_count = 0;
remain = file_size;
while (i <= loop_count && SF_G_CONTINUE_FLAG) {
if (is_random_read) {
offset = ((int64_t)rand() * loop_count / RAND_MAX) *
read_buffer_size;
} else {
offset = file_size - remain;
length = FC_MIN(remain, read_buffer_size);
}
result = fcfs_api_pread(fi, in_buff, length,
offset, &read_bytes);
if (result != 0) {
logError("file: "__FILE__", line: %d, thread index: %d, "
"read from file %s fail, offset: %"PRId64", length: %d, "
"read_bytes: %d, errno: %d, error info: %s", __LINE__,
thread_index, filename, offset, length,
read_bytes, result, STRERROR(result));
break;
}
if (read_bytes != length) {
++(*wait_count);
fc_sleep_ms(1);
continue;
}
fill_buffer(expect_buff, read_buffer_size, offset);
result = memcmp(in_buff, expect_buff, length);
if (result != 0) {
if (fail_count++ < 10) {
fc_sleep_ms(1);
++(*retry_count);
continue;
}
logError("file: "__FILE__", line: %d, thread index: %d, "
"file offset: %"PRId64", read and expect buffer "
"compare result: %d != 0", __LINE__, thread_index,
offset, result);
return result;
}
if (fail_count > 0) {
fail_count = 0;
}
remain -= read_bytes;
++i;
}
return 0;
}
static int read_test(const int thread_index)
{
FCFSAPIFileContext fctx;
FCFSAPIFileInfo fi;
char *expect_buff;
char *in_buff;
int wait_count;
int retry_count;
int i;
int result;
fctx.tid = getpid() + thread_index;
fctx.mode = 0755;
FDIR_SET_OPERATOR(fctx.oper, geteuid(), getegid(), 0, NULL);
if ((result=fcfs_api_open(&fi, filename, O_RDONLY, &fctx)) != 0) {
return result;
}
in_buff = (char *)fc_malloc(read_buffer_size * 2);
if (in_buff == NULL) {
fcfs_api_close(&fi);
return ENOMEM;
}
expect_buff = in_buff + read_buffer_size;
wait_count = retry_count = 0;
for (i=0; i 0 || retry_count > 0) {
logInfo("file: "__FILE__", line: %d, "
"thread index: %d, wait file content ready count: %d, "
"retry count: %d", __LINE__, thread_index, wait_count,
retry_count);
}
return result;
}
static void *read_thread(void *arg)
{
int thread_index;
thread_index = (long)arg;
if (read_test(thread_index) == 0) {
logInfo("file: "__FILE__", line: %d, thread index: %d, "
"read test successfully!", __LINE__, thread_index);
}
FC_ATOMIC_DEC(read_thread_count);
return NULL;
}
static void sigQuitHandler(int sig)
{
if (SF_G_CONTINUE_FLAG) {
SF_G_CONTINUE_FLAG = false;
logInfo("file: "__FILE__", line: %d, "
"catch signal %d, program exiting...",
__LINE__, sig);
}
}
int main(int argc, char *argv[])
{
const bool publish = false;
const char *config_filename = FCFS_FUSE_DEFAULT_CONFIG_FILENAME;
int ch;
int i;
int result;
int status;
struct sigaction act;
long thread_index;
pthread_t wtid;
pthread_t rtid;
is_random_read = is_random_write = false;
read_thread_count = 1;
read_loop_count = 1;
file_size = 64 * 1024 * 1024;
write_buffer_size = read_buffer_size = 4 * 1024;
while ((ch=getopt(argc, argv, "hc:n:s:w:r:t:l:RW")) != -1) {
switch (ch) {
case 'h':
usage(argv);
return 0;
case 'c':
config_filename = optarg;
break;
case 'n':
ns = optarg;
break;
case 's':
if ((result=parse_bytes(optarg, 1, &file_size)) != 0) {
return EINVAL;
}
if (file_size < 1024 * 1024) {
fprintf(stderr, "file size: %"PRId64" "
"is too small < 1MB", file_size);
return EINVAL;
}
file_size = MEM_ALIGN_CEIL(file_size, 1024 * 1024);
break;
case 'w':
if ((result=parse_bytes(optarg, 1, &write_buffer_size)) != 0) {
return EINVAL;
}
write_buffer_size = MEM_ALIGN_CEIL(
write_buffer_size, 1024);
break;
case 'r':
if ((result=parse_bytes(optarg, 1, &read_buffer_size)) != 0) {
return EINVAL;
}
read_buffer_size = MEM_ALIGN_CEIL(
read_buffer_size, 1024);
break;
case 't':
read_thread_count = strtol(optarg, NULL, 10);
break;
case 'l':
read_loop_count = strtol(optarg, NULL, 10);
break;
case 'R':
is_random_read = true;
break;
case 'W':
is_random_write = true;
break;
default:
usage(argv);
return 1;
}
}
log_init();
//g_log_context.log_level = LOG_DEBUG;
if ((result=init()) != 0) {
return result;
}
if ((result=fcfs_api_pooled_init_with_auth(ns,
config_filename, publish)) != 0)
{
return result;
}
if ((result=check_create_root_path()) != 0) {
return result;
}
if ((result=fcfs_api_start()) != 0) {
return result;
}
memset(&act, 0, sizeof(act));
sigemptyset(&act.sa_mask);
act.sa_handler = sigQuitHandler;
if(sigaction(SIGINT, &act, NULL) < 0 ||
sigaction(SIGTERM, &act, NULL) < 0 ||
sigaction(SIGQUIT, &act, NULL) < 0)
{
logCrit("file: "__FILE__", line: %d, "
"call sigaction fail, errno: %d, error info: %s",
__LINE__, errno, strerror(errno));
logCrit("exit abnormally!\n");
return errno;
}
thread_index = 1;
if ((result=pthread_create(&wtid, NULL, write_thread,
(void *)(thread_index++))) != 0)
{
return result;
}
while ((status=FC_ATOMIC_GET(can_read)) == 0) {
fc_sleep_ms(10);
}
if (status < 0) {
return EIO;
}
running_read_threads = read_thread_count;
for (i=0; i
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include "fastcommon/ini_file_reader.h"
#include "fastcommon/shared_func.h"
#include "fastcommon/logger.h"
#include "client_global.h"
#include "simple_connection_manager.h"
#include "client_func.h"
int fcfs_auth_alloc_group_servers(FCFSAuthServerGroup *server_group,
const int alloc_size)
{
int bytes;
bytes = sizeof(ConnectionInfo) * alloc_size;
server_group->servers = (ConnectionInfo *)fc_malloc(bytes);
if (server_group->servers == NULL) {
return errno != 0 ? errno : ENOMEM;
}
memset(server_group->servers, 0, bytes);
server_group->alloc_size = alloc_size;
server_group->count = 0;
return 0;
}
static int fcfs_auth_load_server_config(FCFSAuthClientContext *client_ctx,
IniFullContext *ini_ctx)
{
int result;
if ((result=sf_load_cluster_config(&client_ctx->cluster, ini_ctx,
FCFS_AUTH_DEFAULT_CLUSTER_PORT)) != 0)
{
return result;
}
return 0;
}
static int fcfs_auth_client_do_init_ex(FCFSAuthClientContext *client_ctx,
IniFullContext *ini_ctx)
{
int result;
client_ctx->common_cfg.connect_timeout = iniGetIntValueEx(
ini_ctx->section_name, "connect_timeout",
ini_ctx->context, SF_DEFAULT_CONNECT_TIMEOUT, true);
if (client_ctx->common_cfg.connect_timeout <= 0) {
client_ctx->common_cfg.connect_timeout = SF_DEFAULT_CONNECT_TIMEOUT;
}
client_ctx->common_cfg.network_timeout = iniGetIntValueEx(
ini_ctx->section_name, "network_timeout",
ini_ctx->context, SF_DEFAULT_NETWORK_TIMEOUT, true);
if (client_ctx->common_cfg.network_timeout <= 0) {
client_ctx->common_cfg.network_timeout = SF_DEFAULT_NETWORK_TIMEOUT;
}
if ((result=fcfs_auth_load_server_config(client_ctx, ini_ctx)) != 0) {
return result;
}
if ((result=sf_load_net_retry_config(&client_ctx->
common_cfg.net_retry_cfg, ini_ctx)) != 0)
{
return result;
}
return 0;
}
void fcfs_auth_client_log_config_ex(FCFSAuthClientContext *client_ctx,
const char *extra_config)
{
char net_retry_output[256];
sf_net_retry_config_to_string(&client_ctx->common_cfg.net_retry_cfg,
net_retry_output, sizeof(net_retry_output));
logInfo("fauth v%d.%d.%d, "
"connect_timeout=%d, "
"network_timeout=%d, "
"%s, auth_server_count=%d%s%s",
g_fcfs_auth_global_vars.version.major,
g_fcfs_auth_global_vars.version.minor,
g_fcfs_auth_global_vars.version.patch,
client_ctx->common_cfg.connect_timeout,
client_ctx->common_cfg.network_timeout,
net_retry_output, FC_SID_SERVER_COUNT(client_ctx->cluster.
server_cfg), (extra_config != NULL ? ", " : ""),
(extra_config != NULL ? extra_config : ""));
}
int fcfs_auth_client_load_from_file_ex1(FCFSAuthClientContext *client_ctx,
IniFullContext *ini_ctx)
{
IniContext iniContext;
int result;
if (ini_ctx->context == NULL) {
if ((result=iniLoadFromFile(ini_ctx->filename, &iniContext)) != 0) {
logError("file: "__FILE__", line: %d, "
"load conf file \"%s\" fail, ret code: %d",
__LINE__, ini_ctx->filename, result);
return result;
}
ini_ctx->context = &iniContext;
}
if ((result=fcfs_auth_client_do_init_ex(client_ctx, ini_ctx)) == 0) {
client_ctx->inited = true;
}
if (ini_ctx->context == &iniContext) {
iniFreeContext(&iniContext);
ini_ctx->context = NULL;
}
return result;
}
int fcfs_auth_client_init_ex2(FCFSAuthClientContext *client_ctx,
IniFullContext *ini_ctx, const SFServerGroupIndexType index_type)
{
int result;
int server_group_index;
if ((result=fcfs_auth_client_load_from_file_ex1(
client_ctx, ini_ctx)) != 0)
{
return result;
}
server_group_index = (index_type == sf_server_group_index_type_cluster ?
client_ctx->cluster.cluster_group_index :
client_ctx->cluster.service_group_index);
if ((result=fcfs_auth_simple_connection_manager_init(client_ctx,
&client_ctx->cm, server_group_index)) != 0)
{
return result;
}
return 0;
}
void fcfs_auth_client_destroy_ex(FCFSAuthClientContext *client_ctx)
{
fc_server_destroy(&client_ctx->cluster.server_cfg);
fcfs_auth_simple_connection_manager_destroy(&client_ctx->cm);
memset(client_ctx, 0, sizeof(FCFSAuthClientContext));
}
================================================
FILE: src/auth/client/client_func.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_AUTH_CLIENT_FUNC_H
#define _FCFS_AUTH_CLIENT_FUNC_H
#include "auth_global.h"
#include "client_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#define fcfs_auth_client_load_from_file(filename) \
fcfs_auth_client_load_from_file_ex((&g_fcfs_auth_client_vars.client_ctx), \
filename, NULL)
#define fcfs_auth_client_init_ex(filename, index_type) \
fcfs_auth_client_init_ex1((&g_fcfs_auth_client_vars.client_ctx), \
filename, NULL, index_type)
#define fcfs_auth_client_init(filename) \
fcfs_auth_client_init_ex(filename, \
sf_server_group_index_type_service)
#define fcfs_auth_client_destroy() \
fcfs_auth_client_destroy_ex((&g_fcfs_auth_client_vars.client_ctx))
#define fcfs_auth_client_log_config(client_ctx) \
fcfs_auth_client_log_config_ex(client_ctx, NULL)
int fcfs_auth_client_load_from_file_ex1(FCFSAuthClientContext *client_ctx,
IniFullContext *ini_ctx);
/**
* client initial from config file
* params:
* client_ctx: the client context
* config_filename: the client config filename
* section_name: the section name, NULL or empty for global section
* return: 0 success, != 0 fail, return the error code
**/
static inline int fcfs_auth_client_load_from_file_ex(FCFSAuthClientContext
*client_ctx, const char *config_filename, const char *section_name)
{
IniFullContext ini_ctx;
FAST_INI_SET_FULL_CTX(ini_ctx, config_filename, section_name);
return fcfs_auth_client_load_from_file_ex1(client_ctx, &ini_ctx);
}
int fcfs_auth_client_init_ex2(FCFSAuthClientContext *client_ctx,
IniFullContext *ini_ctx, const SFServerGroupIndexType index_type);
static inline int fcfs_auth_client_init_ex1(FCFSAuthClientContext *client_ctx,
const char *config_filename, const char *section_name,
const SFServerGroupIndexType index_type)
{
IniFullContext ini_ctx;
FAST_INI_SET_FULL_CTX(ini_ctx, config_filename, section_name);
return fcfs_auth_client_init_ex2(client_ctx, &ini_ctx, index_type);
}
/**
* client destroy function
* params:
* client_ctx: tracker group
* return: none
**/
void fcfs_auth_client_destroy_ex(FCFSAuthClientContext *client_ctx);
int fcfs_auth_alloc_group_servers(FCFSAuthServerGroup *server_group,
const int alloc_size);
void fcfs_auth_client_log_config_ex(FCFSAuthClientContext *client_ctx,
const char *extra_config);
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/client/client_global.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include "client_global.h"
FCFSAuthClientGlobalVars g_fcfs_auth_client_vars = {
true, false, {false}
};
================================================
FILE: src/auth/client/client_global.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_AUTH_CLIENT_GLOBAL_H
#define _FCFS_AUTH_CLIENT_GLOBAL_H
#include "auth_global.h"
#include "client_types.h"
typedef struct fcfs_auth_client_global_vars {
bool need_load_passwd; //false for auth server
bool ignore_when_passwd_not_exist; //true for fdir and fstore servers
FCFSAuthClientContext client_ctx;
} FCFSAuthClientGlobalVars;
#define fcfs_auth_client_init_full_ctx_ex(auth, client_ctx) \
(auth)->ctx = client_ctx
#define fcfs_auth_client_init_full_ctx(auth) \
fcfs_auth_client_init_full_ctx_ex(auth, &g_fcfs_auth_client_vars.client_ctx)
#ifdef __cplusplus
extern "C" {
#endif
extern FCFSAuthClientGlobalVars g_fcfs_auth_client_vars;
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/client/client_proto.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include "fastcommon/ini_file_reader.h"
#include "fastcommon/shared_func.h"
#include "fastcommon/logger.h"
#include "fastcommon/sockopt.h"
#include "fastcommon/connection_pool.h"
#include "auth_proto.h"
#include "auth_func.h"
#include "client_global.h"
#include "client_proto.h"
#define check_name(name, caption) check_name_ex(name, caption, true)
#define check_username_ex(username, required) \
check_name_ex(username, "username", required)
#define check_username(username) check_username_ex(username, true)
#define pack_username_ex(username, proto_uname, required) \
pack_name_ex(username, "username", proto_uname, 0, required)
#define pack_username(username, proto_uname) \
pack_username_ex(username, proto_uname, true)
#define check_poolname_ex(poolname, required) \
check_name_ex(poolname, "poolname", required)
#define check_poolname(poolname) check_poolname_ex(poolname, true)
#define pack_poolname_ex(poolname, proto_pname, str_offset, required) \
pack_name_ex(poolname, "poolname", proto_pname, str_offset, required)
#define pack_poolname(poolname, proto_pname) \
pack_poolname_ex(poolname, proto_pname, 0, true)
#define pack_user_pool_pair(username, poolname, up_pair) \
pack_user_pool_pair_ex(username, poolname, up_pair, true)
static inline int check_name_ex(const string_t *name,
const char *caption, const bool required)
{
int min_length;
min_length = required ? 1 : 0;
if (name->len < min_length || name->len > NAME_MAX) {
logError("file: "__FILE__", line: %d, "
"invalid %s length: %d, which <= 0 or > %d",
__LINE__, caption, name->len, NAME_MAX);
return EINVAL;
}
return 0;
}
static inline int pack_name_ex(const string_t *name, const char *caption,
FCFSAuthProtoNameInfo *proto_name, const int str_offset,
const bool required)
{
int result;
if ((result=check_name_ex(name, caption, required)) != 0) {
return result;
}
if (name->len > 0) {
memcpy(proto_name->str + str_offset, name->str, name->len);
}
proto_name->len = name->len;
return 0;
}
static inline int pack_user_pool_pair_ex(const string_t *username,
const string_t *poolname, FCFSAuthProtoUserPoolPair *up_pair,
const bool required)
{
int result;
if ((result=check_username_ex(username, required)) != 0) {
return result;
}
if ((result=check_poolname_ex(poolname, required)) != 0) {
return result;
}
fcfs_auth_pack_user_pool_pair(username, poolname, up_pair);
return 0;
}
static inline int pack_user_passwd_pair(const string_t *username,
const string_t *passwd, FCFSAuthProtoUserPasswdPair *up_pair)
{
if (passwd->len != FCFS_AUTH_PASSWD_LEN) {
logError("file: "__FILE__", line: %d, "
"invalid password length: %d != %d",
__LINE__, passwd->len, FCFS_AUTH_PASSWD_LEN);
return EINVAL;
}
memcpy(up_pair->passwd, passwd->str, passwd->len);
return pack_username(username, &up_pair->username);
}
int fcfs_auth_client_proto_user_login(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username,
const string_t *passwd, const string_t *poolname,
const int flags)
{
FCFSAuthProtoHeader *header;
FCFSAuthProtoUserLoginReq *req;
FCFSAuthProtoNameInfo *proto_pname;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoUserLoginReq) +
2 * NAME_MAX + FCFS_AUTH_PASSWD_LEN];
SFResponseInfo response;
FCFSAuthProtoUserLoginResp login_resp;
int out_bytes;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
req = (FCFSAuthProtoUserLoginReq *)(header + 1);
out_bytes = sizeof(FCFSAuthProtoHeader) + sizeof(*req) +
username->len + poolname->len;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_USER_LOGIN_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
req->flags = flags;
if ((result=pack_user_passwd_pair(username,
passwd, &req->up_pair)) != 0)
{
return result;
}
proto_pname = (FCFSAuthProtoNameInfo *)(req->
up_pair.username.str + username->len);
if ((result=pack_poolname_ex(poolname, proto_pname, 0, false)) != 0) {
return result;
}
response.error.length = 0;
if ((result=sf_send_and_recv_response(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_USER_LOGIN_RESP,
(char *)&login_resp, sizeof(login_resp))) == 0)
{
memcpy(client_ctx->session.id, login_resp.session_id,
FCFS_AUTH_SESSION_ID_LEN);
} else {
auth_log_network_error(&response, conn, result);
}
return result;
}
int fcfs_auth_client_proto_session_subscribe(
FCFSAuthClientContext *client_ctx, ConnectionInfo *conn)
{
FCFSAuthProtoHeader *header;
FCFSAuthProtoSessionSubscribeReq *req;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoSessionSubscribeReq) +
NAME_MAX + FCFS_AUTH_PASSWD_LEN];
SFResponseInfo response;
int out_bytes;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
req = (FCFSAuthProtoSessionSubscribeReq *)(header + 1);
out_bytes = sizeof(FCFSAuthProtoHeader) + sizeof(*req) +
client_ctx->auth_cfg.username.len;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_SESSION_SUBSCRIBE_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
if ((result=pack_user_passwd_pair(&client_ctx->auth_cfg.username,
&client_ctx->auth_cfg.passwd, &req->up_pair)) != 0)
{
return result;
}
response.error.length = 0;
if ((result=sf_send_and_recv_none_body_response(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_SESSION_SUBSCRIBE_RESP)) != 0)
{
auth_log_network_error(&response, conn, result);
}
return result;
}
int fcfs_auth_client_proto_session_validate(
FCFSAuthClientContext *client_ctx, ConnectionInfo *conn,
const string_t *session_id, const string_t *validate_key,
const FCFSAuthValidatePriviledgeType priv_type,
const int64_t pool_id, const int64_t priv_required)
{
FCFSAuthProtoHeader *header;
FCFSAuthProtoSessionValidateReq *req;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoSessionValidateReq) +
NAME_MAX + FCFS_AUTH_PASSWD_LEN];
FCFSAuthProtoSessionValidateResp validate_resp;
SFResponseInfo response;
int out_bytes;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
req = (FCFSAuthProtoSessionValidateReq *)(header + 1);
out_bytes = sizeof(FCFSAuthProtoHeader) + sizeof(*req);
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_SESSION_VALIDATE_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
if (validate_key->len != FCFS_AUTH_PASSWD_LEN) {
logError("file: "__FILE__", line: %d, "
"invalid session validate key length: %d != %d",
__LINE__, validate_key->len, FCFS_AUTH_PASSWD_LEN);
return EINVAL;
}
memcpy(req->validate_key, validate_key->str, validate_key->len);
if (session_id->len != FCFS_AUTH_SESSION_ID_LEN) {
logError("file: "__FILE__", line: %d, "
"invalid session id length: %d != %d", __LINE__,
session_id->len, FCFS_AUTH_SESSION_ID_LEN);
return EINVAL;
}
memcpy(req->session_id, session_id->str, session_id->len);
req->priv_type = priv_type;
long2buff(pool_id, req->pool_id);
long2buff(priv_required, req->priv_required);
response.error.length = 0;
if ((result=sf_send_and_recv_response(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_SESSION_VALIDATE_RESP,
(char *)&validate_resp, sizeof(validate_resp))) == 0)
{
result = buff2int(validate_resp.result);
} else {
auth_log_network_error(&response, conn, result);
}
return result;
}
int fcfs_auth_client_proto_user_create(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const FCFSAuthUserInfo *user)
{
FCFSAuthProtoHeader *header;
FCFSAuthProtoUserCreateReq *req;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoUserCreateReq) +
NAME_MAX + FCFS_AUTH_PASSWD_LEN];
SFResponseInfo response;
int out_bytes;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
req = (FCFSAuthProtoUserCreateReq *)(header + 1);
out_bytes = sizeof(FCFSAuthProtoHeader) + sizeof(*req) + user->name.len;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_USER_CREATE_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
if ((result=pack_user_passwd_pair(&user->name,
&user->passwd, &req->up_pair)) != 0)
{
return result;
}
long2buff(user->priv, req->priv);
response.error.length = 0;
if ((result=sf_send_and_recv_none_body_response(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_USER_CREATE_RESP)) != 0)
{
auth_log_network_error(&response, conn, result);
}
return result;
}
int fcfs_auth_client_proto_user_passwd(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username,
const string_t *passwd)
{
FCFSAuthProtoHeader *header;
FCFSAuthProtoUserPasswdReq *req;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoUserPasswdReq) +
NAME_MAX + FCFS_AUTH_PASSWD_LEN];
SFResponseInfo response;
int out_bytes;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
req = (FCFSAuthProtoUserPasswdReq *)(header + 1);
out_bytes = sizeof(FCFSAuthProtoHeader) + sizeof(*req) + username->len;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_USER_PASSWD_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
if ((result=pack_user_passwd_pair(username, passwd,
&req->up_pair)) != 0)
{
return result;
}
response.error.length = 0;
if ((result=sf_send_and_recv_none_body_response(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_USER_PASSWD_RESP)) != 0)
{
auth_log_network_error(&response, conn, result);
}
return result;
}
typedef int (*client_proto_list_func)(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username,
const string_t *poolname, const SFListLimitInfo *limit,
SFProtoRecvBuffer *buffer, struct fast_mpool_man *mpool,
void *array, bool *is_last);
static int client_proto_user_list_do(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username,
const string_t *poolname, const SFListLimitInfo *limit,
SFProtoRecvBuffer *buffer, struct fast_mpool_man *mpool,
FCFSAuthUserArray *array, bool *is_last)
{
FCFSAuthProtoHeader *header;
FCFSAuthProtoUserListReq *req;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoUserListReq) + NAME_MAX];
SFResponseInfo response;
FCFSAuthProtoListRespHeader *resp_header;
FCFSAuthProtoUserListRespBodyPart *body_part;
FCFSAuthUserInfo *user;
FCFSAuthUserInfo *end;
char *p;
int out_bytes;
int count;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
req = (FCFSAuthProtoUserListReq *)(header + 1);
if ((result=pack_username_ex(username, &req->username, false)) != 0) {
return result;
}
out_bytes = sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoUserListReq) + username->len;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_USER_LIST_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
sf_proto_pack_limit(limit, &req->limit);
response.error.length = 0;
if ((result=sf_send_and_recv_vary_response(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_USER_LIST_RESP, buffer,
sizeof(FCFSAuthProtoListRespHeader))) != 0)
{
auth_log_network_error(&response, conn, result);
return result;
}
resp_header = (FCFSAuthProtoListRespHeader *)buffer->buff;
count = buff2int(resp_header->count);
*is_last = resp_header->is_last;
if ((result=fcfs_auth_user_check_realloc_array(array,
array->count + count)) != 0)
{
return result;
}
p = (char *)(resp_header + 1);
end = array->users + array->count + count;
for (user=array->users+array->count; userpriv = buff2long(body_part->priv);
if ((result=fast_mpool_alloc_string_ex(mpool,
&user->name, body_part->username.str,
body_part->username.len)) != 0)
{
return result;
}
p += sizeof(FCFSAuthProtoUserListRespBodyPart) + user->name.len;
}
if (response.header.body_len != p - buffer->buff) {
logError("file: "__FILE__", line: %d, "
"response body length: %d != expect: %d",
__LINE__, response.header.body_len,
(int)(p - buffer->buff));
return EINVAL;
}
array->count += count;
return result;
}
static int client_proto_list_wrapper(client_proto_list_func list_func,
FCFSAuthClientContext *client_ctx, ConnectionInfo *conn,
const string_t *username, const string_t *poolname,
const SFListLimitInfo *limit, struct fast_mpool_man *mpool,
void *array, int *count)
{
int result;
bool is_last;
SFProtoRBufferFixedWrapper buffer_wrapper;
SFListLimitInfo new_limit;
sf_init_recv_buffer_by_wrapper(&buffer_wrapper);
if (limit->count > 0 && limit->count <= 64) {
result = list_func(client_ctx, conn,
username, poolname, limit, &buffer_wrapper.buffer,
mpool, array, &is_last);
sf_free_recv_buffer(&buffer_wrapper.buffer);
return result;
}
result = 0;
is_last = false;
while (!is_last) {
new_limit.offset = limit->offset + *count;
if (limit->count <= 0) {
new_limit.count = 0;
} else {
new_limit.count = limit->count - *count;
if (new_limit.count == 0) {
break;
}
}
if ((result=list_func(client_ctx, conn, username,
poolname, &new_limit, &buffer_wrapper.buffer,
mpool, array, &is_last)) != 0)
{
break;
}
}
sf_free_recv_buffer(&buffer_wrapper.buffer);
return result;
}
int fcfs_auth_client_proto_user_list(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username,
const SFListLimitInfo *limit, struct fast_mpool_man *mpool,
FCFSAuthUserArray *array)
{
const string_t *poolname = NULL;
return client_proto_list_wrapper((client_proto_list_func)
client_proto_user_list_do, client_ctx, conn, username,
poolname, limit, mpool, array, &array->count);
}
int fcfs_auth_client_proto_user_grant(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username, const int64_t priv)
{
FCFSAuthProtoHeader *header;
FCFSAuthProtoUserGrantReq *req;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoUserGrantReq) + NAME_MAX];
SFResponseInfo response;
int out_bytes;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
req = (FCFSAuthProtoUserGrantReq *)(header + 1);
out_bytes = sizeof(FCFSAuthProtoHeader) + sizeof(*req) + username->len;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_USER_GRANT_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
if ((result=pack_username(username, &req->username)) != 0) {
return result;
}
long2buff(priv, req->priv);
response.error.length = 0;
if ((result=sf_send_and_recv_none_body_response(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_USER_GRANT_RESP)) != 0)
{
auth_log_network_error(&response, conn, result);
}
return result;
}
int fcfs_auth_client_proto_user_remove(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username)
{
FCFSAuthProtoHeader *header;
FCFSAuthProtoUserRemoveReq *req;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoUserRemoveReq) + NAME_MAX];
SFResponseInfo response;
int out_bytes;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
req = (FCFSAuthProtoUserRemoveReq *)(header + 1);
out_bytes = sizeof(FCFSAuthProtoHeader) + sizeof(*req) + username->len;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_USER_REMOVE_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
if ((result=pack_username(username, &req->username)) != 0) {
return result;
}
response.error.length = 0;
if ((result=sf_send_and_recv_none_body_response(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_USER_REMOVE_RESP)) != 0)
{
auth_log_network_error(&response, conn, result);
}
return result;
}
int fcfs_auth_client_proto_spool_create(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, FCFSAuthStoragePoolInfo *spool,
const int name_size, const bool dryrun)
{
FCFSAuthProtoHeader *header;
FCFSAuthProtoSPoolCreateReq *req;
FCFSAuthProtoSPoolCreateResp *resp;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoSPoolCreateReq) + NAME_MAX];
char in_buff[sizeof(FCFSAuthProtoSPoolCreateResp) + NAME_MAX];
SFResponseInfo response;
int out_bytes;
int body_len;
int buff_size;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
req = (FCFSAuthProtoSPoolCreateReq *)(header + 1);
out_bytes = sizeof(FCFSAuthProtoHeader) + sizeof(*req) + spool->name.len;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_SPOOL_CREATE_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
if ((result=pack_poolname_ex(&spool->name,
&req->poolname, 0, false)) != 0)
{
return result;
}
long2buff(spool->quota, req->quota);
req->dryrun = (dryrun ? 1 : 0);
if (name_size < sizeof(in_buff) - sizeof(*resp)) {
buff_size = name_size;
} else {
buff_size = sizeof(in_buff);
}
response.error.length = 0;
if ((result=sf_send_and_recv_response_ex1(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_SPOOL_CREATE_RESP, in_buff,
buff_size, &body_len)) != 0)
{
auth_log_network_error(&response, conn, result);
return result;
}
resp = (FCFSAuthProtoSPoolCreateResp *)in_buff;
if (body_len != sizeof(*resp) + resp->poolname.len) {
logError("file: "__FILE__", line: %d, "
"response body length: %d != expect: %d", __LINE__,
body_len, (int)sizeof(*resp) + resp->poolname.len);
return EINVAL;
}
spool->name.len = resp->poolname.len;
memcpy(spool->name.str, resp->poolname.str, spool->name.len);
return 0;
}
int client_proto_spool_list_do(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username,
const string_t *poolname, const SFListLimitInfo *limit,
SFProtoRecvBuffer *buffer, struct fast_mpool_man *mpool,
FCFSAuthStoragePoolArray *array, bool *is_last)
{
FCFSAuthProtoHeader *header;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoSPoolListReq) + 2 * NAME_MAX];
SFResponseInfo response;
FCFSAuthProtoSPoolListReq *req;
FCFSAuthProtoListRespHeader *resp_header;
FCFSAuthProtoSPoolListRespBodyPart *body_part;
FCFSAuthStoragePoolInfo *spool;
FCFSAuthStoragePoolInfo *end;
char *p;
int out_bytes;
int count;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
out_bytes = sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoSPoolListReq) +
username->len + poolname->len;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_SPOOL_LIST_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
req = (FCFSAuthProtoSPoolListReq *)(header + 1);
if ((result=pack_user_pool_pair_ex(username, poolname,
&req->up_pair, false)) != 0)
{
return result;
}
sf_proto_pack_limit(limit, &req->limit);
response.error.length = 0;
if ((result=sf_send_and_recv_vary_response(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_SPOOL_LIST_RESP, buffer,
sizeof(FCFSAuthProtoListRespHeader))) != 0)
{
auth_log_network_error(&response, conn, result);
return result;
}
resp_header = (FCFSAuthProtoListRespHeader *)buffer->buff;
count = buff2int(resp_header->count);
*is_last = resp_header->is_last;
if ((result=fcfs_auth_spool_check_realloc_array(array,
array->count + count)) != 0)
{
return result;
}
p = (char *)(resp_header + 1);
end = array->spools + array->count + count;
for (spool=array->spools+array->count; spoolquota = buff2long(body_part->quota);
if ((result=fast_mpool_alloc_string_ex(mpool,
&spool->name, body_part->poolname.str,
body_part->poolname.len)) != 0)
{
return result;
}
p += sizeof(FCFSAuthProtoSPoolListRespBodyPart) + spool->name.len;
}
if (response.header.body_len != p - buffer->buff) {
logError("file: "__FILE__", line: %d, "
"response body length: %d != expect: %d",
__LINE__, response.header.body_len,
(int)(p - buffer->buff));
return EINVAL;
}
array->count += count;
return result;
}
int fcfs_auth_client_proto_spool_list(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username,
const string_t *poolname, const SFListLimitInfo *limit,
struct fast_mpool_man *mpool, FCFSAuthStoragePoolArray *array)
{
return client_proto_list_wrapper((client_proto_list_func)
client_proto_spool_list_do, client_ctx, conn, username,
poolname, limit, mpool, array, &array->count);
}
int fcfs_auth_client_proto_spool_remove(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *poolname)
{
FCFSAuthProtoHeader *header;
FCFSAuthProtoSPoolRemoveReq *req;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoSPoolRemoveReq) + NAME_MAX];
SFResponseInfo response;
int out_bytes;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
req = (FCFSAuthProtoSPoolRemoveReq *)(header + 1);
out_bytes = sizeof(FCFSAuthProtoHeader) + sizeof(*req) + poolname->len;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_SPOOL_REMOVE_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
if ((result=pack_poolname(poolname, &req->poolname)) != 0) {
return result;
}
response.error.length = 0;
if ((result=sf_send_and_recv_none_body_response(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_SPOOL_REMOVE_RESP)) != 0)
{
auth_log_network_error(&response, conn, result);
}
return result;
}
int fcfs_auth_client_proto_spool_set_quota(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *poolname, const int64_t quota)
{
FCFSAuthProtoHeader *header;
FCFSAuthProtoSPoolSetQuotaReq *req;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoSPoolSetQuotaReq) + NAME_MAX];
SFResponseInfo response;
int out_bytes;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
req = (FCFSAuthProtoSPoolSetQuotaReq *)(header + 1);
out_bytes = sizeof(FCFSAuthProtoHeader) + sizeof(*req) + poolname->len;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_SPOOL_SET_QUOTA_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
if ((result=pack_poolname(poolname, &req->poolname)) != 0) {
return result;
}
long2buff(quota, req->quota);
response.error.length = 0;
if ((result=sf_send_and_recv_none_body_response(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_SPOOL_SET_QUOTA_RESP)) != 0)
{
auth_log_network_error(&response, conn, result);
}
return result;
}
int fcfs_auth_client_proto_spool_get_quota(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *poolname, int64_t *quota)
{
FCFSAuthProtoHeader *header;
FCFSAuthProtoSPoolGetQuotaReq *req;
FCFSAuthProtoSPoolGetQuotaResp resp;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoSPoolGetQuotaReq) + NAME_MAX];
SFResponseInfo response;
int out_bytes;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
req = (FCFSAuthProtoSPoolGetQuotaReq *)(header + 1);
out_bytes = sizeof(FCFSAuthProtoHeader) + sizeof(*req) + poolname->len;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_SPOOL_GET_QUOTA_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
if ((result=pack_poolname(poolname, &req->poolname)) != 0) {
return result;
}
response.error.length = 0;
if ((result=sf_send_and_recv_response(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_SPOOL_GET_QUOTA_RESP,
(char *)&resp, sizeof(resp))) == 0)
{
*quota = buff2long(resp.quota);
} else {
auth_log_network_error(&response, conn, result);
}
return result;
}
int fcfs_auth_client_proto_gpool_grant(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username, const string_t
*poolname, const FCFSAuthSPoolPriviledges *privs)
{
FCFSAuthProtoHeader *header;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoSPoolGrantReq) + 2 * NAME_MAX];
SFResponseInfo response;
FCFSAuthProtoSPoolGrantReq *req;
int out_bytes;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
out_bytes = sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoSPoolGrantReq) +
username->len + poolname->len;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_GPOOL_GRANT_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
req = (FCFSAuthProtoSPoolGrantReq *)(header + 1);
if ((result=pack_user_pool_pair(username, poolname,
&req->up_pair)) != 0)
{
return result;
}
int2buff(privs->fdir, req->privs.fdir);
int2buff(privs->fstore, req->privs.fstore);
response.error.length = 0;
if ((result=sf_send_and_recv_none_body_response(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_GPOOL_GRANT_RESP)) != 0)
{
auth_log_network_error(&response, conn, result);
}
return result;
}
int fcfs_auth_client_proto_gpool_withdraw(FCFSAuthClientContext
*client_ctx, ConnectionInfo *conn, const string_t *username,
const string_t *poolname)
{
FCFSAuthProtoHeader *header;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoSPoolWithdrawReq) + 2 * NAME_MAX];
SFResponseInfo response;
FCFSAuthProtoSPoolWithdrawReq *req;
int out_bytes;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
out_bytes = sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoSPoolWithdrawReq) +
username->len + poolname->len;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_GPOOL_WITHDRAW_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
req = (FCFSAuthProtoSPoolWithdrawReq *)(header + 1);
if ((result=pack_user_pool_pair(username, poolname,
&req->up_pair)) != 0)
{
return result;
}
response.error.length = 0;
if ((result=sf_send_and_recv_none_body_response(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_GPOOL_WITHDRAW_RESP)) != 0)
{
auth_log_network_error(&response, conn, result);
}
return result;
}
static int client_proto_gpool_list_do(FCFSAuthClientContext
*client_ctx, ConnectionInfo *conn, const string_t *username,
const string_t *poolname, const SFListLimitInfo *limit,
SFProtoRecvBuffer *buffer, struct fast_mpool_man *mpool,
FCFSAuthGrantedPoolArray *array, bool *is_last)
{
FCFSAuthProtoHeader *header;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoGPoolListReq) + 2 * NAME_MAX];
SFResponseInfo response;
FCFSAuthProtoGPoolListReq *req;
FCFSAuthProtoListRespHeader *resp_header;
FCFSAuthProtoGPoolListRespBodyPart *body_part;
FCFSAuthProtoNameInfo *proto_pname;
FCFSAuthGrantedPoolFullInfo *gpool;
FCFSAuthGrantedPoolFullInfo *end;
char *p;
int out_bytes;
int count;
int result;
header = (FCFSAuthProtoHeader *)out_buff;
out_bytes = sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoGPoolListReq) +
username->len + poolname->len;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_GPOOL_LIST_REQ,
out_bytes - sizeof(FCFSAuthProtoHeader));
req = (FCFSAuthProtoGPoolListReq *)(header + 1);
if ((result=pack_user_pool_pair_ex(username, poolname,
&req->up_pair, false)) != 0)
{
return result;
}
sf_proto_pack_limit(limit, &req->limit);
response.error.length = 0;
if ((result=sf_send_and_recv_vary_response(conn, out_buff, out_bytes,
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_GPOOL_LIST_RESP, buffer,
sizeof(FCFSAuthProtoListRespHeader))) != 0)
{
auth_log_network_error(&response, conn, result);
return result;
}
resp_header = (FCFSAuthProtoListRespHeader *)buffer->buff;
count = buff2int(resp_header->count);
*is_last = resp_header->is_last;
if ((result=fcfs_auth_gpool_check_realloc_array(array,
array->count + count)) != 0)
{
return result;
}
p = (char *)(resp_header + 1);
end = array->gpools + array->count + count;
for (gpool=array->gpools+array->count; gpoolgranted.privs.fdir = buff2int(body_part->privs.fdir);
gpool->granted.privs.fstore = buff2int(body_part->privs.fstore);
if ((result=fast_mpool_alloc_string_ex(mpool, &gpool->username,
body_part->up_pair.username.str,
body_part->up_pair.username.len)) != 0)
{
return result;
}
proto_pname = (FCFSAuthProtoNameInfo *)(body_part->up_pair.
username.str + body_part->up_pair.username.len);
if ((result=fast_mpool_alloc_string_ex(mpool, &gpool->pool_name,
proto_pname->str, proto_pname->len)) != 0)
{
return result;
}
p += sizeof(FCFSAuthProtoGPoolListRespBodyPart)
+ gpool->username.len + gpool->pool_name.len;
}
if (response.header.body_len != p - buffer->buff) {
logError("file: "__FILE__", line: %d, "
"response body length: %d != expect: %d",
__LINE__, response.header.body_len,
(int)(p - buffer->buff));
return EINVAL;
}
array->count += count;
return result;
}
int fcfs_auth_client_proto_gpool_list(FCFSAuthClientContext
*client_ctx, ConnectionInfo *conn, const string_t *username,
const string_t *poolname, const SFListLimitInfo *limit,
struct fast_mpool_man *mpool, FCFSAuthGrantedPoolArray *array)
{
return client_proto_list_wrapper((client_proto_list_func)
client_proto_gpool_list_do, client_ctx, conn, username,
poolname, limit, mpool, array, &array->count);
}
int fcfs_auth_client_get_master(FCFSAuthClientContext *client_ctx,
FCFSAuthClientServerEntry *master)
{
const bool shared = false;
int result;
ConnectionInfo *conn;
FCFSAuthProtoHeader *header;
SFResponseInfo response;
FCFSAuthProtoGetServerResp server_resp;
char out_buff[sizeof(FCFSAuthProtoHeader)];
conn = client_ctx->cm.ops.get_connection(
&client_ctx->cm, 0, shared, &result);
if (conn == NULL) {
return result;
}
header = (FCFSAuthProtoHeader *)out_buff;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_GET_MASTER_REQ,
sizeof(out_buff) - sizeof(FCFSAuthProtoHeader));
response.error.length = 0;
if ((result=sf_send_and_recv_response(conn, out_buff, sizeof(out_buff),
&response, client_ctx->common_cfg.network_timeout,
FCFS_AUTH_SERVICE_PROTO_GET_MASTER_RESP,
(char *)&server_resp, sizeof(FCFSAuthProtoGetServerResp))) != 0)
{
auth_log_network_error(&response, conn, result);
} else {
master->server_id = buff2int(server_resp.server_id);
memcpy(master->conn.ip_addr, server_resp.ip_addr, IP_ADDRESS_SIZE);
*(master->conn.ip_addr + IP_ADDRESS_SIZE - 1) = '\0';
master->conn.port = buff2short(server_resp.port);
master->conn.comm_type = conn->comm_type;
}
SF_CLIENT_RELEASE_CONNECTION(&client_ctx->cm, conn, result);
return result;
}
int fcfs_auth_client_cluster_stat(FCFSAuthClientContext *client_ctx,
FCFSAuthClientClusterStatEntry *stats, const int size, int *count)
{
const bool shared = false;
FCFSAuthProtoHeader *header;
FCFSAuthProtoClusterStatRespBodyHeader *body_header;
FCFSAuthProtoClusterStatRespBodyPart *body_part;
FCFSAuthProtoClusterStatRespBodyPart *body_end;
FCFSAuthClientClusterStatEntry *stat;
ConnectionInfo *conn;
char out_buff[sizeof(FCFSAuthProtoHeader)];
char fixed_buff[8 * 1024];
char *in_buff;
SFResponseInfo response;
int result;
int calc_size;
if ((conn=client_ctx->cm.ops.get_master_connection(&client_ctx->cm,
0, shared, &result)) == NULL)
{
return result;
}
header = (FCFSAuthProtoHeader *)out_buff;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_SERVICE_PROTO_CLUSTER_STAT_REQ,
sizeof(out_buff) - sizeof(FCFSAuthProtoHeader));
response.error.length = 0;
in_buff = fixed_buff;
if ((result=sf_send_and_check_response_header(conn, out_buff,
sizeof(out_buff), &response, client_ctx->common_cfg.
network_timeout, FCFS_AUTH_SERVICE_PROTO_CLUSTER_STAT_RESP)) == 0)
{
if (response.header.body_len > sizeof(fixed_buff)) {
in_buff = (char *)fc_malloc(response.header.body_len);
if (in_buff == NULL) {
response.error.length = sprintf(response.error.message,
"malloc %d bytes fail", response.header.body_len);
result = ENOMEM;
}
}
if (result == 0) {
result = tcprecvdata_nb(conn->sock, in_buff,
response.header.body_len, client_ctx->
common_cfg.network_timeout);
}
}
body_header = (FCFSAuthProtoClusterStatRespBodyHeader *)in_buff;
body_part = (FCFSAuthProtoClusterStatRespBodyPart *)(in_buff +
sizeof(FCFSAuthProtoClusterStatRespBodyHeader));
if (result == 0) {
*count = buff2int(body_header->count);
calc_size = sizeof(FCFSAuthProtoClusterStatRespBodyHeader) +
(*count) * sizeof(FCFSAuthProtoClusterStatRespBodyPart);
if (calc_size != response.header.body_len) {
response.error.length = sprintf(response.error.message,
"response body length: %d != calculate size: %d, "
"server count: %d", response.header.body_len,
calc_size, *count);
result = EINVAL;
} else if (size < *count) {
response.error.length = sprintf(response.error.message,
"entry size %d too small < %d", size, *count);
*count = 0;
result = ENOSPC;
}
} else {
*count = 0;
}
if (result != 0) {
auth_log_network_error(&response, conn, result);
} else {
body_end = body_part + (*count);
for (stat=stats; body_partis_online = body_part->is_online;
stat->is_master = body_part->is_master;
stat->server_id = buff2int(body_part->server_id);
memcpy(stat->ip_addr, body_part->ip_addr, IP_ADDRESS_SIZE);
*(stat->ip_addr + IP_ADDRESS_SIZE - 1) = '\0';
stat->port = buff2short(body_part->port);
}
}
SF_CLIENT_RELEASE_CONNECTION(&client_ctx->cm, conn, result);
if (in_buff != fixed_buff) {
if (in_buff != NULL) {
free(in_buff);
}
}
return result;
}
================================================
FILE: src/auth/client/client_proto.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_AUTH_CLIENT_PROTO_H
#define _FCFS_AUTH_CLIENT_PROTO_H
#include "fastcommon/fast_mpool.h"
#include "sf/sf_proto.h"
#include "client_types.h"
typedef struct fcfs_auth_client_cluster_stat_entry {
int server_id;
bool is_online;
bool is_master;
uint16_t port;
char ip_addr[IP_ADDRESS_SIZE];
} FCFSAuthClientClusterStatEntry;
#ifdef __cplusplus
extern "C" {
#endif
int fcfs_auth_client_get_master(FCFSAuthClientContext *client_ctx,
FCFSAuthClientServerEntry *master);
int fcfs_auth_client_cluster_stat(FCFSAuthClientContext *client_ctx,
FCFSAuthClientClusterStatEntry *stats, const int size, int *count);
int fcfs_auth_client_proto_session_subscribe(
FCFSAuthClientContext *client_ctx, ConnectionInfo *conn);
int fcfs_auth_client_proto_session_validate(
FCFSAuthClientContext *client_ctx, ConnectionInfo *conn,
const string_t *session_id, const string_t *validate_key,
const FCFSAuthValidatePriviledgeType priv_type,
const int64_t pool_id, const int64_t priv_required);
int fcfs_auth_client_proto_user_login(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username,
const string_t *passwd, const string_t *poolname,
const int flags);
int fcfs_auth_client_proto_user_create(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const FCFSAuthUserInfo *user);
int fcfs_auth_client_proto_user_passwd(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username,
const string_t *passwd);
int fcfs_auth_client_proto_user_list(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username,
const SFListLimitInfo *limit, struct fast_mpool_man *mpool,
FCFSAuthUserArray *array);
int fcfs_auth_client_proto_user_grant(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username, const int64_t priv);
int fcfs_auth_client_proto_user_remove(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username);
int fcfs_auth_client_proto_spool_create(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, FCFSAuthStoragePoolInfo *spool,
const int name_size, const bool dryrun);
int fcfs_auth_client_proto_spool_list(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username,
const string_t *poolname, const SFListLimitInfo *limit,
struct fast_mpool_man *mpool, FCFSAuthStoragePoolArray *array);
int fcfs_auth_client_proto_spool_remove(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *poolname);
int fcfs_auth_client_proto_spool_set_quota(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *poolname, const int64_t quota);
int fcfs_auth_client_proto_spool_get_quota(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *poolname, int64_t *quota);
int fcfs_auth_client_proto_gpool_grant(FCFSAuthClientContext *client_ctx,
ConnectionInfo *conn, const string_t *username, const string_t
*poolname, const FCFSAuthSPoolPriviledges *privs);
int fcfs_auth_client_proto_gpool_withdraw(FCFSAuthClientContext
*client_ctx, ConnectionInfo *conn, const string_t *username,
const string_t *poolname);
int fcfs_auth_client_proto_gpool_list(FCFSAuthClientContext
*client_ctx, ConnectionInfo *conn, const string_t *username,
const string_t *poolname, const SFListLimitInfo *limit,
struct fast_mpool_man *mpool, FCFSAuthGrantedPoolArray *array);
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/client/client_types.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_AUTH_CLIENT_TYPES_H
#define _FCFS_AUTH_CLIENT_TYPES_H
#include "fastcommon/common_define.h"
#include "sf/sf_configs.h"
#include "sf/sf_connection_manager.h"
#include "sf/sf_cluster_cfg.h"
#include "auth_types.h"
#define FCFS_AUTH_CLIENT_DEFAULT_CONFIG_FILENAME "/etc/fastcfs/auth/client.conf"
typedef struct fcfs_auth_client_user_key_pair {
string_t username;
string_t key_filename;
} FCFSAuthClientUserKeyPair;
typedef struct fcfs_auth_client_server_entry {
int server_id;
ConnectionInfo conn;
char status;
} FCFSAuthClientServerEntry;
typedef struct fcfs_auth_server_group {
int alloc_size;
int count;
ConnectionInfo *servers;
} FCFSAuthServerGroup;
typedef struct fcfs_auth_client_common_cfg {
string_t username;
string_t passwd;
string_t secret_key_filename;
unsigned char passwd_buff[FCFS_AUTH_PASSWD_LEN];
char *buff; //for username and secret_key_filename
} FCFSAuthClientCommonCfg;
typedef struct fcfs_auth_client_context {
bool inited;
SFClusterConfig cluster;
SFConnectionManager cm;
FCFSAuthClientCommonCfg auth_cfg;
SFClientCommonConfig common_cfg;
struct {
string_t *poolname;
char id[FCFS_AUTH_SESSION_ID_LEN];
} session;
} FCFSAuthClientContext;
typedef struct fcfs_auth_client_full_context {
bool enabled;
FCFSAuthClientContext *ctx;
} FCFSAuthClientFullContext;
#endif
================================================
FILE: src/auth/client/fcfs_auth_client.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include "sf/idempotency/client/rpc_wrapper.h"
#include "../common/auth_func.h"
#include "fcfs_auth_client.h"
#define GET_MASTER_CONNECTION(cm, arg1, result) \
(cm)->ops.get_master_connection(cm, arg1, true, result)
static int load_auth_user_passwd(FCFSAuthClientCommonCfg *auth_cfg,
IniContext *ini_context, const char *auth_config_filename)
{
int result;
bool need_resolve;
string_t username;
string_t secret_key_filename;
FilenameString new_key_filename;
char full_secret_filename[PATH_MAX];
string_t new_filename;
if (g_fcfs_auth_client_vars.client_ctx.auth_cfg.username.str == NULL) {
username.str = iniGetStrValue(NULL, "username", ini_context);
if (username.str == NULL || *(username.str) == '\0') {
username.str = "admin";
}
username.len = strlen(username.str);
} else {
username = g_fcfs_auth_client_vars.client_ctx.auth_cfg.username;
}
if (g_fcfs_auth_client_vars.client_ctx.auth_cfg.
secret_key_filename.str == NULL)
{
secret_key_filename.str = iniGetStrValue(NULL,
"secret_key_filename", ini_context);
if (secret_key_filename.str == NULL ||
*(secret_key_filename.str) == '\0')
{
secret_key_filename.str = "keys/${username}.key";
}
secret_key_filename.len = strlen(secret_key_filename.str);
need_resolve = true;
} else {
secret_key_filename = g_fcfs_auth_client_vars.
client_ctx.auth_cfg.secret_key_filename;
need_resolve = false;
}
auth_cfg->passwd.str = (char *)auth_cfg->passwd_buff;
auth_cfg->passwd.len = FCFS_AUTH_PASSWD_LEN;
fcfs_auth_replace_filename_with_username(&secret_key_filename,
&username, &new_key_filename);
if (need_resolve) {
new_filename.str = full_secret_filename;
new_filename.len = resolve_path(auth_config_filename,
FC_FILENAME_STRING_PTR(new_key_filename),
full_secret_filename, sizeof(full_secret_filename));
} else {
new_filename.str = FC_FILENAME_STRING_PTR(new_key_filename);
new_filename.len = strlen(new_filename.str);
}
if (g_fcfs_auth_client_vars.need_load_passwd) {
if ((result=fcfs_auth_load_passwd_ex(new_filename.str,
auth_cfg->passwd_buff, g_fcfs_auth_client_vars.
ignore_when_passwd_not_exist)) != 0)
{
logError("file: "__FILE__", line: %d, "
"config file: %s, secret_key_filename: %s, "
"load password fail, ret code: %d", __LINE__,
auth_config_filename, new_filename.str, result);
return result;
}
} else {
memset(auth_cfg->passwd_buff, 0, FCFS_AUTH_PASSWD_LEN);
}
auth_cfg->buff = (char *)fc_malloc(username.len + 1 +
new_filename.len + 1);
if (auth_cfg->buff == NULL) {
return ENOMEM;
}
auth_cfg->username.str = auth_cfg->buff;
auth_cfg->username.len = username.len;
memcpy(auth_cfg->username.str, username.str, username.len + 1);
auth_cfg->secret_key_filename.str =
auth_cfg->username.str + username.len + 1;
auth_cfg->secret_key_filename.len = new_filename.len;
memcpy(auth_cfg->secret_key_filename.str,
new_filename.str, new_filename.len + 1);
return 0;
}
static int load_auth_config(FCFSAuthClientFullContext *auth,
const char *auth_config_filename,
const SFServerGroupIndexType index_type)
{
int result;
IniContext ini_context;
char *client_config_filename;
char full_config_filename[PATH_MAX];
if ((result=iniLoadFromFile(auth_config_filename, &ini_context)) != 0) {
logError("file: "__FILE__", line: %d, "
"load conf file \"%s\" fail, ret code: %d",
__LINE__, auth_config_filename, result);
return result;
}
auth->enabled = iniGetBoolValue(NULL, "auth_enabled", &ini_context, false);
do {
if ((!auth->enabled) || auth->ctx->inited) {
break;
}
if ((result=load_auth_user_passwd(&auth->ctx->auth_cfg,
&ini_context, auth_config_filename)) != 0)
{
break;
}
client_config_filename = iniGetStrValue(NULL,
"client_config_filename", &ini_context);
if (client_config_filename == NULL ||
*client_config_filename == '\0')
{
logError("file: "__FILE__", line: %d, "
"config file: %s, item \"client_config_filename\" "
"not exist or empty", __LINE__, auth_config_filename);
result = ENOENT;
break;
}
resolve_path(auth_config_filename, client_config_filename,
full_config_filename, sizeof(full_config_filename));
result = fcfs_auth_client_init_ex1(auth->ctx, full_config_filename,
NULL, index_type);
} while (0);
iniFreeContext(&ini_context);
return result;
}
int fcfs_auth_load_config_ex(FCFSAuthClientFullContext *auth,
const char *config_filename, const char *section_name,
const SFServerGroupIndexType index_type)
{
int result;
IniContext ini_context;
char *auth_config_filename;
char full_auth_filename[PATH_MAX];
if ((result=iniLoadFromFile(config_filename, &ini_context)) != 0) {
logError("file: "__FILE__", line: %d, "
"load conf file \"%s\" fail, ret code: %d",
__LINE__, config_filename, result);
return result;
}
auth_config_filename = iniGetStrValue(section_name,
"auth_config_filename", &ini_context);
if (auth_config_filename == NULL || *auth_config_filename == '\0') {
logError("file: "__FILE__", line: %d, "
"config file: %s, item \"auth_config_filename\" "
"not exist or empty", __LINE__, config_filename);
result = ENOENT;
} else {
resolve_path(config_filename, auth_config_filename,
full_auth_filename, sizeof(full_auth_filename));
result = load_auth_config(auth, full_auth_filename, index_type);
}
iniFreeContext(&ini_context);
return result;
}
void fcfs_auth_config_to_string_ex(const FCFSAuthClientFullContext *auth,
const char *caption, char *output, const int size)
{
int len;
len = snprintf(output, size, "%s{enabled: %d", caption, auth->enabled);
if (auth->enabled) {
len += snprintf(output + len, size - len, ", username: %s, "
"secret_key_filename: %s",
auth->ctx->auth_cfg.username.str,
auth->ctx->auth_cfg.secret_key_filename.str);
}
snprintf(output + len, size - len, "}");
}
int fcfs_auth_client_user_login_ex(FCFSAuthClientContext *client_ctx,
const string_t *username, const string_t *passwd,
const string_t *poolname, const int flags)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_user_login,
username, passwd, poolname, flags);
}
int fcfs_auth_client_session_subscribe(FCFSAuthClientContext *client_ctx)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_session_subscribe);
}
int fcfs_auth_client_session_validate(FCFSAuthClientContext *client_ctx,
const string_t *session_id, const string_t *validate_key,
const FCFSAuthValidatePriviledgeType priv_type,
const int64_t pool_id, const int64_t priv_required)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_session_validate,
session_id, validate_key, priv_type, pool_id, priv_required);
}
int fcfs_auth_client_user_create(FCFSAuthClientContext *client_ctx,
const FCFSAuthUserInfo *user)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_user_create, user);
}
int fcfs_auth_client_user_passwd(FCFSAuthClientContext *client_ctx,
const string_t *username, const string_t *passwd)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_user_passwd,
username, passwd);
}
int fcfs_auth_client_user_list(FCFSAuthClientContext *client_ctx,
const string_t *username, const SFListLimitInfo *limit,
struct fast_mpool_man *mpool, FCFSAuthUserArray *array)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_user_list,
username, limit, mpool, array);
}
int fcfs_auth_client_user_grant(FCFSAuthClientContext *client_ctx,
const string_t *username, const int64_t priv)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_user_grant,
username, priv);
}
int fcfs_auth_client_user_remove(FCFSAuthClientContext *client_ctx,
const string_t *username)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_user_remove,
username);
}
int fcfs_auth_client_spool_create(FCFSAuthClientContext *client_ctx,
FCFSAuthStoragePoolInfo *spool, const int name_size,
const bool dryrun)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_spool_create,
spool, name_size, dryrun);
}
int fcfs_auth_client_spool_list(FCFSAuthClientContext *client_ctx,
const string_t *username, const string_t *poolname,
const SFListLimitInfo *limit, struct fast_mpool_man *mpool,
FCFSAuthStoragePoolArray *array)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_spool_list,
username, poolname, limit, mpool, array);
}
int fcfs_auth_client_spool_remove(FCFSAuthClientContext *client_ctx,
const string_t *poolname)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_spool_remove,
poolname);
}
int fcfs_auth_client_spool_set_quota(FCFSAuthClientContext *client_ctx,
const string_t *poolname, const int64_t quota)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_spool_set_quota,
poolname, quota);
}
int fcfs_auth_client_spool_get_quota(FCFSAuthClientContext *client_ctx,
const string_t *poolname, int64_t *quota)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_spool_get_quota,
poolname, quota);
}
int fcfs_auth_client_gpool_grant(FCFSAuthClientContext *client_ctx,
const string_t *username, const string_t *poolname,
const FCFSAuthSPoolPriviledges *privs)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_gpool_grant,
username, poolname, privs);
}
int fcfs_auth_client_gpool_withdraw(FCFSAuthClientContext *client_ctx,
const string_t *username, const string_t *poolname)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_gpool_withdraw,
username, poolname);
}
int fcfs_auth_client_gpool_list(FCFSAuthClientContext *client_ctx,
const string_t *username, const string_t *poolname,
const SFListLimitInfo *limit, struct fast_mpool_man *mpool,
FCFSAuthGrantedPoolArray *array)
{
SF_CLIENT_IDEMPOTENCY_QUERY_WRAPPER(client_ctx, &client_ctx->cm,
GET_MASTER_CONNECTION, 0, fcfs_auth_client_proto_gpool_list,
username, poolname, limit, mpool, array);
}
================================================
FILE: src/auth/client/fcfs_auth_client.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_AUTH_CLIENT_H
#define _FCFS_AUTH_CLIENT_H
#include "auth_proto.h"
#include "client_types.h"
#include "client_func.h"
#include "client_global.h"
#include "client_proto.h"
#include "session_regenerate.h"
#define fcfs_auth_load_config(auth, config_filename) \
fcfs_auth_load_config_ex(auth, config_filename, NULL, \
sf_server_group_index_type_service)
#ifdef __cplusplus
extern "C" {
#endif
int fcfs_auth_load_config_ex(FCFSAuthClientFullContext *auth,
const char *config_filename, const char *section_name,
const SFServerGroupIndexType index_type);
void fcfs_auth_config_to_string_ex(const FCFSAuthClientFullContext *auth,
const char *caption, char *output, const int size);
static inline void fcfs_auth_config_to_string(const FCFSAuthClientFullContext
*auth, char *output, const int size)
{
const char *caption = "auth ";
fcfs_auth_config_to_string_ex(auth, caption, output, size);
}
int fcfs_auth_client_user_login_ex(FCFSAuthClientContext *client_ctx,
const string_t *username, const string_t *passwd,
const string_t *poolname, const int flags);
static inline int fcfs_auth_client_user_login(
FCFSAuthClientContext *client_ctx,
const string_t *username, const string_t *passwd)
{
const string_t poolname = {NULL, 0};
const int flags = 0;
return fcfs_auth_client_user_login_ex(client_ctx,
username, passwd, &poolname, flags);
}
static inline int fcfs_auth_client_session_create_ex(
FCFSAuthClientFullContext *auth, string_t *poolname,
const bool publish)
{
int result;
int flags;
/*
logInfo("file: "__FILE__", line: %d, "
"auth_enabled: %d, username: %s, secret_key_filename: %s",
__LINE__, auth->enabled, auth->ctx->auth_cfg.username.str,
auth->ctx->auth_cfg.secret_key_filename.str);
*/
if (auth->enabled) {
auth->ctx->session.poolname = poolname;
if (publish) {
if ((result=session_regenerate_init()) != 0) {
return result;
}
flags = FCFS_AUTH_SESSION_FLAGS_PUBLISH;
} else {
flags = 0;
}
return fcfs_auth_client_user_login_ex(auth->ctx, &auth->
ctx->auth_cfg.username, &auth->ctx->auth_cfg.passwd,
poolname, flags);
} else {
return 0;
}
}
static inline int fcfs_auth_client_session_create(
FCFSAuthClientFullContext *auth, const bool publish)
{
#define AUTH_EMPTY_POOL_NAME SF_G_EMPTY_STRING
return fcfs_auth_client_session_create_ex(auth,
&AUTH_EMPTY_POOL_NAME, publish);
}
int fcfs_auth_client_session_subscribe(FCFSAuthClientContext *client_ctx);
int fcfs_auth_client_session_validate(FCFSAuthClientContext *client_ctx,
const string_t *session_id, const string_t *validate_key,
const FCFSAuthValidatePriviledgeType priv_type,
const int64_t pool_id, const int64_t priv_required);
int fcfs_auth_client_user_create(FCFSAuthClientContext *client_ctx,
const FCFSAuthUserInfo *user);
int fcfs_auth_client_user_passwd(FCFSAuthClientContext *client_ctx,
const string_t *username, const string_t *passwd);
int fcfs_auth_client_user_list(FCFSAuthClientContext *client_ctx,
const string_t *username, const SFListLimitInfo *limit,
struct fast_mpool_man *mpool, FCFSAuthUserArray *array);
int fcfs_auth_client_user_grant(FCFSAuthClientContext *client_ctx,
const string_t *username, const int64_t priv);
int fcfs_auth_client_user_remove(FCFSAuthClientContext *client_ctx,
const string_t *username);
/* storage pool operations */
int fcfs_auth_client_spool_create(FCFSAuthClientContext *client_ctx,
FCFSAuthStoragePoolInfo *spool, const int name_size,
const bool dryrun);
int fcfs_auth_client_spool_list(FCFSAuthClientContext *client_ctx,
const string_t *username, const string_t *poolname,
const SFListLimitInfo *limit, struct fast_mpool_man *mpool,
FCFSAuthStoragePoolArray *array);
int fcfs_auth_client_spool_remove(FCFSAuthClientContext *client_ctx,
const string_t *poolname);
int fcfs_auth_client_spool_set_quota(FCFSAuthClientContext *client_ctx,
const string_t *poolname, const int64_t quota);
int fcfs_auth_client_spool_get_quota(FCFSAuthClientContext *client_ctx,
const string_t *poolname, int64_t *quota);
/* pool granted operations */
int fcfs_auth_client_gpool_grant(FCFSAuthClientContext *client_ctx,
const string_t *username, const string_t *poolname,
const FCFSAuthSPoolPriviledges *privs);
int fcfs_auth_client_gpool_withdraw(FCFSAuthClientContext *client_ctx,
const string_t *username, const string_t *poolname);
int fcfs_auth_client_gpool_list(FCFSAuthClientContext *client_ctx,
const string_t *username, const string_t *poolname,
const SFListLimitInfo *limit, struct fast_mpool_man *mpool,
FCFSAuthGrantedPoolArray *array);
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/client/fcfs_auth_for_server.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include "sf/idempotency/client/rpc_wrapper.h"
#include "../common/auth_func.h"
#include "fcfs_auth_for_server.h"
int fcfs_auth_for_server_check_priv(FCFSAuthClientContext *client_ctx,
SFRequestInfo *request, SFResponseInfo *response,
const FCFSAuthValidatePriviledgeType priv_type,
const int64_t the_priv)
{
int result;
bool validate;
ServerSessionIdInfo session;
string_t session_id;
if ((result=sf_server_check_min_body_length(response, request->
header.body_len, FCFS_AUTH_SESSION_ID_LEN)) != 0)
{
return result;
}
session.id = buff2long(request->body);
if (session.fields.publish) {
switch (priv_type) {
case fcfs_auth_validate_priv_type_user:
result = server_session_user_priv_granted(
session.id, the_priv);
break;
case fcfs_auth_validate_priv_type_pool_fdir:
result = server_session_fdir_priv_granted(
session.id, the_priv);
break;
default:
result = server_session_fstore_priv_granted(
session.id, the_priv);
break;
}
if (result == SF_SESSION_ERROR_NOT_EXIST) {
validate = (g_current_time - session.fields.ts <=
g_server_session_cfg.validate_within_fresh_seconds);
} else {
validate = false;
}
} else {
validate = true;
}
if (validate) {
const int64_t pool_id = 0;
FC_SET_STRING_EX(session_id, request->body, FCFS_AUTH_SESSION_ID_LEN);
result = fcfs_auth_client_session_validate(client_ctx,
&session_id, &g_server_session_cfg.validate_key,
priv_type, pool_id, the_priv);
}
/*
logInfo("check priv cmd: %d, session: %"PRId64", validate: %d, "
"error no: %d", request->header.cmd, session.id, validate, result);
*/
if (result != 0) {
return result;
}
request->body += FCFS_AUTH_SESSION_ID_LEN;
request->header.body_len -= FCFS_AUTH_SESSION_ID_LEN;
return 0;
}
================================================
FILE: src/auth/client/fcfs_auth_for_server.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_AUTH_FOR_SERVER_H
#define _FCFS_AUTH_FOR_SERVER_H
#include "fcfs_auth_client.h"
#include "server_session.h"
#include "session_sync.h"
#define fcfs_auth_for_server_init(auth, ini_ctx, cluster_filename) \
fcfs_auth_for_server_init_ex(auth, ini_ctx, cluster_filename, NULL)
#ifdef __cplusplus
extern "C" {
#endif
int fcfs_auth_for_server_check_priv(FCFSAuthClientContext *client_ctx,
SFRequestInfo *request, SFResponseInfo *response,
const FCFSAuthValidatePriviledgeType priv_type,
const int64_t the_priv);
static inline int fcfs_auth_for_server_init_ex(FCFSAuthClientFullContext
*auth, IniFullContext *ini_ctx, const char *cluster_filename,
const char *section_name)
{
int result;
g_fcfs_auth_client_vars.ignore_when_passwd_not_exist = true;
if ((result=fcfs_auth_load_config_ex(auth, cluster_filename,
section_name, sf_server_group_index_type_cluster)) != 0)
{
return result;
}
if (auth->enabled) {
if ((result=server_session_init(ini_ctx)) != 0) {
return result;
}
if ((result=session_sync_init()) != 0) {
return result;
}
}
return result;
}
static inline void fcfs_auth_for_server_cfg_to_string(const
FCFSAuthClientFullContext *auth, char *output, const int size)
{
const char *caption = "";
char sz_session_config[512];
char sz_auth_config[1024];
fcfs_auth_config_to_string_ex(auth, caption,
sz_auth_config, sizeof(sz_auth_config));
if (auth->enabled) {
server_session_cfg_to_string_ex(sz_session_config,
sizeof(sz_session_config), true);
snprintf(output, size, "auth {%s, %s}",
sz_auth_config, sz_session_config);
} else {
snprintf(output, size, "auth {%s}", sz_auth_config);
}
}
static inline int fcfs_auth_for_server_start(const
FCFSAuthClientFullContext *auth)
{
if (auth->enabled) {
return session_sync_start();
} else {
return 0;
}
}
static inline void fcfs_auth_for_server_destroy(
FCFSAuthClientFullContext *auth)
{
fcfs_auth_client_destroy_ex(auth->ctx);
}
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/client/session_regenerate.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include "fastcommon/pthread_func.h"
#include "fastcommon/logger.h"
#include "sf/sf_proto.h"
#include "sf/sf_global.h"
#include "auth_func.h"
#include "client_global.h"
#include "fcfs_auth_client.h"
#include "session_regenerate.h"
typedef struct synced_session_array {
bool inited;
pthread_mutex_t lock;
} SessionRegenerateContext;
static SessionRegenerateContext session_ctx;
static int session_regenerate_do()
{
char old_session_id[FCFS_AUTH_SESSION_ID_LEN];
int result;
memcpy(old_session_id, g_fcfs_auth_client_vars.client_ctx.
session.id, FCFS_AUTH_SESSION_ID_LEN);
PTHREAD_MUTEX_LOCK(&session_ctx.lock);
if (memcmp(old_session_id, g_fcfs_auth_client_vars.client_ctx.
session.id, FCFS_AUTH_SESSION_ID_LEN) == 0)
{
result = fcfs_auth_client_user_login_ex(&g_fcfs_auth_client_vars.
client_ctx, &g_fcfs_auth_client_vars.client_ctx.auth_cfg.
username, &g_fcfs_auth_client_vars.client_ctx.auth_cfg.
passwd, g_fcfs_auth_client_vars.client_ctx.session.poolname,
FCFS_AUTH_SESSION_FLAGS_PUBLISH);
} else {
result = 0;
}
PTHREAD_MUTEX_UNLOCK(&session_ctx.lock);
return result;
}
static int fcfs_auth_error_handler(const int errnum)
{
if (errnum == SF_SESSION_ERROR_NOT_EXIST) {
if (session_regenerate_do() == EPERM) {
return EPERM;
} else {
return SF_RETRIABLE_ERROR_NO_SERVER;
}
} else {
return errnum;
}
}
int session_regenerate_init()
{
int result;
if (session_ctx.inited) {
return 0;
}
if ((result=init_pthread_lock(&session_ctx.lock)) != 0) {
return result;
}
sf_set_error_handler(fcfs_auth_error_handler);
session_ctx.inited = true;
return 0;
}
================================================
FILE: src/auth/client/session_regenerate.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_AUTH_SESSION_REGENERATE_H
#define _FCFS_AUTH_SESSION_REGENERATE_H
#ifdef __cplusplus
extern "C" {
#endif
int session_regenerate_init();
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/client/session_sync.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include "fastcommon/shared_func.h"
#include "fastcommon/logger.h"
#include "sf/sf_proto.h"
#include "sf/sf_global.h"
#include "auth_proto.h"
#include "auth_func.h"
#include "server_session.h"
#include "client_global.h"
#include "client_proto.h"
#include "session_sync.h"
typedef struct synced_session_entry {
char operation;
uint64_t session_id;
SessionSyncedFields fields;
} SyncedSessionEntry;
typedef struct synced_session_array {
int alloc;
int count;
SyncedSessionEntry *entries;
SFProtoRecvBuffer buffer;
} SyncedSessionArray;
static SyncedSessionArray session_array;
static int synced_session_array_init(SyncedSessionArray *array)
{
int result;
if ((result=sf_init_recv_buffer(&array->buffer, 0)) != 0) {
return result;
}
array->alloc = array->count = 0;
array->entries = NULL;
return 0;
}
static int check_realloc_session_array(SyncedSessionArray *array,
const int target_count)
{
SyncedSessionEntry *new_entries;
int new_alloc;
int bytes;
if (target_count <= array->alloc) {
return 0;
}
if (array->alloc == 0) {
new_alloc = 4 * 1024;
} else {
new_alloc = 2 * array->alloc;
}
while (new_alloc < target_count) {
new_alloc *= 2;
}
bytes = sizeof(SyncedSessionEntry) * new_alloc;
new_entries = (SyncedSessionEntry *)fc_malloc(bytes);
if (new_entries == NULL) {
logError("file: "__FILE__", line: %d, "
"malloc %d bytes fail", __LINE__, bytes);
return ENOMEM;
}
if (array->entries != NULL) {
free(array->entries);
}
array->entries = new_entries;
array->alloc = new_alloc;
return 0;
}
static int parse_session_push(SFResponseInfo *response)
{
FCFSAuthProtoSessionPushRespBodyHeader *body_header;
FCFSAuthProtoSessionPushRespBodyPart *body_part;
SyncedSessionEntry *entry;
SyncedSessionEntry *end;
char *p;
int count;
int result;
body_header = (FCFSAuthProtoSessionPushRespBodyHeader *)
session_array.buffer.buff;
p = (char *)(body_header + 1);
count = buff2int(body_header->count);
if ((result=check_realloc_session_array(
&session_array, count)) != 0)
{
return result;
}
end = session_array.entries + count;
for (entry=session_array.entries; entry
response->header.body_len)
{
response->error.length = sprintf(
response->error.message,
"body length: %d is too small",
response->header.body_len);
return EINVAL;
}
body_part = (FCFSAuthProtoSessionPushRespBodyPart *)p;
entry->operation = body_part->operation;
entry->session_id = buff2long(body_part->session_id);
if (entry->operation == FCFS_AUTH_SESSION_OP_TYPE_CREATE) {
entry->fields.user.id = buff2long(body_part->entry->user.id);
entry->fields.user.priv = buff2long(body_part->entry->user.priv);
entry->fields.pool.id = buff2long(body_part->entry->pool.id);
entry->fields.pool.available = body_part->entry->pool.available;
entry->fields.pool.privs.fdir = buff2int(
body_part->entry->pool.privs.fdir);
entry->fields.pool.privs.fstore = buff2int(
body_part->entry->pool.privs.fstore);
p += sizeof(FCFSAuthProtoSessionPushRespBodyPart) +
sizeof(FCFSAuthProtoSessionPushEntry);
} else {
p += sizeof(FCFSAuthProtoSessionPushRespBodyPart);
}
}
if (response->header.body_len != (p - session_array.buffer.buff)) {
response->error.length = sprintf(response->error.message,
"body length: %d != expect: %d",
response->header.body_len,
(int)(p - session_array.buffer.buff));
return EINVAL;
}
session_array.count = count;
return 0;
}
static void deal_session_array()
{
const bool publish = true;
ServerSessionEntry session;
SyncedSessionEntry *entry;
SyncedSessionEntry *end;
end = session_array.entries + session_array.count;
for (entry=session_array.entries; entrysession_id, entry->operation);
if (entry->operation == FCFS_AUTH_SESSION_OP_TYPE_CREATE) {
len += sprintf(buff + len, ", user {id: %"PRId64
", priv: %"PRId64"}", entry->fields.user.id,
entry->fields.user.priv);
if (entry->fields.pool.id != 0) {
len += sprintf(buff + len, ", pool {id: %"PRId64
", avail: %d, privs: {fdir: %d, fstore: %d}}",
entry->fields.pool.id, entry->fields.pool.available,
entry->fields.pool.privs.fdir,
entry->fields.pool.privs.fstore);
}
}
logInfo("%s", buff);
}
if (entry->operation == FCFS_AUTH_SESSION_OP_TYPE_CREATE) {
session.id_info.id = entry->session_id;
session.fields = &entry->fields;
server_session_add(&session, publish);
} else {
server_session_delete(entry->session_id);
}
}
}
static int session_sync(ConnectionInfo *conn)
{
const int network_timeout = 2;
int result;
SFResponseInfo response;
response.error.length = 0;
while (SF_G_CONTINUE_FLAG) {
result = sf_recv_vary_response(conn, &response, network_timeout,
FCFS_AUTH_SERVICE_PROTO_SESSION_PUSH_REQ, &session_array.
buffer, sizeof(FCFSAuthProtoSessionPushRespBodyHeader));
if (result == 0) {
if ((result=parse_session_push(&response)) != 0) {
if (response.error.length > 0) {
auth_log_network_error(&response, conn, result);
}
break;
}
deal_session_array();
} else if (result == ETIMEDOUT) {
if ((result=sf_active_test(conn, &response,
g_fcfs_auth_client_vars.client_ctx.
common_cfg.network_timeout)) != 0)
{
break;
}
} else {
auth_log_network_error(&response, conn, result);
break;
}
}
if (SF_G_CONTINUE_FLAG) {
server_session_clear();
}
return result;
}
static void *session_sync_thread_func(void *arg)
{
const bool shared = false;
SFConnectionManager *cm;
ConnectionInfo *conn;
int result;
#ifdef OS_LINUX
prctl(PR_SET_NAME, "session-sync");
#endif
cm = &g_fcfs_auth_client_vars.client_ctx.cm;
while (SF_G_CONTINUE_FLAG) {
if ((conn=cm->ops.get_master_connection(cm, 0,
shared, &result)) == NULL)
{
sleep(1);
continue;
}
if ((result=fcfs_auth_client_proto_session_subscribe(
&g_fcfs_auth_client_vars.client_ctx, conn)) == 0)
{
session_sync(conn);
} else if (result == ENOENT) {
sleep(5);
} else if (result == EPERM) {
if ((result=fcfs_auth_load_passwd_ex(g_fcfs_auth_client_vars.
client_ctx.auth_cfg.secret_key_filename.str,
g_fcfs_auth_client_vars.client_ctx.auth_cfg.
passwd_buff, g_fcfs_auth_client_vars.
ignore_when_passwd_not_exist)) != 0)
{
logError("file: "__FILE__", line: %d, "
"secret_key_filename: %s, "
"load password fail, ret code: %d", __LINE__,
g_fcfs_auth_client_vars.client_ctx.auth_cfg.
secret_key_filename.str, result);
sleep(30);
}
sleep(10);
}
cm->ops.close_connection(cm, conn);
sleep(1);
}
return NULL;
}
int session_sync_init()
{
int result;
if ((result=synced_session_array_init(&session_array)) != 0) {
return result;
}
return 0;
}
int session_sync_start()
{
pthread_t tid;
return fc_create_thread(&tid, session_sync_thread_func,
NULL, SF_G_THREAD_STACK_SIZE);
}
================================================
FILE: src/auth/client/session_sync.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_AUTH_SESSION_SYNC_H
#define _FCFS_AUTH_SESSION_SYNC_H
#ifdef __cplusplus
extern "C" {
#endif
int session_sync_init();
int session_sync_start();
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/client/simple_connection_manager.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include "fastcommon/shared_func.h"
#include "fastcommon/logger.h"
#include "fastcommon/connection_pool.h"
#include "client_global.h"
#include "client_func.h"
#include "client_proto.h"
#include "simple_connection_manager.h"
typedef struct fcfs_auth_cm_simple_extra {
/* master connection cache */
struct {
volatile bool valid;
ConnectionInfo conn;
} master_cache;
ConnectionPool cpool;
FCFSAuthClientContext *client_ctx;
FCFSAuthServerGroup *cluster_sarray;
} FCFSAuthCMSimpleExtra;
static int check_realloc_group_servers(FCFSAuthServerGroup *server_group)
{
int bytes;
int alloc_size;
ConnectionInfo *servers;
if (server_group->alloc_size > server_group->count) {
return 0;
}
if (server_group->alloc_size > 0) {
alloc_size = server_group->alloc_size * 2;
} else {
alloc_size = 4;
}
bytes = sizeof(ConnectionInfo) * alloc_size;
servers = (ConnectionInfo *)fc_malloc(bytes);
if (servers == NULL) {
return errno != 0 ? errno : ENOMEM;
}
memset(servers, 0, bytes);
if (server_group->count > 0) {
memcpy(servers, server_group->servers,
sizeof(ConnectionInfo) * server_group->count);
}
server_group->servers = servers;
server_group->alloc_size = alloc_size;
return 0;
}
static ConnectionInfo *get_spec_connection(SFConnectionManager *cm,
const ConnectionInfo *target, const bool shared, int *err_no)
{
FCFSAuthCMSimpleExtra *extra;
FCFSAuthServerGroup *cluster_sarray;
ConnectionInfo *conn;
ConnectionInfo *end;
extra = (FCFSAuthCMSimpleExtra *)cm->extra;
cluster_sarray = extra->cluster_sarray;
end = cluster_sarray->servers + cluster_sarray->count;
for (conn=cluster_sarray->servers; connservers + cluster_sarray->count++;
conn_pool_set_server_info(conn, target->ip_addr, target->port);
}
return conn_pool_get_connection_ex(&extra->cpool,
target, "fauth", shared, err_no);
}
static ConnectionInfo *get_connection(SFConnectionManager *cm,
const int group_index, const bool shared, int *err_no)
{
int index;
int i;
FCFSAuthServerGroup *cluster_sarray;
ConnectionInfo *conn;
ConnectionInfo *server;
cluster_sarray = ((FCFSAuthCMSimpleExtra *)cm->extra)->cluster_sarray;
index = rand() % cluster_sarray->count;
server = cluster_sarray->servers + index;
if ((conn=get_spec_connection(cm, server, shared, err_no)) != NULL) {
return conn;
}
i = (index + 1) % cluster_sarray->count;
while (i != index) {
server = cluster_sarray->servers + i;
if ((conn=get_spec_connection(cm, server, shared, err_no)) != NULL) {
return conn;
}
i = (i + 1) % cluster_sarray->count;
}
logError("file: "__FILE__", line: %d, "
"get_connection fail, configured server count: %d",
__LINE__, cluster_sarray->count);
return NULL;
}
static ConnectionInfo *get_master_connection(SFConnectionManager *cm,
const int group_index, const bool shared, int *err_no)
{
FCFSAuthCMSimpleExtra *extra;
ConnectionInfo *conn;
FCFSAuthClientServerEntry master;
SFNetRetryIntervalContext net_retry_ctx;
int i;
extra = (FCFSAuthCMSimpleExtra *)cm->extra;
if (extra->master_cache.valid) {
if ((conn=conn_pool_get_connection_ex(&extra->cpool, &extra->
master_cache.conn, "fauth", shared, err_no)) != NULL)
{
return conn;
} else {
extra->master_cache.valid = false;
}
}
sf_init_net_retry_interval_context(&net_retry_ctx,
&cm->common_cfg->net_retry_cfg.interval_mm,
&cm->common_cfg->net_retry_cfg.connect);
i = 0;
while (1) {
if ((*err_no=fcfs_auth_client_get_master(extra->
client_ctx, &master)) != 0)
{
SF_NET_RETRY_CHECK_AND_SLEEP(net_retry_ctx,
cm->common_cfg->net_retry_cfg.
connect.times, ++i, *err_no);
continue;
}
if ((conn=get_spec_connection(cm, &master.conn,
shared, err_no)) == NULL)
{
break;
}
extra->master_cache.valid = true;
extra->master_cache.conn = *conn;
return conn;
}
logError("file: "__FILE__", line: %d, "
"get_master_connection fail, errno: %d",
__LINE__, *err_no);
return NULL;
}
static void release_connection(SFConnectionManager *cm,
ConnectionInfo *conn)
{
FCFSAuthCMSimpleExtra *extra;
extra = (FCFSAuthCMSimpleExtra *)cm->extra;
conn_pool_close_connection_ex(&extra->cpool, conn, false);
}
static void close_connection(SFConnectionManager *cm,
ConnectionInfo *conn)
{
FCFSAuthCMSimpleExtra *extra;
extra = (FCFSAuthCMSimpleExtra *)cm->extra;
if (extra->master_cache.valid && FC_CONNECTION_SERVER_EQUAL1(
extra->master_cache.conn, *conn))
{
extra->master_cache.valid = false;
}
conn_pool_close_connection_ex(&extra->cpool, conn, true);
}
static void copy_to_server_group_array(FCFSAuthClientContext *client_ctx,
FCFSAuthServerGroup *server_group, const int server_group_index)
{
FCServerInfo *server;
FCServerInfo *end;
ConnectionInfo *conn;
int server_count;
server_count = FC_SID_SERVER_COUNT(client_ctx->cluster.server_cfg);
conn = server_group->servers;
end = FC_SID_SERVERS(client_ctx->cluster.server_cfg) + server_count;
for (server=FC_SID_SERVERS(client_ctx->cluster.server_cfg); servergroup_addrs[server_group_index].
address_array.addrs[0]->conn;
}
server_group->count = server_count;
/*
{
char formatted_ip[FORMATTED_IP_SIZE];
printf("auth_server count: %d\n", server_group->count);
for (conn=server_group->servers; connservers+
server_group->count; conn++)
{
format_ip_address(conn->ip_addr, formatted_ip);
printf("auth_server=%s:%u\n", formatted_ip, conn->port);
}
}
*/
}
int fcfs_auth_simple_connection_manager_init(FCFSAuthClientContext *client_ctx,
SFConnectionManager *cm, const int server_group_index)
{
const int max_count_per_entry = 0;
const int max_idle_time = 3600;
FCFSAuthCMSimpleExtra *extra;
FCFSAuthServerGroup *cluster_sarray;
int server_count;
int htable_init_capacity;
int result;
cluster_sarray = (FCFSAuthServerGroup *)fc_malloc(
sizeof(FCFSAuthServerGroup));
if (cluster_sarray == NULL) {
return ENOMEM;
}
server_count = FC_SID_SERVER_COUNT(client_ctx->cluster.server_cfg);
if ((result=fcfs_auth_alloc_group_servers(cluster_sarray,
server_count)) != 0)
{
return result;
}
copy_to_server_group_array(client_ctx, cluster_sarray, server_group_index);
extra = (FCFSAuthCMSimpleExtra *)fc_malloc(sizeof(FCFSAuthCMSimpleExtra));
if (extra == NULL) {
return ENOMEM;
}
memset(extra, 0, sizeof(FCFSAuthCMSimpleExtra));
htable_init_capacity = 4 * server_count;
if (htable_init_capacity < 256) {
htable_init_capacity = 256;
}
if ((result=conn_pool_init_ex1(&extra->cpool, client_ctx->common_cfg.
connect_timeout, max_count_per_entry, max_idle_time,
htable_init_capacity, NULL, client_ctx,
sf_cm_validate_connection_callback, cm,
sizeof(SFConnectionParameters), NULL)) != 0)
{
return result;
}
extra->cluster_sarray = cluster_sarray;
extra->client_ctx = client_ctx;
cm->server_group_index = server_group_index;
cm->extra = extra;
cm->common_cfg = &client_ctx->common_cfg;
cm->ops.get_connection = get_connection;
cm->ops.get_spec_connection = get_spec_connection;
cm->ops.get_master_connection = get_master_connection;
cm->ops.get_readable_connection = get_master_connection;
cm->ops.release_connection = release_connection;
cm->ops.close_connection = close_connection;
cm->ops.get_connection_params = sf_cm_get_connection_params;
return 0;
}
void fcfs_auth_simple_connection_manager_destroy(SFConnectionManager *cm)
{
FCFSAuthCMSimpleExtra *extra;
extra = (FCFSAuthCMSimpleExtra *)cm->extra;
if (extra->cluster_sarray != NULL) {
if (extra->cluster_sarray->servers != NULL) {
free(extra->cluster_sarray->servers);
extra->cluster_sarray->servers = NULL;
extra->cluster_sarray->count = 0;
extra->cluster_sarray->alloc_size = 0;
}
free(extra->cluster_sarray);
extra->cluster_sarray = NULL;
}
}
================================================
FILE: src/auth/client/simple_connection_manager.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_AUTH_SIMPLE_CONNECTION_MANAGER_H
#define _FCFS_AUTH_SIMPLE_CONNECTION_MANAGER_H
#include "client_types.h"
#ifdef __cplusplus
extern "C" {
#endif
int fcfs_auth_simple_connection_manager_init(FCFSAuthClientContext *client_ctx,
SFConnectionManager *cm, const int server_group_index);
void fcfs_auth_simple_connection_manager_destroy(SFConnectionManager *cm);
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/client/tools/Makefile.in
================================================
.SUFFIXES: .c .o .lo
COMPILE = $(CC) $(CFLAGS)
INC_PATH = -I../../common -I/usr/local/include
LIB_PATH = -L.. $(LIBS) -lfcfsauthclient -lfastcommon -lserverframe
TARGET_PATH = $(TARGET_PREFIX)/bin
STATIC_OBJS = tool_func.o
ALL_PRGS = fcfs_user fcfs_pool fauth_list_servers fauth_cluster_stat
all: $(STATIC_OBJS) $(ALL_PRGS)
.o:
$(COMPILE) -o $@ $< $(STATIC_OBJS) $(LIB_PATH) $(INC_PATH)
.c:
$(COMPILE) -o $@ $< $(STATIC_OBJS) $(LIB_PATH) $(INC_PATH)
.c.o:
$(COMPILE) -c -o $@ $< $(INC_PATH)
install:
mkdir -p $(TARGET_PATH)
cp -f $(ALL_PRGS) $(TARGET_PATH)
clean:
rm -f $(STATIC_OBJS) $(ALL_PRGS)
================================================
FILE: src/auth/client/tools/fauth_cluster_stat.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "fastcommon/logger.h"
#include "../fcfs_auth_client.h"
static void usage(char *argv[])
{
fprintf(stderr, "Usage: %s [-c config_filename=%s]\n",
argv[0], FCFS_AUTH_CLIENT_DEFAULT_CONFIG_FILENAME);
}
static void output(FCFSAuthClientClusterStatEntry *stats, const int count)
{
FCFSAuthClientClusterStatEntry *stat;
FCFSAuthClientClusterStatEntry *end;
char formatted_ip[FORMATTED_IP_SIZE];
end = stats + count;
for (stat=stats; statip_addr, formatted_ip);
printf( "server_id: %d, host: %s:%u, "
"is_online: %d, is_master: %d\n",
stat->server_id, formatted_ip, stat->port,
stat->is_online, stat->is_master);
}
printf("\nserver count: %d\n\n", count);
}
int main(int argc, char *argv[])
{
#define CLUSTER_MAX_SERVER_COUNT 16
int ch;
const char *config_filename = FCFS_AUTH_CLIENT_DEFAULT_CONFIG_FILENAME;
int count;
FCFSAuthClientClusterStatEntry stats[CLUSTER_MAX_SERVER_COUNT];
int result;
while ((ch=getopt(argc, argv, "hc:")) != -1) {
switch (ch) {
case 'h':
usage(argv);
break;
case 'c':
config_filename = optarg;
break;
default:
usage(argv);
return 1;
}
}
log_init();
//g_log_context.log_level = LOG_DEBUG;
if ((result=fcfs_auth_client_init(config_filename)) != 0) {
return result;
}
if ((result=fcfs_auth_client_cluster_stat(&g_fcfs_auth_client_vars.client_ctx,
stats, CLUSTER_MAX_SERVER_COUNT, &count)) != 0)
{
fprintf(stderr, "fcfs_auth_client_cluster_stat fail, "
"errno: %d, error info: %s\n", result, STRERROR(result));
return result;
}
output(stats, count);
return 0;
}
================================================
FILE: src/auth/client/tools/fauth_list_servers.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "sf/sf_cluster_cfg.h"
#include "../client_types.h"
static void usage(char *argv[])
{
fprintf(stderr, "\nUsage: %s \n", argv[0]);
}
int main(int argc, char *argv[])
{
const bool share_between_groups = false;
const bool calc_sign = false;
const char *config_filename;
SFClusterConfig cluster;
FCServerInfo *server;
FCServerInfo *end;
FCAddressInfo **addrs;
int i;
int result;
if (argc < 2) {
usage(argv);
return EINVAL;
}
config_filename = argv[1];
log_init();
if ((result=sf_load_cluster_config_by_file(&cluster, config_filename,
FCFS_AUTH_DEFAULT_CLUSTER_PORT, share_between_groups,
calc_sign)) != 0)
{
return result;
}
printf("fauth_group=(");
end = FC_SID_SERVERS(cluster.server_cfg) +
FC_SID_SERVER_COUNT(cluster.server_cfg);
for (server=FC_SID_SERVERS(cluster.server_cfg), i=0;
servergroup_addrs[cluster.cluster_group_index].
address_array.addrs;
if (i > 0) {
printf(" ");
}
printf("%s", (*addrs)->conn.ip_addr);
}
printf(")\n");
return 0;
}
================================================
FILE: src/auth/client/tools/fcfs_pool.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "fastcommon/logger.h"
#include "tool_func.h"
#include "../../common/auth_func.h"
#include "../fcfs_auth_client.h"
#define PARAM_OPTION_INCLUDED 1
#define PARAM_OPTION_REQUIRED 2
#define DRY_RUN_OPTION_STR "--dryrun"
const int mpool_alloc_size_once = 16 * 1024;
const int mpool_discard_size = 8;
const SFListLimitInfo limit = {0, 0};
static int current_index;
static FCFSAuthStoragePoolInfo spool;
static struct {
string_t fdir;
string_t fstore;
} privs;
static string_t username = {0};
static bool dryrun;
static void usage(char *argv[])
{
fprintf(stderr, "\nUsage: %s [-c config_filename=%s]\n"
"\t[-u admin_username=admin]\n"
"\t[-k admin_secret_key_filename=/etc/fastcfs/auth/keys/"
"${admin_username}.key]\n"
"\t[-d fastdir_access=rw]\n"
"\t[-s faststore_access=rw]\n"
"\t [username] [pool_name] [quota]\n\n"
"\tthe operations and following parameters: \n"
"\t create [pool_name] [%s]\n"
"\t quota \n"
"\t delete | remove \n"
"\t plist | pool-list [username] [pool_name]\n"
"\t grant \n"
"\t cancel | withdraw \n"
"\t glist | grant-list | granted-list [username] [pool_name]\n\n"
"\t* the pool name can contain %s for auto generated id when "
"create pool, such as 'pool-%s'\n"
"\t the pool name template configurated in the server side "
"will be used when not specify the pool name\n"
"\t you can set the initial value of auto increment id and "
"the pool name template in server.conf of the server side\n\n"
"\t* the quota parameter is required for create and quota operations\n"
"\t the default unit of quota is GiB, %s for no limit\n\n"
"\tFastDIR and FastStore accesses are:\n"
"\t %c: read only\n"
"\t %c: write only\n"
"\t %c%c: read and write\n\n",
argv[0], FCFS_AUTH_CLIENT_DEFAULT_CONFIG_FILENAME,
DRY_RUN_OPTION_STR, FCFS_AUTH_AUTO_ID_TAG_STR,
FCFS_AUTH_AUTO_ID_TAG_STR, FCFS_AUTH_UNLIMITED_QUOTA_STR,
POOL_ACCESS_NAME_READ_CHR, POOL_ACCESS_NAME_WRITE_CHR,
POOL_ACCESS_NAME_READ_CHR, POOL_ACCESS_NAME_WRITE_CHR);
}
static int create_spool(int argc, char *argv[])
{
int result;
FILE *fp;
char name_buff[NAME_MAX];
char prompt[32];
if (spool.name.len > sizeof(name_buff)) {
fprintf(stderr, "pool name length: %d is too large, exceeds %d",
spool.name.len, (int)sizeof(name_buff));
return ENAMETOOLONG;
}
memcpy(name_buff, spool.name.str, spool.name.len);
spool.name.str = name_buff;
if ((result=fcfs_auth_client_spool_create(&g_fcfs_auth_client_vars.
client_ctx, &spool, sizeof(name_buff), dryrun)) == 0)
{
strcpy(prompt, "success");
fp = stdout;
} else {
strcpy(prompt, "fail");
fp = stderr;
}
fprintf(fp, "%screate pool %.*s %s\n", (dryrun ? "[DRYRUN] " : ""),
spool.name.len, spool.name.str, prompt);
return result;
}
static int quota_spool(int argc, char *argv[])
{
int result;
char buff[64];
if ((result=fcfs_auth_client_spool_set_quota(&g_fcfs_auth_client_vars.
client_ctx, &spool.name, spool.quota)) == 0)
{
if (spool.quota == FCFS_AUTH_UNLIMITED_QUOTA_VAL) {
strcpy(buff, FCFS_AUTH_UNLIMITED_QUOTA_STR);
} else {
long_to_comma_str(spool.quota / (1024 * 1024 * 1024), buff);
strcat(buff, "GiB");
}
printf("pool %s, set quota to %s success\n", spool.name.str, buff);
} else {
fprintf(stderr, "pool %s, set quota fail\n", spool.name.str);
}
return result;
}
static inline int parse_pool_access(const string_t *privs,
const char *caption, int *pv)
{
if (privs->str == NULL) {
*pv = FCFS_AUTH_POOL_ACCESS_ALL;
return 0;
} else {
return fcfs_auth_parse_pool_access(privs, pv);
}
}
static int grant_privilege(int argc, char *argv[])
{
int result;
FILE *fp;
char prompt[32];
FCFSAuthSPoolPriviledges pvs;
if ((result=parse_pool_access(&privs.fdir, "FastDIR", &pvs.fdir)) != 0) {
usage(argv);
return result;
}
if ((result=parse_pool_access(&privs.fstore, "FastStore",
&pvs.fstore)) != 0)
{
usage(argv);
return result;
}
if ((pvs.fdir == FCFS_AUTH_POOL_ACCESS_NONE) &&
(pvs.fstore == FCFS_AUTH_POOL_ACCESS_NONE))
{
fprintf(stderr, "no access priviledges to grant\n");
usage(argv);
return ENOENT;
}
if ((result=fcfs_auth_client_gpool_grant(&g_fcfs_auth_client_vars.
client_ctx, &username, &spool.name, &pvs)) == 0)
{
strcpy(prompt, "success");
fp = stdout;
} else {
strcpy(prompt, "fail");
fp = stderr;
}
fprintf(fp, "grant access priviledge of pool %.*s to user %.*s %s\n",
spool.name.len, spool.name.str, username.len, username.str, prompt);
return result;
}
static int withdraw_privilege(int argc, char *argv[])
{
int result;
FILE *fp;
char prompt[32];
if ((result=fcfs_auth_client_gpool_withdraw(&g_fcfs_auth_client_vars.
client_ctx, &username, &spool.name)) == 0)
{
strcpy(prompt, "success");
fp = stdout;
} else {
strcpy(prompt, "fail");
fp = stderr;
}
fprintf(fp, "withdraw access priviledge of pool %.*s from user %.*s %s\n",
spool.name.len, spool.name.str, username.len, username.str, prompt);
return result;
}
static int remove_spool(int argc, char *argv[])
{
int result;
if ((result=fcfs_auth_client_spool_remove(&g_fcfs_auth_client_vars.
client_ctx, &spool.name)) == 0)
{
printf("remove pool %s success\n", spool.name.str);
} else {
fprintf(stderr, "remove pool %s fail\n", spool.name.str);
}
return result;
}
static void output_spools(FCFSAuthStoragePoolArray *array)
{
FCFSAuthStoragePoolInfo *spool;
FCFSAuthStoragePoolInfo *end;
char buff[64];
printf("%5s %50s %16s\n", "No.", "pool_name", "quota (GiB)");
end = array->spools + array->count;
for (spool=array->spools; spoolquota == FCFS_AUTH_UNLIMITED_QUOTA_VAL) {
strcpy(buff, FCFS_AUTH_UNLIMITED_QUOTA_STR);
} else {
long_to_comma_str(spool->quota / (1024 * 1024 * 1024), buff);
}
printf("%4d. %50.*s %16s\n", (int)((spool - array->spools) + 1),
spool->name.len, spool->name.str, buff);
}
}
static void output_gpools(FCFSAuthGrantedPoolArray *array)
{
FCFSAuthGrantedPoolFullInfo *gpool;
FCFSAuthGrantedPoolFullInfo *end;
char buff1[64];
char buff2[64];
string_t priv_names_fdir;
string_t priv_names_fstore;
printf("%5s %32s %50s %16s %16s\n", "No.", "owner_name", "pool_name",
"fdir_priv", "fstore_priv");
priv_names_fdir.str = buff1;
priv_names_fstore.str = buff2;
end = array->gpools + array->count;
for (gpool=array->gpools; gpoolgpools) + 1),
gpool->username.len, gpool->username.str,
gpool->pool_name.len, gpool->pool_name.str,
fcfs_auth_pool_access_to_string(gpool->
granted.privs.fdir, &priv_names_fdir),
fcfs_auth_pool_access_to_string(gpool->
granted.privs.fstore, &priv_names_fstore));
}
}
static int list_spool(int argc, char *argv[])
{
struct fast_mpool_man mpool;
FCFSAuthStoragePoolArray spool_array;
int result;
if ((result=fast_mpool_init(&mpool, mpool_alloc_size_once,
mpool_discard_size)) != 0)
{
return result;
}
fcfs_auth_spool_init_array(&spool_array);
if ((result=fcfs_auth_client_spool_list(&g_fcfs_auth_client_vars.
client_ctx, &username, &spool.name, &limit,
&mpool, &spool_array)) == 0)
{
output_spools(&spool_array);
} else {
fprintf(stderr, "list storage pool fail\n");
}
fcfs_auth_spool_free_array(&spool_array);
fast_mpool_destroy(&mpool);
return result;
}
static int list_gpool(int argc, char *argv[])
{
struct fast_mpool_man mpool;
FCFSAuthGrantedPoolArray gpool_array;
int result;
if ((result=fast_mpool_init(&mpool, mpool_alloc_size_once,
mpool_discard_size)) != 0)
{
return result;
}
fcfs_auth_granted_init_array(&gpool_array);
if ((result=fcfs_auth_client_gpool_list(&g_fcfs_auth_client_vars.
client_ctx, &username, &spool.name, &limit,
&mpool, &gpool_array)) == 0)
{
output_gpools(&gpool_array);
} else {
fprintf(stderr, "list storage pool fail\n");
}
fcfs_auth_granted_free_array(&gpool_array);
fast_mpool_destroy(&mpool);
return result;
}
int main(int argc, char *argv[])
{
int ch;
int op_type;
const char *config_filename = FCFS_AUTH_CLIENT_DEFAULT_CONFIG_FILENAME;
char *operation;
FCFSAuthClientUserKeyPair admin;
unsigned char passwd_buff[FCFS_AUTH_PASSWD_LEN + 1];
FilenameString admin_key_filename;
string_t passwd;
int username_options;
int poolname_options;
bool need_quota;
int result;
if (argc < 2) {
usage(argv);
return 1;
}
FC_SET_STRING(admin.username, "admin");
FC_SET_STRING(admin.key_filename,
"/etc/fastcfs/auth/keys/${username}.key");
FC_SET_STRING_NULL(privs.fdir);
FC_SET_STRING_NULL(privs.fstore);
while ((ch=getopt(argc, argv, "hc:u:k:d:s:")) != -1) {
switch (ch) {
case 'h':
usage(argv);
return 0;
case 'c':
config_filename = optarg;
break;
case 'u':
FC_SET_STRING_EX(admin.username, optarg, strlen(optarg));
break;
case 'k':
FC_SET_STRING_EX(admin.key_filename, optarg, strlen(optarg));
break;
case 'd':
FC_SET_STRING(privs.fdir, optarg);
break;
case 's':
FC_SET_STRING(privs.fstore, optarg);
break;
default:
usage(argv);
return 1;
}
}
current_index = optind;
if (current_index >= argc) {
fprintf(stderr, "expect operation\n");
usage(argv);
return 1;
}
srand(time(NULL));
log_init();
//g_log_context.log_level = LOG_DEBUG;
operation = argv[current_index++];
if (current_index < argc) {
char *last;
last = argv[argc - 1];
dryrun = (strcasecmp(last, DRY_RUN_OPTION_STR) == 0);
if (dryrun) {
--argc; //remove the last parameter
}
}
if (strcasecmp(operation, "create") == 0) {
op_type = FCFS_AUTH_SERVICE_PROTO_SPOOL_CREATE_REQ;
username_options = 0;
if (current_index + 1 < argc) {
poolname_options = PARAM_OPTION_INCLUDED |
PARAM_OPTION_REQUIRED;
} else {
poolname_options = 0;
}
need_quota = true;
} else if (strcasecmp(operation, "grant") == 0) {
op_type = FCFS_AUTH_SERVICE_PROTO_GPOOL_GRANT_REQ;
username_options = PARAM_OPTION_INCLUDED |
PARAM_OPTION_REQUIRED;
poolname_options = PARAM_OPTION_INCLUDED |
PARAM_OPTION_REQUIRED;
need_quota = false;
} else if (strcasecmp(operation, "quota") == 0) {
op_type = FCFS_AUTH_SERVICE_PROTO_SPOOL_SET_QUOTA_REQ;
username_options = 0;
poolname_options = PARAM_OPTION_INCLUDED |
PARAM_OPTION_REQUIRED;
need_quota = true;
} else if (strcasecmp(operation, "delete") == 0 ||
strcasecmp(operation, "remove") == 0)
{
op_type = FCFS_AUTH_SERVICE_PROTO_SPOOL_REMOVE_REQ;
username_options = 0;
poolname_options = PARAM_OPTION_INCLUDED |
PARAM_OPTION_REQUIRED;
need_quota = false;
} else if (strcasecmp(operation, "plist") == 0 ||
strcasecmp(operation, "pool-list") == 0 ||
strcasecmp(operation, "pool_list") == 0)
{
op_type = FCFS_AUTH_SERVICE_PROTO_SPOOL_LIST_REQ;
username_options = PARAM_OPTION_INCLUDED;
poolname_options = PARAM_OPTION_INCLUDED;
need_quota = false;
} else if (strcasecmp(operation, "withdraw") == 0 ||
strcasecmp(operation, "cancel") == 0)
{
op_type = FCFS_AUTH_SERVICE_PROTO_GPOOL_WITHDRAW_REQ;
username_options = PARAM_OPTION_INCLUDED |
PARAM_OPTION_REQUIRED;
poolname_options = PARAM_OPTION_INCLUDED |
PARAM_OPTION_REQUIRED;
need_quota = false;
} else if (strcasecmp(operation, "glist") == 0 ||
strcasecmp(operation, "grant-list") == 0 ||
strcasecmp(operation, "grant_list") == 0 ||
strcasecmp(operation, "granted-list") == 0 ||
strcasecmp(operation, "granted_list") == 0)
{
op_type = FCFS_AUTH_SERVICE_PROTO_GPOOL_LIST_REQ;
username_options = PARAM_OPTION_INCLUDED;
poolname_options = PARAM_OPTION_INCLUDED;
need_quota = false;
} else if (strcasecmp(operation, "config-setid") == 0 ||
strcasecmp(operation, "config_setid") == 0 ||
strcasecmp(operation, "cfg-setid") == 0 ||
strcasecmp(operation, "cfg_setid") == 0)
{
op_type = FCFS_AUTH_SERVICE_PROTO_GPOOL_LIST_REQ;
username_options = PARAM_OPTION_INCLUDED;
poolname_options = PARAM_OPTION_INCLUDED;
need_quota = false;
} else {
fprintf(stderr, "unknow operation: %s\n", operation);
usage(argv);
return 1;
}
if ((username_options & PARAM_OPTION_INCLUDED) != 0) {
if (current_index < argc) {
FC_SET_STRING(username, argv[current_index]);
current_index++;
} else if ((username_options & PARAM_OPTION_REQUIRED) != 0) {
fprintf(stderr, "expect username\n");
usage(argv);
return 1;
}
}
if ((poolname_options & PARAM_OPTION_INCLUDED) != 0) {
if (current_index < argc) {
FC_SET_STRING(spool.name, argv[current_index]);
current_index++;
} else if ((poolname_options & PARAM_OPTION_REQUIRED) != 0) {
fprintf(stderr, "expect pool name\n");
usage(argv);
return 1;
} else {
FC_SET_STRING_NULL(spool.name);
}
}
if (current_index < argc) {
if (strcasecmp(argv[current_index],
FCFS_AUTH_UNLIMITED_QUOTA_STR) == 0)
{
spool.quota = FCFS_AUTH_UNLIMITED_QUOTA_VAL;
} else if ((result=parse_bytes(argv[current_index],
1024 * 1024 * 1024, &spool.quota)) != 0)
{
fprintf(stderr, "parse quota field fail!\n");
if (op_type == FCFS_AUTH_SERVICE_PROTO_SPOOL_CREATE_REQ) {
fprintf(stderr, "\nUsage: %s create [pool_name] "
"[%s]\nFor example: %s create %s %s %s\n\n",
argv[0], DRY_RUN_OPTION_STR, argv[0],
(spool.name.str != NULL ? spool.name.str :
argv[current_index]), FCFS_AUTH_UNLIMITED_QUOTA_STR,
(dryrun ? DRY_RUN_OPTION_STR : ""));
}
return 1;
}
current_index++;
} else if (need_quota) {
fprintf(stderr, "expect quota\n");
usage(argv);
return 1;
}
passwd.str = (char *)passwd_buff;
passwd.len = FCFS_AUTH_PASSWD_LEN;
fcfs_auth_replace_filename_with_username(&admin.key_filename,
&admin.username, &admin_key_filename);
if ((result=fcfs_auth_load_passwd(
FC_FILENAME_STRING_PTR(admin_key_filename),
passwd_buff)) != 0)
{
return result;
}
if ((result=fcfs_auth_client_init(config_filename)) != 0) {
return result;
}
if ((result=fcfs_auth_client_user_login(&g_fcfs_auth_client_vars.
client_ctx, &admin.username, &passwd)) != 0)
{
return result;
}
switch (op_type) {
case FCFS_AUTH_SERVICE_PROTO_SPOOL_CREATE_REQ:
return create_spool(argc, argv);
case FCFS_AUTH_SERVICE_PROTO_SPOOL_LIST_REQ:
return list_spool(argc, argv);
case FCFS_AUTH_SERVICE_PROTO_SPOOL_REMOVE_REQ:
return remove_spool(argc, argv);
case FCFS_AUTH_SERVICE_PROTO_SPOOL_SET_QUOTA_REQ:
return quota_spool(argc, argv);
case FCFS_AUTH_SERVICE_PROTO_GPOOL_GRANT_REQ:
return grant_privilege(argc, argv);
case FCFS_AUTH_SERVICE_PROTO_GPOOL_WITHDRAW_REQ:
return withdraw_privilege(argc, argv);
case FCFS_AUTH_SERVICE_PROTO_GPOOL_LIST_REQ:
return list_gpool(argc, argv);
}
return 0;
}
================================================
FILE: src/auth/client/tools/fcfs_user.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "fastcommon/logger.h"
#include "tool_func.h"
#include "../../common/auth_func.h"
#include "../fcfs_auth_client.h"
const int mpool_alloc_size_once = 16 * 1024;
const int mpool_discard_size = 8;
const SFListLimitInfo limit = {0, 0};
static int current_index;
static FCFSAuthUserInfo user;
static bool priv_set = false;
static bool confirmed = false; //for option -y
static void usage(char *argv[])
{
fprintf(stderr, "\nUsage: %s [-c config_filename=%s]\n"
"\t[-u admin_username=admin]\n"
"\t[-k admin_secret_key_filename=/etc/fastcfs/auth/keys/"
"${username}.key]\n"
"\t[-p priviledges=%s]\n"
"\t [username]\n"
"\t[user_secret_key_filename=keys/${username}.key]\n\n"
"\tthe operations and parameters are: \n"
"\t create [user_secret_key_filename]\n"
"\t passwd | secret-key [user_secret_key_filename] "
"[-y]: regenerate user's secret key\n"
"\t grant , the option <-p priviledges> is required\n"
"\t delete | remove \n"
"\t list [username]\n\n"
"\t[user_secret_key_filename]: specify the filename to store the "
"generated secret key of the user\n"
"\t[priviledges]: the granted priviledges seperate by comma, "
"priviledges:\n"
"\t %s: user management\n"
"\t %s: create storage pool\n"
"\t %s: monitor cluster\n"
"\t %s: subscribe session for FastDIR and FastStore server side\n"
"\t %s: for all priviledges\n\n",
argv[0], FCFS_AUTH_CLIENT_DEFAULT_CONFIG_FILENAME,
USER_PRIV_NAME_CREATE_POOL_STR,
USER_PRIV_NAME_USER_MANAGE_STR,
USER_PRIV_NAME_CREATE_POOL_STR,
USER_PRIV_NAME_MONITOR_CLUSTER_STR,
USER_PRIV_NAME_SUBSCRIBE_SESSION_STR,
USER_PRIV_NAME_ALL_PRIVS_STR);
}
static int user_create_or_passwd(int argc, char *argv[], const int cmd)
{
string_t input_key_filename;
FilenameString user_key_filename;
unsigned char passwd_buff[FCFS_AUTH_PASSWD_LEN + 1];
const char *caption;
char *filename;
char abs_path[PATH_MAX];
int result;
if (current_index < argc) {
FC_SET_STRING(input_key_filename, argv[current_index]);
} else {
FC_SET_STRING(input_key_filename, "keys/${username}.key");
}
fcfs_auth_replace_filename_with_username(&input_key_filename,
&user.name, &user_key_filename);
filename = FC_FILENAME_STRING_PTR(user_key_filename);
getAbsolutePath(filename, abs_path, sizeof(abs_path));
if ((result=fc_mkdirs(abs_path, 0755)) != 0) {
return result;
}
fcfs_auth_generate_passwd(passwd_buff);
FC_SET_STRING_EX(user.passwd, (char *)passwd_buff, FCFS_AUTH_PASSWD_LEN);
if (cmd == FCFS_AUTH_SERVICE_PROTO_USER_CREATE_REQ) {
caption = "create user";
result = fcfs_auth_client_user_create(&g_fcfs_auth_client_vars.
client_ctx, &user);
} else {
caption = "regenerate secret key for user";
result = fcfs_auth_client_user_passwd(&g_fcfs_auth_client_vars.
client_ctx, &user.name, &user.passwd);
}
if (result == 0) {
if ((result=fcfs_auth_save_passwd(filename, passwd_buff)) == 0) {
printf("%s %s success, secret key store to file: %s\n",
caption, user.name.str, filename);
} else {
char hex_buff[2 * FCFS_AUTH_PASSWD_LEN + 1];
bin2hex((char *)passwd_buff, FCFS_AUTH_PASSWD_LEN, hex_buff);
printf("%s %s success, but secret key store to "
"file: %s fail, the secret key is:\n%s\n",
caption, user.name.str, filename, hex_buff);
}
} else {
fprintf(stderr, "%s %s fail\n", caption, user.name.str);
}
return result;
}
static inline int create_user(int argc, char *argv[])
{
return user_create_or_passwd(argc, argv,
FCFS_AUTH_SERVICE_PROTO_USER_CREATE_REQ);
}
static inline int passwd_user(int argc, char *argv[])
{
return user_create_or_passwd(argc, argv,
FCFS_AUTH_SERVICE_PROTO_USER_PASSWD_REQ);
}
static int grant_privilege(int argc, char *argv[])
{
int result;
if (!priv_set) {
fprintf(stderr, "expect parameter: granted priviledges!\n");
usage(argv);
return EINVAL;
}
if ((result=fcfs_auth_client_user_grant(&g_fcfs_auth_client_vars.
client_ctx, &user.name, user.priv)) == 0)
{
printf("grant user priviledge success\n");
} else {
fprintf(stderr, "grant user priviledge fail\n");
}
return result;
}
static int remove_user(int argc, char *argv[])
{
int result;
if ((result=fcfs_auth_client_user_remove(&g_fcfs_auth_client_vars.
client_ctx, &user.name)) == 0)
{
printf("remove user %s success\n", user.name.str);
} else {
fprintf(stderr, "remove user %s fail\n", user.name.str);
}
return result;
}
static void output_users(FCFSAuthUserArray *array)
{
FCFSAuthUserInfo *user;
FCFSAuthUserInfo *end;
char buff[256];
string_t priv_names;
printf("%5s %32s %32s\n", "No.", "username", "priviledges");
priv_names.str = buff;
end = array->users + array->count;
for (user=array->users; userusers) + 1),
user->name.len, user->name.str,
fcfs_auth_user_priv_to_string(user->priv, &priv_names));
}
}
static int list_user(int argc, char *argv[])
{
struct fast_mpool_man mpool;
FCFSAuthUserArray user_array;
int result;
if ((result=fast_mpool_init(&mpool, mpool_alloc_size_once,
mpool_discard_size)) != 0)
{
return result;
}
fcfs_auth_user_init_array(&user_array);
if ((result=fcfs_auth_client_user_list(&g_fcfs_auth_client_vars.
client_ctx, &user.name, &limit, &mpool,
&user_array)) == 0)
{
output_users(&user_array);
} else {
fprintf(stderr, "list user fail\n");
}
fcfs_auth_user_free_array(&user_array);
fast_mpool_destroy(&mpool);
return result;
}
int main(int argc, char *argv[])
{
int ch;
const char *config_filename = FCFS_AUTH_CLIENT_DEFAULT_CONFIG_FILENAME;
char *operation;
FCFSAuthClientUserKeyPair admin;
unsigned char passwd_buff[FCFS_AUTH_PASSWD_LEN + 1];
FilenameString admin_key_filename;
string_t passwd;
string_t privs;
bool need_username;
int result;
if (argc < 2) {
usage(argv);
return 1;
}
FC_SET_STRING(admin.username, "admin");
FC_SET_STRING(admin.key_filename,
"/etc/fastcfs/auth/keys/${username}.key");
FC_SET_STRING_NULL(privs);
while ((ch=getopt(argc, argv, "hc:u:k:p:y")) != -1) {
switch (ch) {
case 'h':
usage(argv);
return 0;
case 'c':
config_filename = optarg;
break;
case 'u':
FC_SET_STRING_EX(admin.username, optarg, strlen(optarg));
break;
case 'k':
FC_SET_STRING_EX(admin.key_filename, optarg, strlen(optarg));
break;
case 'p':
FC_SET_STRING(privs, optarg);
break;
case 'y':
confirmed = true;
break;
default:
usage(argv);
return 1;
}
}
current_index = optind;
if (current_index >= argc) {
fprintf(stderr, "expect operation\n");
usage(argv);
return 1;
}
srand(time(NULL));
log_init();
//g_log_context.log_level = LOG_DEBUG;
operation = argv[current_index++];
if (strcasecmp(operation, "create") == 0) {
need_username = true;
} else if (strcasecmp(operation, "passwd") == 0 ||
strcasecmp(operation, "secret-key") == 0)
{
need_username = true;
} else if (strcasecmp(operation, "grant") == 0) {
need_username = true;
} else if (strcasecmp(operation, "delete") == 0 ||
strcasecmp(operation, "remove") == 0)
{
need_username = true;
} else if (strcasecmp(operation, "list") == 0) {
need_username = false;
} else {
fprintf(stderr, "unknow operation: %s\n", operation);
usage(argv);
return 1;
}
if (current_index < argc) {
FC_SET_STRING(user.name, argv[current_index]);
current_index++;
} else if (need_username) {
fprintf(stderr, "expect username\n");
usage(argv);
return 1;
} else {
FC_SET_STRING_NULL(user.name);
}
if (privs.str == NULL) {
user.priv = FCFS_AUTH_USER_PRIV_CREATE_POOL;
} else {
if ((result=fcfs_auth_parse_user_priv(&privs, &user.priv)) != 0) {
usage(argv);
return 1;
}
priv_set = true;
}
passwd.str = (char *)passwd_buff;
passwd.len = FCFS_AUTH_PASSWD_LEN;
fcfs_auth_replace_filename_with_username(&admin.key_filename,
&admin.username, &admin_key_filename);
if ((result=fcfs_auth_load_passwd(
FC_FILENAME_STRING_PTR(admin_key_filename),
passwd_buff)) != 0)
{
return result;
}
if ((result=fcfs_auth_client_init(config_filename)) != 0) {
return result;
}
if ((result=fcfs_auth_client_user_login(&g_fcfs_auth_client_vars.
client_ctx, &admin.username, &passwd)) != 0)
{
return result;
}
if (strcasecmp(operation, "create") == 0) {
return create_user(argc, argv);
} else if (strcasecmp(operation, "passwd") == 0 ||
strcasecmp(operation, "secret-key") == 0)
{
if (fc_string_equal(&admin.username, &user.name) && !confirmed) {
fprintf(stderr, "you MUST use -y option to regenerate "
"the secret key \nwhen the user is same with "
"the admin user!\n\n");
return EAGAIN;
}
return passwd_user(argc, argv);
} else if (strcasecmp(operation, "grant") == 0) {
return grant_privilege(argc, argv);
} else if (strcasecmp(operation, "delete") == 0 ||
strcasecmp(operation, "remove") == 0)
{
return remove_user(argc, argv);
} else if (strcasecmp(operation, "list") == 0) {
return list_user(argc, argv);
}
return 0;
}
================================================
FILE: src/auth/client/tools/tool_func.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include "tool_func.h"
#define FCFS_USER_PRIV_ARRAY_COUNT (FCFS_AUTH_USER_PRIV_COUNT + 1)
static id_name_pair_t user_priv_list[FCFS_USER_PRIV_ARRAY_COUNT] = {
{FCFS_AUTH_USER_PRIV_USER_MANAGE,
{USER_PRIV_NAME_USER_MANAGE_STR,
USER_PRIV_NAME_USER_MANAGE_LEN}},
{FCFS_AUTH_USER_PRIV_CREATE_POOL,
{USER_PRIV_NAME_CREATE_POOL_STR,
USER_PRIV_NAME_CREATE_POOL_LEN}},
{FCFS_AUTH_USER_PRIV_SUBSCRIBE_SESSION,
{USER_PRIV_NAME_SUBSCRIBE_SESSION_STR,
USER_PRIV_NAME_SUBSCRIBE_SESSION_LEN}},
{FCFS_AUTH_USER_PRIV_MONITOR_CLUSTER,
{USER_PRIV_NAME_MONITOR_CLUSTER_STR,
USER_PRIV_NAME_MONITOR_CLUSTER_LEN}},
{FCFS_AUTH_USER_PRIV_ALL,
{USER_PRIV_NAME_ALL_PRIVS_STR,
USER_PRIV_NAME_ALL_PRIVS_LEN}}
};
static inline int64_t fcfs_auth_get_user_priv(const string_t *str)
{
id_name_pair_t *pair;
id_name_pair_t *end;
end = user_priv_list + FCFS_USER_PRIV_ARRAY_COUNT;
for (pair=user_priv_list; pairname, str)) {
return pair->id;
}
}
return FCFS_AUTH_USER_PRIV_NONE;
}
static inline const string_t *fcfs_auth_get_user_priv_name(const int64_t priv)
{
id_name_pair_t *pair;
id_name_pair_t *end;
end = user_priv_list + FCFS_USER_PRIV_ARRAY_COUNT;
for (pair=user_priv_list; pairid == priv) {
return &pair->name;
}
}
return NULL;
}
int fcfs_auth_parse_user_priv(const string_t *str, int64_t *priv)
{
const bool ignore_empty = true;
string_t parts[2 * FCFS_AUTH_USER_PRIV_COUNT];
string_t *p;
string_t *end;
int64_t n;
int count;
*priv = 0;
count = split_string_ex(str, ',', parts, sizeof(parts) /
sizeof(string_t), ignore_empty);
end = parts + count;
for (p=parts; plen, p->str);
return EINVAL;
}
*priv |= n;
}
return 0;
}
const char *fcfs_auth_user_priv_to_string(
const int64_t priv, string_t *str)
{
id_name_pair_t *pair;
id_name_pair_t *end;
char *p;
const string_t *name;
if ((name=fcfs_auth_get_user_priv_name(priv)) != NULL) {
memcpy(str->str, name->str, name->len);
str->len = name->len;
} else {
p = str->str;
end = user_priv_list + FCFS_USER_PRIV_ARRAY_COUNT;
for (pair=user_priv_list; pairid) == pair->id) {
memcpy(p, pair->name.str, pair->name.len);
p += pair->name.len;
*p++ = ',';
}
}
str->len = p - str->str;
if (str->len > 0) {
str->len--; //remove last comma
}
}
*(str->str + str->len) = '\0';
return str->str;
}
int fcfs_auth_parse_pool_access(const string_t *str, int *priv)
{
const char *p;
const char *end;
*priv = FCFS_AUTH_POOL_ACCESS_NONE;
end = str->str + str->len;
for (p=str->str; pstr;
if ((priv & FCFS_AUTH_POOL_ACCESS_READ) != 0) {
*p++ = POOL_ACCESS_NAME_READ_CHR;
}
if ((priv & FCFS_AUTH_POOL_ACCESS_WRITE) != 0) {
*p++ = POOL_ACCESS_NAME_WRITE_CHR;
}
*p = '\0';
str->len = p - str->str;
return str->str;
}
================================================
FILE: src/auth/client/tools/tool_func.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_AUTH_TOOL_FUNC_H
#define _FCFS_AUTH_TOOL_FUNC_H
#include "sf/sf_proto.h"
#include "auth_types.h"
#define USER_PRIV_NAME_USER_MANAGE_STR "user"
#define USER_PRIV_NAME_CREATE_POOL_STR "pool"
#define USER_PRIV_NAME_SUBSCRIBE_SESSION_STR "session"
#define USER_PRIV_NAME_MONITOR_CLUSTER_STR "cluster"
#define USER_PRIV_NAME_ALL_PRIVS_STR "*"
#define USER_PRIV_NAME_USER_MANAGE_LEN \
(sizeof(USER_PRIV_NAME_USER_MANAGE_STR) - 1)
#define USER_PRIV_NAME_CREATE_POOL_LEN \
(sizeof(USER_PRIV_NAME_CREATE_POOL_STR) - 1)
#define USER_PRIV_NAME_SUBSCRIBE_SESSION_LEN \
(sizeof(USER_PRIV_NAME_SUBSCRIBE_SESSION_STR) - 1)
#define USER_PRIV_NAME_MONITOR_CLUSTER_LEN \
(sizeof(USER_PRIV_NAME_MONITOR_CLUSTER_STR) - 1)
#define USER_PRIV_NAME_ALL_PRIVS_LEN \
(sizeof(USER_PRIV_NAME_ALL_PRIVS_STR) - 1)
#define POOL_ACCESS_NAME_READ_CHR 'r'
#define POOL_ACCESS_NAME_WRITE_CHR 'w'
#ifdef __cplusplus
extern "C" {
#endif
int fcfs_auth_parse_user_priv(const string_t *str, int64_t *priv);
const char *fcfs_auth_user_priv_to_string(
const int64_t priv, string_t *str);
int fcfs_auth_parse_pool_access(const string_t *str, int *priv);
const char *fcfs_auth_pool_access_to_string(const int priv, string_t *str);
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/common/auth_func.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include "fastcommon/system_info.h"
#include "fastcommon/sched_thread.h"
#include "fastcommon/md5.h"
#include "fastcommon/http_func.h"
#include "sf/sf_global.h"
#include "auth_func.h"
void fcfs_auth_generate_passwd(unsigned char passwd[16])
{
struct {
time_t current_time;
pid_t pid;
int random;
#if defined(OS_LINUX) || defined(OS_FREEBSD)
struct fast_sysinfo si;
#endif
int hash_codes[4];
} input;
input.current_time = get_current_time();
input.pid = getpid();
input.random = rand();
#if defined(OS_LINUX) || defined(OS_FREEBSD)
get_sysinfo(&input.si);
#endif
/*
logInfo("procs: %d, pid: %d, random: %d",
input.si.procs, input.pid, input.random);
*/
INIT_HASH_CODES4(input.hash_codes);
CALC_HASH_CODES4(&input, sizeof(input), input.hash_codes);
FINISH_HASH_CODES4(input.hash_codes);
my_md5_buffer((char *)&input, sizeof(input), passwd);
}
int fcfs_auth_save_passwd(const char *filename, unsigned char passwd[16])
{
char hex_buff[2 * FCFS_AUTH_PASSWD_LEN + 1];
bin2hex((char *)passwd, FCFS_AUTH_PASSWD_LEN, hex_buff);
return safeWriteToFile(filename, hex_buff,
FCFS_AUTH_PASSWD_LEN * 2);
}
int fcfs_auth_load_passwd_ex(const char *filename,
unsigned char passwd[16], const bool ignore_enoent)
{
int result;
int len;
int64_t file_size;
char hex_buff[2 * FCFS_AUTH_PASSWD_LEN + 4];
file_size = sizeof(hex_buff);
if (IS_URL_RESOURCE(filename)) {
int http_status;
int content_len;
char buff[8 * 1024];
char *content;
char error_info[512];
content = buff;
content_len = sizeof(buff);
if ((result=get_url_content_ex(filename, strlen(filename),
SF_G_CONNECT_TIMEOUT, SF_G_NETWORK_TIMEOUT,
&http_status, &content, &content_len,
error_info)) != 0)
{
if (*error_info != '\0') {
logError("file: "__FILE__", line: %d, "
"%s fetch fail, %s", __LINE__,
filename, error_info);
} else {
logError("file: "__FILE__", line: %d, "
"%s fetch fail, errno: %d, error info: %s",
__LINE__, filename, result, STRERROR(result));
}
return result;
}
if (http_status != 200) {
if (http_status == 404 && ignore_enoent) {
memset(passwd, 0, FCFS_AUTH_PASSWD_LEN);
return 0;
}
logError("file: "__FILE__", line: %d, "
"HTTP status code: %d != 200, url: %s",
__LINE__, http_status, filename);
return http_status == 404 ? ENOENT : EACCES;
}
if (content_len >= sizeof(hex_buff)) {
logError("file: "__FILE__", line: %d, "
"%s is not a valid secret file because the content "
"length: %d >= %d", __LINE__, filename, content_len,
(int)sizeof(hex_buff));
return EOVERFLOW;
}
memcpy(hex_buff, content, content_len + 1);
file_size = content_len;
} else {
if (access(filename, F_OK) != 0) {
if (errno == ENOENT && ignore_enoent) {
memset(passwd, 0, FCFS_AUTH_PASSWD_LEN);
return 0;
}
}
if ((result=getFileContentEx(filename,
hex_buff, 0, &file_size)) != 0)
{
return result;
}
}
if (file_size > 2 * FCFS_AUTH_PASSWD_LEN) {
trim_right(hex_buff);
file_size = strlen(hex_buff);
}
if (file_size != 2 * FCFS_AUTH_PASSWD_LEN) {
logError("file: "__FILE__", line: %d, "
"invalid secret filename: %s whose file size MUST be: %d",
__LINE__, filename, 2 * FCFS_AUTH_PASSWD_LEN);
return EINVAL;
}
hex2bin(hex_buff, (char *)passwd, &len);
return 0;
}
int fcfs_auth_replace_filename_with_username(const string_t *src,
const string_t *username, FilenameString *new_filename)
{
#define USERNAME_VARIABLE_STR "${username}"
#define USERNAME_VARIABLE_LEN (sizeof(USERNAME_VARIABLE_STR) - 1)
string_t tag;
FC_INIT_FILENAME_STRING(*new_filename);
FC_SET_STRING_EX(tag, USERNAME_VARIABLE_STR, USERNAME_VARIABLE_LEN);
return str_replace(src, &tag, username, &new_filename->s,
FC_FILENAME_BUFFER_SIZE(*new_filename));
}
int fcfs_auth_user_check_realloc_array(FCFSAuthUserArray *array,
const int target_count)
{
int new_alloc;
FCFSAuthUserInfo *new_users;
if (array->alloc >= target_count) {
return 0;
}
new_alloc = array->alloc;
while (new_alloc < target_count) {
new_alloc *= 2;
}
new_users = (FCFSAuthUserInfo *)fc_malloc(
sizeof(FCFSAuthUserInfo) * new_alloc);
if (new_users == NULL) {
return ENOMEM;
}
if (array->count > 0) {
int bytes;
bytes = sizeof(FCFSAuthUserInfo) * array->count;
memcpy(new_users, array->users, bytes);
}
if (array->users != array->fixed) {
free(array->users);
}
array->users = new_users;
array->alloc = new_alloc;
return 0;
}
int fcfs_auth_spool_check_realloc_array(FCFSAuthStoragePoolArray *array,
const int target_count)
{
int new_alloc;
FCFSAuthStoragePoolInfo *new_spools;
if (array->alloc >= target_count) {
return 0;
}
new_alloc = array->alloc;
while (new_alloc < target_count) {
new_alloc *= 2;
}
new_spools = (FCFSAuthStoragePoolInfo *)fc_malloc(
sizeof(FCFSAuthStoragePoolInfo) * new_alloc);
if (new_spools == NULL) {
return ENOMEM;
}
if (array->count > 0) {
int bytes;
bytes = sizeof(FCFSAuthStoragePoolInfo) * array->count;
memcpy(new_spools, array->spools, bytes);
}
if (array->spools != array->fixed) {
free(array->spools);
}
array->spools = new_spools;
array->alloc = new_alloc;
return 0;
}
int fcfs_auth_gpool_check_realloc_array(FCFSAuthGrantedPoolArray *array,
const int target_count)
{
int new_alloc;
FCFSAuthGrantedPoolFullInfo *new_gpools;
if (array->alloc >= target_count) {
return 0;
}
new_alloc = array->alloc;
while (new_alloc < target_count) {
new_alloc *= 2;
}
new_gpools = (FCFSAuthGrantedPoolFullInfo *)fc_malloc(
sizeof(FCFSAuthGrantedPoolFullInfo) * new_alloc);
if (new_gpools == NULL) {
return ENOMEM;
}
if (array->count > 0) {
int bytes;
bytes = sizeof(FCFSAuthGrantedPoolFullInfo) * array->count;
memcpy(new_gpools, array->gpools, bytes);
}
if (array->gpools != array->fixed) {
free(array->gpools);
}
array->gpools = new_gpools;
array->alloc = new_alloc;
return 0;
}
================================================
FILE: src/auth/common/auth_func.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_AUTH_FUNC_H
#define _FCFS_AUTH_FUNC_H
#include "sf/sf_proto.h"
#include "auth_types.h"
#define fcfs_auth_load_passwd(filename, passwd) \
fcfs_auth_load_passwd_ex(filename, passwd, false)
#ifdef __cplusplus
extern "C" {
#endif
static inline void fcfs_auth_user_init_array(FCFSAuthUserArray *array)
{
array->users = array->fixed;
array->alloc = FCFS_AUTH_FIXED_USER_COUNT;
array->count = 0;
}
static inline void fcfs_auth_user_free_array(FCFSAuthUserArray *array)
{
if (array->users != array->fixed) {
if (array->users != NULL) {
free(array->users);
}
array->users = array->fixed;
array->alloc = FCFS_AUTH_FIXED_USER_COUNT;
}
}
static inline void fcfs_auth_spool_init_array(
FCFSAuthStoragePoolArray *array)
{
array->spools = array->fixed;
array->alloc = FCFS_AUTH_FIXED_USER_COUNT;
array->count = 0;
}
static inline void fcfs_auth_spool_free_array(
FCFSAuthStoragePoolArray *array)
{
if (array->spools != array->fixed) {
if (array->spools != NULL) {
free(array->spools);
}
array->spools = array->fixed;
array->alloc = FCFS_AUTH_FIXED_USER_COUNT;
}
}
static inline void fcfs_auth_granted_init_array(
FCFSAuthGrantedPoolArray *array)
{
array->gpools = array->fixed;
array->alloc = FCFS_AUTH_FIXED_USER_COUNT;
array->count = 0;
}
static inline void fcfs_auth_granted_free_array(
FCFSAuthGrantedPoolArray *array)
{
if (array->gpools != array->fixed) {
if (array->gpools != NULL) {
free(array->gpools);
}
array->gpools = array->fixed;
array->alloc = FCFS_AUTH_FIXED_USER_COUNT;
}
}
int fcfs_auth_user_check_realloc_array(FCFSAuthUserArray *array,
const int target_count);
int fcfs_auth_spool_check_realloc_array(FCFSAuthStoragePoolArray *array,
const int target_count);
int fcfs_auth_gpool_check_realloc_array(FCFSAuthGrantedPoolArray *array,
const int target_count);
void fcfs_auth_generate_passwd(unsigned char passwd[16]);
int fcfs_auth_save_passwd(const char *filename, unsigned char passwd[16]);
int fcfs_auth_load_passwd_ex(const char *filename,
unsigned char passwd[16], const bool ignore_enoent);
int fcfs_auth_replace_filename_with_username(const string_t *src,
const string_t *username, FilenameString *new_filename);
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/common/auth_global.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include "auth_global.h"
FCFSAuthGlobalVars g_fcfs_auth_global_vars = {
{5, 5, 0}
};
================================================
FILE: src/auth/common/auth_global.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_AUTH_GLOBAL_H
#define _FCFS_AUTH_GLOBAL_H
#include "fastcommon/common_define.h"
typedef struct fcfs_auth_global_vars {
Version version;
} FCFSAuthGlobalVars;
#ifdef __cplusplus
extern "C" {
#endif
extern FCFSAuthGlobalVars g_fcfs_auth_global_vars;
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/common/auth_proto.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include "auth_proto.h"
void fcfs_auth_proto_init()
{
}
const char *fcfs_auth_get_cmd_caption(const int cmd)
{
switch (cmd) {
case FCFS_AUTH_SERVICE_PROTO_USER_LOGIN_REQ:
return "USER_LOGIN_REQ";
case FCFS_AUTH_SERVICE_PROTO_USER_LOGIN_RESP:
return "USER_LOGIN_RESP";
case FCFS_AUTH_SERVICE_PROTO_SESSION_SUBSCRIBE_REQ:
return "SESSION_SUBSCRIBE_REQ";
case FCFS_AUTH_SERVICE_PROTO_SESSION_SUBSCRIBE_RESP:
return "SESSION_SUBSCRIBE_RESP";
case FCFS_AUTH_SERVICE_PROTO_SESSION_PUSH_REQ:
return "SESSION_PUSH_REQ";
case FCFS_AUTH_SERVICE_PROTO_SESSION_PUSH_RESP:
return "SESSION_PUSH_RESP";
case FCFS_AUTH_SERVICE_PROTO_SESSION_VALIDATE_REQ:
return "SESSION_VALIDATE_REQ";
case FCFS_AUTH_SERVICE_PROTO_SESSION_VALIDATE_RESP:
return "SESSION_VALIDATE_RESP";
case FCFS_AUTH_SERVICE_PROTO_USER_CREATE_REQ:
return "USER_CREATE_REQ";
case FCFS_AUTH_SERVICE_PROTO_USER_CREATE_RESP:
return "USER_CREATE_RESP";
case FCFS_AUTH_SERVICE_PROTO_USER_LIST_REQ:
return "USER_LIST_REQ";
case FCFS_AUTH_SERVICE_PROTO_USER_LIST_RESP:
return "USER_LIST_RESP";
case FCFS_AUTH_SERVICE_PROTO_USER_GRANT_REQ:
return "USER_GRANT_REQ";
case FCFS_AUTH_SERVICE_PROTO_USER_GRANT_RESP:
return "USER_GRANT_RESP";
case FCFS_AUTH_SERVICE_PROTO_USER_REMOVE_REQ:
return "USER_REMOVE_REQ";
case FCFS_AUTH_SERVICE_PROTO_USER_REMOVE_RESP:
return "USER_REMOVE_RESP";
case FCFS_AUTH_SERVICE_PROTO_USER_PASSWD_REQ:
return "USER_PASSWD_REQ";
case FCFS_AUTH_SERVICE_PROTO_USER_PASSWD_RESP:
return "USER_PASSWD_RESP";
case FCFS_AUTH_SERVICE_PROTO_SPOOL_CREATE_REQ:
return "SPOOL_CREATE_REQ";
case FCFS_AUTH_SERVICE_PROTO_SPOOL_CREATE_RESP:
return "SPOOL_CREATE_RESP";
case FCFS_AUTH_SERVICE_PROTO_SPOOL_LIST_REQ:
return "SPOOL_LIST_REQ";
case FCFS_AUTH_SERVICE_PROTO_SPOOL_LIST_RESP:
return "SPOOL_LIST_RESP";
case FCFS_AUTH_SERVICE_PROTO_SPOOL_REMOVE_REQ:
return "SPOOL_REMOVE_REQ";
case FCFS_AUTH_SERVICE_PROTO_SPOOL_REMOVE_RESP:
return "SPOOL_REMOVE_RESP";
case FCFS_AUTH_SERVICE_PROTO_SPOOL_SET_QUOTA_REQ:
return "SPOOL_SET_QUOTA_REQ";
case FCFS_AUTH_SERVICE_PROTO_SPOOL_SET_QUOTA_RESP:
return "SPOOL_SET_QUOTA_RESP";
case FCFS_AUTH_SERVICE_PROTO_SPOOL_GET_QUOTA_REQ:
return "SPOOL_GET_QUOTA_REQ";
case FCFS_AUTH_SERVICE_PROTO_SPOOL_GET_QUOTA_RESP:
return "SPOOL_GET_QUOTA_RESP";
case FCFS_AUTH_SERVICE_PROTO_GPOOL_GRANT_REQ:
return "GPOOL_GRANT_REQ";
case FCFS_AUTH_SERVICE_PROTO_GPOOL_GRANT_RESP:
return "GPOOL_GRANT_RESP";
case FCFS_AUTH_SERVICE_PROTO_GPOOL_WITHDRAW_REQ:
return "GPOOL_WITHDRAW_REQ";
case FCFS_AUTH_SERVICE_PROTO_GPOOL_WITHDRAW_RESP:
return "GPOOL_WITHDRAW_RESP";
case FCFS_AUTH_SERVICE_PROTO_GPOOL_LIST_REQ:
return "GPOOL_LIST_REQ";
case FCFS_AUTH_SERVICE_PROTO_GPOOL_LIST_RESP:
return "GPOOL_LIST_RESP";
case FCFS_AUTH_SERVICE_PROTO_GET_MASTER_REQ:
return "GET_MASTER_REQ";
case FCFS_AUTH_SERVICE_PROTO_GET_MASTER_RESP:
return "GET_MASTER_RESP";
case FCFS_AUTH_SERVICE_PROTO_CLUSTER_STAT_REQ:
return "CLUSTER_STAT_REQ";
case FCFS_AUTH_SERVICE_PROTO_CLUSTER_STAT_RESP:
return "CLUSTER_STAT_RESP";
case FCFS_AUTH_CLUSTER_PROTO_GET_SERVER_STATUS_REQ:
return "GET_SERVER_STATUS_REQ";
case FCFS_AUTH_CLUSTER_PROTO_GET_SERVER_STATUS_RESP:
return "GET_SERVER_STATUS_RESP";
case FCFS_AUTH_CLUSTER_PROTO_JOIN_MASTER:
return "JOIN_MASTER";
case FCFS_AUTH_CLUSTER_PROTO_PING_MASTER_REQ:
return "PING_MASTER_REQ";
case FCFS_AUTH_CLUSTER_PROTO_PING_MASTER_RESP:
return "PING_MASTER_RESP";
case FCFS_AUTH_CLUSTER_PROTO_PRE_SET_NEXT_MASTER:
return "PRE_SET_NEXT_MASTER";
case FCFS_AUTH_CLUSTER_PROTO_COMMIT_NEXT_MASTER:
return "COMMIT_NEXT_MASTER";
default:
return sf_get_cmd_caption(cmd);
}
}
================================================
FILE: src/auth/common/auth_proto.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_AUTH_PROTO_H
#define _FCFS_AUTH_PROTO_H
#include "sf/sf_proto.h"
#include "auth_types.h"
#define FCFS_AUTH_SERVICE_PROTO_USER_LOGIN_REQ 9
#define FCFS_AUTH_SERVICE_PROTO_USER_LOGIN_RESP 10
#define FCFS_AUTH_SERVICE_PROTO_SESSION_SUBSCRIBE_REQ 11
#define FCFS_AUTH_SERVICE_PROTO_SESSION_SUBSCRIBE_RESP 12
#define FCFS_AUTH_SERVICE_PROTO_SESSION_PUSH_REQ 13
#define FCFS_AUTH_SERVICE_PROTO_SESSION_PUSH_RESP 14
#define FCFS_AUTH_SERVICE_PROTO_SESSION_VALIDATE_REQ 15
#define FCFS_AUTH_SERVICE_PROTO_SESSION_VALIDATE_RESP 16
#define FCFS_AUTH_SERVICE_PROTO_USER_CREATE_REQ 21
#define FCFS_AUTH_SERVICE_PROTO_USER_CREATE_RESP 22
#define FCFS_AUTH_SERVICE_PROTO_USER_LIST_REQ 23
#define FCFS_AUTH_SERVICE_PROTO_USER_LIST_RESP 24
#define FCFS_AUTH_SERVICE_PROTO_USER_GRANT_REQ 25
#define FCFS_AUTH_SERVICE_PROTO_USER_GRANT_RESP 26
#define FCFS_AUTH_SERVICE_PROTO_USER_REMOVE_REQ 27
#define FCFS_AUTH_SERVICE_PROTO_USER_REMOVE_RESP 28
#define FCFS_AUTH_SERVICE_PROTO_USER_PASSWD_REQ 29
#define FCFS_AUTH_SERVICE_PROTO_USER_PASSWD_RESP 30
#define FCFS_AUTH_SERVICE_PROTO_GET_MASTER_REQ 61
#define FCFS_AUTH_SERVICE_PROTO_GET_MASTER_RESP 62
#define FCFS_AUTH_SERVICE_PROTO_CLUSTER_STAT_REQ 63
#define FCFS_AUTH_SERVICE_PROTO_CLUSTER_STAT_RESP 64
#define FCFS_AUTH_SERVICE_PROTO_SPOOL_CREATE_REQ 71
#define FCFS_AUTH_SERVICE_PROTO_SPOOL_CREATE_RESP 72
#define FCFS_AUTH_SERVICE_PROTO_SPOOL_LIST_REQ 73
#define FCFS_AUTH_SERVICE_PROTO_SPOOL_LIST_RESP 74
#define FCFS_AUTH_SERVICE_PROTO_SPOOL_REMOVE_REQ 75
#define FCFS_AUTH_SERVICE_PROTO_SPOOL_REMOVE_RESP 76
#define FCFS_AUTH_SERVICE_PROTO_SPOOL_SET_QUOTA_REQ 77
#define FCFS_AUTH_SERVICE_PROTO_SPOOL_SET_QUOTA_RESP 78
#define FCFS_AUTH_SERVICE_PROTO_SPOOL_GET_QUOTA_REQ 79
#define FCFS_AUTH_SERVICE_PROTO_SPOOL_GET_QUOTA_RESP 80
#define FCFS_AUTH_SERVICE_PROTO_GPOOL_GRANT_REQ 91
#define FCFS_AUTH_SERVICE_PROTO_GPOOL_GRANT_RESP 92
#define FCFS_AUTH_SERVICE_PROTO_GPOOL_WITHDRAW_REQ 93
#define FCFS_AUTH_SERVICE_PROTO_GPOOL_WITHDRAW_RESP 94
#define FCFS_AUTH_SERVICE_PROTO_GPOOL_LIST_REQ 95
#define FCFS_AUTH_SERVICE_PROTO_GPOOL_LIST_RESP 96
//cluster commands
#define FCFS_AUTH_CLUSTER_PROTO_GET_SERVER_STATUS_REQ 201
#define FCFS_AUTH_CLUSTER_PROTO_GET_SERVER_STATUS_RESP 202
#define FCFS_AUTH_CLUSTER_PROTO_JOIN_MASTER 203 //slave -> master
#define FCFS_AUTH_CLUSTER_PROTO_PING_MASTER_REQ 205
#define FCFS_AUTH_CLUSTER_PROTO_PING_MASTER_RESP 206
#define FCFS_AUTH_CLUSTER_PROTO_PRE_SET_NEXT_MASTER 207 //notify next leader to other servers
#define FCFS_AUTH_CLUSTER_PROTO_COMMIT_NEXT_MASTER 208 //commit next leader to other servers
typedef SFCommonProtoHeader FCFSAuthProtoHeader;
typedef struct fcfs_auth_proto_name_info {
unsigned char len;
char str[0];
} FCFSAuthProtoNameInfo;
typedef struct fcfs_auth_proto_user_passwd_pair {
char passwd[FCFS_AUTH_PASSWD_LEN];
FCFSAuthProtoNameInfo username;
} FCFSAuthProtoUserPasswdPair;
typedef struct fcfs_auth_proto_user_pool_pair {
FCFSAuthProtoNameInfo username;
FCFSAuthProtoNameInfo poolname;
} FCFSAuthProtoUserPoolPair;
typedef struct fcfs_auth_proto_pool_priviledges {
char fdir[4];
char fstore[4];
} FCFSAuthProtoPoolPriviledges;
typedef struct fcfs_auth_proto_user_login_req {
unsigned char flags;
FCFSAuthProtoUserPasswdPair up_pair;
FCFSAuthProtoNameInfo poolname;
} FCFSAuthProtoUserLoginReq;
typedef struct fcfs_auth_proto_user_login_resp {
char session_id[FCFS_AUTH_SESSION_ID_LEN];
} FCFSAuthProtoUserLoginResp;
typedef struct fcfs_auth_proto_session_subscribe_req {
FCFSAuthProtoUserPasswdPair up_pair;
} FCFSAuthProtoSessionSubscribeReq;
typedef struct fcfs_auth_proto_session_validate_req {
char session_id[FCFS_AUTH_SESSION_ID_LEN];
char validate_key[FCFS_AUTH_PASSWD_LEN];
char priv_type;
char padding[7];
char pool_id[8];
char priv_required[8];
} FCFSAuthProtoSessionValidateReq;
typedef struct fcfs_auth_proto_session_validate_resp {
char result[4];
} FCFSAuthProtoSessionValidateResp;
typedef struct fcfs_auth_proto_session_push_resp_body_header {
char count[4];
} FCFSAuthProtoSessionPushRespBodyHeader;
typedef struct fcfs_auth_proto_session_push_entry {
struct {
char available;
char id[8];
FCFSAuthProtoPoolPriviledges privs;
} pool;
struct {
char id[8];
char priv[8];
} user;
} FCFSAuthProtoSessionPushEntry;
typedef struct fcfs_auth_proto_session_push_resp_body_part {
char session_id[FCFS_AUTH_SESSION_ID_LEN];
char operation;
FCFSAuthProtoSessionPushEntry entry[0];
} FCFSAuthProtoSessionPushRespBodyPart;
typedef struct fcfs_auth_proto_user_create_req {
char priv[8];
FCFSAuthProtoUserPasswdPair up_pair;
} FCFSAuthProtoUserCreateReq;
typedef struct fcfs_auth_proto_user_passwd_req {
FCFSAuthProtoUserPasswdPair up_pair;
} FCFSAuthProtoUserPasswdReq;
typedef struct fcfs_auth_proto_user_list_req {
SFProtoLimitInfo limit;
FCFSAuthProtoNameInfo username;
} FCFSAuthProtoUserListReq;
typedef struct fcfs_auth_proto_list_resp_header {
char count[4];
char is_last;
char padding[3];
} FCFSAuthProtoListRespHeader;
typedef struct fcfs_auth_proto_user_list_resp_body_part {
char priv[8];
FCFSAuthProtoNameInfo username;
} FCFSAuthProtoUserListRespBodyPart;
typedef struct fcfs_auth_proto_user_grant_req {
char priv[8];
FCFSAuthProtoNameInfo username;
} FCFSAuthProtoUserGrantReq;
typedef struct fcfs_auth_proto_user_remove_req {
FCFSAuthProtoNameInfo username;
} FCFSAuthProtoUserRemoveReq;
typedef struct fcfs_auth_proto_spool_create_req {
char quota[8];
char dryrun;
FCFSAuthProtoNameInfo poolname;
} FCFSAuthProtoSPoolCreateReq;
typedef struct fcfs_auth_proto_spool_create_resp {
FCFSAuthProtoNameInfo poolname;
} FCFSAuthProtoSPoolCreateResp;
typedef struct fcfs_auth_proto_spool_list_req {
SFProtoLimitInfo limit;
FCFSAuthProtoUserPoolPair up_pair;
} FCFSAuthProtoSPoolListReq;
typedef struct fcfs_auth_proto_spool_list_resp_body_part {
char quota[8];
FCFSAuthProtoNameInfo poolname;
} FCFSAuthProtoSPoolListRespBodyPart;
typedef struct fcfs_auth_proto_spool_remove_req {
FCFSAuthProtoNameInfo poolname;
} FCFSAuthProtoSPoolRemoveReq;
typedef struct fcfs_auth_proto_spool_set_quota_req {
char quota[8];
FCFSAuthProtoNameInfo poolname;
} FCFSAuthProtoSPoolSetQuotaReq;
typedef struct fcfs_auth_proto_spool_get_quota_req {
FCFSAuthProtoNameInfo poolname;
} FCFSAuthProtoSPoolGetQuotaReq;
typedef struct fcfs_auth_proto_spool_get_quota_resp {
char quota[8];
} FCFSAuthProtoSPoolGetQuotaResp;
typedef struct fcfs_auth_proto_spool_grant_req {
FCFSAuthProtoPoolPriviledges privs;
FCFSAuthProtoUserPoolPair up_pair;
} FCFSAuthProtoSPoolGrantReq;
typedef struct fcfs_auth_proto_spool_withdraw_req {
FCFSAuthProtoUserPoolPair up_pair;
} FCFSAuthProtoSPoolWithdrawReq;
typedef FCFSAuthProtoSPoolListReq FCFSAuthProtoGPoolListReq;
typedef struct fcfs_auth_proto_gpool_list_resp_body_part {
FCFSAuthProtoPoolPriviledges privs;
FCFSAuthProtoUserPoolPair up_pair;
} FCFSAuthProtoGPoolListRespBodyPart;
typedef struct fcfs_auth_proto_get_server_resp {
char server_id[4];
char port[2];
char padding[2];
char ip_addr[IP_ADDRESS_SIZE];
} FCFSAuthProtoGetServerResp;
typedef struct fcfs_auth_proto_get_server_status_req {
char server_id[4];
char config_sign[SF_CLUSTER_CONFIG_SIGN_LEN];
} FCFSAuthProtoGetServerStatusReq;
typedef struct fcfs_auth_proto_get_server_status_resp {
char server_id[4];
char is_master;
char padding[3];
} FCFSAuthProtoGetServerStatusResp;
typedef struct fcfs_auth_proto_join_master_req {
char server_id[4]; //the slave server id
char padding[4];
char config_sign[SF_CLUSTER_CONFIG_SIGN_LEN];
} FCFSAuthProtoJoinMasterReq;
typedef struct fcfs_auth_proto_cluster_stat_resp_body_header {
char count[4];
char padding[4];
} FCFSAuthProtoClusterStatRespBodyHeader;
typedef struct fcfs_auth_proto_cluster_stat_resp_body_part {
char server_id[4];
char is_online;
char is_master;
char padding[1];
char port[2];
char ip_addr[IP_ADDRESS_SIZE];
} FCFSAuthProtoClusterStatRespBodyPart;
#define auth_log_network_error_ex(response, conn, result, log_level) \
sf_log_network_error_ex(response, conn, "fauth", result, log_level)
#define auth_log_network_error(response, conn, result) \
sf_log_network_error(response, conn, "fauth", result)
#ifdef __cplusplus
extern "C" {
#endif
void fcfs_auth_proto_init();
const char *fcfs_auth_get_cmd_caption(const int cmd);
static inline void fcfs_auth_parse_user_pool_pair(FCFSAuthProtoUserPoolPair
*up_pair, string_t *username, string_t *poolname)
{
FCFSAuthProtoNameInfo *proto_pname;
FC_SET_STRING_EX(*username, up_pair->username.str,
up_pair->username.len);
proto_pname = (FCFSAuthProtoNameInfo *)(up_pair->username.str +
up_pair->username.len);
FC_SET_STRING_EX(*poolname, proto_pname->str, proto_pname->len);
}
static inline void fcfs_auth_pack_user_pool_pair(const string_t *username,
const string_t *poolname, FCFSAuthProtoUserPoolPair *up_pair)
{
FCFSAuthProtoNameInfo *proto_pname;
up_pair->username.len = username->len;
if (username->len > 0) {
memcpy(up_pair->username.str, username->str, username->len);
}
proto_pname = (FCFSAuthProtoNameInfo *)(up_pair->
username.str + username->len);
proto_pname->len = poolname->len;
if (poolname->len > 0) {
memcpy(proto_pname->str, poolname->str, poolname->len);
}
}
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/common/auth_types.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_AUTH_TYPES_H
#define _FCFS_AUTH_TYPES_H
#include "fastcommon/common_define.h"
#include "sf/sf_types.h"
#define FCFS_AUTH_DEFAULT_CLUSTER_PORT 31011
#define FCFS_AUTH_DEFAULT_SERVICE_PORT 31012
#define FCFS_AUTH_SESSION_FLAGS_PUBLISH 1
#define FCFS_AUTH_USERNAME_MAX_LEN 64
#define FCFS_AUTH_PASSWD_LEN 16
#define FCFS_AUTH_SESSION_ID_LEN 8
#define FCFS_AUTH_FIXED_USER_COUNT 256
#define FCFS_AUTH_FIXED_POOL_COUNT 256
#define FCFS_AUTH_USER_STATUS_NORMAL 0
#define FCFS_AUTH_USER_STATUS_DELETED 1
#define FCFS_AUTH_POOL_STATUS_NORMAL 0
#define FCFS_AUTH_POOL_STATUS_DELETED 1
#define FCFS_AUTH_USER_PRIV_NONE 0
#define FCFS_AUTH_USER_PRIV_USER_MANAGE (1 << 0)
#define FCFS_AUTH_USER_PRIV_CREATE_POOL (1 << 1)
#define FCFS_AUTH_USER_PRIV_MONITOR_CLUSTER (1 << 2)
#define FCFS_AUTH_USER_PRIV_SUBSCRIBE_SESSION (1 << 3)
#define FCFS_AUTH_USER_PRIV_ALL (FCFS_AUTH_USER_PRIV_USER_MANAGE | \
FCFS_AUTH_USER_PRIV_CREATE_POOL | \
FCFS_AUTH_USER_PRIV_MONITOR_CLUSTER | \
FCFS_AUTH_USER_PRIV_SUBSCRIBE_SESSION)
#define FCFS_AUTH_USER_PRIV_COUNT 4
#define FCFS_AUTH_POOL_ACCESS_NONE 0
#define FCFS_AUTH_POOL_ACCESS_WRITE (1 << 1)
#define FCFS_AUTH_POOL_ACCESS_READ (1 << 2)
#define FCFS_AUTH_POOL_ACCESS_ALL (FCFS_AUTH_POOL_ACCESS_WRITE | \
FCFS_AUTH_POOL_ACCESS_READ)
#define FCFS_AUTH_POOL_ACCESS_COUNT 2
#define FCFS_AUTH_UNLIMITED_QUOTA_STR "unlimited"
#define FCFS_AUTH_UNLIMITED_QUOTA_VAL -1
#define FCFS_AUTH_AUTO_ID_TAG_STR "${auto_id}"
#define FCFS_AUTH_AUTO_ID_TAG_LEN (sizeof(FCFS_AUTH_AUTO_ID_TAG_STR) - 1)
#define FCFS_AUTH_PUSH_OPERATION_CREATE_SESSION 'C'
#define FCFS_AUTH_PUSH_OPERATION_UPDATE_SESSION 'U'
#define FCFS_AUTH_PUSH_OPERATION_REMOVE_SESSION 'R'
#define FCFS_AUTH_POOL_AVAILABLE(pool) \
((pool.quota == FCFS_AUTH_UNLIMITED_QUOTA_VAL) || \
(pool.used < pool.quota))
typedef enum {
fcfs_auth_validate_priv_type_user = 'u',
fcfs_auth_validate_priv_type_pool_fdir = 'd',
fcfs_auth_validate_priv_type_pool_fstore = 's'
} FCFSAuthValidatePriviledgeType;
typedef struct fcfs_auth_spool_priviledges {
int fdir;
int fstore;
} FCFSAuthSPoolPriviledges;
typedef struct fcfs_auth_storage_pool_info {
int64_t id;
string_t name;
int64_t quota; //bytes
int64_t used; //bytes
int status;
} FCFSAuthStoragePoolInfo;
typedef struct fcfs_auth_granted_pool_info {
int64_t id;
int64_t pool_id;
FCFSAuthSPoolPriviledges privs;
} FCFSAuthGrantedPoolInfo;
typedef struct fcfs_auth_granted_pool_full_info {
FCFSAuthGrantedPoolInfo granted;
string_t username;
string_t pool_name;
} FCFSAuthGrantedPoolFullInfo;
typedef struct fcfs_auth_user_info {
int64_t id;
string_t name;
string_t passwd;
int64_t priv;
int status;
} FCFSAuthUserInfo;
typedef struct fcfs_auth_storage_pool_array {
FCFSAuthStoragePoolInfo *spools;
FCFSAuthStoragePoolInfo fixed[FCFS_AUTH_FIXED_POOL_COUNT];
int count;
int alloc;
} FCFSAuthStoragePoolArray;
typedef struct fcfs_auth_granted_pool_array {
FCFSAuthGrantedPoolFullInfo *gpools;
FCFSAuthGrantedPoolFullInfo fixed[FCFS_AUTH_FIXED_POOL_COUNT];
int count;
int alloc;
} FCFSAuthGrantedPoolArray;
typedef struct fcfs_auth_user_array {
FCFSAuthUserInfo *users;
FCFSAuthUserInfo fixed[FCFS_AUTH_FIXED_USER_COUNT];
int count;
int alloc;
} FCFSAuthUserArray;
#endif
================================================
FILE: src/auth/common/server_session.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include "fastcommon/shared_func.h"
#include "fastcommon/pthread_func.h"
#include "fastcommon/fast_mblock.h"
#include "auth_func.h"
#include "server_session.h"
#define SESSION_MIN_SHARED_ALLOCATOR_COUNT 1
#define SESSION_MAX_SHARED_ALLOCATOR_COUNT 1000
#define SESSION_DEFAULT_SHARED_ALLOCATOR_COUNT 11
#define SESSION_MIN_HASHTABLE_CAPACITY 1361
#define SESSION_MAX_HASHTABLE_CAPACITY 11229331
#define SESSION_DEFAULT_HASHTABLE_CAPACITY 10949
#define SESSION_MIN_SHARED_LOCK_COUNT 1
#define SESSION_MAX_SHARED_LOCK_COUNT 10000
#define SESSION_DEFAULT_SHARED_LOCK_COUNT 163
#define SESSION_MIN_VALIDATE_WITHIN_FRESH_SECONDS 1
#define SESSION_MAX_VALIDATE_WITHIN_FRESH_SECONDS 31536000
#define SESSION_DEFAULT_VALIDATE_WITHIN_FRESH_SECONDS 5
typedef struct {
ServerSessionHashEntry **buckets;
int capacity;
} ServerSessionHashtable;
typedef struct {
int count;
volatile uint32_t next;
struct fast_mblock_man *allocators;
} ServerSessionAllocatorArray;
typedef struct {
int count;
pthread_mutex_t *locks;
} ServerSessionLockArray;
typedef struct {
int fields_size;
volatile uint16_t sn; //for generate session id
ServerSessionAllocatorArray allocator_array;
ServerSessionLockArray lock_array;
ServerSessionHashtable htable;
ServerSessionCallbacks callbacks;
} ServerSessionContext;
ServerSessionConfig g_server_session_cfg;
static ServerSessionContext session_ctx = {0, 0, {0, 0, NULL}};
#define SESSION_SET_HASHTABLE_LOCK(htable, session_id) \
int32_t bucket_index; \
pthread_mutex_t *lock; \
bucket_index = session_id % (htable).capacity; \
lock = session_ctx.lock_array.locks + (bucket_index % \
session_ctx.lock_array.count)
#define SESSION_SET_BUCKET_AND_LOCK(htable, session_id) \
ServerSessionHashEntry **bucket; \
SESSION_SET_HASHTABLE_LOCK(htable, session_id); \
bucket = (htable).buckets + bucket_index
void server_session_cfg_to_string_ex(char *buff,
const int size, const bool output_all)
{
int len;
len = snprintf(buff, size, "session {shared_allocator_count: %d, "
"shared_lock_count: %d, hashtable_capacity: %d, "
"validate_key_filename: %s",
g_server_session_cfg.shared_allocator_count,
g_server_session_cfg.shared_lock_count,
g_server_session_cfg.hashtable_capacity,
g_server_session_cfg.validate_key_filename.str);
if (output_all) {
snprintf(buff + len, size - len,
", validate_within_fresh_seconds: %d}",
g_server_session_cfg.validate_within_fresh_seconds);
} else {
snprintf(buff + len, size - len, "}");
}
}
static int load_session_validate_key(IniFullContext *ini_ctx)
{
int result;
char *key_filename;
char full_key_filename[PATH_MAX];
string_t validate_key_filename;
key_filename = iniGetStrValue(ini_ctx->section_name,
"validate_key_filename", ini_ctx->context);
if (key_filename == NULL || *key_filename == '\0') {
key_filename = "keys/session_validate.key";
}
validate_key_filename.str = full_key_filename;
validate_key_filename.len = resolve_path(ini_ctx->filename,
key_filename, full_key_filename, sizeof(full_key_filename));
if ((result=fcfs_auth_load_passwd(validate_key_filename.str,
g_server_session_cfg.validate_key_buff)) != 0)
{
logError("file: "__FILE__", line: %d, "
"config file: %s, validate_key_filename: %s, "
"load password fail, ret code: %d", __LINE__,
ini_ctx->filename, validate_key_filename.str, result);
return result;
}
g_server_session_cfg.validate_key.str = (char *)
g_server_session_cfg.validate_key_buff;
g_server_session_cfg.validate_key.len = FCFS_AUTH_PASSWD_LEN;
g_server_session_cfg.validate_key_filename.str = (char *)
fc_malloc(validate_key_filename.len + 1);
if (g_server_session_cfg.validate_key_filename.str == NULL) {
return ENOMEM;
}
g_server_session_cfg.validate_key_filename.len =
validate_key_filename.len;
memcpy(g_server_session_cfg.validate_key_filename.str,
validate_key_filename.str,
validate_key_filename.len + 1);
return 0;
}
static int do_load_session_cfg(const char *session_filename)
{
IniContext ini_context;
IniFullContext ini_ctx;
int result;
if ((result=iniLoadFromFile(session_filename, &ini_context)) != 0) {
logError("file: "__FILE__", line: %d, "
"load session config file \"%s\" fail, ret code: %d",
__LINE__, session_filename, result);
return result;
}
FAST_INI_SET_FULL_CTX_EX(ini_ctx, session_filename, NULL, &ini_context);
session_ctx.allocator_array.count = iniGetIntCorrectValue(
&ini_ctx, "shared_allocator_count",
SESSION_DEFAULT_SHARED_ALLOCATOR_COUNT,
SESSION_MIN_SHARED_ALLOCATOR_COUNT,
SESSION_MAX_SHARED_ALLOCATOR_COUNT);
session_ctx.lock_array.count = iniGetInt64CorrectValue(
&ini_ctx, "shared_lock_count",
SESSION_DEFAULT_SHARED_LOCK_COUNT,
SESSION_MIN_SHARED_LOCK_COUNT,
SESSION_MAX_SHARED_LOCK_COUNT);
session_ctx.htable.capacity = iniGetIntCorrectValue(
&ini_ctx, "hashtable_capacity",
SESSION_DEFAULT_HASHTABLE_CAPACITY,
SESSION_MIN_HASHTABLE_CAPACITY,
SESSION_MAX_HASHTABLE_CAPACITY);
g_server_session_cfg.validate_within_fresh_seconds =
iniGetIntCorrectValue(&ini_ctx, "validate_within_fresh_seconds",
SESSION_DEFAULT_VALIDATE_WITHIN_FRESH_SECONDS,
SESSION_MIN_VALIDATE_WITHIN_FRESH_SECONDS,
SESSION_MAX_VALIDATE_WITHIN_FRESH_SECONDS);
g_server_session_cfg.shared_allocator_count =
session_ctx.allocator_array.count;
g_server_session_cfg.shared_lock_count = session_ctx.lock_array.count;
g_server_session_cfg.hashtable_capacity = session_ctx.htable.capacity;
result = load_session_validate_key(&ini_ctx);
iniFreeContext(&ini_context);
return result;
}
static int load_session_config(IniFullContext *ini_ctx)
{
char *session_config_filename;
char full_session_filename[PATH_MAX];
session_config_filename = iniGetStrValue(NULL,
"session_config_filename", ini_ctx->context);
if (session_config_filename == NULL || *session_config_filename == '\0') {
logError("file: "__FILE__", line: %d, "
"config file: %s, item \"session_config_filename\" "
"not exist or empty", __LINE__, ini_ctx->filename);
return ENOENT;
}
resolve_path(ini_ctx->filename, session_config_filename,
full_session_filename, sizeof(full_session_filename));
return do_load_session_cfg(full_session_filename);
}
static int server_session_alloc_init(ServerSessionHashEntry *session,
struct fast_mblock_man *allocator)
{
session->allocator = allocator;
session->entry.fields = session + 1;
return 0;
}
static int init_allocator_array(ServerSessionAllocatorArray *array)
{
int result;
int bytes;
int element_size;
struct fast_mblock_man *mblock;
struct fast_mblock_man *end;
bytes = sizeof(struct fast_mblock_man) * array->count;
array->allocators = (struct fast_mblock_man *)fc_malloc(bytes);
if (array->allocators == NULL) {
return ENOMEM;
}
element_size = sizeof(ServerSessionHashEntry) + session_ctx.fields_size;
end = array->allocators + array->count;
for (mblock=array->allocators; mblockcount;
array->locks = (pthread_mutex_t *)fc_malloc(bytes);
if (array->locks == NULL) {
return ENOMEM;
}
end = array->locks + array->count;
for (lock=array->locks; lockcapacity;
htable->buckets = (ServerSessionHashEntry **)fc_malloc(bytes);
if (htable->buckets == NULL) {
return ENOMEM;
}
memset(htable->buckets, 0, bytes);
return 0;
}
int server_session_init_ex(IniFullContext *ini_ctx, const int fields_size,
ServerSessionCallbacks *callbacks)
{
int result;
if ((result=load_session_config(ini_ctx)) != 0) {
return result;
}
session_ctx.fields_size = fields_size;
if ((result=init_allocator_array(&session_ctx.allocator_array)) != 0) {
return result;
}
if ((result=init_lock_array(&session_ctx.lock_array)) != 0) {
return result;
}
if ((result=init_hashtable(&session_ctx.htable)) != 0) {
return result;
}
if (callbacks != NULL) {
session_ctx.callbacks = *callbacks;
} else {
session_ctx.callbacks.add_func = NULL;
session_ctx.callbacks.del_func = NULL;
}
srand(time(NULL));
return 0;
}
static inline ServerSessionHashEntry *session_htable_find(ServerSessionHashEntry
**bucket, const uint64_t session_id, ServerSessionHashEntry **prev)
{
ServerSessionHashEntry *current;
if (*bucket == NULL) {
*prev = NULL;
return NULL;
} else if ((*bucket)->entry.id_info.id == session_id) {
*prev = NULL;
return *bucket;
} else if ((*bucket)->entry.id_info.id > session_id) {
*prev = NULL;
return NULL;
}
*prev = *bucket;
while ((current=(*prev)->next) != NULL) {
if (current->entry.id_info.id == session_id) {
return current;
} else if (current->entry.id_info.id > session_id) {
return NULL;
}
*prev = current;
}
return NULL;
}
static int session_htable_insert(ServerSessionHashEntry *se, const bool replace)
{
int result;
ServerSessionHashEntry *previous;
ServerSessionHashEntry *found;
SESSION_SET_BUCKET_AND_LOCK(session_ctx.htable, se->entry.id_info.id);
PTHREAD_MUTEX_LOCK(lock);
if ((found=session_htable_find(bucket, se->entry.
id_info.id, &previous)) == NULL)
{
if (previous == NULL) {
se->next = *bucket;
*bucket = se;
} else {
se->next = previous->next;
previous->next = se;
}
result = 0;
} else {
if (replace) {
found->entry = se->entry;
fast_mblock_free_object(se->allocator, se);
result = 0;
} else {
result = EEXIST;
}
}
PTHREAD_MUTEX_UNLOCK(lock);
return result;
}
ServerSessionEntry *server_session_add_ex(const ServerSessionEntry *entry,
const bool publish, const bool persistent)
{
int result;
bool replace;
struct fast_mblock_man *allocator;
ServerSessionHashEntry *se;
allocator = session_ctx.allocator_array.allocators +
(__sync_fetch_and_add(&session_ctx.allocator_array.next, 1) %
session_ctx.allocator_array.count);
se = (ServerSessionHashEntry *)fast_mblock_alloc_object(allocator);
if (se == NULL) {
return NULL;
}
memcpy(se->entry.fields, entry->fields, session_ctx.fields_size);
if (entry->id_info.id == 0) {
replace = false;
do {
se->entry.id_info.fields.ts = g_current_time;
se->entry.id_info.fields.publish = (publish ? 1 : 0);
se->entry.id_info.fields.persistent = (persistent ? 1 : 0);
se->entry.id_info.fields.rn = (int64_t)rand() * 16384LL / RAND_MAX;
se->entry.id_info.fields.sn = __sync_add_and_fetch(
&session_ctx.sn, 1);
/*
logInfo("session_id: %"PRId64", ts: %d, publish: %d, "
"rand: %u, sn: %u", se->entry.id_info.id,
se->entry.id_info.fields.ts, publish,
se->entry.id_info.fields.rn,
se->entry.id_info.fields.sn);
*/
result = session_htable_insert(se, replace);
} while (result == EEXIST);
} else {
replace = true;
se->entry.id_info.id = entry->id_info.id;
session_htable_insert(se, replace);
}
if (session_ctx.callbacks.add_func != NULL) {
session_ctx.callbacks.add_func(&se->entry);
}
return &se->entry;
}
int server_session_get_fields(const uint64_t session_id, void *fields)
{
int result;
ServerSessionHashEntry *previous;
ServerSessionHashEntry *found;
SESSION_SET_BUCKET_AND_LOCK(session_ctx.htable, session_id);
PTHREAD_MUTEX_LOCK(lock);
if ((found=session_htable_find(bucket, session_id,
&previous)) != NULL)
{
memcpy(fields, found->entry.fields, session_ctx.fields_size);
result = 0;
} else {
result = SF_SESSION_ERROR_NOT_EXIST;
}
PTHREAD_MUTEX_UNLOCK(lock);
return result;
}
int server_session_user_priv_granted(const uint64_t session_id,
const int64_t the_priv)
{
int result;
ServerSessionHashEntry *previous;
ServerSessionHashEntry *found;
SessionSyncedFields *fields;
SESSION_SET_BUCKET_AND_LOCK(session_ctx.htable, session_id);
PTHREAD_MUTEX_LOCK(lock);
if ((found=session_htable_find(bucket, session_id,
&previous)) != NULL)
{
fields = (SessionSyncedFields *)found->entry.fields;
if ((fields->user.priv & the_priv) == the_priv) {
result = 0;
} else {
result = EPERM;
}
} else {
result = SF_SESSION_ERROR_NOT_EXIST;
}
PTHREAD_MUTEX_UNLOCK(lock);
return result;
}
int server_session_fstore_priv_granted(const uint64_t session_id,
const int the_priv)
{
int result;
ServerSessionHashEntry *previous;
ServerSessionHashEntry *found;
SessionSyncedFields *fields;
SESSION_SET_BUCKET_AND_LOCK(session_ctx.htable, session_id);
PTHREAD_MUTEX_LOCK(lock);
if ((found=session_htable_find(bucket, session_id,
&previous)) != NULL)
{
fields = (SessionSyncedFields *)found->entry.fields;
if ((fields->pool.privs.fstore & the_priv) == the_priv) {
result = 0;
} else {
result = EPERM;
}
} else {
result = SF_SESSION_ERROR_NOT_EXIST;
}
PTHREAD_MUTEX_UNLOCK(lock);
return result;
}
int server_session_fdir_priv_granted(const uint64_t session_id,
const int the_priv)
{
int result;
ServerSessionHashEntry *previous;
ServerSessionHashEntry *found;
SessionSyncedFields *fields;
SESSION_SET_BUCKET_AND_LOCK(session_ctx.htable, session_id);
PTHREAD_MUTEX_LOCK(lock);
if ((found=session_htable_find(bucket, session_id,
&previous)) != NULL)
{
fields = (SessionSyncedFields *)found->entry.fields;
if ((fields->pool.privs.fdir & the_priv) == the_priv) {
result = 0;
} else {
result = EPERM;
}
} else {
result = SF_SESSION_ERROR_NOT_EXIST;
}
PTHREAD_MUTEX_UNLOCK(lock);
return result;
}
static inline void free_hash_entry(ServerSessionHashEntry *entry)
{
if (session_ctx.callbacks.del_func != NULL) {
session_ctx.callbacks.del_func(&entry->entry);
}
fast_mblock_free_object(entry->allocator, entry);
}
int server_session_delete(const uint64_t session_id)
{
ServerSessionHashEntry *previous;
ServerSessionHashEntry *found;
SESSION_SET_BUCKET_AND_LOCK(session_ctx.htable, session_id);
PTHREAD_MUTEX_LOCK(lock);
if ((found=session_htable_find(bucket, session_id,
&previous)) != NULL)
{
if (previous == NULL) {
*bucket = (*bucket)->next;
} else {
previous->next = found->next;
}
}
PTHREAD_MUTEX_UNLOCK(lock);
if (found != NULL) {
free_hash_entry(found);
return 0;
} else {
return ENOENT;
}
}
#define SERVER_SESSION_ADD_TO_CHAIN(chain, node) \
if (chain.tail == NULL) { \
chain.head = node; \
} else { \
chain.tail->next = node; \
} \
chain.tail = node
void server_session_clear()
{
typedef struct {
ServerSessionHashEntry *head;
ServerSessionHashEntry *tail;
} ServerSessionHashChain;
ServerSessionHashEntry *current;
ServerSessionHashEntry *deleted;
ServerSessionHashEntry **bucket;
ServerSessionHashEntry **end;
ServerSessionHashChain keep;
ServerSessionHashChain remove;
pthread_mutex_t *lock;
int64_t keep_count;
int64_t remove_count;
keep_count = remove_count = 0;
current = NULL;
end = session_ctx.htable.buckets + session_ctx.htable.capacity;
for (bucket=session_ctx.htable.buckets; bucketentry.id_info.fields.persistent) {
SERVER_SESSION_ADD_TO_CHAIN(keep, current);
keep_count++;
} else {
SERVER_SESSION_ADD_TO_CHAIN(remove, current);
remove_count++;
}
current = current->next;
} while (current != NULL);
*bucket = keep.head;
if (keep.tail != NULL) {
keep.tail->next = NULL;
}
current = remove.head;
if (remove.tail != NULL) {
remove.tail->next = NULL;
}
}
PTHREAD_MUTEX_UNLOCK(lock);
while (current != NULL) {
deleted = current;
current = current->next;
free_hash_entry(deleted);
}
}
if (keep_count > 0 || remove_count > 0) {
char keep_buff[256];
char remove_buff[256];
if (keep_count > 0) {
sprintf(keep_buff, "%"PRId64" sessions persisted", keep_count);
} else {
*keep_buff = '\0';
}
if (remove_count > 0) {
sprintf(remove_buff, "%"PRId64" sessions cleared", remove_count);
} else {
*remove_buff = '\0';
}
if (keep_count > 0 && remove_count > 0) {
logInfo("file: "__FILE__", line: %d, "
"%s, %s", __LINE__, keep_buff, remove_buff);
} else {
logInfo("file: "__FILE__", line: %d, "
"%s", __LINE__, (*keep_buff != '\0') ?
keep_buff : remove_buff);
}
}
}
================================================
FILE: src/auth/common/server_session.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#ifndef _FCFS_AUTH_SERVER_SESSION_H
#define _FCFS_AUTH_SERVER_SESSION_H
#include "fastcommon/ini_file_reader.h"
#include "auth_types.h"
#define FCFS_AUTH_SESSION_OP_TYPE_CREATE 'C'
#define FCFS_AUTH_SESSION_OP_TYPE_REMOVE 'R'
typedef struct server_session_config {
int shared_allocator_count;
int shared_lock_count;
int hashtable_capacity;
int validate_within_fresh_seconds;
string_t validate_key;
string_t validate_key_filename;
unsigned char validate_key_buff[FCFS_AUTH_PASSWD_LEN];
} ServerSessionConfig;
typedef union server_session_id_info {
uint64_t id;
struct {
unsigned int ts;
bool publish : 1;
bool persistent : 1;
unsigned int rn : 14;
unsigned int sn : 16;
} fields;
} ServerSessionIdInfo;
typedef struct session_synced_fields {
struct {
int64_t id;
int64_t priv;
} user;
struct {
int64_t id;
bool available;
FCFSAuthSPoolPriviledges privs;
} pool;
} SessionSyncedFields;
typedef struct server_session_entry {
ServerSessionIdInfo id_info;
void *fields;
} ServerSessionEntry;
typedef struct server_session_hash_entry {
ServerSessionEntry entry;
struct fast_mblock_man *allocator; //for free
struct server_session_hash_entry *next; //for hashtable
} ServerSessionHashEntry;
typedef void (*server_session_callback)(ServerSessionEntry *session);
typedef struct server_session_callbacks {
server_session_callback add_func;
server_session_callback del_func;
} ServerSessionCallbacks;
#define FCFS_AUTH_SERVER_SESSION_BY_FIELDS(fields) \
&((ServerSessionHashEntry *)fields - 1)->entry
#ifdef __cplusplus
extern "C" {
#endif
extern ServerSessionConfig g_server_session_cfg;
#define server_session_init(ini_ctx) \
server_session_init_ex(ini_ctx, sizeof(SessionSyncedFields), NULL)
#define server_session_cfg_to_string(buff, size) \
server_session_cfg_to_string_ex(buff, size, false)
#define server_session_add(entry, publish) \
server_session_add_ex(entry, publish, false)
int server_session_init_ex(IniFullContext *ini_ctx, const int fields_size,
ServerSessionCallbacks *callbacks);
void server_session_cfg_to_string_ex(char *buff,
const int size, const bool output_all);
ServerSessionEntry *server_session_add_ex(const ServerSessionEntry *entry,
const bool publish, const bool persistent);
int server_session_get_fields(const uint64_t session_id, void *fields);
int server_session_user_priv_granted(const uint64_t session_id,
const int64_t the_priv);
int server_session_fstore_priv_granted(const uint64_t session_id,
const int the_priv);
int server_session_fdir_priv_granted(const uint64_t session_id,
const int the_priv);
int server_session_delete(const uint64_t session_id);
void server_session_clear();
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/conf/auth.conf
================================================
# enable / disable authentication
# default value is false
auth_enabled = false
# the username for login
# default value is admin
username = admin
# the secret key filename of the user
# variable ${username} will be replaced with the value of username
# default value is keys/${username}.key
secret_key_filename = keys/${username}.key
# the config filename of auth client
client_config_filename = client.conf
================================================
FILE: src/auth/conf/client.conf
================================================
# the base path to store log files
base_path = /opt/fastcfs/auth
# config the cluster servers
cluster_config_filename = cluster.conf
================================================
FILE: src/auth/conf/cluster.conf
================================================
[master-election]
# the quorum for master election
# set quorum to majority to avoid brain-split
# value list:
## any: no requirement
## majority: more than half
## auto: set to majority when the number of nodes is odd,
## otherwise set to any
# default value is auto
quorum = auto
# if enable vote node when the number of servers is even
# the default value is false
vote_node_enabled = false
# the cluster config filename of the vote node
# this parameter is valid when vote_node_enabled is true
vote_node_cluster_filename = ../vote/cluster.conf
[group-cluster]
# the default cluster port
port = 31011
[group-service]
# the default service port
port = 31012
## Important:server group mark, don't modify this line.
# config a server
# section format: [server-$id]
# server id is a 32 bits natural number (1, 2, 3 etc.),
[server-1]
# format: host[:port]
# host can be an IP address or a hostname, IPv6 is supported
# IP address is recommended
# can occur more than once
host = 172.16.168.128
================================================
FILE: src/auth/conf/full/auth.conf
================================================
# enable / disable authentication
# default value is false
auth_enabled = false
# the username for login
# default value is admin
username = admin
# the secret key filename of the user
# variable ${username} will be replaced with the value of username
# default value is keys/${username}.key
secret_key_filename = keys/${username}.key
# the config filename of auth client
client_config_filename = client.conf
================================================
FILE: src/auth/conf/full/client.conf
================================================
# connect timeout in seconds
# default value is 10
# Note: in the intranet network (LAN), 10 seconds is enough.
connect_timeout = 10
# network timeout in seconds
# default value is 60
network_timeout = 60
# the base path to store log files
base_path = /opt/fastcfs/auth
# config the cluster servers
cluster_config_filename = cluster.conf
#standard log level as syslog, case insensitive, value list:
### emerg for emergency
### alert
### crit for critical
### error
### warn for warning
### notice
### info
### debug
log_level = info
================================================
FILE: src/auth/conf/full/cluster.conf
================================================
[master-election]
# the quorum for master election
# set quorum to majority to avoid brain-split
# value list:
## any: no requirement
## majority: more than half
## auto: set to majority when the number of nodes is odd,
## otherwise set to any
# default value is auto
quorum = auto
# the timeout to determinate master lost
# the default value is 3 seconds
master_lost_timeout = 3
# the max wait time for master election
# this parameter is for the master restart
# the default value is 5 seconds
max_wait_time = 5
# if enable vote node when the number of servers is even
# the default value is false
vote_node_enabled = false
# the cluster config filename of the vote node
# this parameter is valid when vote_node_enabled is true
vote_node_cluster_filename = ../vote/cluster.conf
[group-cluster]
# the default cluster port
port = 31011
[group-service]
# the default service port
port = 31012
## Important:server group mark, don't modify this line.
# config a server
# section format: [server-$id]
# server id is a 32 bits natural number (1, 2, 3 etc.),
[server-1]
# format: host[:port]
# host can be an IP address or a hostname, IPv6 is supported
# IP address is recommended
# can occur more than once
host = 172.16.168.128
================================================
FILE: src/auth/conf/full/server.conf
================================================
# connect timeout in seconds
# default value is 10
# Note: in the intranet network (LAN), 10 seconds is enough.
# do NOT set to 1 second because of time accuracy!
connect_timeout = 10
# network timeout in seconds for send and recv
# default value is 60
network_timeout = 60
# the base path to store log files
# this path must be exist
base_path = /opt/fastcfs/auth
# max concurrent connections this server support
# you should set this parameter larger, eg. 10240
# default value is 256
max_connections = 10240
# the min network buff size
# default value 8KB
min_buff_size = 64KB
# the max network buff size
# default value 128KB
max_buff_size = 256KB
# max pkg size
# default value is 16K
max_pkg_size = 256KB
# if io_uring send with zero copy when Linux kernel version >= 5.19
# set to true when the NIC support zero copy
# can be overwritten in sections: [cluster] and [service]
# default value is true
use_send_zc = true
# TCP quick ack for Linux (setsockopt with TCP_QUICKACK option)
# default value is true
tcp_quick_ack = true
# config the cluster servers and groups
cluster_config_filename = cluster.conf
# the session config filename
session_config_filename = session.conf
#standard log level as syslog, case insensitive, value list:
### emerg for emergency
### alert
### crit for critical
### error
### warn for warning
### notice
### info
### debug
log_level = info
#unix group name to run this program,
#not set (empty) means run by the group of current user
run_by_group=
#unix username to run this program,
#not set (empty) means run by current user
run_by_user =
# thread stack size, should >= 64KB
# default value is 256KB
thread_stack_size = 256KB
# NOTE: following global parameters for error log and slow log
# which can be overwritten in [error-log] and [slow-log] sections
# sync log buff to disk every interval seconds
# default value is 1 seconds
sync_log_buff_interval = 1
# if rotate the log file every day
# set to true for rotate the log file anyway at the rotate time
# default value is true
log_file_rotate_everyday = true
# the time to rotate the log file, format is Hour:Minute
# Hour from 0 to 23, Minute from 0 to 59
# valid only when log_file_rotate_everyday is true
# default value is 00:00
log_file_rotate_time = 00:00
# if compress the old log file by gzip
# default value is false
log_file_compress_old = false
# compress the log file days before
# default value is 1
log_file_compress_days_before = 7
# rotate the log file when the log file exceeds this size
# 0 means never rotates log file by log file size
# default value is 0
log_file_rotate_on_size = 0
# keep days of the log files
# 0 means do not delete the old log files
# default value is 15
log_file_keep_days = 15
# the time to delete the old log files, format is Hour:Minute
# Hour from 0 to 23, Minute from 0 to 59
# valid only when log_file_keep_days > 0
# default value is 01:30
log_file_delete_old_time = 01:30
[error-log]
# global log parameters can be overwritten here for error log
[slow-log]
# global log parameters can be overwritten here for slow log
# if enable the slow log
# default value is false
enabled = true
# the filename prefix of the slow log
# default value is slow
filename_prefix = slow
# log the request to the slow log whose response time exceeds this parameter
# default value is 100ms
log_slower_than_ms = 50
[cluster]
# bind an address of this host
# empty for bind all addresses of this host
bind_addr =
# the listen port
port = 31011
# the accept thread count
# default value is 1 which is recommended
accept_threads = 1
# the network thread count
# these threads deal network io
# dispatched by the incoming socket fd
# default value is 4
work_threads = 4
# if io_uring send with zero copy when Linux kernel version >= 5.19
# set to true when the NIC support zero copy
# default value set by global config
use_send_zc = true
[service]
bind_addr =
port = 31012
accept_threads = 1
work_threads = 4
use_send_zc = true
[admin-generate]
# the generate mode for creating the admin user when not exist, value list:
## first: the new created user will be the first user (no other users)
## always: always create this admin user when not exist
# default value is first
mode = first
# the admin user to auto generate
# you should set this parameter to what you want before authd first run
# default value is admin
username = admin
# the filename of the secret key which can be absolute path or relative path
# the relative path based on the path of this config file,
# such as /etc/fastcfs/auth/server.conf
# ${username} will be replaced with the value of above "username" parameter
# Note: this secret key file will be auto generated, do NOT modify it!
secret_key_filename = keys/${username}.key
[pool-generate]
# the initial/first value for auto increment id referred as ${auto_id}
# eg. set 100001 to generate six digital id (the first generated id is 100001)
# default value is 1
auto_id_initial = 1
# the pool name template can contain ${auto_id} for creating pool,
# such as pool-${auto_id}
# default value is ${auto_id}
pool_name_template = ${auto_id}
[FastDIR]
# config the FastDIR client config filename
client_config_filename = ../fdir/client.conf
# the interval to refresh/fetch the usage (used bytes) of the storage pools
# unit: seconds
# default value is 3
pool_usage_refresh_interval = 3
================================================
FILE: src/auth/conf/full/session.conf
================================================
# the capacity (bucket count) of session hashtable
# default value is 10949
hashtable_capacity = 10949
# the shared allocators for hashtabe entry
# NO more than the CPU cores is recommended
# default value is 11
shared_allocator_count = 11
# the shared locks for session hashtable
# default value is 163
shared_lock_count = 163
# the fresh seconds/threshold to validate session from the auth server
# this parameter solves the problem of the new created session
# synchronization delay
#
# if the session does not exist in local and this session generated
# within X seconds, then request the auth server to validate the session
#
# default value is 5
validate_within_fresh_seconds = 5
# the secret key filename for session validation
# the file content is 32 bytes hex characters
validate_key_filename = keys/session_validate.key
================================================
FILE: src/auth/conf/keys/session_validate.key
================================================
dd7702749e369c7e8139d6ca3bf443ce
================================================
FILE: src/auth/conf/server.conf
================================================
# the base path to store log files
# this path must be exist
base_path = /opt/fastcfs/auth
# max concurrent connections this server support
# you should set this parameter larger, eg. 10240
# default value is 256
max_connections = 10240
# config the cluster servers and groups
cluster_config_filename = cluster.conf
# the session config filename
session_config_filename = session.conf
[cluster]
# the listen port
port = 31011
# the network thread count
# these threads deal network io
# dispatched by the incoming socket fd
# default value is 4
work_threads = 4
[service]
# the listen port
port = 31012
# the network thread count
# these threads deal network io
# dispatched by the incoming socket fd
# default value is 4
work_threads = 4
[admin-generate]
# the generate mode for creating the admin user when not exist, value list:
## first: the new created user will be the first user (no other users)
## always: always create this admin user when not exist
# default value is first
mode = first
# the admin user to auto generate
# you should set this parameter to what you want before authd first run
# default value is admin
username = admin
# the filename of the secret key which can be absolute path or relative path
# the relative path based on the path of this config file,
# such as /etc/fastcfs/auth/server.conf
# ${username} will be replaced with the value of above "username" parameter
# Note: this secret key file will be auto generated, do NOT modify it!
secret_key_filename = keys/${username}.key
[FastDIR]
# config the FastDIR client config filename
client_config_filename = ../fdir/client.conf
================================================
FILE: src/auth/conf/session.conf
================================================
# the secret key filename for session validation
# the file content is 32 bytes hex characters
validate_key_filename = keys/session_validate.key
================================================
FILE: src/auth/server/Makefile.in
================================================
.SUFFIXES: .c .o .lo
COMPILE = $(CC) $(CFLAGS)
INC_PATH = -I.. -I../common -I../../include
LIB_PATH = $(LIBS) -lfdirclient -lfastcommon -lserverframe -lfcfsauthclient -lfcfsvoteclient
TARGET_PATH = $(TARGET_PREFIX)/bin
STATIC_OBJS = ../common/auth_global.o ../common/auth_proto.o \
../common/auth_func.o ../common/server_session.o \
db/dao/dao.o db/dao/func.o db/dao/user.o \
db/dao/storage_pool.o db/dao/granted_pool.o \
db/auth_db.o db/pool_usage_updater.o server_global.o \
server_func.o common_handler.o service_handler.o \
cluster_handler.o session_subscribe.o cluster_relationship.o \
cluster_info.o
ALL_PRGS = fcfs_authd
all: $(STATIC_OBJS) $(ALL_PRGS)
$(ALL_PRGS): $(STATIC_OBJS)
.o:
$(COMPILE) -o $@ $< $(STATIC_OBJS) $(LIB_PATH) $(INC_PATH)
.c:
$(COMPILE) -o $@ $< $(STATIC_OBJS) $(LIB_PATH) $(INC_PATH)
.c.o:
$(COMPILE) -c -o $@ $< $(INC_PATH)
install:
mkdir -p $(TARGET_PATH)
cp -f $(ALL_PRGS) $(TARGET_PATH)
clean:
rm -f $(STATIC_OBJS) $(ALL_PRGS)
================================================
FILE: src/auth/server/cluster_handler.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
//cluster_handler.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "fastcommon/logger.h"
#include "fastcommon/sockopt.h"
#include "fastcommon/shared_func.h"
#include "fastcommon/pthread_func.h"
#include "fastcommon/sched_thread.h"
#include "fastcommon/ioevent_loop.h"
#include "sf/sf_util.h"
#include "sf/sf_func.h"
#include "sf/sf_nio.h"
#include "sf/sf_global.h"
#include "common/auth_proto.h"
#include "db/auth_db.h"
#include "server_global.h"
#include "server_func.h"
#include "session_subscribe.h"
#include "cluster_info.h"
#include "cluster_relationship.h"
#include "common_handler.h"
#include "cluster_handler.h"
int cluster_handler_init()
{
return 0;
}
int cluster_handler_destroy()
{
return 0;
}
int cluster_recv_timeout_callback(struct fast_task_info *task)
{
if (SERVER_TASK_TYPE == AUTH_SERVER_TASK_TYPE_RELATIONSHIP &&
CLUSTER_PEER != NULL)
{
logWarning("file: "__FILE__", line: %d, "
"cluster client ip: %s, server id: %d, recv timeout",
__LINE__, task->client_ip, CLUSTER_PEER->server->id);
return ETIMEDOUT;
} else if (SERVER_TASK_TYPE == AUTH_SERVER_TASK_TYPE_SUBSCRIBE &&
SESSION_SUBSCRIBER != NULL)
{
logWarning("file: "__FILE__", line: %d, "
"subscribe client ip: %s, recv timeout",
__LINE__, task->client_ip);
return ETIMEDOUT;
}
return 0;
}
static void session_subscriber_cleanup(AuthServerContext *server_ctx,
ServerSessionSubscriber *subscriber)
{
session_subscribe_unregister(subscriber);
if (__sync_bool_compare_and_swap(&subscriber->nio.in_queue, 1, 0)) {
locked_list_del(&subscriber->nio.dlink,
&server_ctx->cluster.subscribers);
}
session_subscribe_release(subscriber);
}
void cluster_task_finish_cleanup(struct fast_task_info *task)
{
char formatted_ip[FORMATTED_IP_SIZE];
switch (SERVER_TASK_TYPE) {
case AUTH_SERVER_TASK_TYPE_RELATIONSHIP:
if (CLUSTER_PEER != NULL) {
CLUSTER_PEER->is_online = false;
cluster_relationship_add_to_inactive_sarray(CLUSTER_PEER);
CLUSTER_PEER = NULL;
} else {
logError("file: "__FILE__", line: %d, "
"mistake happen! task: %p, SERVER_TASK_TYPE: %d, "
"CLUSTER_PEER is NULL", __LINE__, task,
SERVER_TASK_TYPE);
}
SERVER_TASK_TYPE = SF_SERVER_TASK_TYPE_NONE;
break;
case AUTH_SERVER_TASK_TYPE_SUBSCRIBE:
if (SESSION_SUBSCRIBER != NULL) {
session_subscriber_cleanup(SERVER_CTX, SESSION_SUBSCRIBER);
SESSION_SUBSCRIBER = NULL;
}
format_ip_address(task->client_ip, formatted_ip);
logInfo("file: "__FILE__", line: %d, "
"session subscriber %s:%u offline", __LINE__,
formatted_ip, task->port);
SERVER_TASK_TYPE = SF_SERVER_TASK_TYPE_NONE;
break;
default:
break;
}
sf_task_finish_clean_up(task);
}
void cluster_subscriber_queue_push_ex(ServerSessionSubscriber *subscriber,
const bool notify)
{
AuthServerContext *server_ctx;
if (__sync_bool_compare_and_swap(&subscriber->nio.in_queue, 0, 1)) {
server_ctx = (AuthServerContext *)subscriber->
nio.task->thread_data->arg;
locked_list_add_tail(&subscriber->nio.dlink,
&server_ctx->cluster.subscribers);
if (notify) {
ioevent_notify_thread(subscriber->nio.task->thread_data);
}
}
}
static inline ServerSessionSubscriber *cluster_subscriber_queue_pop(
AuthServerContext *server_context)
{
ServerSessionSubscriber *subscriber;
PTHREAD_MUTEX_LOCK(&server_context->cluster.subscribers.lock);
subscriber = fc_list_first_entry(&server_context->cluster.subscribers.head,
ServerSessionSubscriber, nio.dlink);
if (subscriber != NULL) {
fc_list_del_init(&subscriber->nio.dlink);
__sync_bool_compare_and_swap(&subscriber->nio.in_queue, 1, 0);
}
PTHREAD_MUTEX_UNLOCK(&server_context->cluster.subscribers.lock);
return subscriber;
}
static int cluster_deal_session_subscribe(struct fast_task_info *task)
{
FCFSAuthProtoSessionSubscribeReq *req;
const DBUserInfo *dbuser;
char formatted_ip[FORMATTED_IP_SIZE];
string_t username;
string_t passwd;
int result;
if ((result=server_check_min_body_length(sizeof(
FCFSAuthProtoSessionSubscribeReq) + 1)) != 0)
{
return result;
}
req = (FCFSAuthProtoSessionSubscribeReq *)REQUEST.body;
FC_SET_STRING_EX(username, req->up_pair.username.str,
req->up_pair.username.len);
FC_SET_STRING_EX(passwd, req->up_pair.passwd,
FCFS_AUTH_PASSWD_LEN);
if ((result=server_expect_body_length(
sizeof(FCFSAuthProtoSessionSubscribeReq)
+ username.len)) != 0)
{
return result;
}
if (SERVER_TASK_TYPE != SF_SERVER_TASK_TYPE_NONE) {
RESPONSE.error.length = sprintf(RESPONSE.error.message,
"task type: %d != %d", SERVER_TASK_TYPE,
SF_SERVER_TASK_TYPE_NONE);
return EEXIST;
}
if (!((dbuser=adb_user_get(SERVER_CTX, &username)) != NULL &&
fc_string_equal(&dbuser->user.passwd, &passwd)))
{
RESPONSE.error.length = sprintf(RESPONSE.error.message,
"user login fail, username or password not correct");
return EPERM;
}
if ((dbuser->user.priv & FCFS_AUTH_USER_PRIV_SUBSCRIBE_SESSION) == 0) {
RESPONSE.error.length = sprintf(RESPONSE.error.message,
"username: %.*s, permission denied for session "
"subscription", username.len, username.str);
return EPERM;
}
if ((SESSION_SUBSCRIBER=session_subscribe_alloc()) == NULL) {
RESPONSE.error.length = sprintf(RESPONSE.error.message,
"session subscribe register fail");
return ENOMEM;
}
SESSION_SUBSCRIBER->nio.task = task;
session_subscribe_register(SESSION_SUBSCRIBER);
if (!fc_queue_empty(&SESSION_SUBSCRIBER->queue)) {
cluster_subscriber_queue_push_ex(SESSION_SUBSCRIBER, false);
}
format_ip_address(task->client_ip, formatted_ip);
logInfo("file: "__FILE__", line: %d, "
"session subscriber %s:%u joined", __LINE__,
formatted_ip, task->port);
SERVER_TASK_TYPE = AUTH_SERVER_TASK_TYPE_SUBSCRIBE;
RESPONSE.header.cmd = FCFS_AUTH_SERVICE_PROTO_SESSION_SUBSCRIBE_RESP;
return 0;
}
static int session_validate(const int64_t session_id,
const FCFSAuthValidatePriviledgeType priv_type,
const int64_t pool_id, const int64_t priv_required)
{
int result;
int64_t session_priv;
ServerSessionFields fields;
if ((result=server_session_get_fields(session_id, &fields)) != 0) {
return result;
}
switch (priv_type) {
case fcfs_auth_validate_priv_type_user:
session_priv = (fields.dbuser != NULL) ? fields.dbuser->
user.priv : (FCFS_AUTH_USER_PRIV_MONITOR_CLUSTER |
FCFS_AUTH_USER_PRIV_SUBSCRIBE_SESSION);
break;
case fcfs_auth_validate_priv_type_pool_fdir:
/*
//TODO
if (fields.dbpool != NULL) {
if (fields.dbpool->pool.id != pool_id) {
return EACCES;
}
}
*/
session_priv = fields.pool_privs.fdir;
break;
case fcfs_auth_validate_priv_type_pool_fstore:
session_priv = fields.pool_privs.fstore;
break;
default:
session_priv = 0;
break;
}
/*
logInfo("session_id: %"PRId64", session_priv: %"PRId64", "
"priv_required: %"PRId64", check result: %d",
session_id, session_priv, priv_required,
((session_priv & priv_required) == priv_required) ? 0 : EPERM);
*/
return ((session_priv & priv_required) == priv_required) ? 0 : EPERM;
}
static int cluster_deal_session_validate(struct fast_task_info *task)
{
FCFSAuthProtoSessionValidateReq *req;
FCFSAuthProtoSessionValidateResp *resp;
int64_t session_id;
int64_t pool_id;
string_t validate_key;
int64_t priv_required;
FCFSAuthValidatePriviledgeType priv_type;
int result;
if ((result=server_expect_body_length(sizeof(*req))) != 0) {
return result;
}
req = (FCFSAuthProtoSessionValidateReq *)REQUEST.body;
session_id = buff2long(req->session_id);
FC_SET_STRING_EX(validate_key, req->validate_key, FCFS_AUTH_PASSWD_LEN);
priv_type = req->priv_type;
pool_id = buff2long(req->pool_id);
priv_required = buff2long(req->priv_required);
if (!fc_string_equal(&validate_key, &g_server_session_cfg.validate_key)) {
RESPONSE.error.length = sprintf(RESPONSE.error.message,
"session validate key not correct");
return EACCES;
}
if ((result=session_validate(session_id, priv_type, pool_id,
priv_required)) == SF_SESSION_ERROR_NOT_EXIST)
{
RESPONSE.error.length = sprintf(RESPONSE.error.message,
"session id: %"PRId64" not exist", session_id);
TASK_CTX.common.log_level = LOG_WARNING;
return result;
}
resp = (FCFSAuthProtoSessionValidateResp *)SF_PROTO_SEND_BODY(task);
int2buff(result, resp->result);
RESPONSE.header.body_len = sizeof(*resp);
RESPONSE.header.cmd = FCFS_AUTH_SERVICE_PROTO_SESSION_VALIDATE_RESP;
TASK_ARG->context.common.response_done = true;
return 0;
}
static int cluster_check_config_sign(struct fast_task_info *task,
const int server_id, const char *config_sign)
{
if (memcmp(config_sign, CLUSTER_CONFIG_SIGN_BUF,
SF_CLUSTER_CONFIG_SIGN_LEN) != 0)
{
char peer_hex[2 * SF_CLUSTER_CONFIG_SIGN_LEN + 1];
char my_hex[2 * SF_CLUSTER_CONFIG_SIGN_LEN + 1];
bin2hex(config_sign, SF_CLUSTER_CONFIG_SIGN_LEN, peer_hex);
bin2hex((const char *)CLUSTER_CONFIG_SIGN_BUF,
SF_CLUSTER_CONFIG_SIGN_LEN, my_hex);
RESPONSE.error.length = sprintf(RESPONSE.error.message,
"server #%d 's cluster config md5: %s != mine: %s",
server_id, peer_hex, my_hex);
return EFAULT;
}
return 0;
}
static int cluster_deal_get_server_status(struct fast_task_info *task)
{
int result;
int server_id;
FCFSAuthProtoGetServerStatusReq *req;
FCFSAuthProtoGetServerStatusResp *resp;
if ((result=server_expect_body_length(sizeof(
FCFSAuthProtoGetServerStatusReq))) != 0)
{
return result;
}
req = (FCFSAuthProtoGetServerStatusReq *)REQUEST.body;
server_id = buff2int(req->server_id);
if ((result=cluster_check_config_sign(task, server_id,
req->config_sign)) != 0)
{
return result;
}
resp = (FCFSAuthProtoGetServerStatusResp *)SF_PROTO_SEND_BODY(task);
resp->is_master = MYSELF_IS_MASTER;
int2buff(CLUSTER_MY_SERVER_ID, resp->server_id);
RESPONSE.header.body_len = sizeof(FCFSAuthProtoGetServerStatusResp);
RESPONSE.header.cmd = FCFS_AUTH_CLUSTER_PROTO_GET_SERVER_STATUS_RESP;
TASK_CTX.common.response_done = true;
return 0;
}
static int cluster_deal_join_master(struct fast_task_info *task)
{
int result;
int server_id;
FCFSAuthProtoJoinMasterReq *req;
FCFSAuthClusterServerInfo *peer;
if ((result=server_expect_body_length(sizeof(
FCFSAuthProtoJoinMasterReq))) != 0)
{
return result;
}
req = (FCFSAuthProtoJoinMasterReq *)REQUEST.body;
server_id = buff2int(req->server_id);
peer = fcfs_auth_get_server_by_id(server_id);
if (peer == NULL) {
RESPONSE.error.length = sprintf(
RESPONSE.error.message,
"peer server id: %d not exist", server_id);
return ENOENT;
}
if ((result=cluster_check_config_sign(task, server_id,
req->config_sign)) != 0)
{
return result;
}
if (CLUSTER_MYSELF_PTR != CLUSTER_MASTER_ATOM_PTR &&
CLUSTER_MYSELF_PTR != CLUSTER_NEXT_MASTER)
{
RESPONSE.error.length = sprintf(
RESPONSE.error.message,
"i am not master");
return SF_RETRIABLE_ERROR_NOT_MASTER;
}
if (peer == CLUSTER_MYSELF_PTR) {
RESPONSE.error.length = sprintf(
RESPONSE.error.message,
"can't join self");
return EINVAL;
}
if (CLUSTER_PEER != NULL) {
RESPONSE.error.length = sprintf(
RESPONSE.error.message,
"peer server id: %d already joined", server_id);
return EEXIST;
}
SERVER_TASK_TYPE = AUTH_SERVER_TASK_TYPE_RELATIONSHIP;
CLUSTER_PEER = peer;
CLUSTER_PEER->is_online = true;
cluster_relationship_remove_from_inactive_sarray(peer);
return 0;
}
static int cluster_deal_ping_master(struct fast_task_info *task)
{
int result;
if ((result=server_expect_body_length(0)) != 0) {
return result;
}
if (CLUSTER_PEER == NULL) {
RESPONSE.error.length = sprintf(
RESPONSE.error.message,
"please join first");
return EINVAL;
}
if (CLUSTER_MYSELF_PTR != CLUSTER_MASTER_ATOM_PTR &&
CLUSTER_MYSELF_PTR != CLUSTER_NEXT_MASTER)
{
RESPONSE.error.length = sprintf(
RESPONSE.error.message,
"i am not master");
return SF_RETRIABLE_ERROR_NOT_MASTER;
}
RESPONSE.header.cmd = FCFS_AUTH_CLUSTER_PROTO_PING_MASTER_RESP;
return 0;
}
static int cluster_deal_next_master(struct fast_task_info *task)
{
int result;
int master_id;
FCFSAuthClusterServerInfo *master;
if ((result=server_expect_body_length(4)) != 0) {
return result;
}
if (CLUSTER_MYSELF_PTR == CLUSTER_MASTER_ATOM_PTR) {
RESPONSE.error.length = sprintf(
RESPONSE.error.message,
"i am already master");
cluster_relationship_trigger_reselect_master();
return EEXIST;
}
master_id = buff2int(REQUEST.body);
master = fcfs_auth_get_server_by_id(master_id);
if (master == NULL) {
RESPONSE.error.length = sprintf(
RESPONSE.error.message,
"master server id: %d not exist", master_id);
return ENOENT;
}
if (REQUEST.header.cmd == FCFS_AUTH_CLUSTER_PROTO_PRE_SET_NEXT_MASTER) {
return cluster_relationship_pre_set_master(master);
} else {
return cluster_relationship_commit_master(master);
}
}
static int cluster_process(struct fast_task_info *task)
{
int result;
int cmd;
cmd = REQUEST.header.cmd;
if (!MYSELF_IS_MASTER) {
if (cmd == FCFS_AUTH_SERVICE_PROTO_SESSION_SUBSCRIBE_REQ) {
RESPONSE.error.length = sprintf(
RESPONSE.error.message,
"i am not master");
return SF_RETRIABLE_ERROR_NOT_MASTER;
}
if (cmd == FCFS_AUTH_SERVICE_PROTO_SESSION_VALIDATE_REQ) {
if (CLUSTER_MYSELF_PTR != CLUSTER_NEXT_MASTER) {
RESPONSE.error.length = sprintf(
RESPONSE.error.message,
"i am not the next master");
return SF_RETRIABLE_ERROR_NOT_MASTER;
}
}
}
switch (cmd) {
case SF_PROTO_ACTIVE_TEST_REQ:
if (SERVER_TASK_TYPE == AUTH_SERVER_TASK_TYPE_SUBSCRIBE &&
!MYSELF_IS_MASTER)
{
RESPONSE.error.length = sprintf(
RESPONSE.error.message,
"i am not master");
return SF_RETRIABLE_ERROR_NOT_MASTER;
}
RESPONSE.header.cmd = SF_PROTO_ACTIVE_TEST_RESP;
return sf_proto_deal_active_test(task, &REQUEST, &RESPONSE);
case FCFS_AUTH_SERVICE_PROTO_SESSION_SUBSCRIBE_REQ:
return cluster_deal_session_subscribe(task);
case FCFS_AUTH_SERVICE_PROTO_SESSION_VALIDATE_REQ:
return cluster_deal_session_validate(task);
case FCFS_AUTH_CLUSTER_PROTO_GET_SERVER_STATUS_REQ:
return cluster_deal_get_server_status(task);
case FCFS_AUTH_CLUSTER_PROTO_PRE_SET_NEXT_MASTER:
case FCFS_AUTH_CLUSTER_PROTO_COMMIT_NEXT_MASTER:
return cluster_deal_next_master(task);
case FCFS_AUTH_CLUSTER_PROTO_JOIN_MASTER:
return cluster_deal_join_master(task);
case FCFS_AUTH_CLUSTER_PROTO_PING_MASTER_REQ:
return cluster_deal_ping_master(task);
case FCFS_AUTH_SERVICE_PROTO_GET_MASTER_REQ:
if ((result=fcfs_auth_deal_get_master(task,
CLUSTER_GROUP_INDEX)) == 0)
{
RESPONSE.header.cmd = FCFS_AUTH_SERVICE_PROTO_GET_MASTER_RESP;
}
return result;
case SF_SERVICE_PROTO_GET_LEADER_REQ:
if ((result=fcfs_auth_deal_get_master(task,
CLUSTER_GROUP_INDEX)) == 0)
{
RESPONSE.header.cmd = SF_SERVICE_PROTO_GET_LEADER_RESP;
}
return result;
default:
RESPONSE.error.length = sprintf(RESPONSE.error.message,
"unkown cmd: %d", REQUEST.header.cmd);
return -EINVAL;
}
}
int cluster_deal_task(struct fast_task_info *task, const int stage)
{
int result;
if (stage == SF_NIO_STAGE_CONTINUE) {
if (task->continue_callback != NULL) {
result = task->continue_callback(task);
} else {
result = RESPONSE_STATUS;
if (result == TASK_STATUS_CONTINUE) {
logError("file: "__FILE__", line: %d, "
"unexpect status: %d", __LINE__, result);
result = EBUSY;
}
}
} else {
sf_proto_init_task_context(task, &TASK_CTX.common);
result = cluster_process(task);
}
if (result == TASK_STATUS_CONTINUE) {
return 0;
} else {
RESPONSE_STATUS = result;
return sf_proto_deal_task_done(task, "cluster", &TASK_CTX.common);
}
}
static int cluster_deal_queue(AuthServerContext *server_context,
ServerSessionSubscriber *subscriber)
{
struct fast_task_info *task;
struct fc_queue_info qinfo;
ServerSessionSubscribeEntry *previous;
ServerSessionSubscribeEntry *entry;
FCFSAuthProtoHeader *proto_header;
FCFSAuthProtoSessionPushRespBodyHeader *body_header;
FCFSAuthProtoSessionPushRespBodyPart *body_part;
char *p;
char *end;
int count;
int result;
task = subscriber->nio.task;
if (ioevent_is_canceled(task) || !sf_nio_task_send_done(
subscriber->nio.task))
{
return EAGAIN;
}
fc_queue_try_pop_to_queue(&subscriber->queue, &qinfo);
if (qinfo.head == NULL) {
return 0;
}
previous = NULL;
entry = (ServerSessionSubscribeEntry *)qinfo.head;
proto_header = (FCFSAuthProtoHeader *)task->send.ptr->data;
body_header = (FCFSAuthProtoSessionPushRespBodyHeader *)
(proto_header + 1);
p = (char *)(body_header + 1);
end = SF_SEND_BUFF_END(task);
count = 0;
while (entry != NULL) {
body_part = (FCFSAuthProtoSessionPushRespBodyPart *)p;
if (p + sizeof(FCFSAuthProtoSessionPushRespBodyPart) +
sizeof(FCFSAuthProtoSessionPushEntry) > end)
{
break;
}
long2buff(entry->session_id, body_part->session_id);
body_part->operation = entry->operation;
if (entry->operation == FCFS_AUTH_SESSION_OP_TYPE_CREATE) {
long2buff(entry->fields.user.id, body_part->entry->user.id);
long2buff(entry->fields.user.priv, body_part->entry->user.priv);
long2buff(entry->fields.pool.id, body_part->entry->pool.id);
body_part->entry->pool.available = entry->fields.pool.available;
int2buff(entry->fields.pool.privs.fdir,
body_part->entry->pool.privs.fdir);
int2buff(entry->fields.pool.privs.fstore,
body_part->entry->pool.privs.fstore);
p += sizeof(FCFSAuthProtoSessionPushRespBodyPart) +
sizeof(FCFSAuthProtoSessionPushEntry);
} else {
p += sizeof(FCFSAuthProtoSessionPushRespBodyPart);
}
++count;
previous = entry;
entry = entry->next;
}
if (entry == NULL) {
result = 0;
} else {
struct fc_queue_info remain_qinfo;
previous->next = NULL;
remain_qinfo.head = entry;
remain_qinfo.tail = qinfo.tail;
fc_queue_push_queue_to_head_silence(
&subscriber->queue, &remain_qinfo);
result = EAGAIN;
}
session_subscribe_free_entries(qinfo.head);
int2buff(count, body_header->count);
task->send.ptr->length = p - task->send.ptr->data;
SF_PROTO_SET_HEADER(proto_header, FCFS_AUTH_SERVICE_PROTO_SESSION_PUSH_REQ,
task->send.ptr->length - sizeof(FCFSAuthProtoHeader));
sf_send_add_event(task);
return result;
}
int cluster_thread_loop_callback(struct nio_thread_data *thread_data)
{
AuthServerContext *server_context;
ServerSessionSubscriber *subscriber;
int count;
int i;
server_context = (AuthServerContext *)thread_data->arg;
count = locked_list_count(&server_context->cluster.subscribers);
for (i=0; icluster.subscribers) != 0) {
return NULL;
}
return server_context;
}
================================================
FILE: src/auth/server/cluster_handler.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
//cluster_handler.h
#ifndef FCFS_AUTH_CLUSTER_HANDLER_H
#define FCFS_AUTH_CLUSTER_HANDLER_H
#include
#include
#include
#include "fastcommon/fast_task_queue.h"
#include "server_types.h"
#ifdef __cplusplus
extern "C" {
#endif
int cluster_handler_init();
int cluster_handler_destroy();
int cluster_deal_task(struct fast_task_info *task, const int stage);
void cluster_task_finish_cleanup(struct fast_task_info *task);
void *cluster_alloc_thread_extra_data(const int thread_index);
int cluster_thread_loop_callback(struct nio_thread_data *thread_data);
int cluster_recv_timeout_callback(struct fast_task_info *task);
void cluster_subscriber_queue_push_ex(ServerSessionSubscriber *subscriber,
const bool notify);
#define cluster_subscriber_queue_push(subscriber) \
cluster_subscriber_queue_push_ex(subscriber, true)
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/server/cluster_info.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include "fastcommon/logger.h"
#include "fastcommon/shared_func.h"
#include "fastcommon/sched_thread.h"
#include "fastcommon/local_ip_func.h"
#include "server_global.h"
#include "cluster_info.h"
static int init_cluster_server_array()
{
int bytes;
FCFSAuthClusterServerInfo *cs;
FCServerInfo *server;
FCServerInfo *end;
bytes = sizeof(FCFSAuthClusterServerInfo) *
FC_SID_SERVER_COUNT(CLUSTER_SERVER_CONFIG);
if ((CLUSTER_SERVER_ARRAY.servers=(FCFSAuthClusterServerInfo *)
fc_malloc(bytes)) == NULL)
{
return ENOMEM;
}
memset(CLUSTER_SERVER_ARRAY.servers, 0, bytes);
end = FC_SID_SERVERS(CLUSTER_SERVER_CONFIG) +
FC_SID_SERVER_COUNT(CLUSTER_SERVER_CONFIG);
for (server=FC_SID_SERVERS(CLUSTER_SERVER_CONFIG),
cs=CLUSTER_SERVER_ARRAY.servers; serverserver = server;
}
CLUSTER_SERVER_ARRAY.count = FC_SID_SERVER_COUNT(CLUSTER_SERVER_CONFIG);
return 0;
}
static int find_myself_in_cluster_config(const char *filename)
{
const char *local_ip;
struct {
const char *ip_addr;
int port;
} found;
FCServerInfo *server;
FCFSAuthClusterServerInfo *myself;
SFNetworkHandler *service_handler;
SFNetworkHandler *cluster_handler;
char formatted_found_ip[FORMATTED_IP_SIZE];
char formatted_local_ip[FORMATTED_IP_SIZE];
int ports[4];
int count;
int i;
service_handler = SERVICE_SF_CTX.handlers[SF_IPV4_ADDRESS_FAMILY_INDEX].
handlers + SF_SOCKET_NETWORK_HANDLER_INDEX;
cluster_handler = CLUSTER_SF_CTX.handlers[SF_IPV4_ADDRESS_FAMILY_INDEX].
handlers + SF_SOCKET_NETWORK_HANDLER_INDEX;
count = 0;
ports[count++] = service_handler->inner.port;
if (service_handler->outer.port != service_handler->inner.port) {
ports[count++] = service_handler->outer.port;
}
ports[count++] = cluster_handler->inner.port;
if (cluster_handler->outer.port != cluster_handler->inner.port) {
ports[count++] = cluster_handler->outer.port;
}
found.ip_addr = NULL;
found.port = 0;
local_ip = get_first_local_ip();
while (local_ip != NULL) {
for (i=0; iserver->id);
return EEXIST;
}
found.ip_addr = local_ip;
found.port = ports[i];
}
}
local_ip = get_next_local_ip(local_ip);
}
if (CLUSTER_MYSELF_PTR == NULL) {
logError("file: "__FILE__", line: %d, "
"cluster config file: %s, can't find myself "
"by my local ip and listen port", __LINE__, filename);
return ENOENT;
}
return 0;
}
FCFSAuthClusterServerInfo *fcfs_auth_get_server_by_id(const int server_id)
{
FCServerInfo *server;
server = fc_server_get_by_id(&CLUSTER_SERVER_CONFIG, server_id);
if (server == NULL) {
return NULL;
}
return CLUSTER_SERVER_ARRAY.servers + (server -
FC_SID_SERVERS(CLUSTER_SERVER_CONFIG));
}
int cluster_info_init(const char *cluster_config_filename)
{
int result;
if ((result=init_cluster_server_array()) != 0) {
return result;
}
if ((result=find_myself_in_cluster_config(cluster_config_filename)) != 0) {
return result;
}
return 0;
}
================================================
FILE: src/auth/server/cluster_info.h
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
//cluster_info.h
#ifndef _CLUSTER_INFO_H_
#define _CLUSTER_INFO_H_
#include
#include
#include "server_global.h"
#ifdef __cplusplus
extern "C" {
#endif
int cluster_info_init(const char *cluster_config_filename);
int cluster_info_destroy();
FCFSAuthClusterServerInfo *fcfs_auth_get_server_by_id(const int server_id);
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/server/cluster_relationship.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
#include "fastcommon/logger.h"
#include "fastcommon/sockopt.h"
#include "fastcommon/shared_func.h"
#include "fastcommon/pthread_func.h"
#include "fastcommon/sched_thread.h"
#include "sf/sf_configs.h"
#include "sf/sf_service.h"
#include "sf/sf_func.h"
#include "fastcfs/vote/fcfs_vote_client.h"
#include "common/auth_proto.h"
#include "db/auth_db.h"
#include "db/pool_usage_updater.h"
#include "server_global.h"
#include "session_subscribe.h"
#include "cluster_relationship.h"
#define NEED_REQUEST_VOTE_NODE(active_count) \
SF_ELECTION_QUORUM_NEED_REQUEST_VOTE_NODE(MASTER_ELECTION_QUORUM, \
VOTE_NODE_ENABLED, CLUSTER_SERVER_ARRAY.count, active_count)
#define NEED_CHECK_VOTE_NODE() \
SF_ELECTION_QUORUM_NEED_CHECK_VOTE_NODE(MASTER_ELECTION_QUORUM, \
VOTE_NODE_ENABLED, CLUSTER_SERVER_ARRAY.count)
typedef struct fcfs_auth_cluster_server_status {
FCFSAuthClusterServerInfo *cs;
bool is_master;
int server_id;
} FCFSAuthClusterServerStatus;
typedef struct fcfs_auth_cluster_server_detect_entry {
FCFSAuthClusterServerInfo *cs;
int next_time;
} FCFSAuthClusterServerDetectEntry;
typedef struct fcfs_auth_cluster_server_detect_array {
FCFSAuthClusterServerDetectEntry *entries;
int count;
int alloc;
pthread_mutex_t lock;
} FCFSAuthClusterServerDetectArray;
typedef struct fcfs_auth_cluster_relationship_context {
FCFSAuthClusterServerDetectArray inactive_server_array;
ConnectionInfo vote_connection;
} FCFSAuthClusterRelationshipContext;
#define INACTIVE_SERVER_ARRAY relationship_ctx.inactive_server_array
#define VOTE_CONNECTION relationship_ctx.vote_connection
static FCFSAuthClusterRelationshipContext relationship_ctx = {
{NULL, 0, 0}
};
#define SET_SERVER_DETECT_ENTRY(entry, server) \
do { \
entry->cs = server; \
entry->next_time = g_current_time + 1; \
} while (0)
static inline void proto_unpack_server_status(
FCFSAuthProtoGetServerStatusResp *resp,
FCFSAuthClusterServerStatus *server_status)
{
server_status->is_master = resp->is_master;
server_status->server_id = buff2int(resp->server_id);
}
static int proto_get_server_status(ConnectionInfo *conn,
const int network_timeout,
FCFSAuthClusterServerStatus *server_status)
{
int result;
FCFSAuthProtoHeader *header;
FCFSAuthProtoGetServerStatusReq *req;
FCFSAuthProtoGetServerStatusResp *resp;
SFResponseInfo response;
char out_buff[sizeof(FCFSAuthProtoHeader) +
sizeof(FCFSAuthProtoGetServerStatusReq)];
char in_body[sizeof(FCFSAuthProtoGetServerStatusResp)];
char formatted_ip[FORMATTED_IP_SIZE];
header = (FCFSAuthProtoHeader *)out_buff;
SF_PROTO_SET_HEADER(header, FCFS_AUTH_CLUSTER_PROTO_GET_SERVER_STATUS_REQ,
sizeof(out_buff) - sizeof(FCFSAuthProtoHeader));
req = (FCFSAuthProtoGetServerStatusReq *)(out_buff +
sizeof(FCFSAuthProtoHeader));
int2buff(CLUSTER_MY_SERVER_ID, req->server_id);
memcpy(req->config_sign, CLUSTER_CONFIG_SIGN_BUF,
SF_CLUSTER_CONFIG_SIGN_LEN);
response.error.length = 0;
if ((result=sf_send_and_check_response_header(conn, out_buff,
sizeof(out_buff), &response, network_timeout,
FCFS_AUTH_CLUSTER_PROTO_GET_SERVER_STATUS_RESP)) != 0)
{
auth_log_network_error(&response, conn, result);
return result;
}
if (response.header.body_len != sizeof(FCFSAuthProtoGetServerStatusResp)) {
format_ip_address(conn->ip_addr, formatted_ip);
logError("file: "__FILE__", line: %d, "
"server %s:%u, recv body length: %d != %d",
__LINE__, formatted_ip, conn->port,
response.header.body_len, (int)
sizeof(FCFSAuthProtoGetServerStatusResp));
return EINVAL;
}
if ((result=tcprecvdata_nb(conn->sock, in_body, response.
header.body_len, network_timeout)) != 0)
{
format_ip_address(conn->ip_addr, formatted_ip);
logError("file: "__FILE__", line: %d, "
"recv from server %s:%u fail, "
"errno: %d, error info: %s",
__LINE__, formatted_ip, conn->port,
result, STRERROR(result));
return result;
}
resp = (FCFSAuthProtoGetServerStatusResp *)in_body;
proto_unpack_server_status(resp, server_status);
return 0;
}
static void init_inactive_server_array()
{
FCFSAuthClusterServerInfo *cs;
FCFSAuthClusterServerInfo *end;
FCFSAuthClusterServerDetectEntry *entry;
PTHREAD_MUTEX_LOCK(&INACTIVE_SERVER_ARRAY.lock);
entry = INACTIVE_SERVER_ARRAY.entries;
end = CLUSTER_SERVER_ARRAY.servers + CLUSTER_SERVER_ARRAY.count;
for (cs=CLUSTER_SERVER_ARRAY.servers; csserver_id);
memcpy(req->config_sign, CLUSTER_CONFIG_SIGN_BUF,
SF_CLUSTER_CONFIG_SIGN_LEN);
response.error.length = 0;
if ((result=sf_send_and_recv_none_body_response(conn, out_buff,
sizeof(out_buff), &response, network_timeout,
SF_PROTO_ACK)) != 0)
{
auth_log_network_error(&response, conn, result);
}
return result;
}
static int proto_ping_master(ConnectionInfo *conn, const int network_timeout)
{
FCFSAuthProtoHeader header;
SFResponseInfo response;
int result;
SF_PROTO_SET_HEADER(&header, FCFS_AUTH_CLUSTER_PROTO_PING_MASTER_REQ, 0);
response.error.length = 0;
if ((result=sf_send_and_recv_none_body_response(conn, (char *)&header,
sizeof(header), &response, network_timeout,
FCFS_AUTH_CLUSTER_PROTO_PING_MASTER_RESP)) != 0)
{
auth_log_network_error(&response, conn, result);
}
return result;
}
static int cluster_cmp_server_status(const void *p1, const void *p2)
{
FCFSAuthClusterServerStatus *status1;
FCFSAuthClusterServerStatus *status2;
int sub;
status1 = (FCFSAuthClusterServerStatus *)p1;
status2 = (FCFSAuthClusterServerStatus *)p2;
sub = (int)status1->is_master - (int)status2->is_master;
if (sub != 0) {
return sub;
}
return (int)status1->server_id - (int)status2->server_id;
}
#define cluster_get_server_status(server_status) \
cluster_get_server_status_ex(server_status, true)
static int cluster_get_server_status_ex(FCFSAuthClusterServerStatus
*server_status, const bool log_connect_error)
{
const int connect_timeout = 2;
const int network_timeout = 2;
ConnectionInfo conn;
int result;
if (server_status->cs == CLUSTER_MYSELF_PTR) {
server_status->is_master = MYSELF_IS_MASTER;
server_status->server_id = CLUSTER_MY_SERVER_ID;
return 0;
} else {
if ((result=fc_server_make_connection_ex(&CLUSTER_GROUP_ADDRESS_ARRAY(
server_status->cs->server), &conn, "fauth",
connect_timeout, NULL, log_connect_error)) != 0)
{
return result;
}
result = proto_get_server_status(&conn,
network_timeout, server_status);
conn_pool_disconnect_server(&conn);
return result;
}
}
static int do_check_brainsplit(FCFSAuthClusterServerInfo *cs)
{
int result;
const bool log_connect_error = false;
FCFSAuthClusterServerStatus server_status;
char formatted_ip[FORMATTED_IP_SIZE];
server_status.cs = cs;
server_status.is_master = false;
server_status.server_id = 0;
if ((result=cluster_get_server_status_ex(&server_status,
log_connect_error)) != 0)
{
return result;
}
if (server_status.is_master) {
format_ip_address(CLUSTER_GROUP_ADDRESS_FIRST_IP(
cs->server), formatted_ip);
logWarning("file: "__FILE__", line: %d, "
"two masters occurs, anonther master id: %d, %s:%u, "
"trigger re-select master ...", __LINE__, cs->server->id,
formatted_ip, CLUSTER_GROUP_ADDRESS_FIRST_PORT(cs->server));
cluster_relationship_trigger_reselect_master();
return EEXIST;
}
return 0;
}
static int cluster_check_brainsplit(int *inactive_count)
{
FCFSAuthClusterServerDetectEntry *entry;
FCFSAuthClusterServerDetectEntry *end;
int result;
end = INACTIVE_SERVER_ARRAY.entries + *inactive_count;
for (entry=INACTIVE_SERVER_ARRAY.entries; entry= INACTIVE_SERVER_ARRAY.entries +
INACTIVE_SERVER_ARRAY.count)
{
break;
}
if (entry->next_time > g_current_time) {
continue;
}
result = do_check_brainsplit(entry->cs);
if (result == 0) { //success
--(*inactive_count);
} else if (result == EEXIST) { //brain-split occurs
return result;
}
entry->next_time = g_current_time + 1;
}
return 0;
}
static inline void fill_join_request(FCFSVoteClientJoinRequest *join_request,
const bool persistent)
{
join_request->server_id = CLUSTER_MY_SERVER_ID;
join_request->is_leader = (CLUSTER_MYSELF_PTR ==
CLUSTER_MASTER_ATOM_PTR ? 1 : 0);
join_request->group_id = 1;
join_request->response_size = sizeof(FCFSAuthProtoGetServerStatusResp);
join_request->service_id = FCFS_VOTE_SERVICE_ID_FAUTH;
join_request->persistent = persistent;
}
static inline int vote_node_active_check()
{
int result;
FCFSVoteClientJoinRequest join_request;
if (VOTE_CONNECTION.sock < 0) {
fill_join_request(&join_request, true);
if ((result=fcfs_vote_client_join(&VOTE_CONNECTION,
&join_request)) != 0)
{
return result;
}
}
if ((result=vote_client_proto_active_check(&VOTE_CONNECTION)) != 0) {
vote_client_proto_close_connection(&VOTE_CONNECTION);
}
return result;
}
static int master_check()
{
int result;
int active_count;
int inactive_count;
int vote_node_active;
if (NEED_CHECK_VOTE_NODE()) {
if ((result=vote_node_active_check()) == 0) {
vote_node_active = 1;
} else {
if (result == SF_CLUSTER_ERROR_LEADER_INCONSISTENT) {
logWarning("file: "__FILE__", line: %d, "
"trigger re-select master because master "
"inconsistent with the vote node", __LINE__);
cluster_relationship_trigger_reselect_master();
return EBUSY;
}
vote_node_active = 0;
}
} else {
vote_node_active = 0;
}
PTHREAD_MUTEX_LOCK(&INACTIVE_SERVER_ARRAY.lock);
inactive_count = INACTIVE_SERVER_ARRAY.count;
PTHREAD_MUTEX_UNLOCK(&INACTIVE_SERVER_ARRAY.lock);
if (inactive_count > 0) {
if ((result=cluster_check_brainsplit(&inactive_count)) != 0) {
return result;
}
active_count = (CLUSTER_SERVER_ARRAY.count -
inactive_count) + vote_node_active;
if (!sf_election_quorum_check(MASTER_ELECTION_QUORUM,
VOTE_NODE_ENABLED, CLUSTER_SERVER_ARRAY.count,
active_count))
{
logWarning("file: "__FILE__", line: %d, "
"trigger re-select master because alive server "
"count: %d < half of total server count: %d ...",
__LINE__, active_count, CLUSTER_SERVER_ARRAY.count);
cluster_relationship_trigger_reselect_master();
return EBUSY;
}
}
return 0;
}
static int get_vote_server_status(FCFSAuthClusterServerStatus *server_status)
{
FCFSVoteClientJoinRequest join_request;
SFGetServerStatusRequest status_request;
FCFSAuthProtoGetServerStatusResp resp;
int result;
if (VOTE_CONNECTION.sock >= 0) {
status_request.servers_sign = CLUSTER_CONFIG_SIGN_BUF;
status_request.cluster_sign = NULL;
status_request.server_id = CLUSTER_MY_SERVER_ID;
status_request.is_leader = (CLUSTER_MYSELF_PTR ==
CLUSTER_MASTER_ATOM_PTR ? 1 : 0);
result = vote_client_proto_get_vote(&VOTE_CONNECTION,
&status_request, (char *)&resp, sizeof(resp));
if (result != 0) {
vote_client_proto_close_connection(&VOTE_CONNECTION);
}
} else {
fill_join_request(&join_request, false);
result = fcfs_vote_client_get_vote(&join_request,
CLUSTER_CONFIG_SIGN_BUF, NULL,
(char *)&resp, sizeof(resp));
}
if (result == 0) {
proto_unpack_server_status(&resp, server_status);
}
return result;
}
static int notify_vote_next_leader(FCFSAuthClusterServerStatus *server_status,
const unsigned char vote_req_cmd)
{
FCFSVoteClientJoinRequest join_request;
fill_join_request(&join_request, false);
return fcfs_vote_client_notify_next_leader(&join_request, vote_req_cmd);
}
static int cluster_get_master(FCFSAuthClusterServerStatus *server_status,
const bool log_connect_error, int *active_count)
{
#define STATUS_ARRAY_FIXED_COUNT 8
FCFSAuthClusterServerInfo *server;
FCFSAuthClusterServerInfo *end;
FCFSAuthClusterServerStatus *current_status;
FCFSAuthClusterServerStatus *cs_status;
FCFSAuthClusterServerStatus status_array[STATUS_ARRAY_FIXED_COUNT];
char formatted_ip[FORMATTED_IP_SIZE];
int result;
int r;
int i;
memset(server_status, 0, sizeof(FCFSAuthClusterServerStatus));
if (CLUSTER_SERVER_ARRAY.count < STATUS_ARRAY_FIXED_COUNT) {
cs_status = status_array;
} else {
int bytes;
bytes = sizeof(FCFSAuthClusterServerStatus) * CLUSTER_SERVER_ARRAY.count;
cs_status = (FCFSAuthClusterServerStatus *)fc_malloc(bytes);
if (cs_status == NULL) {
return ENOMEM;
}
}
current_status = cs_status;
result = 0;
end = CLUSTER_SERVER_ARRAY.servers + CLUSTER_SERVER_ARRAY.count;
for (server=CLUSTER_SERVER_ARRAY.servers; servercs = server;
r = cluster_get_server_status_ex(current_status, log_connect_error);
if (r == 0) {
current_status++;
} else if (r != ENOENT) {
result = r;
}
}
*active_count = current_status - cs_status;
if (*active_count == 0) {
logError("file: "__FILE__", line: %d, "
"get server status fail, "
"server count: %d", __LINE__,
CLUSTER_SERVER_ARRAY.count);
return result == 0 ? ENOENT : result;
}
if (NEED_REQUEST_VOTE_NODE(*active_count)) {
current_status->cs = NULL;
if (get_vote_server_status(current_status) == 0) {
++(*active_count);
}
}
qsort(cs_status, *active_count,
sizeof(FCFSAuthClusterServerStatus),
cluster_cmp_server_status);
if (FC_LOG_BY_LEVEL(LOG_DEBUG)) {
for (i=0; i<*active_count; i++) {
if (cs_status[i].cs == NULL) {
logDebug("file: "__FILE__", line: %d, "
"%d. status from vote server", __LINE__, i + 1);
} else {
format_ip_address(CLUSTER_GROUP_ADDRESS_FIRST_IP(
cs_status[i].cs->server), formatted_ip);
logDebug("file: "__FILE__", line: %d, "
"server_id: %d, ip and port %s:%u, is_master: %d",
__LINE__, cs_status[i].server_id, formatted_ip,
CLUSTER_GROUP_ADDRESS_FIRST_PORT(cs_status[i].cs->server),
cs_status[i].is_master);
}
}
}
memcpy(server_status, cs_status + (*active_count - 1),
sizeof(FCFSAuthClusterServerStatus));
if (cs_status != status_array) {
free(cs_status);
}
return 0;
}
static int do_notify_master_changed(FCFSAuthClusterServerInfo *cs,
FCFSAuthClusterServerInfo *master, const unsigned char cmd,
bool *bConnectFail)
{
int connect_timeout;
char out_buff[sizeof(FCFSAuthProtoHeader) + 4];
ConnectionInfo conn;
FCFSAuthProtoHeader *header;
SFResponseInfo response;
int result;
connect_timeout = FC_MIN(CLUSTER_CONNECT_TIMEOUT, 2);
if ((result=fc_server_make_connection(&CLUSTER_GROUP_ADDRESS_ARRAY(
cs->server), &conn, "fauth", connect_timeout)) != 0)
{
*bConnectFail = true;
return result;
}
*bConnectFail = false;
header = (FCFSAuthProtoHeader *)out_buff;
SF_PROTO_SET_HEADER(header, cmd, sizeof(out_buff) -
sizeof(FCFSAuthProtoHeader));
int2buff(master->server->id, out_buff + sizeof(FCFSAuthProtoHeader));
response.error.length = 0;
if ((result=sf_send_and_recv_none_body_response(&conn, out_buff,
sizeof(out_buff), &response, CLUSTER_NETWORK_TIMEOUT,
SF_PROTO_ACK)) != 0)
{
auth_log_network_error(&response, &conn, result);
}
conn_pool_disconnect_server(&conn);
return result;
}
int cluster_relationship_pre_set_master(FCFSAuthClusterServerInfo *master)
{
FCFSAuthClusterServerInfo *next_master;
next_master = CLUSTER_NEXT_MASTER;
if (next_master == NULL) {
CLUSTER_NEXT_MASTER = master;
} else if (next_master != master) {
logError("file: "__FILE__", line: %d, "
"try to set next master id: %d, "
"but next master: %d already exist",
__LINE__, master->server->id, next_master->server->id);
CLUSTER_NEXT_MASTER = NULL;
return EEXIST;
}
return 0;
}
static int load_data()
{
int result;
if ((result=adb_load_data((AuthServerContext *)
sf_get_random_thread_data()->arg)) != 0)
{
return result;
}
if ((result=adb_check_generate_admin_user((AuthServerContext *)
sf_get_random_thread_data()->arg)) != 0)
{
return result;
}
return 0;
}
static int cluster_relationship_set_master(FCFSAuthClusterServerInfo
*new_master, const time_t start_time)
{
int result;
FCFSAuthClusterServerInfo *old_master;
char formatted_ip[FORMATTED_IP_SIZE];
old_master = CLUSTER_MASTER_ATOM_PTR;
if (new_master == old_master) {
format_ip_address(CLUSTER_GROUP_ADDRESS_FIRST_IP(
new_master->server), formatted_ip);
logDebug("file: "__FILE__", line: %d, "
"the server id: %d, %s:%u already is master",
__LINE__, new_master->server->id, formatted_ip,
CLUSTER_GROUP_ADDRESS_FIRST_PORT(new_master->server));
return 0;
}
if (CLUSTER_MYSELF_PTR == new_master) {
if ((result=load_data()) != 0) {
sf_terminate_myself();
return result;
}
} else {
char time_used[128];
if (start_time > 0) {
sprintf(time_used, ", election time used: %ds",
(int)(g_current_time - start_time));
} else {
*time_used = '\0';
}
format_ip_address(CLUSTER_GROUP_ADDRESS_FIRST_IP(
new_master->server), formatted_ip);
logInfo("file: "__FILE__", line: %d, "
"the master server id: %d, %s:%u%s",
__LINE__, new_master->server->id, formatted_ip,
CLUSTER_GROUP_ADDRESS_FIRST_PORT(new_master->server),
time_used);
}
do {
if (__sync_bool_compare_and_swap(&CLUSTER_MASTER_PTR,
old_master, new_master))
{
break;
}
old_master = CLUSTER_MASTER_ATOM_PTR;
} while (old_master != new_master);
if (CLUSTER_MYSELF_PTR == new_master) {
if ((result=pool_usage_updater_start()) != 0) {
sf_terminate_myself();
return result;
}
}
return 0;
}
int cluster_relationship_commit_master(FCFSAuthClusterServerInfo *master)
{
const time_t start_time = 0;
FCFSAuthClusterServerInfo *next_master;
int result;
next_master = CLUSTER_NEXT_MASTER;
if (next_master == NULL) {
logError("file: "__FILE__", line: %d, "
"next master is NULL", __LINE__);
return EBUSY;
}
if (next_master != master) {
logError("file: "__FILE__", line: %d, "
"next master server id: %d != expected server id: %d",
__LINE__, next_master->server->id, master->server->id);
CLUSTER_NEXT_MASTER = NULL;
return EBUSY;
}
result = cluster_relationship_set_master(master, start_time);
CLUSTER_NEXT_MASTER = NULL;
return result;
}
void cluster_relationship_trigger_reselect_master()
{
FCFSAuthClusterServerInfo *master;
master = CLUSTER_MASTER_ATOM_PTR;
if (CLUSTER_MYSELF_PTR != master) {
return;
}
if (!cluster_unset_master(master)) {
return;
}
if (NEED_CHECK_VOTE_NODE()) {
vote_client_proto_close_connection(&VOTE_CONNECTION);
}
session_subscribe_clear_session();
server_session_clear();
pool_usage_updater_terminate();
auth_db_destroy();
}
static int cluster_pre_set_next_master(FCFSAuthClusterServerInfo *cs,
FCFSAuthClusterServerStatus *server_status, bool *bConnectFail)
{
FCFSAuthClusterServerInfo *master;
int result;
master = server_status->cs;
if (cs == CLUSTER_MYSELF_PTR) {
if ((result=cluster_relationship_pre_set_master(master)) == 0) {
init_inactive_server_array();
}
return result;
} else {
return do_notify_master_changed(cs, master,
FCFS_AUTH_CLUSTER_PROTO_PRE_SET_NEXT_MASTER, bConnectFail);
}
}
static int cluster_commit_next_master(FCFSAuthClusterServerInfo *cs,
FCFSAuthClusterServerStatus *server_status, bool *bConnectFail)
{
FCFSAuthClusterServerInfo *master;
master = server_status->cs;
if (cs == CLUSTER_MYSELF_PTR) {
return cluster_relationship_commit_master(master);
} else {
return do_notify_master_changed(cs, master,
FCFS_AUTH_CLUSTER_PROTO_COMMIT_NEXT_MASTER, bConnectFail);
}
}
typedef int (*cluster_notify_next_master_func)(FCFSAuthClusterServerInfo *cs,
FCFSAuthClusterServerStatus *server_status, bool *bConnectFail);
static int notify_next_master(cluster_notify_next_master_func notify_func,
FCFSAuthClusterServerStatus *server_status, const unsigned
char vote_req_cmd, int *success_count)
{
FCFSAuthClusterServerInfo *server;
FCFSAuthClusterServerInfo *send;
int result;
bool bConnectFail;
result = ENOENT;
*success_count = 0;
send = CLUSTER_SERVER_ARRAY.servers + CLUSTER_SERVER_ARRAY.count;
for (server=CLUSTER_SERVER_ARRAY.servers; server 1) {
need_log = true;
last_log_time = g_current_time;
} if (g_current_time - last_log_time > 8) {
need_log = ((i + 1) % 10 == 0);
if (need_log) {
last_log_time = g_current_time;
}
} else {
need_log = false;
}
if ((result=cluster_get_master(&server_status,
need_log, &active_count)) != 0)
{
return result;
}
++i;
if (!sf_election_quorum_check(MASTER_ELECTION_QUORUM,
VOTE_NODE_ENABLED, CLUSTER_SERVER_ARRAY.count,
active_count))
{
sleep_secs = 1;
if (need_log) {
logWarning("file: "__FILE__", line: %d, "
"round %dth select master fail because alive server "
"count: %d < half of total server count: %d, "
"try again after %d seconds.", __LINE__, i,
active_count, CLUSTER_SERVER_ARRAY.count,
sleep_secs);
}
sleep(sleep_secs);
continue;
}
if ((active_count == CLUSTER_SERVER_ARRAY.count) ||
(active_count >= 2 && server_status.is_master))
{
break;
}
remain_time = ELECTION_MAX_WAIT_TIME - (g_current_time - start_time);
if (remain_time <= 0) {
break;
}
sleep_secs = FC_MIN(remain_time, max_sleep_secs);
logWarning("file: "__FILE__", line: %d, "
"round %dth select master, alive server count: %d "
"< server count: %d, try again after %d seconds.",
__LINE__, i, active_count, CLUSTER_SERVER_ARRAY.count,
sleep_secs);
sleep(sleep_secs);
if ((i % 2 == 0) && (max_sleep_secs < 8)) {
max_sleep_secs *= 2;
}
}
next_master = CLUSTER_MASTER_ATOM_PTR;
if (next_master != NULL) {
format_ip_address(CLUSTER_GROUP_ADDRESS_FIRST_IP(
next_master->server), formatted_ip);
logInfo("file: "__FILE__", line: %d, "
"abort election because the master exists, "
"master id: %d, %s:%u, election time used: %ds",
__LINE__, next_master->server->id, formatted_ip,
CLUSTER_GROUP_ADDRESS_FIRST_PORT(next_master->server),
(int)(g_current_time - start_time));
return 0;
}
next_master = server_status.cs;
if (CLUSTER_MYSELF_PTR == next_master) {
if ((result=cluster_notify_master_changed(
&server_status)) != 0)
{
return result;
}
format_ip_address(CLUSTER_GROUP_ADDRESS_FIRST_IP(
next_master->server), formatted_ip);
logInfo("file: "__FILE__", line: %d, "
"I am the new master, id: %d, %s:%u, election "
"time used: %ds", __LINE__, next_master->server->id,
formatted_ip, CLUSTER_GROUP_ADDRESS_FIRST_PORT(next_master->
server), (int)(g_current_time - start_time));
} else {
if (server_status.is_master) {
cluster_relationship_set_master(next_master, start_time);
} else if (CLUSTER_MASTER_ATOM_PTR == NULL) {
format_ip_address(CLUSTER_GROUP_ADDRESS_FIRST_IP(
next_master->server), formatted_ip);
logInfo("file: "__FILE__", line: %d, "
"election time used: %ds, waiting for the candidate "
"master server id: %d, %s:%u notify ...", __LINE__,
(int)(g_current_time - start_time), next_master->server->id,
formatted_ip, CLUSTER_GROUP_ADDRESS_FIRST_PORT(
next_master->server));
return ENOENT;
}
}
return 0;
}
static int cluster_ping_master(FCFSAuthClusterServerInfo *master,
ConnectionInfo *conn, const int timeout, bool *is_ping)
{
int connect_timeout;
int network_timeout;
int result;
if (CLUSTER_MYSELF_PTR == master) {
*is_ping = false;
return master_check();
}
network_timeout = FC_MIN(CLUSTER_NETWORK_TIMEOUT, timeout);
*is_ping = true;
if (conn->sock < 0) {
connect_timeout = FC_MIN(CLUSTER_CONNECT_TIMEOUT, timeout);
if ((result=fc_server_make_connection(&CLUSTER_GROUP_ADDRESS_ARRAY(
master->server), conn, "fauth",
connect_timeout)) != 0)
{
return result;
}
if ((result=proto_join_master(conn, network_timeout)) != 0) {
conn_pool_disconnect_server(conn);
return result;
}
}
if ((result=proto_ping_master(conn, network_timeout)) != 0) {
conn_pool_disconnect_server(conn);
}
return result;
}
static void *cluster_thread_entrance(void* arg)
{
#define MAX_SLEEP_SECONDS 10
int result;
int fail_count;
int sleep_seconds;
int ping_remain_time;
time_t ping_start_time;
bool is_ping;
FCFSAuthClusterServerInfo *master;
ConnectionInfo mconn; //master connection
char formatted_ip[FORMATTED_IP_SIZE];
#ifdef OS_LINUX
prctl(PR_SET_NAME, "relationship");
#endif
memset(&mconn, 0, sizeof(mconn));
mconn.sock = -1;
fail_count = 0;
sleep_seconds = 1;
ping_start_time = g_current_time;
while (SF_G_CONTINUE_FLAG) {
master = CLUSTER_MASTER_ATOM_PTR;
if (master == NULL) {
if (cluster_select_master() != 0) {
sleep_seconds = 1 + (int)((double)rand()
* (double)MAX_SLEEP_SECONDS / RAND_MAX);
} else {
if (mconn.sock >= 0) {
conn_pool_disconnect_server(&mconn);
}
ping_start_time = g_current_time;
sleep_seconds = 1;
}
} else {
ping_remain_time = ELECTION_MASTER_LOST_TIMEOUT -
(g_current_time - ping_start_time);
if (ping_remain_time < 2) {
ping_remain_time = 2;
}
if ((result=cluster_ping_master(master, &mconn,
ping_remain_time, &is_ping)) == 0)
{
fail_count = 0;
ping_start_time = g_current_time;
sleep_seconds = 1;
} else if (is_ping) {
++fail_count;
format_ip_address(CLUSTER_GROUP_ADDRESS_FIRST_IP(
master->server), formatted_ip);
logError("file: "__FILE__", line: %d, "
"%dth ping master id: %d, %s:%u fail", __LINE__,
fail_count, master->server->id, formatted_ip,
CLUSTER_GROUP_ADDRESS_FIRST_PORT(master->server));
if (result == SF_RETRIABLE_ERROR_NOT_MASTER) {
cluster_unset_master(master);
fail_count = 0;
sleep_seconds = 0;
} else if (g_current_time - ping_start_time >
ELECTION_MASTER_LOST_TIMEOUT)
{
if (fail_count > 1) {
cluster_unset_master(master);
fail_count = 0;
}
sleep_seconds = 0;
} else {
sleep_seconds = 1;
}
} else {
sleep_seconds = 0; //master check fail
}
}
if (sleep_seconds > 0) {
sleep(sleep_seconds);
}
}
return NULL;
}
int cluster_relationship_init()
{
int result;
int bytes;
pthread_t tid;
VOTE_CONNECTION.sock = -1;
bytes = sizeof(FCFSAuthClusterServerDetectEntry) * CLUSTER_SERVER_ARRAY.count;
INACTIVE_SERVER_ARRAY.entries = (FCFSAuthClusterServerDetectEntry *)
fc_malloc(bytes);
if (INACTIVE_SERVER_ARRAY.entries == NULL) {
return ENOMEM;
}
if ((result=init_pthread_lock(&INACTIVE_SERVER_ARRAY.lock)) != 0) {
logError("file: "__FILE__", line: %d, "
"init_pthread_lock fail, errno: %d, error info: %s",
__LINE__, result, STRERROR(result));
return result;
}
INACTIVE_SERVER_ARRAY.alloc = CLUSTER_SERVER_ARRAY.count;
return fc_create_thread(&tid, cluster_thread_entrance, NULL,
SF_G_THREAD_STACK_SIZE);
}
int cluster_relationship_destroy()
{
return 0;
}
void cluster_relationship_add_to_inactive_sarray(FCFSAuthClusterServerInfo *cs)
{
FCFSAuthClusterServerDetectEntry *entry;
FCFSAuthClusterServerDetectEntry *end;
bool found;
found = false;
PTHREAD_MUTEX_LOCK(&INACTIVE_SERVER_ARRAY.lock);
if (INACTIVE_SERVER_ARRAY.count > 0) {
end = INACTIVE_SERVER_ARRAY.entries + INACTIVE_SERVER_ARRAY.count;
for (entry=INACTIVE_SERVER_ARRAY.entries; entrycs == cs) {
found = true;
break;
}
}
}
if (!found) {
if (INACTIVE_SERVER_ARRAY.count < INACTIVE_SERVER_ARRAY.alloc) {
entry = INACTIVE_SERVER_ARRAY.entries + INACTIVE_SERVER_ARRAY.count;
SET_SERVER_DETECT_ENTRY(entry, cs);
INACTIVE_SERVER_ARRAY.count++;
} else {
logError("file: "__FILE__", line: %d, "
"server id: %d, add to inactive array fail "
"because array is full", __LINE__, cs->server->id);
}
} else {
logWarning("file: "__FILE__", line: %d, "
"server id: %d, already in inactive array!",
__LINE__, cs->server->id);
}
PTHREAD_MUTEX_UNLOCK(&INACTIVE_SERVER_ARRAY.lock);
}
void cluster_relationship_remove_from_inactive_sarray(FCFSAuthClusterServerInfo *cs)
{
FCFSAuthClusterServerDetectEntry *entry;
FCFSAuthClusterServerDetectEntry *p;
FCFSAuthClusterServerDetectEntry *end;
PTHREAD_MUTEX_LOCK(&INACTIVE_SERVER_ARRAY.lock);
end = INACTIVE_SERVER_ARRAY.entries + INACTIVE_SERVER_ARRAY.count;
for (entry=INACTIVE_SERVER_ARRAY.entries; entrycs == cs) {
break;
}
}
if (entry < end) {
for (p=entry+1; p
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
//cluster_relationship.h
#ifndef _CLUSTER_RELATIONSHIP_H_
#define _CLUSTER_RELATIONSHIP_H_
#include
#include
#include "server_types.h"
#ifdef __cplusplus
extern "C" {
#endif
int cluster_relationship_init();
int cluster_relationship_destroy();
int cluster_relationship_pre_set_master(FCFSAuthClusterServerInfo *master);
int cluster_relationship_commit_master(FCFSAuthClusterServerInfo *master);
void cluster_relationship_trigger_reselect_master();
void cluster_relationship_add_to_inactive_sarray(FCFSAuthClusterServerInfo *cs);
void cluster_relationship_remove_from_inactive_sarray(FCFSAuthClusterServerInfo *cs);
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: src/auth/server/common_handler.c
================================================
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
//common_handler.c
#include
#include
#include
#include
#include
#include
#include