diff --git a/.clang-format b/.clang-format index fa13380a3d..da0d029bcd 100644 --- a/.clang-format +++ b/.clang-format @@ -4,6 +4,7 @@ BasedOnStyle: Google AccessModifierOffset: -3 DerivePointerAlignment: false IndentWidth: 4 +AlignAfterOpenBracket: DontAlign --- Language: Proto BasedOnStyle: Google diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index b0ceec4da5..fa4c88720e 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -14,7 +14,7 @@ jobs: # fetch everything to be able to compare with any ref fetch-depth: 0 - - name: Check + - name: Check env: LANG: "C.UTF-8" LC_ALL: "C.UTF-8" diff --git a/.gitignore b/.gitignore index 208afe07e7..92dc59bcf5 100755 --- a/.gitignore +++ b/.gitignore @@ -169,3 +169,11 @@ test/integration/snapshotcloneserver/config/*.conf *.deb *.whl + +*.class +curvefs/sdk/java/target/ +curvefs/sdk/java/native/build +curvefs/sdk/libcurvefs/examples/bin +curvefs/sdk/output/ +hadoop-test/ +nnbench-test/ diff --git a/.obm.cfg b/.obm.cfg index 012870a5fd..ada426f8e5 100644 --- a/.obm.cfg +++ b/.obm.cfg @@ -1,2 +1,2 @@ -container_name: curve-build-playground-master +container_name: curve-build-playground.master container_image: opencurvedocker/curve-base:build-debian11 diff --git a/Makefile b/Makefile index c71b5ab045..749e838ba2 100644 --- a/Makefile +++ b/Makefile @@ -124,3 +124,9 @@ docker: format: @bash util/format.sh $(commit_id) + +init-hadoop: + @bash util/init-hadoop.sh + +sdk: + @bash util/sdk.sh diff --git a/WORKSPACE b/WORKSPACE index 70772b05f5..a423f1c46a 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -142,7 +142,7 @@ git_repository( patches = [ "//:thirdparties/brpc/brpc.patch", "//:thirdparties/brpc/fix-gcc11.patch", - "//:thirdparties/brpc/0001-bvar-warning-on-conflict-bvar-name.patch", + "//:thirdparties/brpc/0001-bvar-warning-on-conflict-bvar-name.patch", ], patch_args = ["-p1"], ) @@ -192,7 +192,6 @@ new_local_repository( path = "thirdparties/memcache/libmemcached-1.1.2", ) - http_archive( name = "aws", urls = ["https://github.com/aws/aws-sdk-cpp/archive/1.7.340.tar.gz"], @@ -259,6 +258,21 @@ http_archive( build_file = "//:thirdparties/spdlog.BUILD", ) +# incbin +new_git_repository( + name = "incbin", + remote = "https://github.com/graphitemaster/incbin.git", + commit = "6e576cae5ab5810f25e2631f2e0b80cbe7dc8cbf", + build_file = "//:thirdparties/incbin.BUILD", +) + +# config +new_local_repository( + name = "config", + build_file = "//:thirdparties/config.BUILD", + path = "thirdparties/config", +) + # Bazel platform rules. http_archive( name = "platforms", @@ -274,6 +288,13 @@ new_local_repository( path = "thirdparties/rocksdb", ) +# jni +new_local_repository( + name = "jni", + build_file = "//:thirdparties/jni.BUILD", + path = "thirdparties", +) + # Hedron's Compile Commands Extractor for Bazel # https://github.com/hedronvision/bazel-compile-commands-extractor http_archive( diff --git a/curvefs/conf/client.conf b/curvefs/conf/client.conf index 9b3d449ec9..755d624920 100644 --- a/curvefs/conf/client.conf +++ b/curvefs/conf/client.conf @@ -126,6 +126,15 @@ fuseClient.throttle.burstReadIops=0 # the times that read burst Iops can continue, default 180s fuseClient.throttle.burstReadIopsSecs=180 +#### vfs (virtual filesystem) +#{ +vfs.userPermission.uid=0 +vfs.userPermission.gids=0 +vfs.userPermission.umask=0022 +vfs.entryCache.lruSize=2000000 +vfs.attrCache.lruSize=2000000 +#} + #### filesystem metadata # { # fs.disableXAttr: diff --git a/curvefs/sdk/.clang-format b/curvefs/sdk/.clang-format new file mode 100644 index 0000000000..47a38a93f2 --- /dev/null +++ b/curvefs/sdk/.clang-format @@ -0,0 +1,2 @@ +DisableFormat: true +SortIncludes: Never diff --git a/curvefs/sdk/README.md b/curvefs/sdk/README.md new file mode 100644 index 0000000000..c58aa8feba --- /dev/null +++ b/curvefs/sdk/README.md @@ -0,0 +1,18 @@ +Hadoop SDK +=== + +How to build +--- + +``` bash +$ git clone git@github.com:opencurve/curve.git +$ cd curve +$ make dep stor=fs +$ make sdk +``` + +It will generate a jar after build success: + +``` +Build SDK success => /curve/curvefs/sdk/output/curvefs-hadoop-1.0-SNAPSHOT.jar +``` diff --git a/curvefs/sdk/java/native/BUILD b/curvefs/sdk/java/native/BUILD new file mode 100644 index 0000000000..3361aeea44 --- /dev/null +++ b/curvefs/sdk/java/native/BUILD @@ -0,0 +1,36 @@ +# +# Copyright (c) 2023 NetEase Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +load("//:copts.bzl", "CURVE_DEFAULT_COPTS") + +cc_binary( + name = "curvefs_jni", + srcs = glob([ + "*.h", + "*.cpp", + ]), + visibility = ["//visibility:public"], + copts = CURVE_DEFAULT_COPTS, + linkopts = [ + "-Wl,-rpath=/tmp/libcurvefs,--disable-new-dtags", + ], + deps = [ + "@com_google_absl//absl/cleanup", + "@jni//:copy_jni_hdr_lib", + "//curvefs/sdk/libcurvefs:curvefs_lib", + ], + linkshared = True, +) diff --git a/curvefs/sdk/java/native/io_opencurve_curve_fs_libfs_CurveFSMount.cpp b/curvefs/sdk/java/native/io_opencurve_curve_fs_libfs_CurveFSMount.cpp new file mode 100644 index 0000000000..d9c0abed81 --- /dev/null +++ b/curvefs/sdk/java/native/io_opencurve_curve_fs_libfs_CurveFSMount.cpp @@ -0,0 +1,688 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-08-08 + * Author: Jingli Chen (Wine93) + */ + +#include +#include + +#include "absl/cleanup/cleanup.h" +#include "curvefs/sdk/libcurvefs/libcurvefs.h" +#include "curvefs/sdk/java/native/io_opencurve_curve_fs_libfs_CurveFSMount.h" + +/* Cached field IDs for io.opencurve.curve.fs.CurveStat */ +static jfieldID curvestat_mode_fid; +static jfieldID curvestat_uid_fid; +static jfieldID curvestat_gid_fid; +static jfieldID curvestat_size_fid; +static jfieldID curvestat_blksize_fid; +static jfieldID curvestat_blocks_fid; +static jfieldID curvestat_a_time_fid; +static jfieldID curvestat_m_time_fid; +static jfieldID curvestat_is_file_fid; +static jfieldID curvestat_is_directory_fid; +static jfieldID curvestat_is_symlink_fid; + +/* Cached field IDs for io.opencurve.curve.fs.CurveStatVFS */ +static jfieldID curvestatvfs_bsize_fid; +static jfieldID curvestatvfs_frsize_fid; +static jfieldID curvestatvfs_blocks_fid; +static jfieldID curvestatvfs_bavail_fid; +static jfieldID curvestatvfs_files_fid; +static jfieldID curvestatvfs_fsid_fid; +static jfieldID curvestatvfs_namemax_fid; + +/* + * Setup cached field IDs + */ +static void setup_field_ids(JNIEnv* env) { + jclass curvestat_cls; + jclass curvestatvfs_cls; + +/* + * Get a fieldID from a class with a specific type + * + * clz: jclass + * field: field in clz + * type: integer, long, etc.. + * + * This macro assumes some naming convention that is used + * only in this file: + * + * GETFID(curvestat, mode, I) gets translated into + * curvestat_mode_fid = env->GetFieldID(curvestat_cls, "mode", "I"); + */ +#define GETFID(clz, field, type) do { \ + clz ## _ ## field ## _fid = env->GetFieldID(clz ## _cls, #field, #type); \ + if (!clz ## _ ## field ## _fid) \ + return; \ + } while (0) + + /* Cache CurveStat fields */ + + curvestat_cls = env->FindClass("io/opencurve/curve/fs/libfs/CurveFSStat"); + if (!curvestat_cls) { + return; + } + + GETFID(curvestat, mode, I); + GETFID(curvestat, uid, I); + GETFID(curvestat, gid, I); + GETFID(curvestat, size, J); + GETFID(curvestat, blksize, J); + GETFID(curvestat, blocks, J); + GETFID(curvestat, a_time, J); + GETFID(curvestat, m_time, J); + GETFID(curvestat, is_file, Z); + GETFID(curvestat, is_directory, Z); + GETFID(curvestat, is_symlink, Z); + + /* Cache CurveStatVFS fields */ + + curvestatvfs_cls = + env->FindClass("io/opencurve/curve/fs/libfs/CurveFSStatVFS"); + if (!curvestatvfs_cls) { + return; + } + + GETFID(curvestatvfs, bsize, J); + GETFID(curvestatvfs, frsize, J); + GETFID(curvestatvfs, blocks, J); + GETFID(curvestatvfs, bavail, J); + GETFID(curvestatvfs, files, J); + GETFID(curvestatvfs, fsid, J); + GETFID(curvestatvfs, namemax, J); + +#undef GETFID +} + +static void fill_curvestat(JNIEnv* env, + jobject j_curvestat, + struct stat* stat) { + env->SetIntField(j_curvestat, curvestat_mode_fid, stat->st_mode); + env->SetIntField(j_curvestat, curvestat_uid_fid, stat->st_uid); + env->SetIntField(j_curvestat, curvestat_gid_fid, stat->st_gid); + env->SetLongField(j_curvestat, curvestat_size_fid, stat->st_size); + env->SetLongField(j_curvestat, curvestat_blksize_fid, stat->st_blksize); + env->SetLongField(j_curvestat, curvestat_blocks_fid, stat->st_blocks); + + // mtime + uint64_t time = stat->st_mtim.tv_sec; + time *= 1000; + time += stat->st_mtim.tv_nsec / 1000000; + env->SetLongField(j_curvestat, curvestat_m_time_fid, time); + + // atime + time = stat->st_atim.tv_sec; + time *= 1000; + time += stat->st_atim.tv_nsec / 1000000; + env->SetLongField(j_curvestat, curvestat_a_time_fid, time); + + env->SetBooleanField(j_curvestat, curvestat_is_file_fid, + S_ISREG(stat->st_mode) ? JNI_TRUE : JNI_FALSE); + + env->SetBooleanField(j_curvestat, curvestat_is_directory_fid, + S_ISDIR(stat->st_mode) ? JNI_TRUE : JNI_FALSE); + + env->SetBooleanField(j_curvestat, curvestat_is_symlink_fid, + S_ISLNK(stat->st_mode) ? JNI_TRUE : JNI_FALSE); +} + +static void fill_curvestatvfs(JNIEnv* env, + jobject j_curvestatvfs, + struct statvfs st) { + env->SetLongField(j_curvestatvfs, curvestatvfs_bsize_fid, st.f_bsize); + env->SetLongField(j_curvestatvfs, curvestatvfs_frsize_fid, st.f_frsize); + env->SetLongField(j_curvestatvfs, curvestatvfs_blocks_fid, st.f_blocks); + env->SetLongField(j_curvestatvfs, curvestatvfs_bavail_fid, st.f_bavail); + env->SetLongField(j_curvestatvfs, curvestatvfs_files_fid, st.f_files); + env->SetLongField(j_curvestatvfs, curvestatvfs_fsid_fid, st.f_fsid); + env->SetLongField(j_curvestatvfs, curvestatvfs_namemax_fid, st.f_namemax); +} + +/* Map io_opencurve_curve_fs_libfs_CurveFSMount_O_* open flags to values in libc */ +static inline uint32_t fixup_open_flags(jint jflags) { + uint32_t flags = 0; + +#define FIXUP_OPEN_FLAG(name) \ + if (jflags & io_opencurve_curve_fs_libfs_CurveFSMount_##name) \ + flags |= name; + + FIXUP_OPEN_FLAG(O_RDONLY) + FIXUP_OPEN_FLAG(O_RDWR) + FIXUP_OPEN_FLAG(O_APPEND) + FIXUP_OPEN_FLAG(O_CREAT) + FIXUP_OPEN_FLAG(O_TRUNC) + FIXUP_OPEN_FLAG(O_EXCL) + FIXUP_OPEN_FLAG(O_WRONLY) + FIXUP_OPEN_FLAG(O_DIRECTORY) + +#undef FIXUP_OPEN_FLAG + + return flags; +} + +#define CURVEFS_SETATTR_MODE (1 << 0) +#define CURVEFS_SETATTR_UID (1 << 1) +#define CURVEFS_SETATTR_GID (1 << 2) +#define CURVEFS_SETATTR_SIZE (1 << 3) +#define CURVEFS_SETATTR_ATIME (1 << 4) +#define CURVEFS_SETATTR_MTIME (1 << 5) +#define CURVEFS_SETATTR_ATIME_NOW (1 << 7) +#define CURVEFS_SETATTR_MTIME_NOW (1 << 8) +#define CURVEFS_SETATTR_CTIME (1 << 10) + +/* Map JAVA_SETATTR_* to values in curve lib */ +static inline int fixup_attr_mask(jint jmask) { + int mask = 0; + +#define FIXUP_ATTR_MASK(name) \ + if (jmask & io_opencurve_curve_fs_libfs_CurveFSMount_##name) \ + mask |= CURVEFS_##name; + + FIXUP_ATTR_MASK(SETATTR_MODE) + FIXUP_ATTR_MASK(SETATTR_UID) + FIXUP_ATTR_MASK(SETATTR_GID) + FIXUP_ATTR_MASK(SETATTR_MTIME) + FIXUP_ATTR_MASK(SETATTR_ATIME) + +#undef FIXUP_ATTR_MASK + return mask; +} + +/* + * Exception throwing helper. Adapted from Apache Hadoop header + * org_apache_hadoop.h by adding the do {} while (0) construct. + */ +#define THROW(env, exception_name, message) \ + do { \ + jclass ecls = env->FindClass(exception_name); \ + if (ecls) { \ + int ret = env->ThrowNew(ecls, message); \ + if (ret < 0) { \ + printf("(CurveFS) Fatal Error\n"); \ + } \ + env->DeleteLocalRef(ecls); \ + } \ + } while (0) + +static void handle_error(JNIEnv* env, int rc) { + switch (rc) { + case ENOENT: + THROW(env, "java/io/FileNotFoundException", ""); + return; + case EEXIST: + THROW(env, "org/apache/hadoop/fs/FileAlreadyExistsException", ""); + return; + case ENOTDIR: + THROW(env, "org/apache/hadoop/fs/ParentNotDirectoryException", ""); + return; + default: + break; + } + + THROW(env, "java/io/IOException", strerror(rc)); +} + +// nativeCurveFSCreate: curvefs_create +JNIEXPORT jlong +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSCreate + (JNIEnv* env, jobject) { + setup_field_ids(env); + uintptr_t instance = curvefs_create(); + return reinterpret_cast(instance); +} + +// nativeCurveFSRelease: curvefs_release +JNIEXPORT void +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSRelease + (JNIEnv* env, jobject, jlong j_instance) { + uintptr_t instance = static_cast(j_instance); + return curvefs_release(instance); +} + +// nativeCurveFSConfSet: curvefs_conf_set +JNIEXPORT void +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSConfSet + (JNIEnv* env, jclass, jlong j_instance, jstring j_key, jstring j_value) { + uintptr_t instance = static_cast(j_instance); + const char* key = env->GetStringUTFChars(j_key, NULL); + const char* value = env->GetStringUTFChars(j_value, NULL); + auto defer = absl::MakeCleanup([&]() { + env->ReleaseStringUTFChars(j_key, key); + env->ReleaseStringUTFChars(j_value, value); + }); + + return curvefs_conf_set(instance, key, value); +} + +// nativeCurveFSMount: curvefs_mount +JNIEXPORT jint +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSMount + (JNIEnv* env, jclass, jlong j_instance, + jstring j_fsname, jstring j_mountpoint) { + uintptr_t instance = static_cast(j_instance); + const char* fsname = env->GetStringUTFChars(j_fsname, NULL); + const char* mountpoint = env->GetStringUTFChars(j_mountpoint, NULL); + auto defer = absl::MakeCleanup([&]() { + env->ReleaseStringUTFChars(j_fsname, fsname); + env->ReleaseStringUTFChars(j_mountpoint, mountpoint); + }); + + int rc = curvefs_mount(instance, fsname, mountpoint); + if (rc != 0) { + handle_error(env, rc); + } + return rc; +} + +// nativeCurveFSUmount: curvefs_umount +JNIEXPORT jint +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSUmount + (JNIEnv* env, jclass, jlong j_instance, + jstring j_fsname, jstring j_mountpoint) { + uintptr_t instance = static_cast(j_instance); + const char* fsname = env->GetStringUTFChars(j_fsname, NULL); + const char* mountpoint = env->GetStringUTFChars(j_mountpoint, NULL); + auto defer = absl::MakeCleanup([&]() { + env->ReleaseStringUTFChars(j_fsname, fsname); + env->ReleaseStringUTFChars(j_mountpoint, mountpoint); + }); + + int rc = curvefs_umonut(instance, fsname, mountpoint); + if (rc != 0) { + handle_error(env, rc); + } + return rc; +} + +// nativeCurveFSMkDirs: curvefs_mkdirs +JNIEXPORT jint +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSMkDirs + (JNIEnv* env, jclass, jlong j_instance, jstring j_path, jint j_mode) { + uintptr_t instance = static_cast(j_instance); + const char* path = env->GetStringUTFChars(j_path, NULL); + uint16_t mode = static_cast(j_mode); + auto defer = absl::MakeCleanup([&]() { + env->ReleaseStringUTFChars(j_path, path); + }); + + int rc = curvefs_mkdirs(instance, path, mode); + if (rc == EEXIST) { + rc = 0; + } else if (rc != 0) { + handle_error(env, rc); + } + return rc; +} + +// nativeCurveFSRmDir: curvefs_rmdir +JNIEXPORT jint +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSRmDir + (JNIEnv* env, jclass, jlong j_instance, jstring j_path) { + uintptr_t instance = static_cast(j_instance); + const char* path = env->GetStringUTFChars(j_path, NULL); + auto defer = absl::MakeCleanup([&]() { + env->ReleaseStringUTFChars(j_path, path); + }); + + int rc = curvefs_rmdir(instance, path); + if (rc != 0) { + handle_error(env, rc); + } + return rc; +} + +// nativeCurveFSListDir: curvefs_opendir/curvefs_readdir/curvefs_closedir +JNIEXPORT jobjectArray +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSListDir + (JNIEnv* env, jclass, jlong j_instance, jstring j_path) { + uintptr_t instance = static_cast(j_instance); + const char* path = env->GetStringUTFChars(j_path, NULL); + auto defer = absl::MakeCleanup([&]() { + env->ReleaseStringUTFChars(j_path, path); + }); + + // curvefs_opendir + dir_stream_t dir_stream; + auto rc = curvefs_opendir(instance, path, &dir_stream); + if (rc != 0) { + handle_error(env, rc); + return NULL; + } + + // curvefs_readdir + std::vector dirents; + dirent_t dirent; + for ( ;; ) { + ssize_t n = curvefs_readdir(instance, &dir_stream, &dirent); + if (n < 0) { + handle_error(env, rc); + return NULL; + } else if (n == 0) { + break; + } + dirents.push_back(dirent); + } + + // closedir + rc = curvefs_closedir(instance, &dir_stream); + if (rc != 0) { + handle_error(env, rc); + return NULL; + } + + // extract entry name + jobjectArray j_names = env->NewObjectArray( + dirents.size(), env->FindClass("java/lang/String"), NULL); + + for (int i = 0; i < dirents.size(); i++) { + jstring j_name = env->NewStringUTF(dirents[i].name); + env->SetObjectArrayElement(j_names, i, j_name); + env->DeleteLocalRef(j_name); + } + return j_names; +} + +// nativeCurveFSOpen: curvefs_open +JNIEXPORT jint +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSOpen + (JNIEnv* env, jclass, + jlong j_instance, jstring j_path, jint j_flags, jint j_mode) { + uintptr_t instance = static_cast(j_instance); + const char* path = env->GetStringUTFChars(j_path, NULL); + uint32_t flags = fixup_open_flags(j_flags); + uint16_t mode = static_cast(j_mode); + auto defer = absl::MakeCleanup([&]() { + env->ReleaseStringUTFChars(j_path, path); + }); + + int fd = curvefs_open(instance, path, flags, mode); + if (fd < 0) { + handle_error(env, fd); + } + return fd; +} + +// nativeCurveFSLSeek: curvefs_lseek +JNIEXPORT jlong +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSLSeek + (JNIEnv* env, jclass, + jlong j_instance, jint j_fd, jlong j_offset, jint j_whence) { + uintptr_t instance = static_cast(j_instance); + int fd = static_cast(j_fd); + uint64_t offset = static_cast(j_offset); + + int whence; + switch (j_whence) { + case io_opencurve_curve_fs_libfs_CurveFSMount_SEEK_SET: + whence = SEEK_SET; + break; + case io_opencurve_curve_fs_libfs_CurveFSMount_SEEK_CUR: + whence = SEEK_CUR; + break; + case io_opencurve_curve_fs_libfs_CurveFSMount_SEEK_END: + whence = SEEK_END; + break; + default: + return -1; + } + + int rc = curvefs_lseek(instance, fd, offset, whence); + if (rc != 0) { + handle_error(env, rc); + } + return rc; +} + +// nativieCurveFSRead: curvefs_read +JNIEXPORT jlong +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativieCurveFSRead + (JNIEnv* env, jclass, jlong j_instance, jint j_fd, + jbyteArray j_buffer, jlong j_size, jlong j_offset) { + uintptr_t instance = static_cast(j_instance); + int fd = static_cast(j_fd); + jbyte* c_buffer = env->GetByteArrayElements(j_buffer, NULL); + char* buffer = reinterpret_cast(c_buffer); + size_t count = static_cast(j_size); + auto defer = absl::MakeCleanup([&]() { + env->ReleaseByteArrayElements(j_buffer, c_buffer, 0); + }); + + ssize_t n = curvefs_read(instance, fd, buffer, count); + if (n < 0) { + handle_error(env, n); + } + return static_cast(n); +} + +// nativieCurveFSWrite: curvefs_write +JNIEXPORT jlong +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativieCurveFSWrite + (JNIEnv* env, jclass, jlong j_instance, jint j_fd, + jbyteArray j_buffer, jlong j_size, jlong j_offset) { + uintptr_t instance = static_cast(j_instance); + int fd = static_cast(j_fd); + jbyte* c_buffer = env->GetByteArrayElements(j_buffer, NULL); + char* buffer = reinterpret_cast(c_buffer); + size_t count = static_cast(j_size); + auto defer = absl::MakeCleanup([&]() { + env->ReleaseByteArrayElements(j_buffer, c_buffer, 0); + }); + + ssize_t n = curvefs_write(instance, fd, buffer, count); + if (n < 0) { + handle_error(env, n); + } + return static_cast(n); +} + +// nativeCurveFSFSync: curvefs_fsync +JNIEXPORT jint +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSFSync + (JNIEnv* env, jclass, jlong j_instance, jint j_fd) { + uintptr_t instance = static_cast(j_instance); + int fd = static_cast(j_fd); + + int rc = curvefs_fsync(instance, fd); + if (rc != 0) { + handle_error(env, rc); + } + return rc; +} + +// nativeCurveFSClose: curvefs_close +JNIEXPORT jint +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSClose + (JNIEnv* env, jclass, jlong j_instance, jint j_fd) { + uintptr_t instance = static_cast(j_instance); + int fd = static_cast(j_fd); + + int rc = curvefs_close(instance, fd); + if (rc != 0) { + handle_error(env, rc); + } + return rc; +} + +// nativeCurveFSUnlink: curvefs_unlink +JNIEXPORT jint +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSUnlink + (JNIEnv* env, jclass, jlong j_instance, jstring j_path) { + uintptr_t instance = static_cast(j_instance); + const char* path = env->GetStringUTFChars(j_path, NULL); + auto defer = absl::MakeCleanup([&]() { + env->ReleaseStringUTFChars(j_path, path); + }); + + int rc = curvefs_unlink(instance, path); + if (rc != 0) { + handle_error(env, rc); + } + return rc; +} + +// nativeCurveFSStatFs: curvefs_statfs +JNIEXPORT jint +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSStatFs + (JNIEnv* env, jclass, + jlong j_instance, jobject j_curvestatvfs) { + uintptr_t instance = static_cast(j_instance); + + struct statvfs statvfs; + int rc = curvefs_statfs(instance, &statvfs); + if (rc != 0) { + handle_error(env, rc); + return rc; + } + + fill_curvestatvfs(env, j_curvestatvfs, statvfs); + return rc; +} + +// nativeCurveFSLstat: curvefs_lstat +JNIEXPORT jint +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSLstat + (JNIEnv* env, jclass, + jlong j_instance, jstring j_path, jobject j_curvestat) { + uintptr_t instance = static_cast(j_instance); + const char* path = env->GetStringUTFChars(j_path, NULL); + auto defer = absl::MakeCleanup([&]() { + env->ReleaseStringUTFChars(j_path, path); + }); + + // curvefs_lstat + struct stat stat; + auto rc = curvefs_lstat(instance, path, &stat); + if (rc != 0) { + handle_error(env, rc); + return rc; + } + + fill_curvestat(env, j_curvestat, &stat); + return rc; +} + +// nativeCurveFSFStat: curvefs_fstat +JNIEXPORT jint +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSFStat + (JNIEnv* env, jclass, jlong j_instance, jint j_fd, jobject j_curvestat) { + uintptr_t instance = static_cast(j_instance); + int fd = static_cast(j_fd); + + // curvefs_fstat + struct stat stat; + auto rc = curvefs_fstat(instance, fd, &stat); + if (rc != 0) { + handle_error(env, rc); + return rc; + } + + fill_curvestat(env, j_curvestat, &stat); + return rc; +} + +// nativeCurveFSSetAttr: curvefs_setattr +JNIEXPORT jint +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSSetAttr + (JNIEnv* env, jclass, + jlong j_instance, jstring j_path, jobject j_curvestat, jint j_mask) { + uintptr_t instance = static_cast(j_instance); + const char* path = env->GetStringUTFChars(j_path, NULL); + int to_set = fixup_attr_mask(j_mask); + auto defer = absl::MakeCleanup([&]() { + env->ReleaseStringUTFChars(j_path, path); + }); + + struct stat stat; + memset(&stat, 0, sizeof(stat)); + stat.st_mode = env->GetIntField(j_curvestat, curvestat_mode_fid); + stat.st_uid = env->GetIntField(j_curvestat, curvestat_uid_fid); + stat.st_gid = env->GetIntField(j_curvestat, curvestat_gid_fid); + uint64_t mtime_msec = env->GetLongField(j_curvestat, curvestat_m_time_fid); + uint64_t atime_msec = env->GetLongField(j_curvestat, curvestat_a_time_fid); + stat.st_mtim.tv_sec = mtime_msec / 1000; + stat.st_mtim.tv_nsec = (mtime_msec % 1000) * 1000000; + stat.st_atim.tv_sec = atime_msec / 1000; + stat.st_atim.tv_nsec = (atime_msec % 1000) * 1000000; + + int rc = curvefs_setattr(instance, path, &stat, to_set); + if (rc != 0) { + handle_error(env, rc); + } + return rc; +} + +// nativeCurveFSChmod: curvefs_chmod +JNIEXPORT jint +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSChmod + (JNIEnv* env, jclass, jlong j_instance, jstring j_path, jint j_mode) { + uintptr_t instance = static_cast(j_instance); + uint16_t mode = static_cast(j_mode); + const char* path = env->GetStringUTFChars(j_path, NULL); + auto defer = absl::MakeCleanup([&]() { + env->ReleaseStringUTFChars(j_path, path); + }); + + int rc = curvefs_chmod(instance, path, mode); + if (rc != 0) { + handle_error(env, rc); + } + return rc; +} + +// nativeCurveFSChown: curvefs_chown +JNIEXPORT jint +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSChown + (JNIEnv* env, jclass, + jlong j_instance, jstring j_path, jint j_uid, jint j_gid) { + uintptr_t instance = static_cast(j_instance); + uint32_t uid = static_cast(j_uid); + uint32_t gid = static_cast(j_gid); + const char* path = env->GetStringUTFChars(j_path, NULL); + auto defer = absl::MakeCleanup([&]() { + env->ReleaseStringUTFChars(j_path, path); + }); + + int rc = curvefs_chown(instance, path, uid, gid); + if (rc != 0) { + handle_error(env, rc); + } + return rc; +} + +// nativeCurveFSRename: curvefs_rename +JNIEXPORT jint +JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSRename + (JNIEnv* env, jclass, jlong j_instance, jstring j_src, jstring j_dst) { + uintptr_t instance = static_cast(j_instance); + const char* src = env->GetStringUTFChars(j_src, NULL); + const char* dst = env->GetStringUTFChars(j_dst, NULL); + auto defer = absl::MakeCleanup([&]() { + env->ReleaseStringUTFChars(j_src, src); + env->ReleaseStringUTFChars(j_dst, dst); + }); + + int rc = curvefs_rename(instance, src, dst); + if (rc != 0) { + handle_error(env, rc); + } + return rc; +} diff --git a/curvefs/sdk/java/native/io_opencurve_curve_fs_libfs_CurveFSMount.h b/curvefs/sdk/java/native/io_opencurve_curve_fs_libfs_CurveFSMount.h new file mode 100644 index 0000000000..05d0a21e3f --- /dev/null +++ b/curvefs/sdk/java/native/io_opencurve_curve_fs_libfs_CurveFSMount.h @@ -0,0 +1,221 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class io_opencurve_curve_fs_libfs_CurveFSMount */ + +#ifndef _Included_io_opencurve_curve_fs_libfs_CurveFSMount +#define _Included_io_opencurve_curve_fs_libfs_CurveFSMount +#ifdef __cplusplus +extern "C" { +#endif +#undef io_opencurve_curve_fs_libfs_CurveFSMount_O_RDONLY +#define io_opencurve_curve_fs_libfs_CurveFSMount_O_RDONLY 1L +#undef io_opencurve_curve_fs_libfs_CurveFSMount_O_RDWR +#define io_opencurve_curve_fs_libfs_CurveFSMount_O_RDWR 2L +#undef io_opencurve_curve_fs_libfs_CurveFSMount_O_APPEND +#define io_opencurve_curve_fs_libfs_CurveFSMount_O_APPEND 4L +#undef io_opencurve_curve_fs_libfs_CurveFSMount_O_CREAT +#define io_opencurve_curve_fs_libfs_CurveFSMount_O_CREAT 8L +#undef io_opencurve_curve_fs_libfs_CurveFSMount_O_TRUNC +#define io_opencurve_curve_fs_libfs_CurveFSMount_O_TRUNC 16L +#undef io_opencurve_curve_fs_libfs_CurveFSMount_O_EXCL +#define io_opencurve_curve_fs_libfs_CurveFSMount_O_EXCL 32L +#undef io_opencurve_curve_fs_libfs_CurveFSMount_O_WRONLY +#define io_opencurve_curve_fs_libfs_CurveFSMount_O_WRONLY 64L +#undef io_opencurve_curve_fs_libfs_CurveFSMount_O_DIRECTORY +#define io_opencurve_curve_fs_libfs_CurveFSMount_O_DIRECTORY 128L +#undef io_opencurve_curve_fs_libfs_CurveFSMount_SEEK_SET +#define io_opencurve_curve_fs_libfs_CurveFSMount_SEEK_SET 0L +#undef io_opencurve_curve_fs_libfs_CurveFSMount_SEEK_CUR +#define io_opencurve_curve_fs_libfs_CurveFSMount_SEEK_CUR 1L +#undef io_opencurve_curve_fs_libfs_CurveFSMount_SEEK_END +#define io_opencurve_curve_fs_libfs_CurveFSMount_SEEK_END 2L +#undef io_opencurve_curve_fs_libfs_CurveFSMount_SETATTR_MODE +#define io_opencurve_curve_fs_libfs_CurveFSMount_SETATTR_MODE 1L +#undef io_opencurve_curve_fs_libfs_CurveFSMount_SETATTR_UID +#define io_opencurve_curve_fs_libfs_CurveFSMount_SETATTR_UID 2L +#undef io_opencurve_curve_fs_libfs_CurveFSMount_SETATTR_GID +#define io_opencurve_curve_fs_libfs_CurveFSMount_SETATTR_GID 4L +#undef io_opencurve_curve_fs_libfs_CurveFSMount_SETATTR_MTIME +#define io_opencurve_curve_fs_libfs_CurveFSMount_SETATTR_MTIME 8L +#undef io_opencurve_curve_fs_libfs_CurveFSMount_SETATTR_ATIME +#define io_opencurve_curve_fs_libfs_CurveFSMount_SETATTR_ATIME 16L +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSCreate + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSCreate + (JNIEnv *, jobject); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSRelease + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSRelease + (JNIEnv *, jobject, jlong); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSConfSet + * Signature: (JLjava/lang/String;Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSConfSet + (JNIEnv *, jclass, jlong, jstring, jstring); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSMount + * Signature: (JLjava/lang/String;Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSMount + (JNIEnv *, jclass, jlong, jstring, jstring); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSUmount + * Signature: (JLjava/lang/String;Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSUmount + (JNIEnv *, jclass, jlong, jstring, jstring); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSMkDirs + * Signature: (JLjava/lang/String;I)I + */ +JNIEXPORT jint JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSMkDirs + (JNIEnv *, jclass, jlong, jstring, jint); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSRmDir + * Signature: (JLjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSRmDir + (JNIEnv *, jclass, jlong, jstring); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSListDir + * Signature: (JLjava/lang/String;)[Ljava/lang/String; + */ +JNIEXPORT jobjectArray JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSListDir + (JNIEnv *, jclass, jlong, jstring); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSOpen + * Signature: (JLjava/lang/String;II)I + */ +JNIEXPORT jint JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSOpen + (JNIEnv *, jclass, jlong, jstring, jint, jint); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSLSeek + * Signature: (JIJI)J + */ +JNIEXPORT jlong JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSLSeek + (JNIEnv *, jclass, jlong, jint, jlong, jint); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativieCurveFSRead + * Signature: (JI[BJJ)J + */ +JNIEXPORT jlong JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativieCurveFSRead + (JNIEnv *, jclass, jlong, jint, jbyteArray, jlong, jlong); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativieCurveFSWrite + * Signature: (JI[BJJ)J + */ +JNIEXPORT jlong JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativieCurveFSWrite + (JNIEnv *, jclass, jlong, jint, jbyteArray, jlong, jlong); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSFSync + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSFSync + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSClose + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSClose + (JNIEnv *, jclass, jlong, jint); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSUnlink + * Signature: (JLjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSUnlink + (JNIEnv *, jclass, jlong, jstring); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSStatFs + * Signature: (JLio/opencurve/curve/fs/libfs/CurveFSStatVFS;)I + */ +JNIEXPORT jint JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSStatFs + (JNIEnv *, jclass, jlong, jobject); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSLstat + * Signature: (JLjava/lang/String;Lio/opencurve/curve/fs/libfs/CurveFSStat;)I + */ +JNIEXPORT jint JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSLstat + (JNIEnv *, jclass, jlong, jstring, jobject); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSFStat + * Signature: (JILio/opencurve/curve/fs/libfs/CurveFSStat;)I + */ +JNIEXPORT jint JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSFStat + (JNIEnv *, jclass, jlong, jint, jobject); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSSetAttr + * Signature: (JLjava/lang/String;Lio/opencurve/curve/fs/libfs/CurveFSStat;I)I + */ +JNIEXPORT jint JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSSetAttr + (JNIEnv *, jclass, jlong, jstring, jobject, jint); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSChmod + * Signature: (JLjava/lang/String;I)I + */ +JNIEXPORT jint JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSChmod + (JNIEnv *, jclass, jlong, jstring, jint); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSChown + * Signature: (JLjava/lang/String;II)I + */ +JNIEXPORT jint JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSChown + (JNIEnv *, jclass, jlong, jstring, jint, jint); + +/* + * Class: io_opencurve_curve_fs_libfs_CurveFSMount + * Method: nativeCurveFSRename + * Signature: (JLjava/lang/String;Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_io_opencurve_curve_fs_libfs_CurveFSMount_nativeCurveFSRename + (JNIEnv *, jclass, jlong, jstring, jstring); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/curvefs/sdk/java/pom.xml b/curvefs/sdk/java/pom.xml new file mode 100644 index 0000000000..b3f15f585c --- /dev/null +++ b/curvefs/sdk/java/pom.xml @@ -0,0 +1,92 @@ + + + + 4.0.0 + + io.opencurve.curve.fs.hadoop + curvefs-hadoop + 1.0-SNAPSHOT + + + 8 + 8 + UTF-8 + 2.7.3 + 0.80.5 + 1.15.4 + + + + + ali-maven + http://maven.aliyun.com/nexus/content/groups/public + + + + + + + native/build + + + + + + + net.java.dev.jna + jna-platform + 4.0.0 + + + + org.apache.hadoop + hadoop-common + ${hadoop.version} + provided + + + + org.apache.commons + commons-compress + 1.24.0 + + + + org.apache.flink + flink-hadoop-fs + ${flink.version} + provided + + + + org.apache.flink + flink-core + ${flink.version} + provided + + + + junit + junit + 4.13.1 + test + + + + org.apache.flink + flink-connector-files + ${flink.version} + provided + + + + org.apache.flink + flink-table-common + 1.15.4 + provided + + + + diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/flink/CurveFileSystemFactory.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/flink/CurveFileSystemFactory.java new file mode 100644 index 0000000000..ac42dfaf82 --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/flink/CurveFileSystemFactory.java @@ -0,0 +1,48 @@ +package io.opencurve.curve.fs.flink; + +import io.opencurve.curve.fs.hadoop.CurveFileSystem; +import org.apache.flink.core.fs.FileSystem; +import org.apache.flink.core.fs.FileSystemFactory; +import org.apache.flink.runtime.fs.hdfs.HadoopFileSystem; +import org.apache.hadoop.conf.Configuration; + +import java.io.IOException; +import java.net.URI; + +public class CurveFileSystemFactory implements FileSystemFactory { + private org.apache.hadoop.conf.Configuration conf; + + private static final String CURVE_FS_CONFIG_PREFIXES = "curvefs."; + private static final String FLINK_CONFIG_PREFIXES = "fs."; + public static String SCHEME = "curvefs"; + + @Override + public void configure(org.apache.flink.configuration.Configuration config) { + conf = new Configuration(); + if (config != null) { + for (String key : config.keySet()) { + if (key.startsWith(CURVE_FS_CONFIG_PREFIXES) || key.startsWith(FLINK_CONFIG_PREFIXES)) { + String value = config.getString(key, null); + if (value != null) { + if (CurveFileSystem.class.getCanonicalName().equals(value.trim())) { + SCHEME = key.split("\\.")[1]; + } + conf.set(key, value); + } + } + } + } + } + + @Override + public String getScheme() { + return SCHEME; + } + + @Override + public FileSystem create(URI uri) throws IOException { + CurveFileSystem fs = new CurveFileSystem(); + fs.initialize(uri, conf); + return new HadoopFileSystem(fs); + } +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/flink/CurveFileSystemTableFactory.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/flink/CurveFileSystemTableFactory.java new file mode 100644 index 0000000000..da68151bbd --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/flink/CurveFileSystemTableFactory.java @@ -0,0 +1,10 @@ +package io.opencurve.curve.fs.flink; + +import org.apache.flink.connector.file.table.FileSystemTableFactory; + +public class CurveFileSystemTableFactory extends FileSystemTableFactory { + @Override + public String factoryIdentifier() { + return CurveFileSystemFactory.SCHEME; + } +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFS.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFS.java new file mode 100644 index 0000000000..f15008a363 --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFS.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-08-01 + * Author: NetEase Media Bigdata + */ + +package io.opencurve.curve.fs.hadoop; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.AbstractFileSystem; +import org.apache.hadoop.fs.DelegateToFileSystem; +import io.opencurve.curve.fs.flink.CurveFileSystemFactory; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +/** + * The CurveFS implementation of AbstractFileSystem. + * This impl delegates to the old FileSystem + */ +public class CurveFS extends DelegateToFileSystem { + /** + * This constructor has the signature needed by + * {@link AbstractFileSystem#createFileSystem(URI, Configuration)}. + * + * @param theUri which must be that of localFs + * @param conf + * @throws IOException + * @throws URISyntaxException + */ + CurveFS(final URI theUri, final Configuration conf) throws IOException, + URISyntaxException { + super(theUri, new CurveFileSystem(conf), conf, CurveFileSystemFactory.SCHEME, true); + } +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFSInputStream.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFSInputStream.java new file mode 100644 index 0000000000..2dd1be8d1d --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFSInputStream.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-08-01 + * Author: NetEase Media Bigdata + */ + +package io.opencurve.curve.fs.hadoop; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FSInputStream; +import io.opencurve.curve.fs.libfs.CurveFSMount; + +import java.io.IOException; + +/** + *

+ * An {@link FSInputStream} for a CurveFileSystem and corresponding + * Curve instance. + */ +public class CurveFSInputStream extends FSInputStream { + private static final Log LOG = LogFactory.getLog(CurveFSInputStream.class); + private boolean closed; + + private int fileHandle; + + private long fileLength; + + private CurveFSProto curve; + + private byte[] buffer; + private int bufPos = 0; + private int bufValid = 0; + private long curvePos = 0; + + /** + * Create a new CurveInputStream. + * @param conf The system configuration. Unused. + * @param fh The filehandle provided by Curve to reference. + * @param flength The current length of the file. If the length changes + * you will need to close and re-open it to access the new data. + */ + public CurveFSInputStream(Configuration conf, CurveFSProto curvefs, + int fh, long flength, int bufferSize) { + // Whoever's calling the constructor is responsible for doing the actual curve_open + // call and providing the file handle. + fileLength = flength; + fileHandle = fh; + closed = false; + curve = curvefs; + buffer = new byte[1<<21]; + LOG.debug("CurveInputStream constructor: initializing stream with fh " + + fh + " and file length " + flength); + } + + /** Curve likes things to be closed before it shuts down, + * so closing the IOStream stuff voluntarily in a finalizer is good + */ + protected void finalize() throws Throwable { + try { + if (!closed) { + close(); + } + } finally { + super.finalize(); + } + } + + private synchronized boolean fillBuffer() throws IOException { + bufValid = curve.read(fileHandle, buffer, buffer.length, -1); + bufPos = 0; + if (bufValid < 0) { + int err = bufValid; + + bufValid = 0; + + // attempt to reset to old position. If it fails, too bad. + curve.lseek(fileHandle, curvePos, CurveFSMount.SEEK_SET); + throw new IOException("Failed to fill read buffer! Error code:" + err); + } + curvePos += bufValid; + return (bufValid != 0); + } + + /* + * Get the current position of the stream. + */ + public synchronized long getPos() throws IOException { + return curvePos - bufValid + bufPos; + } + + /** + * Find the number of bytes remaining in the file. + */ + @Override + public synchronized int available() throws IOException { + if (closed) { + throw new IOException("file is closed"); + } + return (int) (fileLength - getPos()); + } + + public synchronized void seek(long targetPos) throws IOException { + LOG.trace("CurveInputStream.seek: Seeking to position " + targetPos + " on fd " + + fileHandle); + if (targetPos > fileLength) { + throw new IOException("CurveInputStream.seek: failed seek to position " + + targetPos + " on fd " + fileHandle + + ": Cannot seek after EOF " + fileLength); + } + long oldPos = curvePos; + + curvePos = curve.lseek(fileHandle, targetPos, CurveFSMount.SEEK_SET); + bufValid = 0; + bufPos = 0; + if (curvePos < 0) { + curvePos = oldPos; + throw new IOException("Curve failed to seek to new position!"); + } + } + + /** + * Failovers are handled by the Curve code at a very low level; + * if there are issues that can be solved by changing sources + * they'll be dealt with before anybody even tries to call this method! + * @return false. + */ + public synchronized boolean seekToNewSource(long targetPos) { + return false; + } + + /** + * Read a byte from the file. + * @return the next byte. + */ + @Override + public synchronized int read() throws IOException { + LOG.trace( + "CurveInputStream.read: Reading a single byte from fd " + fileHandle + + " by calling general read function"); + + byte result[] = new byte[1]; + + if (getPos() >= fileLength) { + return -1; + } + + if (-1 == read(result, 0, 1)) { + return -1; + } + + if (result[0] < 0) { + return 256 + (int) result[0]; + } else { + return result[0]; + } + } + + /** + * Read a specified number of bytes from the file into a byte[]. + * @param buf the byte array to read into. + * @param off the offset to start at in the file + * @param len the number of bytes to read + * @return 0 if successful, otherwise an error code. + * @throws IOException on bad input. + */ + @Override + public synchronized int read(byte buf[], int off, int len) throws IOException { + LOG.trace( + "CurveInputStream.read: Reading " + len + " bytes from fd " + fileHandle); + + if (closed) { + throw new IOException( + "CurveInputStream.read: cannot read " + len + " bytes from fd " + + fileHandle + ": stream closed"); + } + + // ensure we're not past the end of the file + if (getPos() >= fileLength) { + LOG.debug( + "CurveInputStream.read: cannot read " + len + " bytes from fd " + + fileHandle + ": current position is " + getPos() + + " and file length is " + fileLength); + + return -1; + } + + int totalRead = 0; + int initialLen = len; + int read; + + do { + read = Math.min(len, bufValid - bufPos); + try { + System.arraycopy(buffer, bufPos, buf, off, read); + } catch (IndexOutOfBoundsException ie) { + throw new IOException( + "CurveInputStream.read: Indices out of bounds:" + "read length is " + + len + ", buffer offset is " + off + ", and buffer size is " + + buf.length); + } catch (ArrayStoreException ae) { + throw new IOException( + "Uh-oh, CurveInputStream failed to do an array" + + "copy due to type mismatch..."); + } catch (NullPointerException ne) { + throw new IOException( + "CurveInputStream.read: cannot read " + len + "bytes from fd:" + + fileHandle + ": buf is null"); + } + bufPos += read; + len -= read; + off += read; + totalRead += read; + } while (len > 0 && fillBuffer()); + + LOG.trace( + "CurveInputStream.read: Reading " + initialLen + " bytes from fd " + + fileHandle + ": succeeded in reading " + totalRead + " bytes"); + return totalRead; + } + + /** + * Close the CurveInputStream and release the associated filehandle. + */ + @Override + public void close() throws IOException { + LOG.trace("CurveOutputStream.close:enter"); + if (!closed) { + curve.close(fileHandle); + closed = true; + LOG.trace("CurveOutputStream.close:exit"); + } + } +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFSOutputStream.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFSOutputStream.java new file mode 100644 index 0000000000..06855bcd7d --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFSOutputStream.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-08-01 + * Author: NetEase Media Bigdata + */ + +package io.opencurve.curve.fs.hadoop; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import io.opencurve.curve.fs.libfs.CurveFSMount; + +import java.io.IOException; +import java.io.OutputStream; + +/** + *

+ * An {@link OutputStream} for a CurveFileSystem and corresponding + * Curve instance. + * + * TODO: + * - When libcurvefs-jni supports ByteBuffer interface we can get rid of the + * use of the buffer here to reduce memory copies and just use buffers in + * libcurvefs. Currently it might be useful to reduce JNI crossings, but not + * much more. + */ +public class CurveFSOutputStream extends OutputStream { + private boolean closed; + + private CurveFSProto curve; + + private int fileHandle; + + private byte[] buffer; + private int bufUsed = 0; + + /** + * Construct the CurveOutputStream. + * @param conf The FileSystem configuration. + * @param fh The Curve filehandle to connect to. + */ + public CurveFSOutputStream(Configuration conf, CurveFSProto curvefs, + int fh, int bufferSize) { + curve = curvefs; + fileHandle = fh; + closed = false; + buffer = new byte[1<<21]; + } + + /** + * Close the Curve file handle if close() wasn't explicitly called. + */ + protected void finalize() throws Throwable { + try { + if (!closed) { + close(); + } + } finally { + super.finalize(); + } + } + + /** + * Ensure that the stream is opened. + */ + private synchronized void checkOpen() throws IOException { + if (closed) { + throw new IOException("operation on closed stream (fd=" + fileHandle + ")"); + } + } + + /** + * Get the current position in the file. + * @return The file offset in bytes. + */ + public synchronized long getPos() throws IOException { + checkOpen(); + return curve.lseek(fileHandle, 0, CurveFSMount.SEEK_CUR); + } + + @Override + public synchronized void write(int b) throws IOException { + byte buf[] = new byte[1]; + buf[0] = (byte) b; + write(buf, 0, 1); + } + + @Override + public synchronized void write(byte buf[], int off, int len) throws IOException { + checkOpen(); + + while (len > 0) { + int remaining = Math.min(len, buffer.length - bufUsed); + System.arraycopy(buf, off, buffer, bufUsed, remaining); + + bufUsed += remaining; + off += remaining; + len -= remaining; + + if (buffer.length == bufUsed) { + flushBuffer(); + } + } + } + + /* + * Moves data from the buffer into libcurvefs. + */ + private synchronized void flushBuffer() throws IOException { + if (bufUsed == 0) { + return; + } + + while (bufUsed > 0) { + int ret = curve.write(fileHandle, buffer, bufUsed, -1); + if (ret < 0) { + throw new IOException("curve.write: ret=" + ret); + } + + if (ret == bufUsed) { + bufUsed = 0; + return; + } + + assert(ret > 0); + assert(ret < bufUsed); + + /* + * TODO: handle a partial write by shifting the remainder of the data in + * the buffer back to the beginning and retrying the write. It would + * probably be better to use a ByteBuffer 'view' here, and I believe + * using a ByteBuffer has some other performance benefits but we'll + * likely need to update the libcurvefs-jni implementation. + */ + int remaining = bufUsed - ret; + System.arraycopy(buffer, ret, buffer, 0, remaining); + bufUsed -= ret; + } + + assert(bufUsed == 0); + } + + @Override + public synchronized void flush() throws IOException { + checkOpen(); + flushBuffer(); // buffer -> libcurvefs + curve.fsync(fileHandle); // libcurvefs -> cluster + } + + @Override + public synchronized void close() throws IOException { + checkOpen(); + flush(); + curve.close(fileHandle); + closed = true; + } +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFSProto.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFSProto.java new file mode 100644 index 0000000000..df8ab69b21 --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFSProto.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-08-01 + * Author: NetEase Media Bigdata + */ + +package io.opencurve.curve.fs.hadoop; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import io.opencurve.curve.fs.libfs.CurveFSStat; +import io.opencurve.curve.fs.libfs.CurveFSStatVFS; + +import java.io.IOException; +import java.net.URI; + +abstract class CurveFSProto { + // init* + abstract void initialize(URI uri, Configuration conf) throws IOException; + abstract void shutdown() throws IOException; + // directory* + abstract void mkdirs(Path path, int mode) throws IOException; + abstract void rmdir(Path path) throws IOException; + abstract String[] listdir(Path path) throws IOException; + // file* + abstract int open(Path path, int flags, int mode) throws IOException; + abstract long lseek(int fd, long offset, int whence) throws IOException; + abstract int write(int fd, byte[] buf, long size, long offset) throws IOException; + abstract int read(int fd, byte[] buf, long size, long offset) throws IOException; + abstract void fsync(int fd) throws IOException; + abstract void close(int fd) throws IOException; + abstract void unlink(Path path) throws IOException; + // others + abstract void statfs(Path path, CurveFSStatVFS stat) throws IOException; + abstract void lstat(Path path, CurveFSStat stat) throws IOException; + abstract void fstat(int fd, CurveFSStat stat) throws IOException; + abstract void setattr(Path path, CurveFSStat stat, int mask) throws IOException; + abstract void chmod(Path path, int mode) throws IOException; + abstract void chown(Path path, int uid, int gid) throws IOException; + abstract void rename(Path src, Path dst) throws IOException; +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFSTalker.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFSTalker.java new file mode 100644 index 0000000000..90366cc210 --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFSTalker.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-08-01 + * Author: NetEase Media Bigdata + */ + +package io.opencurve.curve.fs.hadoop; + +import org.apache.commons.logging.Log; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import io.opencurve.curve.fs.libfs.CurveFSMount; +import io.opencurve.curve.fs.libfs.CurveFSStat; +import io.opencurve.curve.fs.libfs.CurveFSStatVFS; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URI; +import java.util.Map; + +class CurveFSTalker extends CurveFSProto { + private CurveFSMount mount; + private String fsname = null; + private boolean inited = false; + + private static final String PREFIX_KEY = "curvefs"; + + CurveFSTalker(Configuration conf, Log log) { + mount = null; + } + + private String tostr(Path path) { + if (null == path) { + return "/"; + } + return path.toUri().getPath(); + } + + private void loadCfg(Configuration conf) { + Map m = conf.getValByRegex("^" + PREFIX_KEY + "\\..*"); + for (Map.Entry entry : m.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + if (key.equals(PREFIX_KEY + ".name")) { + fsname = value; + } else { + mount.confSet(key.substring(PREFIX_KEY.length() + 1), value); + } + } + } + + @Override + void initialize(URI uri, Configuration conf) throws IOException { + mount = new CurveFSMount(); + loadCfg(conf); + if (null == fsname || fsname.isEmpty()) { + throw new IOException("curvefs.name is not set"); + } + mount.mount(fsname, "/"); + inited = true; + } + + @Override + void shutdown() throws IOException { + if (inited) { + mount.umount(fsname, "/"); + mount = null; + inited = false; + } + } + + @Override + void mkdirs(Path path, int mode) throws IOException { + mount.mkdirs(tostr(path), mode); + } + + @Override + void rmdir(Path path) throws IOException { + mount.rmdir(tostr(path)); + } + + @Override + String[] listdir(Path path) throws IOException { + CurveFSStat stat = new CurveFSStat(); + try { + mount.lstat(tostr(path), stat); + } catch (FileNotFoundException e) { + return null; + } + if (!stat.isDir()) { + return null; + } + + return mount.listdir(tostr(path)); + } + + @Override + int open(Path path, int flags, int mode) throws IOException { + return mount.open(tostr(path), flags, mode); + } + + @Override + long lseek(int fd, long offset, int whence) throws IOException { + return mount.lseek(fd, offset, whence); + } + + @Override + int write(int fd, byte[] buf, long size, long offset) throws IOException { + return mount.write(fd, buf, size, offset); + } + + @Override + int read(int fd, byte[] buf, long size, long offset) throws IOException { + return mount.read(fd, buf, size, offset); + } + + @Override + void fsync(int fd) throws IOException { + mount.fsync(fd); + } + + @Override + void close(int fd) throws IOException { + mount.close(fd); + } + + @Override + void unlink(Path path) throws IOException { + mount.unlink(tostr(path)); + } + + @Override + void statfs(Path path, CurveFSStatVFS stat) throws IOException { + mount.statfs(tostr(path), stat); + } + + @Override + void lstat(Path path, CurveFSStat stat) throws IOException { + mount.lstat(tostr(path), stat); + } + + @Override + void fstat(int fd, CurveFSStat stat) throws IOException { + mount.fstat(fd, stat); + } + + @Override + void setattr(Path path, CurveFSStat stat, int mask) throws IOException { + mount.setattr(tostr(path), stat, mask); + } + + @Override + void chmod(Path path, int mode) throws IOException { + mount.chmod(tostr(path), mode); + } + + @Override + void chown(Path path, int uid, int gid) throws IOException { + mount.chown(tostr(path), uid, gid); + } + + @Override + void rename(Path src, Path dst) throws IOException { + mount.rename(tostr(src), tostr(dst)); + } +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFileSystem.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFileSystem.java new file mode 100644 index 0000000000..09df042c1b --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/CurveFileSystem.java @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-08-01 + * Author: NetEase Media Bigdata + */ + +package io.opencurve.curve.fs.hadoop; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.*; +import org.apache.hadoop.fs.permission.FsPermission; +import org.apache.hadoop.util.Progressable; +import io.opencurve.curve.fs.libfs.CurveFSMount; +import io.opencurve.curve.fs.libfs.CurveFSStat; +import io.opencurve.curve.fs.libfs.CurveFSStatVFS; +import io.opencurve.curve.fs.hadoop.permission.Permission; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; + +public class CurveFileSystem extends FileSystem { + private static final Log LOG = LogFactory.getLog(CurveFileSystem.class); + + private URI uri; + private Path workingDir; + private CurveFSProto curve = null; + private Permission perm = null; + + public CurveFileSystem() {} + + public CurveFileSystem(Configuration conf) { + setConf(conf); + } + + private Path makeAbsolute(Path path) { + if (path.isAbsolute()) { + return path; + } + return new Path(workingDir, path); + } + + public URI getUri() { + return uri; + } + + public String getScheme() { + return uri.getScheme(); + } + + @Override + public void initialize(URI uri, Configuration conf) throws IOException { + super.initialize(uri, conf); + + if (curve == null) { + curve = new CurveFSTalker(conf, LOG); + } + if (perm == null) { + perm = new Permission(); + } + + perm.initialize(conf); + curve.initialize(uri, conf); + setConf(conf); + this.uri = URI.create(uri.getScheme() + "://" + uri.getAuthority()); + this.workingDir = getHomeDirectory(); + } + + + public FSDataInputStream open(Path path, int bufferSize) throws IOException { + path = makeAbsolute(path); + + // throws filenotfoundexception if path is a directory + int fd = curve.open(path, CurveFSMount.O_RDONLY, 0); + + /* get file size */ + CurveFSStat stat = new CurveFSStat(); + curve.fstat(fd, stat); + + CurveFSInputStream istream = new CurveFSInputStream(getConf(), curve, fd, stat.size, bufferSize); + return new FSDataInputStream(istream); + } + + @Override + public void close() throws IOException { + super.close(); // this method does stuff, make sure it's run! + curve.shutdown(); + } + + public FSDataOutputStream append(Path path, int bufferSize, Progressable progress) throws IOException { + path = makeAbsolute(path); + + if (progress != null) { + progress.progress(); + } + + int fd = curve.open(path, CurveFSMount.O_WRONLY | CurveFSMount.O_APPEND, 0); + if (progress != null) { + progress.progress(); + } + + CurveFSOutputStream ostream = new CurveFSOutputStream(getConf(), curve, fd, bufferSize); + return new FSDataOutputStream(ostream, statistics); + } + + public Path getWorkingDirectory() { + return workingDir; + } + + @Override + public void setWorkingDirectory(Path dir) { + workingDir = makeAbsolute(dir); + } + + @Override + public boolean mkdirs(Path path, FsPermission perms) throws IOException { + path = makeAbsolute(path); + curve.mkdirs(path, (int) perms.toShort()); + return true; + } + + @Override + public boolean mkdirs(Path f) throws IOException { + FsPermission perms = FsPermission.getDirDefault().applyUMask(FsPermission.getUMask(getConf()));; + return mkdirs(f, perms); + } + + public FileStatus getFileStatus(Path path) throws IOException { + path = makeAbsolute(path); + + CurveFSStat stat = new CurveFSStat(); + curve.lstat(path, stat); + String owner = perm.getUsername(stat.uid);; + String group = perm.getGroupname(stat.gid);; + + FileStatus status = new FileStatus( + stat.size, stat.isDir(), 1, stat.blksize, + stat.m_time, stat.a_time, + new FsPermission((short) stat.mode), owner, group, + path.makeQualified(this)); + return status; + } + + + public FileStatus[] listStatus(Path path) throws IOException { + path = makeAbsolute(path); + + if (isFile(path)) { + return new FileStatus[]{getFileStatus(path)}; + } + + String[] dirlist = curve.listdir(path); + if (dirlist != null) { + FileStatus[] status = new FileStatus[dirlist.length]; + for (int i = 0; i < status.length; i++) { + status[i] = getFileStatus(new Path(path, dirlist[i])); + } + curve.shutdown(); + return status; + } else { + throw new FileNotFoundException("File " + path + " does not exist."); + } + + } + + @Override + public void setPermission(Path path, FsPermission permission) throws IOException { + path = makeAbsolute(path); + curve.chmod(path, permission.toShort()); + } + + @Override + public void setTimes(Path path, long mtime, long atime) throws IOException { + path = makeAbsolute(path); + + CurveFSStat stat = new CurveFSStat(); + + int mask = 0; + if (mtime != -1) { + stat.m_time = mtime; + mask |= CurveFSMount.SETATTR_MTIME; + } + + if (atime != -1) { + stat.a_time = atime; + mask |= CurveFSMount.SETATTR_ATIME; + } + + curve.setattr(path, stat, mask); + } + + public FSDataOutputStream create(Path path, FsPermission permission, boolean overwrite, int bufferSize, + short replication, long blockSize, Progressable progress) throws IOException { + + path = makeAbsolute(path); + + boolean exists = exists(path); + + if (progress != null) { + progress.progress(); + } + + int flags = CurveFSMount.O_WRONLY | CurveFSMount.O_CREAT; + + if (exists) { + if (overwrite) { + flags |= CurveFSMount.O_TRUNC; + } else { + throw new FileAlreadyExistsException(); + } + } else { + Path parent = path.getParent(); + if (parent != null) { + if (!mkdirs(parent)) { + throw new IOException("mkdirs failed for " + parent.toString()); + } + } + } + + if (progress != null) { + progress.progress(); + } + + int fd = curve.open(path, flags, (int) permission.toShort()); + + if (progress != null) { + progress.progress(); + } + + OutputStream ostream = new CurveFSOutputStream(getConf(), curve, fd, bufferSize); + return new FSDataOutputStream(ostream, statistics); + } + + @Override + public void setOwner(Path path, String username, String groupname) throws IOException { + CurveFSStat stat = new CurveFSStat(); + curve.lstat(path, stat); + + int uid = stat.uid; + int gid = stat.gid; + if (username != null) { + uid = perm.getUid(username); + } + if (groupname != null) { + gid = perm.getGid(groupname); + } + + curve.chown(path, uid, gid); + } + + @Deprecated + public FSDataOutputStream createNonRecursive(Path path, FsPermission permission, + boolean overwrite, + int bufferSize, short replication, long blockSize, + Progressable progress) throws IOException { + path = makeAbsolute(path); + + Path parent = path.getParent(); + + if (parent != null) { + CurveFSStat stat = new CurveFSStat(); + curve.lstat(parent, stat); // handles FileNotFoundException case + if (stat.isFile()) { + throw new FileAlreadyExistsException(parent.toString()); + } + } + + return this.create(path, permission, overwrite, + bufferSize, replication, blockSize, progress); + } + + @Override + public boolean rename(Path src, Path dst) throws IOException { + src = makeAbsolute(src); + dst = makeAbsolute(dst); + + try { + CurveFSStat stat = new CurveFSStat(); + curve.lstat(dst, stat); + if (stat.isDir()) { + return rename(src, new Path(dst, src.getName())); + } + return false; + } catch (FileNotFoundException e) { + } + + try { + curve.rename(src, dst); + } catch (FileNotFoundException e) { + throw e; + } catch (Exception e) { + return false; + } + return true; + } + + @Deprecated + public boolean delete(Path path) throws IOException { + return delete(path, false); + } + + public boolean delete(Path path, boolean recursive) throws IOException { + path = makeAbsolute(path); + + /* path exists? */ + FileStatus status; + try { + status = getFileStatus(path); + } catch (FileNotFoundException e) { + return false; + } + + /* we're done if its a file */ + if (status.isFile()) { + curve.unlink(path); + return true; + } + + /* get directory contents */ + FileStatus[] dirlist = listStatus(path); + if (dirlist == null) { + return false; + } + + if (!recursive && dirlist.length > 0) { + throw new IOException("Directory " + path.toString() + "is not empty."); + } + + for (FileStatus fs : dirlist) { + if (!delete(fs.getPath(), recursive)) { + return false; + } + } + + curve.rmdir(path); + return true; + } + + @Override + public FsStatus getStatus(Path p) throws IOException { + CurveFSStatVFS stat = new CurveFSStatVFS(); + curve.statfs(p, stat); + + FsStatus status = new FsStatus(stat.bsize * stat.blocks, + stat.bsize * (stat.blocks - stat.bavail), + stat.bsize * stat.bavail); + return status; + } + + @Override + public short getDefaultReplication() { + return 1; + } + + @Override + public long getDefaultBlockSize() { + return super.getDefaultBlockSize(); + } + + @Override + protected int getDefaultPort() { + return super.getDefaultPort(); + } + + @Override + public String getCanonicalServiceName() { + return null; // Does not support Token + } +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/Main.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/Main.java new file mode 100644 index 0000000000..d488e309dc --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/Main.java @@ -0,0 +1,7 @@ +package io.opencurve.curve.fs.hadoop; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/permission/Group.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/permission/Group.java new file mode 100644 index 0000000000..d1605a863a --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/permission/Group.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-08-01 + * Author: Xianfei Cao (caoxianfei1) + */ + +package io.opencurve.curve.fs.hadoop.permission; + +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.security.UserGroupInformation; + +import java.util.HashMap; +import java.io.IOException; +import java.util.List; + +public class Group { + private HashMap groupnames; + private HashMap groupIDs; + private UserGroupInformation ugi; + + private static final String SUPER_GROUPNAME = "supergroup"; + private static final int SUPER_GID = 0; + + public Group() { + groupnames = new HashMap(); + groupIDs = new HashMap(); + } + + private int finger(String groupname) { + return Math.abs(groupname.hashCode()); + } + + private void addGroup(String groupname, int gid) { + groupnames.put(groupname, gid); + groupIDs.put(gid, groupname); + } + + private void loadGroupFromSystem() throws IOException { + List groups = Helper.getAllGroups(); + for (Entry group : groups) { + if (group.id == 0) { + group.id = finger(group.name); + } + addGroup(group.name, group.id); + } + addGroup(SUPER_GROUPNAME, SUPER_GID); + } + + private void loadGroupFromFile() throws IOException { + // implement it + } + + public void initialize(Path path) throws IOException { + this.ugi = UserGroupInformation.getCurrentUser(); + if (path != null) { + loadGroupFromFile(); + } else { + loadGroupFromSystem(); + } + } + + public int[] getCurrentGids() { + String[] groups = {"nogroup"}; + if (ugi.getGroupNames().length > 0) { + groups = ugi.getGroupNames(); + } + + int[] gids = new int[groups.length]; + for (int i = 0; i < groups.length; i++) { + gids[i] = getGid(groups[i]); + } + return gids; + } + + public int getGid(String groupname) { + Integer gid = groupnames.get(groupname); + if (null == gid) { + gid = finger(groupname); + addGroup(groupname, gid); + } + return gid; + } + + public String getGroupname(int gid) { + String groupname = groupIDs.get(gid); + if (null == groupname || groupname.isEmpty()) { + return String.valueOf(gid); + } + return groupname; + } +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/permission/Helper.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/permission/Helper.java new file mode 100644 index 0000000000..fe505123aa --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/permission/Helper.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-08-01 + * Author: Xianfei Cao (caoxianfei1) + */ + +package io.opencurve.curve.fs.hadoop.permission; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.Structure; +import io.opencurve.curve.fs.hadoop.permission.Helper.CLibrary.passwd; +import io.opencurve.curve.fs.hadoop.permission.Helper.CLibrary.group; + +import java.util.Arrays; +import java.util.List; +import java.util.ArrayList; + +class Entry { + String name; + int id; + + public Entry(String name, int id) { + this.name = name; + this.id = id; + } +} + +public class Helper { + public interface CLibrary extends Library { + CLibrary INSTANCE = (CLibrary)Native.loadLibrary("c", CLibrary.class); + passwd getpwent(); + void endpwent(); + group getgrent(); + void endgrent(); + + public static class passwd extends Structure { + public String pw_name; + public String pw_passwd; + public int pw_uid; + public int pw_gid; + public String pw_gecos; + public String pw_dir; + public String pw_shell; + + protected List getFieldOrder() { + return Arrays.asList(new String[] { + "pw_name", "pw_passwd", "pw_uid", "pw_gid", "pw_gecos", "pw_dir", "pw_shell", + }); + } + } + + public static class group extends Structure { + public String gr_name; + public String gr_passwd; + public int gr_gid; + public Pointer gr_mem; + + protected List getFieldOrder() { + return Arrays.asList(new String[] { + "gr_name", "gr_passwd", "gr_gid", "gr_mem", + }); + } + } + } + + public static List getAllUsers() { + CLibrary lib = CLibrary.INSTANCE; + List users = new ArrayList(); + passwd usr = new passwd(); + while ((usr = lib.getpwent()) != null) { + users.add(new Entry(usr.pw_name, usr.pw_uid)); + } + lib.endpwent(); + return users; + } + + public static List getAllGroups() { + CLibrary lib = CLibrary.INSTANCE; + List groups = new ArrayList(); + group grp = new group(); + while ((grp = lib.getgrent()) != null) { + groups.add(new Entry(grp.gr_name, grp.gr_gid)); + } + lib.endgrent(); + return groups; + } +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/permission/Permission.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/permission/Permission.java new file mode 100644 index 0000000000..82ce9c52e0 --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/permission/Permission.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-08-01 + * Author: Xianfei Cao (caoxianfei1) + */ + +package io.opencurve.curve.fs.hadoop.permission; + +import org.apache.hadoop.conf.Configuration; + +import java.io.IOException; + +public class Permission { + private static User user = null; + private static Group group = null; + + public Permission() { + user = new User(); + group = new Group(); + } + + public void initialize(Configuration conf) throws IOException { + user.initialize(null); + group.initialize(null); + } + + public int getCurrentUid() { + return user.getCurrentUid(); + } + + public int getUid(String username) { + return user.getUid(username); + } + + public String getUsername(int uid) { + return user.getUsername(uid); + } + + public int[] getCurrentGids() { + return group.getCurrentGids(); + } + + public int getGid(String groupname) { + return group.getGid(groupname); + } + + public String getGroupname(int gid) { + return group.getGroupname(gid); + } +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/permission/User.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/permission/User.java new file mode 100644 index 0000000000..7b892caf53 --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/hadoop/permission/User.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-08-01 + * Author: Xianfei Cao (caoxianfei1) + */ + +package io.opencurve.curve.fs.hadoop.permission; + +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.security.UserGroupInformation; + +import java.util.HashMap; +import java.io.IOException; +import java.util.List; + +public class User { + private HashMap usernames; + private HashMap userIDs; + private UserGroupInformation ugi; + + private static final String SUPER_USERNAME = "hdfs"; + private static final int SUPER_UID = 0; + + public User() { + usernames = new HashMap(); + userIDs = new HashMap(); + } + + private int finger(String groupname) { + return Math.abs(groupname.hashCode()); + } + + private void addUser(String username, int uid) { + usernames.put(username, uid); + userIDs.put(uid, username); + } + + private void loadUserFromSystem() throws IOException { + List users = Helper.getAllUsers(); + for (Entry user : users) { + if (user.id == 0) { + user.id = finger(user.name); + } + addUser(user.name, user.id); + } + addUser(SUPER_USERNAME, SUPER_UID); + } + + private void loadUserFromFile() throws IOException { + // TODO: implement it + } + + public void initialize(Path path) throws IOException { + this.ugi = UserGroupInformation.getCurrentUser(); + if (path != null) { + loadUserFromFile(); + } else { + loadUserFromSystem(); + } + } + + public int getCurrentUid() { + String username = ugi.getShortUserName(); + return getUid(username); + } + + public int getUid(String username) { + Integer gid = usernames.get(username); + if (null == gid) { + gid = finger(username); + addUser(username, gid); + } + return gid; + } + + public String getUsername(int uid) { + String username = userIDs.get(uid); + if (null == username || username.isEmpty()) { + return String.valueOf(uid); + } + return username; + } +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/libfs/CurveFSMount.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/libfs/CurveFSMount.java new file mode 100644 index 0000000000..7b423dcc0f --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/libfs/CurveFSMount.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-07-07 + * Author: Jingli Chen (Wine93) + */ +package io.opencurve.curve.fs.libfs; + +import java.io.IOException; + +public class CurveFSMount { + // init + private native long nativeCurveFSCreate(); + private native void nativeCurveFSRelease(long instancePtr); + private static native void nativeCurveFSConfSet(long instancePtr, String key, String value); + private static native int nativeCurveFSMount(long instancePtr, String fsname, String mountpoint); + private static native int nativeCurveFSUmount(long instancePtr, String fsname, String mountpoint); + // dir* + private static native int nativeCurveFSMkDirs(long instancePtr, String path, int mode); + private static native int nativeCurveFSRmDir(long instancePtr, String path); + private static native String[] nativeCurveFSListDir(long instancePtr, String path); + // file* + private static native int nativeCurveFSOpen(long instancePtr, String path, int flags, int mode); + private static native long nativeCurveFSLSeek(long instancePtr, int fd, long offset, int whence); + private static native long nativieCurveFSRead(long instancePtr, int fd, byte[] buffer, long size, long offset); + private static native long nativieCurveFSWrite(long instancePtr, int fd, byte[] buffer, long size, long offset); + private static native int nativeCurveFSFSync(long instancePtr, int fd); + private static native int nativeCurveFSClose(long instancePtr, int fd); + private static native int nativeCurveFSUnlink(long instancePtr, String path); + // others + private static native int nativeCurveFSStatFs(long instancePtr, CurveFSStatVFS statvfs); + private static native int nativeCurveFSLstat(long instancePtr, String path, CurveFSStat stat); + private static native int nativeCurveFSFStat(long instancePtr, int fd, CurveFSStat stat); + private static native int nativeCurveFSSetAttr(long instancePtr, String path, CurveFSStat stat, int mask); + private static native int nativeCurveFSChmod(long instancePtr, String path, int mode); + private static native int nativeCurveFSChown(long instancePtr, String path, int uid, int gid); + private static native int nativeCurveFSRename(long instancePtr, String src, String dst); + + /* + * Flags for open(). + * + * Must be synchronized with JNI if changed. + */ + public static final int O_RDONLY = 1; + public static final int O_RDWR = 2; + public static final int O_APPEND = 4; + public static final int O_CREAT = 8; + public static final int O_TRUNC = 16; + public static final int O_EXCL = 32; + public static final int O_WRONLY = 64; + public static final int O_DIRECTORY = 128; + + /* + * Whence flags for seek(). + * + * Must be synchronized with JNI if changed. + */ + public static final int SEEK_SET = 0; + public static final int SEEK_CUR = 1; + public static final int SEEK_END = 2; + + /* + * Attribute flags for setattr(). + * + * Must be synchronized with JNI if changed. + */ + public static final int SETATTR_MODE = 1; + public static final int SETATTR_UID = 2; + public static final int SETATTR_GID = 4; + public static final int SETATTR_MTIME = 8; + public static final int SETATTR_ATIME = 16; + + private static final String CURVEFS_DEBUG_ENV_VAR = "CURVEFS_DEBUG"; + private static final String CLASS_NAME = "io.opencurve.curve.fs.CurveFSMount"; + + private long instancePtr; + + private static void accessLog(String name, String... args) { + String value = System.getenv(CURVEFS_DEBUG_ENV_VAR); + if (!Boolean.valueOf(value)) { + return; + } + + String params = String.join(",", args); + String message = String.format("%s.%s(%s)", CLASS_NAME, name, params); + System.out.println(message); + } + + static { + accessLog("loadLibrary"); + try { + CurveFSNativeLoader.getInstance().loadLibrary(); + } catch(Exception e) {} + } + + protected void finalize() throws Throwable { + accessLog("finalize"); + } + + public CurveFSMount() { + accessLog("CurveMount"); + instancePtr = nativeCurveFSCreate(); + } + + public void confSet(String key, String value) { + accessLog("confSet", key, value); + nativeCurveFSConfSet(instancePtr, key, value); + } + + public void mount(String fsname, String mountpoint) throws IOException { + accessLog("mount"); + nativeCurveFSMount(instancePtr, fsname, mountpoint); + } + + public void umount(String fsname, String mountpoint) throws IOException { + accessLog("umount"); + nativeCurveFSUmount(instancePtr, fsname, mountpoint); + } + + public void shutdown() throws IOException { + accessLog("shutdown"); + } + + // directory* + public void mkdirs(String path, int mode) throws IOException { + accessLog("mkdirs", path.toString()); + nativeCurveFSMkDirs(instancePtr, path, mode); + } + + public void rmdir(String path) throws IOException { + accessLog("rmdir", path.toString()); + nativeCurveFSRmDir(instancePtr, path); + } + + public String[] listdir(String path) throws IOException { + accessLog("listdir", path.toString()); + return nativeCurveFSListDir(instancePtr, path); + } + + // file* + public int open(String path, int flags, int mode) throws IOException { + accessLog("open", path.toString()); + return nativeCurveFSOpen(instancePtr, path, flags, mode); + } + + public long lseek(int fd, long offset, int whence) throws IOException { + accessLog("lseek", String.valueOf(fd), String.valueOf(offset), String.valueOf(whence)); + return nativeCurveFSLSeek(instancePtr, fd, offset, whence); + } + + public int read(int fd, byte[] buf, long size, long offset) throws IOException { + accessLog("read", String.valueOf(fd), String.valueOf(size), String.valueOf(size)); + long rc = nativieCurveFSRead(instancePtr, fd, buf, size, offset); + return (int) rc; + } + + public int write(int fd, byte[] buf, long size, long offset) throws IOException { + accessLog("write", String.valueOf(fd), String.valueOf(size), String.valueOf(size)); + long rc = nativieCurveFSWrite(instancePtr, fd, buf, size, offset); + return (int) rc; + } + + public void fsync(int fd) throws IOException { + accessLog("fsync", String.valueOf(fd)); + nativeCurveFSFSync(instancePtr, fd); + } + + public void close(int fd) throws IOException { + accessLog("close", String.valueOf(fd)); + nativeCurveFSClose(instancePtr, fd); + } + + public void unlink(String path) throws IOException { + accessLog("unlink", path.toString()); + nativeCurveFSUnlink(instancePtr, path); + } + + // others + public void statfs(String path, CurveFSStatVFS statvfs) throws IOException { + accessLog("statfs", path.toString()); + nativeCurveFSStatFs(instancePtr, statvfs); + } + + public void lstat(String path, CurveFSStat stat) throws IOException { + accessLog("lstat", path.toString()); + nativeCurveFSLstat(instancePtr, path, stat); + } + + public void fstat(int fd, CurveFSStat stat) throws IOException { + accessLog("fstat", String.valueOf(fd)); + nativeCurveFSFStat(instancePtr, fd, stat); + } + + public void setattr(String path, CurveFSStat stat, int mask) throws IOException { + accessLog("setattr", path.toString()); + nativeCurveFSSetAttr(instancePtr, path, stat, mask); + } + + public void chmod(String path, int mode) throws IOException { + accessLog("chmod", path.toString()); + nativeCurveFSChmod(instancePtr, path, mode); + } + + public void chown(String path, int uid, int gid) throws IOException { + accessLog("chown", path.toString(), String.valueOf(uid), String.valueOf(gid)); + nativeCurveFSChown(instancePtr, path, uid, gid); + } + + public void rename(String src, String dst) throws IOException { + accessLog("rename", src.toString(), dst.toString()); + nativeCurveFSRename(instancePtr, src, dst); + } +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/libfs/CurveFSNativeLoader.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/libfs/CurveFSNativeLoader.java new file mode 100644 index 0000000000..7ba7a535e8 --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/libfs/CurveFSNativeLoader.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-07-07 + * Author: Jingli Chen (Wine93) + */ + +package io.opencurve.curve.fs.libfs; + +import java.net.URL; +import java.net.URLConnection; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.archivers.ArchiveEntry; +import org.apache.commons.compress.utils.IOUtils; + +public class CurveFSNativeLoader { + boolean initialized = false; + private static final CurveFSNativeLoader instance = new CurveFSNativeLoader(); + + private static final String TMP_DIR = "/tmp"; + private static final String CURVEFS_LIBRARY_PATH = "/tmp/libcurvefs"; + private static final String RESOURCE_TAR_NAME = "libcurvefs.tar"; + private static final String JNI_LIBRARY_NAME = "libcurvefs_jni.so"; + + private CurveFSNativeLoader() {} + + public static CurveFSNativeLoader getInstance() { + return instance; + } + + public long getJarModifiedTime() throws IOException { + URL location = CurveFSNativeLoader.class.getProtectionDomain().getCodeSource().getLocation(); + URLConnection conn = location.openConnection(); + return conn.getLastModified(); + } + + public void descompress(InputStream in, String dest) throws IOException { + File dir = new File(dest); + if (!dir.exists()) { + dir.mkdirs(); + } + + ArchiveEntry entry; + TarArchiveInputStream reader = new TarArchiveInputStream(in); + while ((entry = reader.getNextTarEntry()) != null) { + if (entry.isDirectory()) { + continue; + } + + String path = TMP_DIR + File.separator + entry.getName(); + File file = new File(path); + IOUtils.copy(reader, new FileOutputStream(file)); + } + reader.close(); + } + + public void loadJniLibrary() throws IOException { + File libFile = new File(CURVEFS_LIBRARY_PATH, JNI_LIBRARY_NAME); + System.load(libFile.getAbsolutePath()); + } + + public synchronized void loadLibrary() throws IOException { + if (initialized) { + return; + } + + long jarModifiedTime = getJarModifiedTime(); + File libDir = new File(CURVEFS_LIBRARY_PATH); + if (libDir.exists() && libDir.lastModified() == jarModifiedTime) { + loadJniLibrary(); + initialized = true; + return; + } + + InputStream reader = CurveFSNativeLoader.class.getResourceAsStream("/" + RESOURCE_TAR_NAME); + if (reader == null) { + throw new IOException("Cannot get resource " + RESOURCE_TAR_NAME + " from Jar file."); + } + descompress(reader, CURVEFS_LIBRARY_PATH); + reader.close(); + + libDir.setLastModified(jarModifiedTime); + loadJniLibrary(); + initialized = true; + } +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/libfs/CurveFSStat.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/libfs/CurveFSStat.java new file mode 100644 index 0000000000..d188ca93f5 --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/libfs/CurveFSStat.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-07-07 + * Author: Jingli Chen (Wine93) + */ + +package io.opencurve.curve.fs.libfs; + +public class CurveFSStat { + public boolean is_file; /* S_ISREG */ + public boolean is_directory; /* S_ISDIR */ + public boolean is_symlink; /* S_ISLNK */ + + public int mode; + public int uid; + public int gid; + public long size; + public long blksize; + public long blocks; + public long a_time; + public long m_time; + + public boolean isFile() { + return is_file; + } + + public boolean isDir() { + return is_directory; + } + + public boolean isSymlink() { + return is_symlink; + } +} diff --git a/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/libfs/CurveFSStatVFS.java b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/libfs/CurveFSStatVFS.java new file mode 100644 index 0000000000..5ee2c1b8b0 --- /dev/null +++ b/curvefs/sdk/java/src/main/java/io/opencurve/curve/fs/libfs/CurveFSStatVFS.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-07-07 + * Author: Jingli Chen (Wine93) + */ + +package io.opencurve.curve.fs.libfs; + +public class CurveFSStatVFS { + public long bsize; + public long frsize; + public long blocks; + public long bavail; + public long files; + public long fsid; + public long namemax; +} diff --git a/curvefs/sdk/java/src/main/resources/META-INF/services/org.apache.flink.core.fs.FileSystemFactory b/curvefs/sdk/java/src/main/resources/META-INF/services/org.apache.flink.core.fs.FileSystemFactory new file mode 100644 index 0000000000..49f845958d --- /dev/null +++ b/curvefs/sdk/java/src/main/resources/META-INF/services/org.apache.flink.core.fs.FileSystemFactory @@ -0,0 +1 @@ +io.opencurve.curve.fs.flink.CurveFileSystemFactory diff --git a/curvefs/sdk/java/src/main/resources/META-INF/services/org.apache.flink.table.factories.Factory b/curvefs/sdk/java/src/main/resources/META-INF/services/org.apache.flink.table.factories.Factory new file mode 100644 index 0000000000..767cc341af --- /dev/null +++ b/curvefs/sdk/java/src/main/resources/META-INF/services/org.apache.flink.table.factories.Factory @@ -0,0 +1 @@ +io.opencurve.curve.fs.flink.CurveFileSystemTableFactory diff --git a/curvefs/sdk/java/src/test/java/io/opencurve/curve/fs/others/TestOthers.java b/curvefs/sdk/java/src/test/java/io/opencurve/curve/fs/others/TestOthers.java new file mode 100644 index 0000000000..754e6cc797 --- /dev/null +++ b/curvefs/sdk/java/src/test/java/io/opencurve/curve/fs/others/TestOthers.java @@ -0,0 +1,15 @@ +package io.opencurve.curve.fs.others; + +import junit.framework.TestCase; +import io.opencurve.curve.fs.hadoop.CurveFileSystem; + +import java.io.IOException; +import java.net.URL; + +public class TestOthers extends TestCase { + public void testHelloWorld() throws IOException { + URL location = CurveFileSystem.class.getProtectionDomain().getCodeSource().getLocation(); + System.out.println("Hello World"); + System.out.println(location.getPath()); + } +} diff --git a/curvefs/sdk/libcurvefs/BUILD b/curvefs/sdk/libcurvefs/BUILD new file mode 100644 index 0000000000..44f0f8c703 --- /dev/null +++ b/curvefs/sdk/libcurvefs/BUILD @@ -0,0 +1,44 @@ +# +# Copyright (c) 2023 NetEase Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +load("//:copts.bzl", "CURVE_DEFAULT_COPTS") + +cc_binary( + name = "curvefs", + srcs = [ + "libcurvefs.h", + "libcurvefs.cpp", + ], + copts = CURVE_DEFAULT_COPTS, + visibility = ["//visibility:public"], + deps = [ + "//curvefs/src/client/vfs:vfs", + ], + linkshared = True, +) + +cc_library( + name = "curvefs_lib", + srcs = [ + "libcurvefs.h", + "libcurvefs.cpp", + ], + copts = CURVE_DEFAULT_COPTS, + visibility = ["//visibility:public"], + deps = [ + "//curvefs/src/client/vfs:vfs", + ], +) diff --git a/curvefs/sdk/libcurvefs/README.md b/curvefs/sdk/libcurvefs/README.md new file mode 100644 index 0000000000..839fe28f20 --- /dev/null +++ b/curvefs/sdk/libcurvefs/README.md @@ -0,0 +1,29 @@ +libcurvefs +=== + +SDK C/C++ library for CurveFS. + +Example +=== + +```c +#include "libcurvefs.h" + +int instance = curvefs_create(); +curvefs_conf_set(instance, "s3.ak", "xxx") +curvefs_conf_set(instance, "s3.sk", "xxx") + +... + +int rc = curvefs_mount(instance, "fsname", "/); +if (rc != 0) { + // mount failed +} + +rc = curvefs_mkdir(instance_ptr, "/mydir") +if (rc != 0) { + // mkdir failed +} +``` + +See [examples](examples) for more examples. diff --git a/curvefs/sdk/libcurvefs/examples/Makefile b/curvefs/sdk/libcurvefs/examples/Makefile new file mode 100644 index 0000000000..2e4acf367d --- /dev/null +++ b/curvefs/sdk/libcurvefs/examples/Makefile @@ -0,0 +1,24 @@ +# Copyright (C) 2024 Jingli Chen (Wine93), NetEase Inc. + +root= $(shell echo $${PWD%/curvefs/sdk/libcurvefs/examples}) +so_path?= $(root)/bazel-bin/curvefs/sdk/libcurvefs +hrd_opt?= -I/curve +build_opt?= -L$(so_path) +link_opt?= -Wl,-rpath=$(so_path) -Wall +flags?= $(hrd_opt) $(build_opt) $(link_opt) +targets= mkdir rmdir ls touch read write unlink append rename stat statfs fstat chmod + +libcurvefs: + mkdir -p bin + bazel build \ + --config=gcc7-later \ + --compilation_mode=opt \ + --copt -g \ + --copt -DUNINSTALL_SIGSEGV=1 \ + --copt -DCLIENT_CONF_PATH="\"$(root)/curvefs/conf/client.conf\"" \ + //curvefs/sdk/java/native:curvefs_jni + +$(targets): libcurvefs + gcc ${flags} $@.c -o bin/$@ -lcurvefs + +all: $(targets) diff --git a/curvefs/sdk/libcurvefs/examples/append.c b/curvefs/sdk/libcurvefs/examples/append.c new file mode 100644 index 0000000000..79aaa3f41b --- /dev/null +++ b/curvefs/sdk/libcurvefs/examples/append.c @@ -0,0 +1,48 @@ +#include + +#include "common.h" + +int +main(int argc, char** argv) { + exact_args(argc, 2); + + uintptr_t instance = curvefs_create(); + load_cfg_from_environ(instance); + + char* fsname = get_filesystem_name(); + char* mountpoint = get_mountpoint(); + int rc = curvefs_mount(instance, fsname, mountpoint); + if (rc != 0) { + fprintf(stderr, "mount failed: retcode = %d\n", rc); + return rc; + } + + int fd = curvefs_open(instance, argv[1], O_WRONLY, 0777); + if (fd != 0) { + rc = fd; + fprintf(stderr, "open failed: retcode = %d\n", rc); + return rc; + } + + rc = curvefs_lseek(instance, fd, 0, SEEK_END); + if (rc != 0) { + fprintf(stderr, "lseek failed: retcode = %d\n", rc); + return rc; + } + + ssize_t n = curvefs_write(instance, fd, argv[2], strlen(argv[2])); + if (n < 0) { + rc = n; + fprintf(stderr, "write failed: retcode = %d\n", rc); + return rc; + } else if (n != strlen(argv[2])) { + fprintf(stderr, "write failed: %zd != %zu\n", n, strlen(argv[2])); + return -1; + } + + rc = curvefs_close(instance, fd); + if (rc != 0) { + fprintf(stderr, "close failed: retcode = %d\n", rc); + } + return 0; +} diff --git a/curvefs/sdk/libcurvefs/examples/chmod.c b/curvefs/sdk/libcurvefs/examples/chmod.c new file mode 100644 index 0000000000..f6da02ee77 --- /dev/null +++ b/curvefs/sdk/libcurvefs/examples/chmod.c @@ -0,0 +1,24 @@ +#include "common.h" + +int +main(int argc, char** argv) { + exact_args(argc, 2); + + uintptr_t instance = curvefs_create(); + load_cfg_from_environ(instance); + + char* fsname = get_filesystem_name(); + char* mountpoint = get_mountpoint(); + int rc = curvefs_mount(instance, fsname, mountpoint); + if (rc != 0) { + fprintf(stderr, "mount failed: retcode = %d\n", rc); + return rc; + } + + rc = curvefs_chmod(instance, argv[1], atoi(argv[2])); + if (rc != 0) { + fprintf(stderr, "chmod failed: retcode = %d\n", rc); + return rc; + } + return 0; +} diff --git a/curvefs/sdk/libcurvefs/examples/common.h b/curvefs/sdk/libcurvefs/examples/common.h new file mode 100644 index 0000000000..dc262eb0b2 --- /dev/null +++ b/curvefs/sdk/libcurvefs/examples/common.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CURVEFS_SDK_LIBCURVEFS_EXAMPLES_COMMON_H_ +#define CURVEFS_SDK_LIBCURVEFS_EXAMPLES_COMMON_H_ + +#include +#include +#include + +#include "curvefs/sdk/libcurvefs/libcurvefs.h" + +const char* KEY_FSNAME = "CURVEFS_FSNAME"; +const char* KEY_S3_AK = "s3.ak"; +const char* KEY_S3_SK = "s3.sk"; +const char* KEY_S3_ENDPOINT = "s3.endpoint"; +const char* KEY_S3_BUCKET = "s3.bucket_name"; +const char* KEY_MDS_ADDRS = "mdsOpt.rpcRetryOpt.addrs"; + +char* +require_string(const char* name) { + char* value = getenv(name); + if (strlen(value) == 0) { + fprintf(stderr, "require %s\n", name); + exit(1); + } + return value; +} + +char* +get_filesystem_name() { + return require_string(KEY_FSNAME); +} + +char* +get_mountpoint() { + return "/"; +} + +void +load_cfg_from_environ(uintptr_t instance) { + curvefs_conf_set(instance, KEY_S3_AK, require_string(KEY_S3_AK)); + curvefs_conf_set(instance, KEY_S3_SK, require_string(KEY_S3_SK)); + curvefs_conf_set(instance, KEY_S3_ENDPOINT, + require_string(KEY_S3_ENDPOINT)); + curvefs_conf_set(instance, KEY_S3_BUCKET, require_string(KEY_S3_BUCKET)); + curvefs_conf_set(instance, KEY_MDS_ADDRS, require_string(KEY_MDS_ADDRS)); + curvefs_conf_set(instance, "fs.accessLogging", "true"); + curvefs_conf_set(instance, "client.loglevel", "6"); + curvefs_conf_set(instance, "diskCache.diskCacheType", "0"); +} + +void +exact_args(int argc, int number) { + if (--argc == number) { + return; + } + + fprintf(stderr, "requires exactly %d argument[s]\n", number); + exit(1); +} + +#endif // CURVEFS_SDK_LIBCURVEFS_EXAMPLES_COMMON_H_ diff --git a/curvefs/sdk/libcurvefs/examples/fstat.c b/curvefs/sdk/libcurvefs/examples/fstat.c new file mode 100644 index 0000000000..5745f19e05 --- /dev/null +++ b/curvefs/sdk/libcurvefs/examples/fstat.c @@ -0,0 +1,36 @@ +#include + +#include "common.h" + +int +main(int argc, char** argv) { + exact_args(argc, 1); + + uintptr_t instance = curvefs_create(); + load_cfg_from_environ(instance); + + char* fsname = get_filesystem_name(); + char* mountpoint = get_mountpoint(); + int rc = curvefs_mount(instance, fsname, mountpoint); + if (rc != 0) { + fprintf(stderr, "mount failed: retcode = %d\n", rc); + return rc; + } + + int fd = curvefs_open(instance, argv[1], O_WRONLY, 0777); + if (fd != 0) { + rc = fd; + fprintf(stderr, "open failed: retcode = %d\n", rc); + return rc; + } + + struct stat stat; + rc = curvefs_fstat(instance, fd, &stat); + if (rc != 0) { + fprintf(stderr, "fstat failed: retcode = %d\n", rc); + return rc; + } + + printf("ino=%d, size=%d\n", stat.st_ino, stat.st_size); + return 0; +} diff --git a/curvefs/sdk/libcurvefs/examples/ls.c b/curvefs/sdk/libcurvefs/examples/ls.c new file mode 100644 index 0000000000..71df5f30be --- /dev/null +++ b/curvefs/sdk/libcurvefs/examples/ls.c @@ -0,0 +1,49 @@ +#include "common.h" + +int +main(int argc, char** argv) { + exact_args(argc, 1); + + uintptr_t instance = curvefs_create(); + load_cfg_from_environ(instance); + + // mount + char* fsname = get_filesystem_name(); + char* mountpoint = get_mountpoint(); + int rc = curvefs_mount(instance, fsname, mountpoint); + if (rc != 0) { + fprintf(stderr, "mount failed: retcode = %d\n", rc); + return rc; + } + + // opendir + dir_stream_t dir_stream; + rc = curvefs_opendir(instance, argv[1], &dir_stream); + if (rc != 0) { + fprintf(stderr, "opendir failed: retcode = %d\n", rc); + return rc; + } + + // readdir + dirent_t dirent; + for ( ;; ) { + ssize_t n = curvefs_readdir(instance, &dir_stream, &dirent); + if (n < 0) { + rc = n; + fprintf(stderr, "readdir failed: retcode = %d\n", rc); + break; + } else if (n == 0) { + break; + } + + printf("%s: ino=%d size=%d\n", dirent.name, + dirent.stat.st_ino, + dirent.stat.st_size); + } + + rc = curvefs_closedir(instance, &dir_stream); + if (rc != 0) { + fprintf(stderr, "closedir failed: retcode = %d\n", rc); + } + return rc; +} diff --git a/curvefs/sdk/libcurvefs/examples/mkdir.c b/curvefs/sdk/libcurvefs/examples/mkdir.c new file mode 100644 index 0000000000..c2c5b4bce6 --- /dev/null +++ b/curvefs/sdk/libcurvefs/examples/mkdir.c @@ -0,0 +1,25 @@ +#include "common.h" + +int +main(int argc, char** argv) { + exact_args(argc, 1); + + uintptr_t instance = curvefs_create(); + load_cfg_from_environ(instance); + + char* fsname = get_filesystem_name(); + char* mountpoint = get_mountpoint(); + int rc = curvefs_mount(instance, fsname, mountpoint); + if (rc != 0) { + fprintf(stderr, "mount failed: retcode = %d\n", rc); + return rc; + } + + rc = curvefs_mkdir(instance, argv[1], 0755); + if (rc != 0) { + fprintf(stderr, "mkdir failed: retcode = %d\n", rc); + return rc; + } + + return 0; +} diff --git a/curvefs/sdk/libcurvefs/examples/read.c b/curvefs/sdk/libcurvefs/examples/read.c new file mode 100644 index 0000000000..3dcbd5d4ee --- /dev/null +++ b/curvefs/sdk/libcurvefs/examples/read.c @@ -0,0 +1,44 @@ +#include + +#include "common.h" + +#define MAX_BUFFER_SIZE 4096 + 5 + +int +main(int argc, char** argv) { + exact_args(argc, 1); + + uintptr_t instance = curvefs_create(); + load_cfg_from_environ(instance); + + char* fsname = get_filesystem_name(); + char* mountpoint = get_mountpoint(); + int rc = curvefs_mount(instance, fsname, mountpoint); + if (rc != 0) { + fprintf(stderr, "mount failed: retcode = %d\n", rc); + return rc; + } + + int fd = curvefs_open(instance, argv[1], O_WRONLY, 0777); + if (fd != 0) { + rc = fd; + fprintf(stderr, "open failed: retcode = %d\n", rc); + return rc; + } + + char buffer[MAX_BUFFER_SIZE]; + for ( ;; ) { + ssize_t n = curvefs_read(instance, fd, buffer, sizeof(buffer)); + if (n < 0) { + rc = n; + fprintf(stderr, "read failed: retcode = %d\n", rc); + return rc; + } else if (n == 0) { + break; + } + + buffer[n] = '\0'; + printf("%s", buffer); + } + return 0; +} diff --git a/curvefs/sdk/libcurvefs/examples/rename.c b/curvefs/sdk/libcurvefs/examples/rename.c new file mode 100644 index 0000000000..77f824531b --- /dev/null +++ b/curvefs/sdk/libcurvefs/examples/rename.c @@ -0,0 +1,24 @@ +#include "common.h" + +int +main(int argc, char** argv) { + exact_args(argc, 2); + + uintptr_t instance = curvefs_create(); + load_cfg_from_environ(instance); + + char* fsname = get_filesystem_name(); + char* mountpoint = get_mountpoint(); + int rc = curvefs_mount(instance, fsname, mountpoint); + if (rc != 0) { + fprintf(stderr, "mount failed: retcode = %d\n", rc); + return rc; + } + + rc = curvefs_rename(instance, argv[1], argv[2]); + if (rc != 0) { + fprintf(stderr, "rename failed: retcode = %d\n", rc); + return rc; + } + return 0; +} diff --git a/curvefs/sdk/libcurvefs/examples/rmdir.c b/curvefs/sdk/libcurvefs/examples/rmdir.c new file mode 100644 index 0000000000..7ae25a80a7 --- /dev/null +++ b/curvefs/sdk/libcurvefs/examples/rmdir.c @@ -0,0 +1,25 @@ +#include "common.h" + +int +main(int argc, char** argv) { + exact_args(argc, 1); + + uintptr_t instance = curvefs_create(); + load_cfg_from_environ(instance); + + char* fsname = get_filesystem_name(); + char* mountpoint = get_mountpoint(); + int rc = curvefs_mount(instance, fsname, mountpoint); + if (rc != 0) { + fprintf(stderr, "mount failed: retcode = %d\n", rc); + return rc; + } + + rc = curvefs_rmdir(instance, argv[1]); + if (rc != 0) { + fprintf(stderr, "rmdir failed: retcode = %d\n", rc); + return rc; + } + + return 0; +} diff --git a/curvefs/sdk/libcurvefs/examples/stat.c b/curvefs/sdk/libcurvefs/examples/stat.c new file mode 100644 index 0000000000..34589bc6fa --- /dev/null +++ b/curvefs/sdk/libcurvefs/examples/stat.c @@ -0,0 +1,27 @@ +#include "common.h" + +int +main(int argc, char** argv) { + exact_args(argc, 1); + + uintptr_t instance = curvefs_create(); + load_cfg_from_environ(instance); + + char* fsname = get_filesystem_name(); + char* mountpoint = get_mountpoint(); + int rc = curvefs_mount(instance, fsname, mountpoint); + if (rc != 0) { + fprintf(stderr, "mount failed: retcode = %d\n", rc); + return rc; + } + + struct stat stat; + rc = curvefs_lstat(instance, argv[1], &stat); + if (rc != 0) { + fprintf(stderr, "stat failed: retcode = %d\n", rc); + return rc; + } + + printf("ino=%d, size=%d\n", stat.st_ino, stat.st_size); + return 0; +} diff --git a/curvefs/sdk/libcurvefs/examples/statfs.c b/curvefs/sdk/libcurvefs/examples/statfs.c new file mode 100644 index 0000000000..81f0aee290 --- /dev/null +++ b/curvefs/sdk/libcurvefs/examples/statfs.c @@ -0,0 +1,29 @@ +#include + +#include "common.h" + +int +main(int argc, char** argv) { + exact_args(argc, 0); + + uintptr_t instance = curvefs_create(); + load_cfg_from_environ(instance); + + char* fsname = get_filesystem_name(); + char* mountpoint = get_mountpoint(); + int rc = curvefs_mount(instance, fsname, mountpoint); + if (rc != 0) { + fprintf(stderr, "mount failed: retcode = %d\n", rc); + return rc; + } + + struct statvfs statvfs; + rc = curvefs_statfs(instance, &statvfs); + if (rc != 0) { + fprintf(stderr, "statvfs failed: retcode = %d\n", rc); + return rc; + } + + printf("fsid = %d\n", statvfs.f_fsid); + return 0; +} diff --git a/curvefs/sdk/libcurvefs/examples/touch.c b/curvefs/sdk/libcurvefs/examples/touch.c new file mode 100644 index 0000000000..b3185eb6ec --- /dev/null +++ b/curvefs/sdk/libcurvefs/examples/touch.c @@ -0,0 +1,26 @@ +#include + +#include "common.h" + +int +main(int argc, char** argv) { + exact_args(argc, 1); + + uintptr_t instance = curvefs_create(); + load_cfg_from_environ(instance); + + char* fsname = get_filesystem_name(); + char* mountpoint = get_mountpoint(); + int rc = curvefs_mount(instance, fsname, mountpoint); + if (rc != 0) { + fprintf(stderr, "mount failed: retcode = %d\n", rc); + return rc; + } + + int fd = curvefs_open(instance, argv[1], O_CREAT, 0644); + if (fd < 0) { + rc = fd; + fprintf(stderr, "open failed: retcode = %d\n", rc); + } + return rc; +} diff --git a/curvefs/sdk/libcurvefs/examples/unlink.c b/curvefs/sdk/libcurvefs/examples/unlink.c new file mode 100644 index 0000000000..e20fbe5636 --- /dev/null +++ b/curvefs/sdk/libcurvefs/examples/unlink.c @@ -0,0 +1,25 @@ +#include "common.h" + +int +main(int argc, char** argv) { + exact_args(argc, 1); + + uintptr_t instance = curvefs_create(); + load_cfg_from_environ(instance); + + char* fsname = get_filesystem_name(); + char* mountpoint = get_mountpoint(); + int rc = curvefs_mount(instance, fsname, mountpoint); + if (rc != 0) { + fprintf(stderr, "mount failed: retcode = %d\n", rc); + return rc; + } + + rc = curvefs_unlink(instance, argv[1]); + if (rc != 0) { + fprintf(stderr, "unlink failed: retcode = %d\n", rc); + return rc; + } + + return 0; +} diff --git a/curvefs/sdk/libcurvefs/examples/write.c b/curvefs/sdk/libcurvefs/examples/write.c new file mode 100644 index 0000000000..d3f85c26fb --- /dev/null +++ b/curvefs/sdk/libcurvefs/examples/write.c @@ -0,0 +1,42 @@ +#include + +#include "common.h" + +int +main(int argc, char** argv) { + exact_args(argc, 2); + + uintptr_t instance = curvefs_create(); + load_cfg_from_environ(instance); + + char* fsname = get_filesystem_name(); + char* mountpoint = get_mountpoint(); + int rc = curvefs_mount(instance, fsname, mountpoint); + if (rc != 0) { + fprintf(stderr, "mount failed: retcode = %d\n", rc); + return rc; + } + + int fd = curvefs_open(instance, argv[1], O_WRONLY, 0777); + if (fd != 0) { + rc = fd; + fprintf(stderr, "open failed: retcode = %d\n", rc); + return rc; + } + + ssize_t n = curvefs_write(instance, fd, argv[2], strlen(argv[2])); + if (n < 0) { + rc = n; + fprintf(stderr, "write failed: retcode = %d\n", rc); + return rc; + } else if (n != strlen(argv[2])) { + fprintf(stderr, "write failed: %zd != %zu\n", n, strlen(argv[2])); + return -1; + } + + rc = curvefs_close(instance, fd); + if (rc != 0) { + fprintf(stderr, "close failed: retcode = %d\n", rc); + } + return 0; +} diff --git a/curvefs/sdk/libcurvefs/libcurvefs.cpp b/curvefs/sdk/libcurvefs/libcurvefs.cpp new file mode 100644 index 0000000000..d53c0b51b8 --- /dev/null +++ b/curvefs/sdk/libcurvefs/libcurvefs.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-07-12 + * Author: Jingli Chen (Wine93) + */ + +#include "curvefs/src/client/filesystem/error.h" +#include "curvefs/sdk/libcurvefs/libcurvefs.h" + +using ::curvefs::client::filesystem::CURVEFS_ERROR; +using ::curvefs::client::filesystem::SysErr; +using ::curvefs::client::vfs::DirStream; +using ::curvefs::client::vfs::DirEntry; + +static curvefs_mount_t* get_instance(uintptr_t instance_ptr) { + return reinterpret_cast(instance_ptr); +} + +static void stream_cast(DirStream* stream, dir_stream_t* dir_stream) { + dir_stream->fh = stream->fh; + dir_stream->ino = stream->ino; + dir_stream->offset = stream->offset; +} + +uintptr_t curvefs_create() { + auto mount = new curvefs_mount_t(); + mount->cfg = Configure::Default(); + return reinterpret_cast(mount); +} + +void curvefs_release(uintptr_t instance_ptr) { + auto mount = get_instance(instance_ptr); + delete mount; + mount = nullptr; +} + +void curvefs_conf_set(uintptr_t instance_ptr, + const char* key, + const char* value) { + auto mount = get_instance(instance_ptr); + return mount->cfg->Set(key, value); +} + +int curvefs_mount(uintptr_t instance_ptr, + const char* fsname, + const char* mountpoint) { + auto mount = get_instance(instance_ptr); + mount->vfs = std::make_shared(mount->cfg); + auto rc = mount->vfs->Mount(fsname, mountpoint); + return SysErr(rc); +} + +int curvefs_umonut(uintptr_t instance_ptr, + const char* fsname, + const char* mountpoint) { + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->Umount(fsname, mountpoint); + return SysErr(rc); +} + +int curvefs_mkdir(uintptr_t instance_ptr, const char* path, uint16_t mode) { + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->MkDir(path, mode); + return SysErr(rc); +} + +int curvefs_mkdirs(uintptr_t instance_ptr, const char* path, uint16_t mode) { + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->MkDirs(path, mode); + return SysErr(rc); +} + +int curvefs_rmdir(uintptr_t instance_ptr, const char* path) { + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->RmDir(path); + return SysErr(rc); +} + +int curvefs_opendir(uintptr_t instance_ptr, + const char* path, + dir_stream_t* dir_stream) { + DirStream stream; + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->OpenDir(path, &stream); + if (rc == CURVEFS_ERROR::OK) { + stream_cast(&stream, dir_stream); + } + return SysErr(rc); +} + +ssize_t curvefs_readdir(uintptr_t instance_ptr, + dir_stream_t* dir_stream, + dirent_t* dirent) { + DirEntry dirEntry; + auto mount = get_instance(instance_ptr); + DirStream* stream = reinterpret_cast(dir_stream); + auto rc = mount->vfs->ReadDir(stream, &dirEntry); + if (rc == CURVEFS_ERROR::OK) { + std::string name = dirEntry.name; + name.copy(dirent->name, name.size() ); + dirent->name[name.size()] = '\0'; + mount->vfs->Attr2Stat(&dirEntry.attr, &dirent->stat); + return 1; + } else if (rc == CURVEFS_ERROR::END_OF_FILE) { + return 0; + } + return SysErr(rc); +} + +int curvefs_closedir(uintptr_t instance_ptr, dir_stream_t* dir_stream) { + DirStream* stream = reinterpret_cast(dir_stream); + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->CloseDir(stream); + return SysErr(rc); +} + +int curvefs_open(uintptr_t instance_ptr, + const char* path, + uint32_t flags, + uint16_t mode) { + CURVEFS_ERROR rc; + auto mount = get_instance(instance_ptr); + if (flags & O_CREAT) { + rc = mount->vfs->Create(path, mode); + if (rc != CURVEFS_ERROR::OK) { + return SysErr(rc); + } + } + + uint64_t fd; + rc = mount->vfs->Open(path, flags, mode, &fd); + if (rc != CURVEFS_ERROR::OK) { + return SysErr(rc); + } + return static_cast(fd); +} + +int curvefs_lseek(uintptr_t instance_ptr, + int fd, + uint64_t offset, + int whence) { + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->LSeek(fd, offset, whence); + return SysErr(rc); +} + +ssize_t curvefs_read(uintptr_t instance_ptr, + int fd, + char* buffer, + size_t count) { + size_t nread; + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->Read(fd, buffer, count, &nread); + if (rc != CURVEFS_ERROR::OK) { + return SysErr(rc); + } + return nread; +} + +ssize_t curvefs_write(uintptr_t instance_ptr, + int fd, + char* buffer, + size_t count) { + size_t nwritten; + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->Write(fd, buffer, count, &nwritten); + if (rc != CURVEFS_ERROR::OK) { + return SysErr(rc); + } + return nwritten; +} + +int curvefs_fsync(uintptr_t instance_ptr, int fd) { + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->FSync(fd); + return SysErr(rc); +} + +int curvefs_close(uintptr_t instance_ptr, int fd) { + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->Close(fd); + return SysErr(rc); +} + +int curvefs_unlink(uintptr_t instance_ptr, const char* path) { + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->Unlink(path); + return SysErr(rc); +} + +int curvefs_statfs(uintptr_t instance_ptr, + struct statvfs* statvfs) { + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->StatFs(statvfs); + return SysErr(rc); +} + +int curvefs_lstat(uintptr_t instance_ptr, const char* path, struct stat* stat) { + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->LStat(path, stat); + return SysErr(rc); +} + +int curvefs_fstat(uintptr_t instance_ptr, int fd, struct stat* stat) { + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->FStat(fd, stat); + return SysErr(rc); +} + +int curvefs_setattr(uintptr_t instance_ptr, + const char* path, + struct stat* stat, + int to_set) { + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->SetAttr(path, stat, to_set); + return SysErr(rc); +} + +int curvefs_chmod(uintptr_t instance_ptr, const char* path, uint16_t mode) { + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->Chmod(path, mode); + return SysErr(rc); +} + +int curvefs_chown(uintptr_t instance_ptr, + const char* path, + uint32_t uid, + uint32_t gid) { + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->Chown(path, uid, gid); + return SysErr(rc); +} + +int curvefs_rename(uintptr_t instance_ptr, + const char* oldpath, + const char* newpath) { + auto mount = get_instance(instance_ptr); + auto rc = mount->vfs->Rename(oldpath, newpath); + return SysErr(rc); +} diff --git a/curvefs/sdk/libcurvefs/libcurvefs.h b/curvefs/sdk/libcurvefs/libcurvefs.h new file mode 100644 index 0000000000..35d2f743df --- /dev/null +++ b/curvefs/sdk/libcurvefs/libcurvefs.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-07-12 + * Author: Jingli Chen (Wine93) + */ + +#ifndef CURVEFS_SDK_LIBCURVEFS_LIBCURVEFS_H_ +#define CURVEFS_SDK_LIBCURVEFS_LIBCURVEFS_H_ + +#include +#include +#include + +#ifdef __cplusplus + +#include +#include +#include + +#include "curvefs/src/client/vfs/config.h" +#include "curvefs/src/client/vfs/vfs.h" + +using ::curvefs::client::vfs::Configure; +using ::curvefs::client::vfs::VFS; + +typedef struct { + std::shared_ptr cfg; + std::shared_ptr vfs; +} curvefs_mount_t; + +#endif // __cplusplus + +// Must be synchronized with DirStream if changed +typedef struct { + uint64_t ino; + uint64_t fh; + uint64_t offset; +} dir_stream_t; + +typedef struct { + struct stat stat; + char name[256]; +} dirent_t; + +#ifdef __cplusplus +extern "C" { +#endif + +uintptr_t curvefs_create(); + +void curvefs_release(uintptr_t instance_ptr); + +// NOTE: instance_ptr is the pointer of curvefs_mount_t instance. +void curvefs_conf_set(uintptr_t instance_ptr, + const char* key, + const char* value); + +int curvefs_mount(uintptr_t instance_ptr, + const char* fsname, + const char* mountpoint); + +int curvefs_umonut(uintptr_t instance_ptr, + const char* fsname, + const char* mountpoint); + +// directory +int curvefs_mkdir(uintptr_t instance_ptr, const char* path, uint16_t mode); + +int curvefs_mkdirs(uintptr_t instance_ptr, const char* path, uint16_t mode); + +int curvefs_rmdir(uintptr_t instance_ptr, const char* path); + +int curvefs_opendir(uintptr_t instance_ptr, + const char* path, + dir_stream_t* dir_stream); + +ssize_t curvefs_readdir(uintptr_t instance_ptr, + dir_stream_t* dir_stream, + dirent_t* dirent); + +int curvefs_closedir(uintptr_t instance_ptr, dir_stream_t* dir_stream); + +// file +int curvefs_open(uintptr_t instance_ptr, + const char* path, + uint32_t flags, + uint16_t mode); + +int curvefs_lseek(uintptr_t instance_ptr, + int fd, + uint64_t offset, + int whence); + +ssize_t curvefs_read(uintptr_t instance_ptr, + int fd, + char* buffer, + size_t count); + +ssize_t curvefs_write(uintptr_t instance_ptr, + int fd, + char* buffer, + size_t count); + +int curvefs_fsync(uintptr_t instance_ptr, int fd); + +int curvefs_close(uintptr_t instance_ptr, int fd); + +int curvefs_unlink(uintptr_t instance_ptr, const char* path); + +// others +int curvefs_statfs(uintptr_t instance_ptr, struct statvfs* statvfs); + +int curvefs_lstat(uintptr_t instance_ptr, const char* path, struct stat* stat); + +int curvefs_fstat(uintptr_t instance_ptr, int fd, struct stat* stat); + +int curvefs_setattr(uintptr_t instance_ptr, + const char* path, + struct stat* stat, + int to_set); + +int curvefs_chmod(uintptr_t instance_ptr, const char* path, uint16_t mode); + +int curvefs_chown(uintptr_t instance_ptr, + const char* path, + uint32_t uid, + uint32_t gid); + +int curvefs_rename(uintptr_t instance_ptr, + const char* oldpath, + const char* newpath); +#ifdef __cplusplus +} +#endif + +#endif // CURVEFS_SDK_LIBCURVEFS_LIBCURVEFS_H_ diff --git a/curvefs/src/client/BUILD b/curvefs/src/client/BUILD index 677e32b0b6..450e8b6ced 100644 --- a/curvefs/src/client/BUILD +++ b/curvefs/src/client/BUILD @@ -32,6 +32,19 @@ cc_binary( ], ) +cc_library( + name = "filesystem", + srcs = glob([ + "filesystem/*.cpp", + "filesystem/*.h", + ]), + copts = CURVE_DEFAULT_COPTS, + visibility = ["//visibility:public"], + deps = [ + ":fuse_client_lib", + ], +) + cc_library( name = "filesystem_xattr", hdrs = ["filesystem/xattr.h"], @@ -74,6 +87,7 @@ cc_library( "//curvefs/src/common:curvefs_common", "//curvefs/src/client/lease:curvefs_lease", "//curvefs/src/client/kvclient:memcached_client_lib", + "//curvefs/src/client/logger:logger", ":filesystem_xattr", "//external:brpc", "//external:gflags", diff --git a/curvefs/src/client/client_operator.cpp b/curvefs/src/client/client_operator.cpp index 8d44a5150f..720ce65ee3 100644 --- a/curvefs/src/client/client_operator.cpp +++ b/curvefs/src/client/client_operator.cpp @@ -153,7 +153,7 @@ CURVEFS_ERROR RenameOperator::CheckOverwrite() { if (rc == CURVEFS_ERROR::OK && !dentrys.empty()) { LOG(ERROR) << "The directory is not empty" << ", dentry = (" << dstDentry_.ShortDebugString() << ")"; - rc = CURVEFS_ERROR::NOTEMPTY; + rc = CURVEFS_ERROR::NOT_EMPTY; } return rc; @@ -170,7 +170,7 @@ CURVEFS_ERROR RenameOperator::Precheck() { } rc = dentryManager_->GetDentry(newParentId_, newname_, &dstDentry_); - if (rc == CURVEFS_ERROR::NOTEXIST) { + if (rc == CURVEFS_ERROR::NOT_EXIST) { return CURVEFS_ERROR::OK; } else if (rc == CURVEFS_ERROR::OK) { oldInodeId_ = dstDentry_.inodeid(); @@ -191,7 +191,7 @@ CURVEFS_ERROR RenameOperator::RecordOldInodeInfo() { oldInodeType_ = attr.type(); } else { LOG_ERROR("GetInode", rc); - return CURVEFS_ERROR::NOTEXIST; + return CURVEFS_ERROR::NOT_EXIST; } } diff --git a/curvefs/src/client/common/config.cpp b/curvefs/src/client/common/config.cpp index ad4b29b97c..dc80177ab3 100644 --- a/curvefs/src/client/common/config.cpp +++ b/curvefs/src/client/common/config.cpp @@ -48,7 +48,7 @@ DEFINE_validator(fs_disableXattr, [](const char*, bool value) { return true; }); namespace curvefs { namespace client { namespace common { -static bool pass_bool(const char *, bool) { return true; } +static bool pass_bool(const char*, bool) { return true; } DEFINE_bool(enableCto, true, "acheieve cto consistency"); DEFINE_bool(useFakeS3, false, "Use fake s3 to inject more metadata for testing metaserver"); @@ -314,6 +314,40 @@ void InitKVClientManagerOpt(Configuration *conf, &config->getThreadPooln); } +void GetGids( + Configuration* c, const std::string& key, std::vector* gids) { + std::string str; + std::vector ss; + c->GetValueFatalIfFail(key, &str); + curve::common::SplitString(str, ",", &ss); + uint32_t gid; + for (const auto& s : ss) { + LOG_IF(FATAL, !curve::common::StringToUl(s, &gid)) + << "Invalid `" << key << "`: <" << s << ">"; + gids->push_back(static_cast(gid)); + } +} + +void GetUmask(Configuration* c, const std::string& key, uint16_t* umask) { + std::string str; + c->GetValueFatalIfFail(key, &str); + *umask = stoi(str, 0, 8); +} + +void InitVFSOption(Configuration* c, VFSOption* option) { + { // vfs cache option + auto o = &option->vfsCacheOption; + c->GetValueFatalIfFail("vfs.entryCache.lruSize", &o->entryCacheLruSize); + c->GetValueFatalIfFail("vfs.attrCache.lruSize", &o->attrCacheLruSize); + } + { // user permission option + auto o = &option->userPermissionOption; + c->GetValueFatalIfFail("vfs.userPermission.uid", &o->uid); + GetGids(c, "vfs.userPermission.gids", &o->gids); + GetUmask(c, "vfs.userPermission.umask", &o->umask); + } +} + void InitFileSystemOption(Configuration* c, FileSystemOption* option) { c->GetValueFatalIfFail("fs.cto", &option->cto); c->GetValueFatalIfFail("fs.cto", &FLAGS_enableCto); @@ -383,6 +417,7 @@ void InitFuseClientOption(Configuration *conf, FuseClientOption *clientOption) { InitLeaseOpt(conf, &clientOption->leaseOpt); InitRefreshDataOpt(conf, &clientOption->refreshDataOption); InitKVClientManagerOpt(conf, &clientOption->kvClientManagerOpt); + InitVFSOption(conf, &clientOption->vfsOption); InitFileSystemOption(conf, &clientOption->fileSystemOption); conf->GetValueFatalIfFail("fuseClient.listDentryLimit", diff --git a/curvefs/src/client/common/config.h b/curvefs/src/client/common/config.h index 3d0c91dd70..464b1550c4 100644 --- a/curvefs/src/client/common/config.h +++ b/curvefs/src/client/common/config.h @@ -25,9 +25,10 @@ #include #include +#include -#include "curvefs/src/client/common/common.h" #include "curvefs/proto/common.pb.h" +#include "curvefs/src/client/common/common.h" #include "src/client/config_info.h" #include "src/common/configuration.h" #include "src/common/s3_adapter.h" @@ -180,6 +181,24 @@ struct RefreshDataOption { uint32_t refreshDataIntervalSec = 30; }; +// { vfs option +struct UserPermissionOption { + uint32_t uid; + std::vector gids; + uint16_t umask; +}; + +struct VFSCacheOption { + uint32_t entryCacheLruSize; + uint32_t attrCacheLruSize; +}; + +struct VFSOption { + VFSCacheOption vfsCacheOption; + UserPermissionOption userPermissionOption; +}; +// } + // { filesystem option struct KernelCacheOption { uint32_t entryTimeoutSec; @@ -244,6 +263,7 @@ struct FuseClientOption { LeaseOpt leaseOpt; RefreshDataOption refreshDataOption; KVClientManagerOpt kvClientManagerOpt; + VFSOption vfsOption; FileSystemOption fileSystemOption; uint32_t listDentryLimit; diff --git a/curvefs/src/client/curve_fuse_op.cpp b/curvefs/src/client/curve_fuse_op.cpp index 78c567f589..dd249c8892 100644 --- a/curvefs/src/client/curve_fuse_op.cpp +++ b/curvefs/src/client/curve_fuse_op.cpp @@ -32,12 +32,13 @@ #include "curvefs/src/client/common/common.h" #include "curvefs/src/client/common/config.h" -#include "curvefs/src/client/filesystem/access_log.h" #include "curvefs/src/client/filesystem/error.h" #include "curvefs/src/client/filesystem/meta.h" +#include "curvefs/src/client/filesystem/xattr.h" #include "curvefs/src/client/fuse_client.h" #include "curvefs/src/client/fuse_s3_client.h" #include "curvefs/src/client/fuse_volume_client.h" +#include "curvefs/src/client/logger/access_log.h" #include "curvefs/src/client/metric/client_metric.h" #include "curvefs/src/client/rpcclient/base_client.h" #include "curvefs/src/client/rpcclient/mds_client.h" @@ -47,7 +48,6 @@ #include "curvefs/src/common/metric_utils.h" #include "src/common/configuration.h" #include "src/common/gflags_helper.h" -#include "curvefs/src/client/filesystem/xattr.h" using ::curve::common::Configuration; using ::curvefs::client::CURVEFS_ERROR; @@ -62,24 +62,23 @@ using ::curvefs::client::common::kWarmupCacheStorageType; using ::curvefs::client::common::kWarmupDataType; using ::curvefs::client::common::kWarmupOpType; using ::curvefs::client::common::WarmupStorageType; -using ::curvefs::client::filesystem::AccessLogGuard; using ::curvefs::client::filesystem::AttrOut; using ::curvefs::client::filesystem::EntryOut; using ::curvefs::client::filesystem::FileOut; -using ::curvefs::client::filesystem::InitAccessLog; -using ::curvefs::client::filesystem::Logger; +using ::curvefs::client::filesystem::IsListWarmupXAttr; +using ::curvefs::client::filesystem::IsWarmupXAttr; using ::curvefs::client::filesystem::StrAttr; using ::curvefs::client::filesystem::StrEntry; -using ::curvefs::client::filesystem::StrFormat; using ::curvefs::client::filesystem::StrMode; +using ::curvefs::client::logger::AccessLogGuard; +using ::curvefs::client::logger::InitAccessLog; +using ::curvefs::client::logger::StrFormat; using ::curvefs::client::metric::ClientOpMetric; using ::curvefs::client::metric::InflightGuard; using ::curvefs::client::rpcclient::MDSBaseClient; using ::curvefs::client::rpcclient::MdsClientImpl; using ::curvefs::client::warmup::WarmupProgress; using ::curvefs::common::LatencyUpdater; -using ::curvefs::client::filesystem::IsWarmupXAttr; -using ::curvefs::client::filesystem::IsListWarmupXAttr; using ::curvefs::common::FLAGS_vlog_level; @@ -1006,5 +1005,5 @@ void FuseOpBmap(fuse_req_t req, auto client = Client(); auto fs = client->GetFileSystem(); - return fs->ReplyError(req, CURVEFS_ERROR::NOTSUPPORT); + return fs->ReplyError(req, CURVEFS_ERROR::NOT_SUPPORT); } diff --git a/curvefs/src/client/filesystem/.clang-format b/curvefs/src/client/filesystem/.clang-format new file mode 100644 index 0000000000..a5660a57d8 --- /dev/null +++ b/curvefs/src/client/filesystem/.clang-format @@ -0,0 +1,26 @@ +# I don't like current clang-formtter's specified style and +# and i think my style is more intuitive than it :), so I use +# this file to disable format, let us give some code snippet to prove it: +# +# my: +# std::vector tests { +# { " abc", "abc" }, +# { "abc ", "abc" }, +# { " abc ", "abc" }, +# { " a bc ", "a bc" }, +# { "a b c", "a b c" }, +# { " ", "" }, +# +# +# clang-formatter: +# std::vector tests{ +# {" abc", "abc"}, {"abc ", "abc"}, {" abc ", "abc"}, +# {" a bc ", "a bc"}, {"a b c", "a b c"}, {" ", ""}, +# }; +# +# Maybe you have different opinions, but please have a little mercy for me. +# +# by Wine93, 2023-10-16 + +DisableFormat: true +SortIncludes: Never diff --git a/curvefs/src/client/filesystem/defer_sync.cpp b/curvefs/src/client/filesystem/defer_sync.cpp index a69cdeb3ba..2b33e33ba4 100644 --- a/curvefs/src/client/filesystem/defer_sync.cpp +++ b/curvefs/src/client/filesystem/defer_sync.cpp @@ -81,6 +81,17 @@ void DeferSync::Push(const std::shared_ptr& inode) { inodes_.emplace_back(inode); } +bool DeferSync::IsDefered(Ino ino, InodeAttr* attr) { + LockGuard lk(mutex_); + for (const auto& inode : inodes_) { + if (inode->GetInodeId() == ino) { + inode->GetInodeAttr(attr); + return true; + } + } + return false; +} + } // namespace filesystem } // namespace client } // namespace curvefs diff --git a/curvefs/src/client/filesystem/defer_sync.h b/curvefs/src/client/filesystem/defer_sync.h index 0bd59bb9bc..41264a7e00 100644 --- a/curvefs/src/client/filesystem/defer_sync.h +++ b/curvefs/src/client/filesystem/defer_sync.h @@ -51,6 +51,8 @@ class DeferSync { void Push(const std::shared_ptr& inode); + bool IsDefered(Ino ino, InodeAttr* attr); + private: void SyncTask(); diff --git a/curvefs/src/client/filesystem/dir_cache.cpp b/curvefs/src/client/filesystem/dir_cache.cpp index 64133d33ff..f71a1651b8 100644 --- a/curvefs/src/client/filesystem/dir_cache.cpp +++ b/curvefs/src/client/filesystem/dir_cache.cpp @@ -57,6 +57,15 @@ bool DirEntryList::Get(Ino ino, DirEntry* dirEntry) { return true; } +bool DirEntryList::At(uint32_t index, DirEntry* dirEntry) { + ReadLockGuard lk(rwlock_); + if (index >= entries_.size()) { + return false; + } + *dirEntry = entries_[index]; + return true; +} + bool DirEntryList::UpdateAttr(Ino ino, const InodeAttr& attr) { WriteLockGuard lk(rwlock_); auto iter = index_.find(ino); diff --git a/curvefs/src/client/filesystem/dir_cache.h b/curvefs/src/client/filesystem/dir_cache.h index 0fd0e6a7dd..6c07ae1221 100644 --- a/curvefs/src/client/filesystem/dir_cache.h +++ b/curvefs/src/client/filesystem/dir_cache.h @@ -61,6 +61,8 @@ class DirEntryList { bool Get(Ino ino, DirEntry* dirEntry); + bool At(uint32_t index, DirEntry* dirEntry); + bool UpdateAttr(Ino ino, const InodeAttr& attr); bool UpdateLength(Ino ino, const InodeAttr& open); diff --git a/curvefs/src/client/filesystem/error.cpp b/curvefs/src/client/filesystem/error.cpp index f8a677497b..1a77f467bd 100644 --- a/curvefs/src/client/filesystem/error.cpp +++ b/curvefs/src/client/filesystem/error.cpp @@ -35,15 +35,15 @@ static const std::map> errors = { { CURVEFS_ERROR::INTERNAL, { EIO, "internal error" } }, { CURVEFS_ERROR::UNKNOWN, { -1, "unknown" } }, { CURVEFS_ERROR::EXISTS, { EEXIST, "inode or dentry already exist" } }, - { CURVEFS_ERROR::NOTEXIST, { ENOENT, "inode or dentry not exist" } }, + { CURVEFS_ERROR::NOT_EXIST, { ENOENT, "inode or dentry not exist" } }, { CURVEFS_ERROR::NO_SPACE, { ENOSPC, "no space to alloc" } }, { CURVEFS_ERROR::BAD_FD, { EBADF, "bad file number" } }, - { CURVEFS_ERROR::INVALIDPARAM , { EINVAL , "invalid argument" } }, - { CURVEFS_ERROR::NOPERMISSION, { EACCES, "permission denied" } }, - { CURVEFS_ERROR::NOTEMPTY, { ENOTEMPTY, "directory not empty" } }, - { CURVEFS_ERROR::NOFLUSH, { -1, "no flush" } }, - { CURVEFS_ERROR::NOTSUPPORT, { EOPNOTSUPP, "operation not supported" } }, - { CURVEFS_ERROR::NAMETOOLONG, { ENAMETOOLONG, "file name too long" } }, + { CURVEFS_ERROR::INVALID_PARAM , { EINVAL , "invalid argument" } }, + { CURVEFS_ERROR::NO_PERMISSION, { EACCES, "permission denied" } }, + { CURVEFS_ERROR::NOT_EMPTY, { ENOTEMPTY, "directory not empty" } }, + { CURVEFS_ERROR::NO_FLUSH, { -1, "no flush" } }, + { CURVEFS_ERROR::NOT_SUPPORT, { EOPNOTSUPP, "operation not supported" } }, + { CURVEFS_ERROR::NAME_TOO_LONG, { ENAMETOOLONG, "file name too long" } }, { CURVEFS_ERROR::MOUNT_POINT_EXIST, { -1, "mount point already exist" } }, { CURVEFS_ERROR::MOUNT_FAILED, { -1, "mount failed" } }, { CURVEFS_ERROR::OUT_OF_RANGE, { ERANGE, "out of range" } }, @@ -51,6 +51,8 @@ static const std::map> errors = { { CURVEFS_ERROR::IO_ERROR, { EIO, "I/O error" } }, { CURVEFS_ERROR::STALE, { ESTALE, "stale file handler" } }, { CURVEFS_ERROR::NOSYS, { ENOSYS, "invalid system call" } }, + { CURVEFS_ERROR::END_OF_FILE, { EOF, "end of file" } }, + { CURVEFS_ERROR::NOT_A_DIRECTORY, { ENOTDIR, "not a directory" } }, }; std::string StrErr(CURVEFS_ERROR code) { @@ -86,8 +88,8 @@ std::ostream &operator<<(std::ostream &os, CURVEFS_ERROR code) { CURVEFS_ERROR ToFSError(MetaStatusCode code) { static std::map errs = { { MetaStatusCode::OK, CURVEFS_ERROR::OK }, - { MetaStatusCode::NOT_FOUND, CURVEFS_ERROR::NOTEXIST }, - { MetaStatusCode::PARAM_ERROR, CURVEFS_ERROR::INVALIDPARAM }, + { MetaStatusCode::NOT_FOUND, CURVEFS_ERROR::NOT_EXIST }, + { MetaStatusCode::PARAM_ERROR, CURVEFS_ERROR::INVALID_PARAM }, { MetaStatusCode::INODE_EXIST, CURVEFS_ERROR::EXISTS }, { MetaStatusCode::DENTRY_EXIST, CURVEFS_ERROR::EXISTS }, { MetaStatusCode::SYM_LINK_EMPTY, CURVEFS_ERROR::INTERNAL }, diff --git a/curvefs/src/client/filesystem/error.h b/curvefs/src/client/filesystem/error.h index 1f837ca9d6..75efe38283 100644 --- a/curvefs/src/client/filesystem/error.h +++ b/curvefs/src/client/filesystem/error.h @@ -40,23 +40,25 @@ enum class CURVEFS_ERROR { INTERNAL = -1, UNKNOWN = -2, EXISTS = -3, - NOTEXIST = -4, + NOT_EXIST = -4, NO_SPACE = -5, BAD_FD = -6, - INVALIDPARAM = -7, - NOPERMISSION = -8, - NOTEMPTY = -9, - NOFLUSH = -10, - NOTSUPPORT = -11, - NAMETOOLONG = -12, + INVALID_PARAM = -7, + NO_PERMISSION = -8, + NOT_EMPTY = -9, + NO_FLUSH = -10, + NOT_SUPPORT = -10, + NAME_TOO_LONG = -12, MOUNT_POINT_EXIST = -13, MOUNT_FAILED = -14, OUT_OF_RANGE = -15, NODATA = -16, IO_ERROR = -17, - CACHETOOSMALL = -18, + CACHE_TOO_SMALL = -18, STALE = -19, NOSYS = -20, + END_OF_FILE = -21, + NOT_A_DIRECTORY = -22, }; std::string StrErr(CURVEFS_ERROR code); diff --git a/curvefs/src/client/filesystem/filesystem.cpp b/curvefs/src/client/filesystem/filesystem.cpp index 795c896a5b..2aad563051 100644 --- a/curvefs/src/client/filesystem/filesystem.cpp +++ b/curvefs/src/client/filesystem/filesystem.cpp @@ -234,30 +234,34 @@ FileSystemMember FileSystem::BorrowMember() { } // fuse request* -CURVEFS_ERROR FileSystem::Lookup(Request req, - Ino parent, +CURVEFS_ERROR FileSystem::Lookup(Ino parent, const std::string& name, EntryOut* entryOut) { if (name.size() > option_.maxNameLength) { - return CURVEFS_ERROR::NAMETOOLONG; + return CURVEFS_ERROR::NAME_TOO_LONG; } bool yes = negative_->Get(parent, name); if (yes) { - return CURVEFS_ERROR::NOTEXIST; + return CURVEFS_ERROR::NOT_EXIST; } auto rc = rpc_->Lookup(parent, name, entryOut); if (rc == CURVEFS_ERROR::OK) { negative_->Delete(parent, name); - } else if (rc == CURVEFS_ERROR::NOTEXIST) { + } else if (rc == CURVEFS_ERROR::NOT_EXIST) { negative_->Put(parent, name); } return rc; } -CURVEFS_ERROR FileSystem::GetAttr(Request req, Ino ino, AttrOut* attrOut) { +CURVEFS_ERROR FileSystem::GetAttr(Ino ino, AttrOut* attrOut) { InodeAttr attr; + if (!option_.cto && deferSync_->IsDefered(ino, &attr)) { + *attrOut = AttrOut(attr); + return CURVEFS_ERROR::OK; + } + auto rc = rpc_->GetAttr(ino, &attr); if (rc == CURVEFS_ERROR::OK) { *attrOut = AttrOut(attr); @@ -265,7 +269,7 @@ CURVEFS_ERROR FileSystem::GetAttr(Request req, Ino ino, AttrOut* attrOut) { return rc; } -CURVEFS_ERROR FileSystem::OpenDir(Request req, Ino ino, FileInfo* fi) { +CURVEFS_ERROR FileSystem::OpenDir(Ino ino, FileInfo* fi) { InodeAttr attr; CURVEFS_ERROR rc = rpc_->GetAttr(ino, &attr); if (rc != CURVEFS_ERROR::OK) { @@ -287,8 +291,7 @@ CURVEFS_ERROR FileSystem::OpenDir(Request req, Ino ino, FileInfo* fi) { return CURVEFS_ERROR::OK; } -CURVEFS_ERROR FileSystem::ReadDir(Request req, - Ino ino, +CURVEFS_ERROR FileSystem::ReadDir(Ino ino, FileInfo* fi, std::shared_ptr* entries) { bool yes = dirCache_->Get(ino, entries); @@ -306,12 +309,12 @@ CURVEFS_ERROR FileSystem::ReadDir(Request req, return CURVEFS_ERROR::OK; } -CURVEFS_ERROR FileSystem::ReleaseDir(Request req, Ino ino, FileInfo* fi) { +CURVEFS_ERROR FileSystem::ReleaseDir(Ino ino, FileInfo* fi) { ReleaseHandler(fi->fh); return CURVEFS_ERROR::OK; } -CURVEFS_ERROR FileSystem::Open(Request req, Ino ino, FileInfo* fi) { +CURVEFS_ERROR FileSystem::Open(Ino ino, FileInfo* fi) { std::shared_ptr inode; bool yes = openFiles_->IsOpened(ino, &inode); if (yes) { @@ -343,7 +346,7 @@ CURVEFS_ERROR FileSystem::Open(Request req, Ino ino, FileInfo* fi) { return CURVEFS_ERROR::OK; } -CURVEFS_ERROR FileSystem::Release(Request req, Ino ino) { +CURVEFS_ERROR FileSystem::Release(Ino ino) { openFiles_->Close(ino); return CURVEFS_ERROR::OK; } diff --git a/curvefs/src/client/filesystem/filesystem.h b/curvefs/src/client/filesystem/filesystem.h index c2d48db708..eaa6cacc2a 100644 --- a/curvefs/src/client/filesystem/filesystem.h +++ b/curvefs/src/client/filesystem/filesystem.h @@ -67,25 +67,23 @@ class FileSystem { void Destory(); // fuse request - CURVEFS_ERROR Lookup(Request req, - Ino parent, + CURVEFS_ERROR Lookup(Ino parent, const std::string& name, EntryOut* entryOut); - CURVEFS_ERROR GetAttr(Request req, Ino ino, AttrOut* attrOut); + CURVEFS_ERROR GetAttr(Ino ino, AttrOut* attrOut); - CURVEFS_ERROR OpenDir(Request req, Ino ino, FileInfo* fi); + CURVEFS_ERROR OpenDir(Ino ino, FileInfo* fi); - CURVEFS_ERROR ReadDir(Request req, - Ino ino, + CURVEFS_ERROR ReadDir(Ino ino, FileInfo* fi, std::shared_ptr* entries); - CURVEFS_ERROR ReleaseDir(Request req, Ino ino, FileInfo* fi); + CURVEFS_ERROR ReleaseDir(Ino ino, FileInfo* fi); - CURVEFS_ERROR Open(Request req, Ino ino, FileInfo* fi); + CURVEFS_ERROR Open(Ino ino, FileInfo* fi); - CURVEFS_ERROR Release(Request req, Ino ino); + CURVEFS_ERROR Release(Ino ino); // fuse reply: we control all replies to vfs layer in same entrance. void ReplyError(Request req, CURVEFS_ERROR code); @@ -129,15 +127,6 @@ class FileSystem { void ReleaseHandler(uint64_t fh); - // utility: others - FileSystemMember BorrowMember(); - - private: - FRIEND_TEST(FileSystemTest, Attr2Stat); - FRIEND_TEST(FileSystemTest, Entry2Param); - FRIEND_TEST(FileSystemTest, SetEntryTimeout); - FRIEND_TEST(FileSystemTest, SetAttrTimeout); - // utility: convert to system type. void Attr2Stat(InodeAttr* attr, struct stat* stat); @@ -148,6 +137,9 @@ class FileSystem { void SetAttrTimeout(AttrOut* attrOut); + // utility: others + FileSystemMember BorrowMember(); + private: FileSystemOption option_; ExternalMember member; diff --git a/curvefs/src/client/filesystem/lookup_cache.cpp b/curvefs/src/client/filesystem/lookup_cache.cpp index d5c473a114..7e49b0db1c 100644 --- a/curvefs/src/client/filesystem/lookup_cache.cpp +++ b/curvefs/src/client/filesystem/lookup_cache.cpp @@ -83,7 +83,7 @@ bool LookupCache::Put(Ino parent, const std::string& name) { if (yes) { entry.uses++; } else { - entry.uses = 0; + entry.uses = 1; } entry.expireTime = Now() + TimeSpec(option_.negativeTimeoutSec, 0); diff --git a/curvefs/src/client/filesystem/meta.cpp b/curvefs/src/client/filesystem/meta.cpp index 47bbeced83..4c835fd4d7 100644 --- a/curvefs/src/client/filesystem/meta.cpp +++ b/curvefs/src/client/filesystem/meta.cpp @@ -123,6 +123,10 @@ std::string StrAttr(AttrOut attrOut) { return Attr2Str(attrOut.attr); } +std::string StrAttr(InodeAttr attr) { + return Attr2Str(attr); +} + } // namespace filesystem } // namespace client } // namespace curvefs diff --git a/curvefs/src/client/filesystem/meta.h b/curvefs/src/client/filesystem/meta.h index 1165a1fb4f..c10ec1b0d9 100644 --- a/curvefs/src/client/filesystem/meta.h +++ b/curvefs/src/client/filesystem/meta.h @@ -171,6 +171,8 @@ std::string StrEntry(EntryOut entryOut); std::string StrAttr(AttrOut attrOut); +std::string StrAttr(InodeAttr attr); + } // namespace filesystem } // namespace client } // namespace curvefs diff --git a/curvefs/src/client/filesystem/rpc_client.cpp b/curvefs/src/client/filesystem/rpc_client.cpp index a7ec92764d..236c50687f 100644 --- a/curvefs/src/client/filesystem/rpc_client.cpp +++ b/curvefs/src/client/filesystem/rpc_client.cpp @@ -54,7 +54,7 @@ CURVEFS_ERROR RPCClient::Lookup(Ino parent, Dentry dentry; CURVEFS_ERROR rc = dentryManager_->GetDentry(parent, name, &dentry); if (rc != CURVEFS_ERROR::OK) { - if (rc != CURVEFS_ERROR::NOTEXIST) { + if (rc != CURVEFS_ERROR::NOT_EXIST) { LOG(ERROR) << "rpc(lookup::GetDentry) failed, retCode = " << rc << ", parent = " << parent << ", name = " << name; } diff --git a/curvefs/src/client/filesystem/utils.cpp b/curvefs/src/client/filesystem/utils.cpp index 0a6b6c38e0..dd4e2a5c6c 100644 --- a/curvefs/src/client/filesystem/utils.cpp +++ b/curvefs/src/client/filesystem/utils.cpp @@ -40,7 +40,7 @@ bool IsVolmeFile(const InodeAttr& attr) { return attr.type() == FsFileType::TYPE_FILE; } -bool IsSymLink(const InodeAttr& attr) { +bool IsSymlink(const InodeAttr& attr) { return attr.type() == FsFileType::TYPE_SYM_LINK; } diff --git a/curvefs/src/client/filesystem/utils.h b/curvefs/src/client/filesystem/utils.h index 8f37104e1d..706fa3d271 100644 --- a/curvefs/src/client/filesystem/utils.h +++ b/curvefs/src/client/filesystem/utils.h @@ -42,7 +42,7 @@ bool IsS3File(const InodeAttr& attr); bool IsVolmeFile(const InodeAttr& attr); // symbol link -bool IsSymLink(const InodeAttr& attr); +bool IsSymlink(const InodeAttr& attr); struct TimeSpec AttrMtime(const InodeAttr& attr); diff --git a/curvefs/src/client/fuse_client.cpp b/curvefs/src/client/fuse_client.cpp index b944b37f15..e3159fcc81 100644 --- a/curvefs/src/client/fuse_client.cpp +++ b/curvefs/src/client/fuse_client.cpp @@ -23,53 +23,55 @@ #include "curvefs/src/client/fuse_client.h" -#include #include #include +#include #include -#include -#include #include +#include #include #include +#include +#include "absl/memory/memory.h" #include "curvefs/proto/mds.pb.h" +#include "curvefs/src/client/client_operator.h" #include "curvefs/src/client/common/common.h" #include "curvefs/src/client/filesystem/error.h" #include "curvefs/src/client/filesystem/xattr.h" #include "curvefs/src/client/fuse_common.h" -#include "curvefs/src/client/client_operator.h" #include "curvefs/src/client/inode_wrapper.h" #include "curvefs/src/client/warmup/warmup_manager.h" #include "curvefs/src/client/xattr_manager.h" #include "curvefs/src/common/define.h" -#include "src/common/net_common.h" -#include "src/common/dummyserver.h" #include "src/client/client_common.h" -#include "absl/memory/memory.h" +#include "src/common/dummyserver.h" +#include "src/common/net_common.h" #define PORT_LIMIT 65535 -using ::curvefs::common::S3Info; -using ::curvefs::common::Volume; -using ::curvefs::mds::topology::PartitionTxId; -using ::curvefs::mds::FSStatusCode_Name; -using ::curvefs::client::filesystem::ExternalMember; +using ::curvefs::client::common::FuseClientOption; using ::curvefs::client::filesystem::DirEntry; using ::curvefs::client::filesystem::DirEntryList; +using ::curvefs::client::filesystem::ExternalMember; using ::curvefs::client::filesystem::FileOut; +using ::curvefs::client::filesystem::IsSpecialXAttr; using ::curvefs::client::filesystem::MAX_XATTR_NAME_LENGTH; using ::curvefs::client::filesystem::MAX_XATTR_VALUE_LENGTH; -using ::curvefs::client::filesystem::XATTR_DIR_FILES; -using ::curvefs::client::filesystem::XATTR_DIR_SUBDIRS; using ::curvefs::client::filesystem::XATTR_DIR_ENTRIES; using ::curvefs::client::filesystem::XATTR_DIR_FBYTES; -using ::curvefs::client::filesystem::XATTR_DIR_RFILES; +using ::curvefs::client::filesystem::XATTR_DIR_FILES; +using ::curvefs::client::filesystem::XATTR_DIR_PREFIX; +using ::curvefs::client::filesystem::XATTR_DIR_RENTRIES; using ::curvefs::client::filesystem::XATTR_DIR_RFBYTES; +using ::curvefs::client::filesystem::XATTR_DIR_RFILES; using ::curvefs::client::filesystem::XATTR_DIR_RSUBDIRS; -using ::curvefs::client::filesystem::XATTR_DIR_RENTRIES; -using ::curvefs::client::filesystem::XATTR_DIR_PREFIX; -using ::curvefs::client::filesystem::IsSpecialXAttr; +using ::curvefs::client::filesystem::XATTR_DIR_SUBDIRS; +using ::curvefs::common::FSType; +using ::curvefs::common::S3Info; +using ::curvefs::common::Volume; +using ::curvefs::mds::FSStatusCode_Name; +using ::curvefs::mds::topology::PartitionTxId; #define RETURN_IF_UNSUCCESS(action) \ do { \ @@ -279,8 +281,8 @@ CURVEFS_ERROR FuseClient::FuseOpLookup(fuse_req_t req, fuse_ino_t parent, const char* name, EntryOut* entryOut) { - CURVEFS_ERROR rc = fs_->Lookup(req, parent, name, entryOut); - if (rc != CURVEFS_ERROR::OK && rc != CURVEFS_ERROR::NOTEXIST) { + CURVEFS_ERROR rc = fs_->Lookup(parent, name, entryOut); + if (rc != CURVEFS_ERROR::OK && rc != CURVEFS_ERROR::NOT_EXIST) { LOG(ERROR) << "Lookup() failed, retCode = " << rc << ", parent = " << parent << ", name = " << name; } @@ -329,8 +331,8 @@ CURVEFS_ERROR FuseClient::HandleOpenFlags(fuse_req_t req, // update parent summary info const Inode *inode = inodeWrapper->GetInodeLocked(); XAttr xattr; - xattr.mutable_xattrinfos()->insert({XATTR_DIR_FBYTES, - std::to_string(length)}); + xattr.mutable_xattrinfos()->insert( + {XATTR_DIR_FBYTES, std::to_string(length)}); for (const auto &it : inode->parent()) { auto tret = xattrManager_->UpdateParentInodeXattr( it, xattr, false); @@ -343,7 +345,7 @@ CURVEFS_ERROR FuseClient::HandleOpenFlags(fuse_req_t req, } inodeWrapper->GetInodeAttrLocked(&fileOut->attr); } else { - return CURVEFS_ERROR::NOPERMISSION; + return CURVEFS_ERROR::NO_PERMISSION; } } return CURVEFS_ERROR::OK; @@ -353,7 +355,7 @@ CURVEFS_ERROR FuseClient::FuseOpOpen(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi, FileOut* fileOut) { - CURVEFS_ERROR rc = fs_->Open(req, ino, fi); + CURVEFS_ERROR rc = fs_->Open(ino, fi); if (rc != CURVEFS_ERROR::OK) { LOG(ERROR) << "open(" << ino << ") failed, retCode = " << rc; return rc; @@ -400,19 +402,19 @@ CURVEFS_ERROR FuseClient::MakeNode( bool internal, std::shared_ptr& inodeWrapper) { if (strlen(name) > option_.fileSystemOption.maxNameLength) { - return CURVEFS_ERROR::NAMETOOLONG; + return CURVEFS_ERROR::NAME_TOO_LONG; } // check if node is recycle or under recycle if (!internal && strcmp(name, RECYCLENAME) == 0 && parent == ROOTINODEID) { LOG(WARNING) << "Can not make node " << RECYCLENAME << " under root dir."; - return CURVEFS_ERROR::NOPERMISSION; + return CURVEFS_ERROR::NO_PERMISSION; } if (!internal && parent == RECYCLEINODEID) { LOG(WARNING) << "Can not make node under recycle."; - return CURVEFS_ERROR::NOPERMISSION; + return CURVEFS_ERROR::NO_PERMISSION; } const struct fuse_ctx *ctx = fuse_req_ctx(req); @@ -423,6 +425,7 @@ CURVEFS_ERROR FuseClient::MakeNode( } else { param.length = 0; } + param.uid = ctx->uid; param.gid = ctx->gid; param.mode = mode; @@ -480,8 +483,8 @@ CURVEFS_ERROR FuseClient::MakeNode( } else { xattr.mutable_xattrinfos()->insert({XATTR_DIR_FILES, "1"}); } - xattr.mutable_xattrinfos()->insert({XATTR_DIR_FBYTES, - std::to_string(inodeWrapper->GetLength())}); + xattr.mutable_xattrinfos()->insert( + {XATTR_DIR_FBYTES, std::to_string(inodeWrapper->GetLength())}); auto tret = xattrManager_->UpdateParentInodeXattr(parent, xattr, true); if (tret != CURVEFS_ERROR::OK) { LOG(ERROR) << "UpdateParentInodeXattr failed," @@ -559,8 +562,8 @@ CURVEFS_ERROR FuseClient::DeleteNode(uint64_t ino, fuse_ino_t parent, } else { xattr.mutable_xattrinfos()->insert({XATTR_DIR_FILES, "1"}); } - xattr.mutable_xattrinfos()->insert({XATTR_DIR_FBYTES, - std::to_string(inodeWrapper->GetLength())}); + xattr.mutable_xattrinfos()->insert( + {XATTR_DIR_FBYTES, std::to_string(inodeWrapper->GetLength())}); auto tret = xattrManager_->UpdateParentInodeXattr(parent, xattr, false); if (tret != CURVEFS_ERROR::OK) { LOG(WARNING) << "UpdateParentInodeXattr failed," @@ -587,7 +590,7 @@ CURVEFS_ERROR FuseClient::CreateManageNode(fuse_req_t req, ManageInodeType manageType, EntryOut* entryOut) { if (strlen(name) > option_.fileSystemOption.maxNameLength) { - return CURVEFS_ERROR::NAMETOOLONG; + return CURVEFS_ERROR::NAME_TOO_LONG; } InodeParam param; @@ -650,8 +653,8 @@ CURVEFS_ERROR FuseClient::CreateManageNode(fuse_req_t req, } else { xattr.mutable_xattrinfos()->insert({XATTR_DIR_FILES, "1"}); } - xattr.mutable_xattrinfos()->insert({XATTR_DIR_FBYTES, - std::to_string(inodeWrapper->GetLength())}); + xattr.mutable_xattrinfos()->insert( + {XATTR_DIR_FBYTES, std::to_string(inodeWrapper->GetLength())}); auto tret = xattrManager_->UpdateParentInodeXattr(parent, xattr, true); if (tret != CURVEFS_ERROR::OK) { LOG(ERROR) << "UpdateParentInodeXattr failed," @@ -666,12 +669,12 @@ CURVEFS_ERROR FuseClient::CreateManageNode(fuse_req_t req, CURVEFS_ERROR FuseClient::GetOrCreateRecycleDir(fuse_req_t req, Dentry *out) { auto ret = dentryManager_->GetDentry(ROOTINODEID, RECYCLENAME, out); - if (ret != CURVEFS_ERROR::OK && ret != CURVEFS_ERROR::NOTEXIST) { + if (ret != CURVEFS_ERROR::OK && ret != CURVEFS_ERROR::NOT_EXIST) { LOG(ERROR) << "dentryManager_ GetDentry fail, ret = " << ret << ", inode = " << ROOTINODEID << ", name = " << RECYCLENAME; return ret; - } else if (ret == CURVEFS_ERROR::NOTEXIST) { + } else if (ret == CURVEFS_ERROR::NOT_EXIST) { LOG(INFO) << "recycle dir is not exist, create " << RECYCLENAME << ", parentid = " << ROOTINODEID; EntryOut entryOut; @@ -708,12 +711,12 @@ CURVEFS_ERROR FuseClient::MoveToRecycle(fuse_req_t req, fuse_ino_t ino, uint64_t recycleTimeDirIno; ret = dentryManager_->GetDentry(RECYCLEINODEID, recycleTimeDirName.c_str(), &dentry); - if (ret != CURVEFS_ERROR::OK && ret != CURVEFS_ERROR::NOTEXIST) { + if (ret != CURVEFS_ERROR::OK && ret != CURVEFS_ERROR::NOT_EXIST) { LOG(ERROR) << "dentryManager_ GetDentry fail, ret = " << ret << ", inode = " << RECYCLEINODEID << ", name = " << recycleTimeDirName; return ret; - } else if (ret == CURVEFS_ERROR::NOTEXIST) { + } else if (ret == CURVEFS_ERROR::NOT_EXIST) { std::shared_ptr inode; bool internal = true; ret = MakeNode(req, RECYCLEINODEID, recycleTimeDirName.c_str(), @@ -772,13 +775,13 @@ bool FuseClient::ShouldMoveToRecycle(fuse_ino_t parent) { CURVEFS_ERROR FuseClient::RemoveNode(fuse_req_t req, fuse_ino_t parent, const char *name, FsFileType type) { if (strlen(name) > option_.fileSystemOption.maxNameLength) { - return CURVEFS_ERROR::NAMETOOLONG; + return CURVEFS_ERROR::NAME_TOO_LONG; } // check if node is recycle or recycle time dir if ((strcmp(name, RECYCLENAME) == 0 && parent == ROOTINODEID) || parent == RECYCLEINODEID) { - return CURVEFS_ERROR::NOPERMISSION; + return CURVEFS_ERROR::NO_PERMISSION; } Dentry dentry; @@ -803,7 +806,7 @@ CURVEFS_ERROR FuseClient::RemoveNode(fuse_req_t req, fuse_ino_t parent, } if (!dentryList.empty()) { LOG(ERROR) << "rmdir not empty"; - return CURVEFS_ERROR::NOTEMPTY; + return CURVEFS_ERROR::NOT_EMPTY; } } @@ -830,7 +833,7 @@ CURVEFS_ERROR FuseClient::RemoveNode(fuse_req_t req, fuse_ino_t parent, CURVEFS_ERROR FuseClient::FuseOpOpenDir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) { - CURVEFS_ERROR rc = fs_->OpenDir(req, ino, fi); + CURVEFS_ERROR rc = fs_->OpenDir(ino, fi); if (rc != CURVEFS_ERROR::OK) { LOG(ERROR) << "opendir() failed, retCode = " << rc << ", ino = " << ino; @@ -850,7 +853,7 @@ CURVEFS_ERROR FuseClient::FuseOpReadDir(fuse_req_t req, DirBufferHead* buffer = handler->buffer; if (!handler->padding) { auto entries = std::make_shared(); - CURVEFS_ERROR rc = fs_->ReadDir(req, ino, fi, &entries); + CURVEFS_ERROR rc = fs_->ReadDir(ino, fi, &entries); if (rc != CURVEFS_ERROR::OK) { LOG(ERROR) << "readdir() failed, retCode = " << rc << ", ino = " << ino << ", fh = " << fi->fh; @@ -880,7 +883,7 @@ CURVEFS_ERROR FuseClient::FuseOpReadDir(fuse_req_t req, CURVEFS_ERROR FuseClient::FuseOpReleaseDir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info* fi) { - CURVEFS_ERROR rc = fs_->ReleaseDir(req, ino, fi); + CURVEFS_ERROR rc = fs_->ReleaseDir(ino, fi); if (rc != CURVEFS_ERROR::OK) { LOG(ERROR) << "releasedir() failed, retCode = " << rc << ", ino = " << ino; @@ -899,7 +902,7 @@ CURVEFS_ERROR FuseClient::FuseOpRename(fuse_req_t req, fuse_ino_t parent, // is only used in linux interface renameat(), not required by posix, // we can ignore it now if (flags != 0) { - return CURVEFS_ERROR::INVALIDPARAM; + return CURVEFS_ERROR::INVALID_PARAM; } uint64_t maxNameLength = option_.fileSystemOption.maxNameLength; @@ -908,7 +911,7 @@ CURVEFS_ERROR FuseClient::FuseOpRename(fuse_req_t req, fuse_ino_t parent, << ", name len = " << strlen(name) << ", new name = " << newname << ", new name len = " << strlen(newname) << ", maxNameLength = " << maxNameLength; - return CURVEFS_ERROR::NAMETOOLONG; + return CURVEFS_ERROR::NAME_TOO_LONG; } auto renameOp = @@ -950,7 +953,7 @@ CURVEFS_ERROR FuseClient::FuseOpGetAttr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, AttrOut* attrOut) { - CURVEFS_ERROR rc = fs_->GetAttr(req, ino, attrOut); + CURVEFS_ERROR rc = fs_->GetAttr(ino, attrOut); if (rc != CURVEFS_ERROR::OK) { LOG(ERROR) << "getattr() fail, retCode = " << rc << ", ino = " << ino; @@ -1026,8 +1029,8 @@ CURVEFS_ERROR FuseClient::FuseOpSetAttr(fuse_req_t req, // update parent summary info const Inode* inode = inodeWrapper->GetInodeLocked(); XAttr xattr; - xattr.mutable_xattrinfos()->insert({XATTR_DIR_FBYTES, - std::to_string(std::abs(changeSize))}); + xattr.mutable_xattrinfos()->insert( + {XATTR_DIR_FBYTES, std::to_string(std::abs(changeSize))}); bool direction = changeSize > 0; for (const auto &it : inode->parent()) { auto tret = xattrManager_->UpdateParentInodeXattr( @@ -1146,36 +1149,26 @@ CURVEFS_ERROR FuseClient::FuseOpListXattr(fuse_req_t req, fuse_ino_t ino, // get xattr key for (const auto &it : inodeAttr.xattr()) { + if (option_.fileSystemOption.disableXAttr && + !IsSpecialXAttr(it.first)) { + continue; + } // +1 because, the format is key\0key\0 *realSize += it.first.length() + 1; } - // add summary xattr key - if (inodeAttr.type() == FsFileType::TYPE_DIRECTORY) { - *realSize += strlen(XATTR_DIR_RFILES) + 1; - *realSize += strlen(XATTR_DIR_RSUBDIRS) + 1; - *realSize += strlen(XATTR_DIR_RENTRIES) + 1; - *realSize += strlen(XATTR_DIR_RFBYTES) + 1; - } - if (size == 0) { return CURVEFS_ERROR::OK; } else if (size >= *realSize) { for (const auto &it : inodeAttr.xattr()) { + if (option_.fileSystemOption.disableXAttr && + !IsSpecialXAttr(it.first)) { + continue; + } auto tsize = it.first.length() + 1; memcpy(value, it.first.c_str(), tsize); value += tsize; } - if (inodeAttr.type() == FsFileType::TYPE_DIRECTORY) { - memcpy(value, XATTR_DIR_RFILES, strlen(XATTR_DIR_RFILES) + 1); - value += strlen(XATTR_DIR_RFILES) + 1; - memcpy(value, XATTR_DIR_RSUBDIRS, strlen(XATTR_DIR_RSUBDIRS) + 1); - value += strlen(XATTR_DIR_RSUBDIRS) + 1; - memcpy(value, XATTR_DIR_RENTRIES, strlen(XATTR_DIR_RENTRIES) + 1); - value += strlen(XATTR_DIR_RENTRIES) + 1; - memcpy(value, XATTR_DIR_RFBYTES, strlen(XATTR_DIR_RFBYTES) + 1); - value += strlen(XATTR_DIR_RFBYTES) + 1; - } return CURVEFS_ERROR::OK; } return CURVEFS_ERROR::OUT_OF_RANGE; @@ -1187,7 +1180,7 @@ CURVEFS_ERROR FuseClient::FuseOpSymlink(fuse_req_t req, const char* name, EntryOut* entryOut) { if (strlen(name) > option_.fileSystemOption.maxNameLength) { - return CURVEFS_ERROR::NAMETOOLONG; + return CURVEFS_ERROR::NAME_TOO_LONG; } const struct fuse_ctx *ctx = fuse_req_ctx(req); InodeParam param; @@ -1234,8 +1227,8 @@ CURVEFS_ERROR FuseClient::FuseOpSymlink(fuse_req_t req, XAttr xattr; xattr.mutable_xattrinfos()->insert({XATTR_DIR_ENTRIES, "1"}); xattr.mutable_xattrinfos()->insert({XATTR_DIR_FILES, "1"}); - xattr.mutable_xattrinfos()->insert({XATTR_DIR_FBYTES, - std::to_string(inodeWrapper->GetLength())}); + xattr.mutable_xattrinfos()->insert( + {XATTR_DIR_FBYTES, std::to_string(inodeWrapper->GetLength())}); auto tret = xattrManager_->UpdateParentInodeXattr(parent, xattr, true); if (tret != CURVEFS_ERROR::OK) { LOG(ERROR) << "UpdateParentInodeXattr failed," @@ -1255,7 +1248,7 @@ CURVEFS_ERROR FuseClient::FuseOpLink(fuse_req_t req, FsFileType type, EntryOut* entryOut) { if (strlen(newname) > option_.fileSystemOption.maxNameLength) { - return CURVEFS_ERROR::NAMETOOLONG; + return CURVEFS_ERROR::NAME_TOO_LONG; } std::shared_ptr inodeWrapper; CURVEFS_ERROR ret = inodeManager_->GetInode(ino, inodeWrapper); @@ -1295,8 +1288,8 @@ CURVEFS_ERROR FuseClient::FuseOpLink(fuse_req_t req, XAttr xattr; xattr.mutable_xattrinfos()->insert({XATTR_DIR_ENTRIES, "1"}); xattr.mutable_xattrinfos()->insert({XATTR_DIR_FILES, "1"}); - xattr.mutable_xattrinfos()->insert({XATTR_DIR_FBYTES, - std::to_string(inodeWrapper->GetLength())}); + xattr.mutable_xattrinfos()->insert( + {XATTR_DIR_FBYTES, std::to_string(inodeWrapper->GetLength())}); auto tret = xattrManager_->UpdateParentInodeXattr( newparent, xattr, true); if (tret != CURVEFS_ERROR::OK) { @@ -1328,7 +1321,7 @@ CURVEFS_ERROR FuseClient::FuseOpReadLink(fuse_req_t req, fuse_ino_t ino, CURVEFS_ERROR FuseClient::FuseOpRelease(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { - CURVEFS_ERROR rc = fs_->Release(req, ino); + CURVEFS_ERROR rc = fs_->Release(ino); if (rc != CURVEFS_ERROR::OK) { LOG(ERROR) << "release() failed, ino = " << ino; } diff --git a/curvefs/src/client/fuse_client.h b/curvefs/src/client/fuse_client.h index ea8971f9ba..13adc3c591 100644 --- a/curvefs/src/client/fuse_client.h +++ b/curvefs/src/client/fuse_client.h @@ -43,6 +43,7 @@ #include "curvefs/src/client/common/config.h" #include "curvefs/src/client/dentry_cache_manager.h" #include "curvefs/src/client/dir_buffer.h" +#include "curvefs/src/client/filesystem/error.h" #include "curvefs/src/client/filesystem/filesystem.h" #include "curvefs/src/client/filesystem/meta.h" #include "curvefs/src/client/fuse_common.h" @@ -58,6 +59,7 @@ #include "curvefs/src/common/fast_align.h" #include "curvefs/src/common/s3util.h" #include "src/common/concurrent/concurrent.h" +#include "src/common/configuration.h" #include "src/common/throttle.h" #define DirectIOAlignment 512 @@ -65,10 +67,11 @@ using ::curve::common::Atomic; using ::curve::common::InterruptibleSleeper; using ::curve::common::Thread; +using ::curvefs::client::filesystem::CURVEFS_ERROR; +using ::curvefs::client::metric::FSMetric; using ::curvefs::common::FSType; using ::curvefs::metaserver::DentryFlag; using ::curvefs::metaserver::ManageInodeType; -using ::curvefs::client::metric::FSMetric; namespace curvefs { namespace client { @@ -79,15 +82,16 @@ class WarmupManager; } using common::FuseClientOption; +using ::curve::common::Configuration; +using ::curvefs::client::filesystem::AttrOut; +using ::curvefs::client::filesystem::EntryOut; +using ::curvefs::client::filesystem::FileOut; +using ::curvefs::client::filesystem::FileSystem; using rpcclient::MDSBaseClient; using rpcclient::MdsClient; using rpcclient::MdsClientImpl; using rpcclient::MetaServerClient; using rpcclient::MetaServerClientImpl; -using ::curvefs::client::filesystem::FileSystem; -using ::curvefs::client::filesystem::EntryOut; -using ::curvefs::client::filesystem::AttrOut; -using ::curvefs::client::filesystem::FileOut; using curvefs::common::is_aligned; @@ -294,13 +298,9 @@ class FuseClient { } } - std::shared_ptr GetFsInfo() { - return fsInfo_; - } + std::shared_ptr GetFsInfo() { return fsInfo_; } - std::shared_ptr GetFileSystem() { - return fs_; - } + virtual std::shared_ptr GetFileSystem() { return fs_; } virtual void FlushAll(); diff --git a/curvefs/src/client/fuse_common.h b/curvefs/src/client/fuse_common.h index 816bc7b5fb..d033afc6bc 100644 --- a/curvefs/src/client/fuse_common.h +++ b/curvefs/src/client/fuse_common.h @@ -26,9 +26,9 @@ #define FUSE_USE_VERSION 34 -#include -#include #include +#include +#include #ifdef __cplusplus extern "C" { diff --git a/curvefs/src/client/fuse_s3_client.cpp b/curvefs/src/client/fuse_s3_client.cpp index 216a65bf0b..508f1a745e 100644 --- a/curvefs/src/client/fuse_s3_client.cpp +++ b/curvefs/src/client/fuse_s3_client.cpp @@ -26,8 +26,8 @@ #include #include -#include "curvefs/src/client/kvclient/memcache_client.h" #include "curvefs/src/client/filesystem/xattr.h" +#include "curvefs/src/client/kvclient/memcache_client.h" namespace curvefs { namespace client { @@ -43,11 +43,11 @@ DECLARE_bool(supportKVcache); namespace curvefs { namespace client { -using curvefs::client::common::FLAGS_supportKVcache; using curvefs::client::common::FLAGS_enableCto; +using curvefs::client::common::FLAGS_supportKVcache; +using ::curvefs::client::filesystem::XATTR_DIR_FBYTES; using curvefs::mds::topology::MemcacheClusterInfo; using curvefs::mds::topology::MemcacheServerInfo; -using ::curvefs::client::filesystem::XATTR_DIR_FBYTES; CURVEFS_ERROR FuseS3Client::Init(const FuseClientOption &option) { FuseClientOption opt(option); @@ -77,7 +77,7 @@ CURVEFS_ERROR FuseS3Client::Init(const FuseClientOption &option) { LOG(ERROR) << "writeCacheMaxByte is too small" << ", at least " << MIN_WRITE_CACHE_SIZE << " (8MB)" ", writeCacheMaxByte = " << writeCacheMaxByte; - return CURVEFS_ERROR::CACHETOOSMALL; + return CURVEFS_ERROR::CACHE_TOO_SMALL; } auto fsCacheManager = std::make_shared( @@ -166,7 +166,7 @@ CURVEFS_ERROR FuseS3Client::FuseOpWrite(fuse_req_t req, fuse_ino_t ino, if (fi->flags & O_DIRECT) { if (!(is_aligned(off, DirectIOAlignment) && is_aligned(size, DirectIOAlignment))) - return CURVEFS_ERROR::INVALIDPARAM; + return CURVEFS_ERROR::INVALID_PARAM; } uint64_t start = butil::cpuwide_time_us(); int wRet = s3Adaptor_->Write(ino, off, size, buf); @@ -206,8 +206,8 @@ CURVEFS_ERROR FuseS3Client::FuseOpWrite(fuse_req_t req, fuse_ino_t ino, if (enableSumInDir_ && changeSize != 0) { const Inode* inode = inodeWrapper->GetInodeLocked(); XAttr xattr; - xattr.mutable_xattrinfos()->insert({XATTR_DIR_FBYTES, - std::to_string(changeSize)}); + xattr.mutable_xattrinfos()->insert( + {XATTR_DIR_FBYTES, std::to_string(changeSize)}); for (const auto &it : inode->parent()) { auto tret = xattrManager_->UpdateParentInodeXattr(it, xattr, true); if (tret != CURVEFS_ERROR::OK) { @@ -240,7 +240,7 @@ CURVEFS_ERROR FuseS3Client::FuseOpRead(fuse_req_t req, fuse_ino_t ino, if (fi->flags & O_DIRECT) { if (!(is_aligned(off, DirectIOAlignment) && is_aligned(size, DirectIOAlignment))) - return CURVEFS_ERROR::INVALIDPARAM; + return CURVEFS_ERROR::INVALID_PARAM; } uint64_t start = butil::cpuwide_time_us(); diff --git a/curvefs/src/client/fuse_volume_client.cpp b/curvefs/src/client/fuse_volume_client.cpp index fc270a0282..26bcecdaa7 100644 --- a/curvefs/src/client/fuse_volume_client.cpp +++ b/curvefs/src/client/fuse_volume_client.cpp @@ -150,7 +150,7 @@ CURVEFS_ERROR FuseVolumeClient::FuseOpWrite(fuse_req_t req, if (!(is_aligned(off, DirectIOAlignment) && is_aligned(size, DirectIOAlignment))) { fsMetric_->userWrite.eps.count << 1; - return CURVEFS_ERROR::INVALIDPARAM; + return CURVEFS_ERROR::INVALID_PARAM; } } @@ -208,7 +208,7 @@ CURVEFS_ERROR FuseVolumeClient::FuseOpRead(fuse_req_t req, is_aligned(size, DirectIOAlignment))) { fsMetric_->userRead.eps.count << 1; - return CURVEFS_ERROR::INVALIDPARAM; + return CURVEFS_ERROR::INVALID_PARAM; } } diff --git a/curvefs/src/client/inode_cache_manager.cpp b/curvefs/src/client/inode_cache_manager.cpp index b71ac2ffa7..e8601c1526 100644 --- a/curvefs/src/client/inode_cache_manager.cpp +++ b/curvefs/src/client/inode_cache_manager.cpp @@ -147,7 +147,7 @@ CURVEFS_ERROR InodeCacheManagerImpl::BatchGetInodeAttrAsync( // split inodeIds by partitionId and batch limit std::vector> inodeGroups; if (!metaClient_->SplitRequestInodes(fsId_, *inodeIds, &inodeGroups)) { - return CURVEFS_ERROR::NOTEXIST; + return CURVEFS_ERROR::NOT_EXIST; } ::curve::common::Mutex mutex; diff --git a/curvefs/src/client/logger/BUILD b/curvefs/src/client/logger/BUILD new file mode 100644 index 0000000000..e5a115c166 --- /dev/null +++ b/curvefs/src/client/logger/BUILD @@ -0,0 +1,32 @@ +# +# Copyright (c) 2023 NetEase Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +load("//:copts.bzl", "CURVE_DEFAULT_COPTS") + +cc_library( + name = "logger", + srcs = glob(["*.cpp"]), + hdrs = glob(["*.h"]), + copts = CURVE_DEFAULT_COPTS, + visibility = ["//visibility:public"], + deps = [ + "//external:glog", + "@spdlog//:spdlog", + "@com_google_absl//absl/strings:str_format", + "//curvefs/src/common:dynamic_vlog", + "//curvefs/src/client/common:common", + ], +) diff --git a/curvefs/src/client/logger/access_log.cpp b/curvefs/src/client/logger/access_log.cpp new file mode 100644 index 0000000000..28c9255b9f --- /dev/null +++ b/curvefs/src/client/logger/access_log.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-08-14 + * Author: Jingli Chen (Wine93) + */ + +#include "curvefs/src/client/logger/access_log.h" + +namespace curvefs { +namespace client { +namespace logger { + +std::shared_ptr Logger; +bool inited = false; + +bool InitAccessLog(const std::string& prefix) { + if (inited) { + return true; + } + + std::string filename = StrFormat("%s/access.%d.log", prefix, getpid()); + Logger = spdlog::daily_logger_mt("fuse_access", filename, 0, 0); + spdlog::flush_every(std::chrono::seconds(1)); + inited = true; + return true; +} + +} // namespace logger +} // namespace client +} // namespace curvefs diff --git a/curvefs/src/client/filesystem/access_log.h b/curvefs/src/client/logger/access_log.h similarity index 75% rename from curvefs/src/client/filesystem/access_log.h rename to curvefs/src/client/logger/access_log.h index 608b564f65..5c9e075087 100644 --- a/curvefs/src/client/filesystem/access_log.h +++ b/curvefs/src/client/logger/access_log.h @@ -20,6 +20,8 @@ * Author: Jingli Chen (Wine93) */ +// clang-format off + #include #include #include @@ -32,8 +34,8 @@ #include "absl/strings/str_format.h" #include "curvefs/src/client/common/config.h" -#ifndef CURVEFS_SRC_CLIENT_FILESYSTEM_ACCESS_LOG_H_ -#define CURVEFS_SRC_CLIENT_FILESYSTEM_ACCESS_LOG_H_ +#ifndef CURVEFS_SRC_CLIENT_LOGGER_ACCESS_LOG_H_ +#define CURVEFS_SRC_CLIENT_LOGGER_ACCESS_LOG_H_ namespace curvefs { namespace client { @@ -42,24 +44,20 @@ namespace common { DECLARE_bool(access_logging); } -namespace filesystem { +namespace logger { using ::absl::StrFormat; using ::curvefs::client::common::FLAGS_access_logging; using MessageHandler = std::function; -static std::shared_ptr Logger; +extern std::shared_ptr Logger; +extern bool inited; -bool InitAccessLog(const std::string& prefix) { - std::string filename = StrFormat("%s/access_%d.log", prefix, getpid()); - Logger = spdlog::daily_logger_mt("fuse_access", filename, 0, 0); - spdlog::flush_every(std::chrono::seconds(1)); - return true; -} +bool InitAccessLog(const std::string& prefix); struct AccessLogGuard { explicit AccessLogGuard(MessageHandler handler) - : enable(FLAGS_access_logging), + : enable(FLAGS_access_logging && inited), handler(handler) { if (!enable) { return; @@ -82,8 +80,8 @@ struct AccessLogGuard { butil::Timer timer; }; -} // namespace filesystem +} // namespace logger } // namespace client } // namespace curvefs -#endif // CURVEFS_SRC_CLIENT_FILESYSTEM_ACCESS_LOG_H_ +#endif // CURVEFS_SRC_CLIENT_LOGGER_ACCESS_LOG_H_ diff --git a/curvefs/src/client/logger/error_log.h b/curvefs/src/client/logger/error_log.h new file mode 100644 index 0000000000..a259ce755a --- /dev/null +++ b/curvefs/src/client/logger/error_log.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-07-03 + * Author: Jingli Chen (Wine93) + */ + +// clang-format off + +#include + +#include +#include +#include + +#include "curvefs/src/common/dynamic_vlog.h" + +#ifndef CURVEFS_SRC_CLIENT_LOGGER_ERROR_LOG_H_ +#define CURVEFS_SRC_CLIENT_LOGGER_ERROR_LOG_H_ + +namespace curvefs { +namespace client { +namespace logger { + +using ::curvefs::common::FLAGS_vlog_level; + +inline bool InitErrorLog(const std::string& prefix, + const std::string& name, + int32_t loglevel) { + FLAGS_log_dir = prefix; + FLAGS_v = loglevel; + FLAGS_vlog_level = loglevel; + FLAGS_minloglevel = 0; + FLAGS_logtostderr = 0; + FLAGS_alsologtostderr = 0; + google::InitGoogleLogging(name.c_str()); + return true; +} + +inline void ShutdownErrorLog() { google::ShutdownGoogleLogging(); } + +} // namespace logger +} // namespace client +} // namespace curvefs + +#endif // CURVEFS_SRC_CLIENT_LOGGER_ERROR_LOG_H_ diff --git a/curvefs/src/client/metric/client_metric.h b/curvefs/src/client/metric/client_metric.h index 58a23fa84b..bfbf0f3373 100644 --- a/curvefs/src/client/metric/client_metric.h +++ b/curvefs/src/client/metric/client_metric.h @@ -28,6 +28,7 @@ #include #include +#include #include #include "src/client/client_metric.h" diff --git a/curvefs/src/client/s3/client_s3_adaptor.cpp b/curvefs/src/client/s3/client_s3_adaptor.cpp index 89fb0257b6..81a0148e01 100644 --- a/curvefs/src/client/s3/client_s3_adaptor.cpp +++ b/curvefs/src/client/s3/client_s3_adaptor.cpp @@ -72,7 +72,7 @@ S3ClientAdaptorImpl::Init( LOG(ERROR) << "chunkSize:" << chunkSize_ << " is not integral multiple for the blockSize:" << blockSize_; - return CURVEFS_ERROR::INVALIDPARAM; + return CURVEFS_ERROR::INVALID_PARAM; } prefetchBlocks_ = option.prefetchBlocks; prefetchExecQueueNum_ = option.prefetchExecQueueNum; diff --git a/curvefs/src/client/s3/client_s3_cache_manager.cpp b/curvefs/src/client/s3/client_s3_cache_manager.cpp index c169c45675..1bd098eb71 100644 --- a/curvefs/src/client/s3/client_s3_cache_manager.cpp +++ b/curvefs/src/client/s3/client_s3_cache_manager.cpp @@ -232,7 +232,7 @@ CURVEFS_ERROR FsCacheManager::FsSync(bool force) { g_s3MultiManagerMetric->fileManagerNum << -1; } } - } else if (ret == CURVEFS_ERROR::NOTEXIST) { + } else if (ret == CURVEFS_ERROR::NOT_EXIST) { iter->second->ReleaseCache(); WriteLockGuard writeLockGuard(rwLock_); auto iter1 = fileCacheManagerMap_.find(iter->first); @@ -1808,7 +1808,7 @@ CURVEFS_ERROR ChunkCacheManager::Flush(uint64_t inodeId, bool force, assert(flushingDataCache_->IsDirty()); do { ret = flushingDataCache_->Flush(inodeId, toS3); - if (ret == CURVEFS_ERROR::NOTEXIST) { + if (ret == CURVEFS_ERROR::NOT_EXIST) { LOG(WARNING) << "dataCache flush failed. ret:" << ret << ",index:" << index_ << ",data chunkpos:" << flushingDataCache_->GetChunkPos(); diff --git a/curvefs/src/client/sdk_helper.cpp b/curvefs/src/client/sdk_helper.cpp new file mode 100644 index 0000000000..e75ae21978 --- /dev/null +++ b/curvefs/src/client/sdk_helper.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-08-08 + * Author: Jingli Chen (Wine93) + */ + +// clang-format off + +#include "curvefs/src/client/logger/access_log.h" +#include "curvefs/src/client/logger/error_log.h" +#include "src/common/gflags_helper.h" +#include "curvefs/src/client/sdk_helper.h" + +namespace curvefs { +namespace client { + +using ::curve::common::GflagsLoadValueFromConfIfCmdNotSet; +using ::curvefs::client::logger::InitAccessLog; +using ::curvefs::client::logger::InitErrorLog; +using ::curvefs::client::logger::ShutdownErrorLog; + +void SDKHelper::InitLog(Configuration* cfg) { + // prefix + std::string prefix; + cfg->GetStringValue("client.common.logDir", &prefix); + + // name + static std::string name = "/curvefs-sdk"; + + // log level + int32_t loglevel = 0; + curve::common::GflagsLoadValueFromConfIfCmdNotSet dummy; + dummy.Load(cfg, "v", "client.loglevel", &loglevel); + + InitErrorLog(prefix, name, loglevel); + InitAccessLog(prefix); +} + +void SDKHelper::InitOption(Configuration* cfg, FuseClientOption* option) { + cfg->PrintConfig(); + InitFuseClientOption(cfg, option); +} + +FSType SDKHelper::Str2Type(const std::string& s) { + if (s == "s3") { + return FSType::TYPE_S3; + } else if (s == "volume") { + return FSType::TYPE_VOLUME; + } + return FSType(); +} + +std::string SDKHelper::Type2Str(FSType t) { + if (t == FSType::TYPE_S3) { + return "s3"; + } else if (t == FSType::TYPE_VOLUME) { + return "volume"; + } + return "unknown"; +} + +bool SDKHelper::GetFsInfoFromMDS(const MdsOption& option, + const std::string& fsname, + FsInfo* info) { + MdsClientImpl client; + MDSBaseClient base; + client.Init(option, &base); + auto rc = client.GetFsInfo(fsname, info); + if (rc != FSStatusCode::OK) { + LOG(ERROR) << "Get fsinfo from mds failed, fsname = " << fsname + << ", retCode = " << FSStatusCode_Name(rc); + return false; + } + return true; +} + +bool SDKHelper::CheckFsType(FSType real, FSType arg) { + if (real != arg) { + LOG(ERROR) << "The fstype obtained from the mds is " + << FSType_Name(real) << ", but user specified is " + << FSType_Name(arg); + return false; + } else if (real != FSType::TYPE_VOLUME && real != FSType::TYPE_S3) { + LOG(ERROR) << "The fstype obtained from the mds is " + << FSType_Name(real) << ", which is not supported"; + return false; + } + return true; +} + +MountOption SDKHelper::GetMountOption(const std::string& fsname, + const std::string& mountpoint) { + auto mountOption = MountOption(); + mountOption.mountPoint = mountpoint.c_str(); + mountOption.fsName = fsname.c_str(); + mountOption.fsType = Type2Str(FSType::TYPE_S3).c_str(); + return mountOption; +} + +CURVEFS_ERROR SDKHelper::CheckMountOption(std::shared_ptr client, + const MdsOption& mdsOption, + MountOption* mountOption) { + FsInfo info; + bool yes = GetFsInfoFromMDS(mdsOption, mountOption->fsName, &info) && + CheckFsType(info.fstype(), Str2Type(mountOption->fsType)); + if (!yes) { + return CURVEFS_ERROR::INTERNAL; + } + client->SetFsInfo(std::make_shared(info)); + return CURVEFS_ERROR::OK; +} + +CURVEFS_ERROR SDKHelper::Mount(std::shared_ptr client, + const std::string& fsname, + const std::string& mountpoint, + FuseClientOption option) { + auto mountOption = GetMountOption(fsname, mountpoint); + auto rc = CheckMountOption(client, option.mdsOpt, &mountOption); + if (rc != CURVEFS_ERROR::OK) { + return rc; + } + + rc = client->Init(option); + if (rc != CURVEFS_ERROR::OK) { + return rc; + } + + rc = client->Run(); + if (rc != CURVEFS_ERROR::OK) { + return rc; + } + + rc = client->SetMountStatus(&mountOption); + if (rc != CURVEFS_ERROR::OK) { + return rc; + } + + return client->FuseOpInit(nullptr, nullptr); +} + +CURVEFS_ERROR SDKHelper::Umount(std::shared_ptr client, + const std::string& fsname, + const std::string& mountpoint) { + auto mountOption = GetMountOption(fsname, mountpoint); + client->FuseOpDestroy(&mountOption); + client->Fini(); + client->UnInit(); + ShutdownErrorLog(); + return CURVEFS_ERROR::OK; +} + +} // namespace client +} // namespace curvefs diff --git a/curvefs/src/client/sdk_helper.h b/curvefs/src/client/sdk_helper.h new file mode 100644 index 0000000000..0a5b3c4fce --- /dev/null +++ b/curvefs/src/client/sdk_helper.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-08-08 + * Author: Jingli Chen (Wine93) + */ + +// clang-format off + +#ifndef CURVEFS_SRC_CLIENT_SDK_HELPER_H_ +#define CURVEFS_SRC_CLIENT_SDK_HELPER_H_ + +#include +#include + +#include "curvefs/proto/mds.pb.h" +#include "curvefs/proto/metaserver.pb.h" +#include "curvefs/src/client/common/config.h" +#include "curvefs/src/client/fuse_client.h" +#include "curvefs/src/client/fuse_common.h" +#include "curvefs/src/client/fuse_s3_client.h" +#include "curvefs/src/client/fuse_volume_client.h" +#include "src/common/configuration.h" + +namespace curvefs { +namespace client { + +using ::curve::common::Configuration; +using ::curvefs::client::common::MdsOption; +using ::curvefs::common::FSType; +using ::curvefs::mds::FsInfo; + +class SDKHelper { + public: + SDKHelper() = default; + + void InitLog(Configuration* cfg); + + void InitOption(Configuration* cfg, FuseClientOption* option); + + CURVEFS_ERROR Mount(std::shared_ptr client, + const std::string& fsname, + const std::string& mountpoint, + FuseClientOption option); + + CURVEFS_ERROR Umount(std::shared_ptr client, + const std::string& fsname, + const std::string& mountpoint); + + private: + FSType Str2Type(const std::string& s); + + std::string Type2Str(FSType t); + + bool GetFsInfoFromMDS(const MdsOption& option, + const std::string& fsname, + FsInfo* info); + + bool CheckFsType(FSType real, FSType arg); + + MountOption GetMountOption(const std::string& fsname, + const std::string& mountpoint); + + CURVEFS_ERROR CheckMountOption(std::shared_ptr client, + const MdsOption& mdsOption, + MountOption* mountOption); +}; + +} // namespace client +} // namespace curvefs + +#endif // CURVEFS_SRC_CLIENT_SDK_HELPER_H_ diff --git a/curvefs/src/client/vfs/.clang-format b/curvefs/src/client/vfs/.clang-format new file mode 100644 index 0000000000..a5660a57d8 --- /dev/null +++ b/curvefs/src/client/vfs/.clang-format @@ -0,0 +1,26 @@ +# I don't like current clang-formtter's specified style and +# and i think my style is more intuitive than it :), so I use +# this file to disable format, let us give some code snippet to prove it: +# +# my: +# std::vector tests { +# { " abc", "abc" }, +# { "abc ", "abc" }, +# { " abc ", "abc" }, +# { " a bc ", "a bc" }, +# { "a b c", "a b c" }, +# { " ", "" }, +# +# +# clang-formatter: +# std::vector tests{ +# {" abc", "abc"}, {"abc ", "abc"}, {" abc ", "abc"}, +# {" a bc ", "a bc"}, {"a b c", "a b c"}, {" ", ""}, +# }; +# +# Maybe you have different opinions, but please have a little mercy for me. +# +# by Wine93, 2023-10-16 + +DisableFormat: true +SortIncludes: Never diff --git a/curvefs/src/client/vfs/BUILD b/curvefs/src/client/vfs/BUILD new file mode 100644 index 0000000000..ba2926ff6f --- /dev/null +++ b/curvefs/src/client/vfs/BUILD @@ -0,0 +1,32 @@ +# +# Copyright (c) 2023 NetEase Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +load("//:copts.bzl", "CURVE_DEFAULT_COPTS") + +cc_library( + name = "vfs", + srcs = glob(["*.cpp"]), + hdrs = glob(["*.h"]), + copts = CURVE_DEFAULT_COPTS, + visibility = ["//visibility:public"], + deps = [ + "@incbin//:incbin", + "//src/common:curve_common", + "//curvefs/proto:metaserver_cc_proto", + "//curvefs/src/client:filesystem", + "//curvefs/src/client/logger:logger", + ], +) diff --git a/curvefs/src/client/vfs/README.md b/curvefs/src/client/vfs/README.md new file mode 100644 index 0000000000..b074365365 --- /dev/null +++ b/curvefs/src/client/vfs/README.md @@ -0,0 +1,21 @@ + +CurveFS VFS Design +=== + +Permission +--- + +`uid/gid` AND `euid/egid` AND `suid/sgid` + +```C++ +euid = uid +egid = gid + +if (suid != NULL) { + euid = suid; +} + +if (sgid != NULL) { + egid = sgid; +} +``` diff --git a/curvefs/src/client/vfs/cache.cpp b/curvefs/src/client/vfs/cache.cpp new file mode 100644 index 0000000000..c10fe93aff --- /dev/null +++ b/curvefs/src/client/vfs/cache.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-07-04 + * Author: Jingli Chen (Wine93) + */ + +#include + +#include "absl/strings/str_format.h" +#include "curvefs/src/client/filesystem/utils.h" +#include "curvefs/src/client/vfs/cache.h" + +namespace curvefs { +namespace client { +namespace vfs { + +#define RETURN_FALSE_IF_DISABLED() \ + do { \ + if (!enable_) { \ + return false; \ + } \ + } while (0) + +using ::curvefs::client::filesystem::Now; + +EntryCache::EntryCache(size_t lruSize) + : enable_(lruSize > 0), + lru_(std::make_shared(lruSize)) {} + +std::string EntryCache::EntryKey(Ino parent, const std::string& name) { + return absl::StrFormat("%lu:%s", parent, name); +} + +bool EntryCache::Get(Ino parent, const std::string& name, Ino* ino) { + RETURN_FALSE_IF_DISABLED(); + Entry value; + auto key = EntryKey(parent, name); + bool yes = lru_->Get(key, &value); + if (!yes) { + return false; + } else if (value.expire < Now()) { + return false; + } + *ino = value.ino; + return true; +} + +bool EntryCache::Put(Ino parent, + const std::string& name, + Ino ino, + uint64_t timeoutSec) { + RETURN_FALSE_IF_DISABLED(); + auto key = EntryKey(parent, name); + Entry value; + value.ino = ino; + value.expire = Now() + TimeSpec(timeoutSec, 0); + lru_->Put(key, value); + return true; +} + +bool EntryCache::Delete(Ino parent, const std::string& name) { + RETURN_FALSE_IF_DISABLED(); + auto key = EntryKey(parent, name); + lru_->Remove(key); + return true; +} + +size_t EntryCache::Size() { + return lru_->Size(); +} + +AttrCache::AttrCache(size_t lruSize) + : enable_(lruSize > 0), + lru_(std::make_shared(lruSize)) {} + +bool AttrCache::Get(Ino ino, InodeAttr* attr) { + RETURN_FALSE_IF_DISABLED(); + Attr value; + bool yes = lru_->Get(ino, &value); + if (!yes) { + return false; + } else if (value.expire < Now()) { + return false; + } + *attr = value.attr; + return true; +} + +bool AttrCache::Put(Ino ino, const InodeAttr& attr, uint64_t timeoutSec) { + RETURN_FALSE_IF_DISABLED(); + Attr value; + value.attr = std::move(attr); + value.expire = Now() + TimeSpec(timeoutSec, 0); + lru_->Put(ino, value); + return true; +} + +bool AttrCache::Delete(Ino ino) { + RETURN_FALSE_IF_DISABLED(); + lru_->Remove(ino); + return true; +} + +size_t AttrCache::Size() { + return lru_->Size(); +} + +} // namespace vfs +} // namespace client +} // namespace curvefs diff --git a/curvefs/src/client/vfs/cache.h b/curvefs/src/client/vfs/cache.h new file mode 100644 index 0000000000..f1653444a8 --- /dev/null +++ b/curvefs/src/client/vfs/cache.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-07-04 + * Author: Jingli Chen (Wine93) + */ + +#ifndef CURVEFS_SRC_CLIENT_VFS_CACHE_H_ +#define CURVEFS_SRC_CLIENT_VFS_CACHE_H_ + +#include +#include + +#include "src/common/lru_cache.h" +#include "curvefs/src/client/vfs/meta.h" + +namespace curvefs { +namespace client { +namespace vfs { + +using ::curve::common::LRUCache; + +class EntryCache { + public: + struct Entry { + Ino ino; + TimeSpec expire; + }; + + // TODO(Wine93): is there a more effective type for entry cache? maybe + // absl::btree> is a choise, + // but it is a bit complex to implement lru evit strategy. + using LRUType = LRUCache; + + public: + EntryCache() = delete; + + explicit EntryCache(size_t lruSize); + + bool Get(Ino parent, const std::string& name, Ino* ino); + + bool Put(Ino parent, const std::string& name, Ino ino, uint64_t timeoutSec); + + bool Delete(Ino parent, const std::string& name); + + size_t Size(); + + private: + std::string EntryKey(Ino parent, const std::string& name); + + private: + bool enable_; + std::shared_ptr lru_; +}; + +class AttrCache { + public: + struct Attr { + InodeAttr attr; + TimeSpec expire; + }; + + using LRUType = LRUCache; + + public: + AttrCache() = delete; + + explicit AttrCache(size_t lruSize); + + bool Get(Ino ino, InodeAttr* attr); + + bool Put(Ino ino, const InodeAttr& attr, uint64_t timeoutSec); + + bool Delete(Ino ino); + + size_t Size(); + + private: + bool enable_; + std::shared_ptr lru_; +}; + +} // namespace vfs +} // namespace client +} // namespace curvefs + +#endif // CURVEFS_SRC_CLIENT_VFS_CACHE_H_ diff --git a/curvefs/src/client/vfs/config.cpp b/curvefs/src/client/vfs/config.cpp new file mode 100644 index 0000000000..a75f01eb80 --- /dev/null +++ b/curvefs/src/client/vfs/config.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2023 NetEase Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Project: Curve + * Created Date: 2023-07-11 + * Author: Jingli Chen (Wine93) + */ + +#define INCBIN_STYLE INCBIN_STYLE_SNAKE +#define INCBIN_PREFIX g_ + +#include + +#include +#include + +#include "absl/strings/string_view.h" +#include "absl/strings/str_split.h" +#include "curvefs/src/client/vfs/utils.h" +#include "curvefs/src/client/vfs/config.h" + +/* Usage: INCBIN(<>, <>) + * + * Symbols defined by INCBIN + * ------------------------------------------ + * const unsigned char g_client_conf_data[] // g_<>_data + * const unsigned char* const g_client_conf_end; // g_<