-
Notifications
You must be signed in to change notification settings - Fork 383
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(Draft) Gvfs-fuse implementation and code structure layout #5738
Changes from 10 commits
30581af
18cd375
b7cbeab
fe4ad01
2ae9427
c9459aa
ae1e591
9d584d7
b13c594
5156f9d
36282f2
cd11e47
4f6e980
5eba1f0
bf2b1d2
a5bb26d
7d08dae
a2b7ad4
8f76564
a9db9a6
3b2fb12
9abd45d
0631316
a48ba1a
bebcd73
f6b0ceb
b0734f1
7640a8f
8ac961b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
name: Build gvfs-fuse and testing | ||
|
||
# Controls when the workflow will run | ||
on: | ||
push: | ||
branches: [ "main", "branch-*" ] | ||
pull_request: | ||
branches: [ "main", "branch-*" ] | ||
workflow_dispatch: | ||
|
||
concurrency: | ||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | ||
cancel-in-progress: true | ||
|
||
jobs: | ||
changes: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: dorny/paths-filter@v2 | ||
id: filter | ||
with: | ||
filters: | | ||
source_changes: | ||
- .github/** | ||
- api/** | ||
- bin/** | ||
- catalogs/** | ||
- clients/filesystem-fuse/** | ||
- common/** | ||
- conf/** | ||
- core/** | ||
- dev/** | ||
- gradle/** | ||
- meta/** | ||
- scripts/** | ||
- server/** | ||
- server-common/** | ||
- build.gradle.kts | ||
- gradle.properties | ||
- gradlew | ||
- setting.gradle.kts | ||
outputs: | ||
source_changes: ${{ steps.filter.outputs.source_changes }} | ||
|
||
# Build for AMD64 architecture | ||
Gvfs-Build: | ||
needs: changes | ||
if: needs.changes.outputs.source_changes == 'true' | ||
runs-on: ubuntu-latest | ||
timeout-minutes: 60 | ||
strategy: | ||
matrix: | ||
architecture: [linux/amd64] | ||
java-version: [ 17 ] | ||
env: | ||
PLATFORM: ${{ matrix.architecture }} | ||
steps: | ||
- uses: actions/checkout@v3 | ||
|
||
- uses: actions/setup-java@v4 | ||
with: | ||
java-version: ${{ matrix.java-version }} | ||
distribution: 'temurin' | ||
cache: 'gradle' | ||
|
||
- name: Set up QEMU | ||
uses: docker/setup-qemu-action@v2 | ||
|
||
- name: Check required command | ||
run: | | ||
dev/ci/check_commands.sh | ||
|
||
- name: Build and test Gravitino | ||
run: | | ||
./gradlew :clients:filesystem-fuse:build -PenableFuse=true | ||
|
||
- name: Package Gravitino | ||
run: | | ||
./gradlew compileDistribution -x test -PjdkVersion=${{ matrix.java-version }} -PenableFuse=true | ||
|
||
- name: Free up disk space | ||
run: | | ||
dev/ci/util_free_space.sh | ||
|
||
- name: Upload tests reports | ||
uses: actions/upload-artifact@v3 | ||
if: ${{ (failure() && steps.integrationTest.outcome == 'failure') || contains(github.event.pull_request.labels.*.name, 'upload log') }} | ||
with: | ||
name: trino-connector-integrate-test-reports-${{ matrix.java-version }} | ||
path: | | ||
clients/filesystem-fuse/build/test/log/*.log | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,8 +29,13 @@ repository = "https://github.com/apache/gravitino" | |
name = "gvfs-fuse" | ||
path = "src/main.rs" | ||
|
||
[lib] | ||
name="gvfs_fuse" | ||
|
||
[dependencies] | ||
dashmap = "5.5.3" | ||
futures-util = "0.3.30" | ||
fuse3 = { version = "0.8.1", "features" = ["tokio-runtime", "unprivileged"] } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do you plan to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the thread mode of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'm not sure which one would be better to use right now. What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My concern about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think we should use fuser? |
||
libc = "0.2.164" | ||
log = "0.4.22" | ||
tokio = { version = "1.38.0", features = ["full"] } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you 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. | ||
*/ | ||
use crate::filesystem::{FileStat, OpenedFile}; | ||
use std::collections::HashMap; | ||
use std::sync::atomic::AtomicU64; | ||
|
||
// FileHandleManager is a manager for opened files. | ||
pub(crate) struct FileHandleManager { | ||
// file_handle_map is a map of file_handle_id to opned file. | ||
file_handle_map: HashMap<u64, OpenedFile>, | ||
|
||
// file_handle_id_generator is used to generate unique file handle IDs. | ||
handle_id_generator: AtomicU64, | ||
} | ||
|
||
impl FileHandleManager { | ||
pub fn new() -> Self { | ||
Self { | ||
file_handle_map: Default::default(), | ||
handle_id_generator: AtomicU64::new(1), | ||
} | ||
} | ||
|
||
pub(crate) fn next_handle_id(&self) -> u64 { | ||
self.handle_id_generator | ||
.fetch_add(1, std::sync::atomic::Ordering::SeqCst) | ||
} | ||
|
||
pub(crate) fn open_file(&mut self, file: &FileStat) -> OpenedFile { | ||
let file_handle = OpenedFile { | ||
file_id: file.inode, | ||
handle_id: self.next_handle_id(), | ||
size: file.size, | ||
}; | ||
self.file_handle_map | ||
.insert(file_handle.handle_id, file_handle.clone()); | ||
file_handle | ||
} | ||
|
||
pub(crate) fn get_file(&self, handle_id: u64) -> Option<OpenedFile> { | ||
self.file_handle_map.get(&handle_id).map(|x| x.clone()) | ||
} | ||
|
||
pub(crate) fn remove_file(&mut self, handle_id: u64) { | ||
self.file_handle_map.remove(&handle_id); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you 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. | ||
*/ | ||
use fuse3::{Errno, FileType, Timestamp}; | ||
use std::time::SystemTime; | ||
|
||
/// File system interface for the file system implementation. it use by FuseApiHandle | ||
/// the `file_id` and `parent_file_id` it is the unique identifier for the file system, it is used to identify the file or directory | ||
/// the `fh` it is the file handle, it is used to identify the opened file, it is used to read or write the file content | ||
pub trait IFileSystem: Send + Sync { | ||
fn get_file_path(&self, file_id: u64) -> String; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add async to all interfaces? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add Result to wrap errors for all interfaces? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll consider adding async later. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, all the interface wrap by |
||
|
||
fn get_opened_file(&self, file_id: u64, fh: u64) -> Option<OpenedFile>; | ||
|
||
fn stat(&self, file_id: u64) -> Option<FileStat>; | ||
|
||
fn lookup(&self, parent_file_id: u64, name: &str) -> Option<FileStat>; | ||
|
||
fn read_dir(&self, dir_file_id: u64) -> Vec<FileStat>; | ||
|
||
fn open_file(&self, file_id: u64) -> Result<OpenedFile, Errno>; | ||
|
||
fn create_file(&self, parent_file_id: u64, name: &str) -> Result<OpenedFile, Errno>; | ||
|
||
fn create_dir(&self, parent_file_id: u64, name: &str) -> Result<OpenedFile, Errno>; | ||
|
||
fn set_attr(&self, file_id: u64, file_stat: &FileStat) -> Result<(), Errno>; | ||
|
||
fn update_file_status(&self, file_id: u64, file_stat: &FileStat); | ||
|
||
fn read(&self, file_id: u64, fh: u64) -> Box<dyn FileReader>; | ||
|
||
fn write(&self, file_id: u64, fh: u64) -> Box<dyn FileWriter>; | ||
|
||
fn remove_file(&self, parent_file_id: u64, name: &str) -> Result<(), Errno>; | ||
|
||
fn remove_dir(&self, parent_file_id: u64, name: &str) -> Result<(), Errno>; | ||
|
||
fn close_file(&self, file_id: u64, fh: u64) -> Result<(), Errno>; | ||
} | ||
|
||
pub struct FileSystemContext { | ||
// system user id | ||
pub(crate) uid: u32, | ||
|
||
// system group id | ||
pub(crate) gid: u32, | ||
} | ||
|
||
impl FileSystemContext { | ||
pub(crate) fn new(uid: u32, gid: u32) -> Self { | ||
FileSystemContext { uid, gid } | ||
} | ||
} | ||
|
||
#[derive(Clone, Debug)] | ||
pub(crate) struct FileStat { | ||
// inode id for the file system, also call file id | ||
pub(crate) inode: u64, | ||
|
||
// parent inode id | ||
pub(crate) parent_inode: u64, | ||
|
||
// file name | ||
pub(crate) name: String, | ||
|
||
// file path of the fuse file system root | ||
pub(crate) path: String, | ||
|
||
// file size | ||
pub(crate) size: u64, | ||
|
||
// file type like regular file or directory and so on | ||
pub(crate) kind: FileType, | ||
|
||
// file permission | ||
pub(crate) perm: u16, | ||
|
||
// file access time | ||
pub(crate) atime: Timestamp, | ||
|
||
// file modify time | ||
pub(crate) mtime: Timestamp, | ||
|
||
// file create time | ||
pub(crate) ctime: Timestamp, | ||
|
||
// file link count | ||
pub(crate) nlink: u32, | ||
} | ||
|
||
impl FileStat { | ||
// TODO need to handle the file permission by config | ||
pub fn new_file(name: &str, inode: u64, parent_inode: u64) -> Self { | ||
let atime = Timestamp::from(SystemTime::now()); | ||
Self { | ||
inode: inode, | ||
parent_inode: parent_inode, | ||
name: name.into(), | ||
path: "".to_string(), | ||
size: 0, | ||
kind: FileType::RegularFile, | ||
perm: 0o664, | ||
atime: atime, | ||
mtime: atime, | ||
ctime: atime, | ||
nlink: 1, | ||
} | ||
} | ||
|
||
pub fn new_dir(name: &str, inode: u64, parent_inode: u64) -> Self { | ||
let atime = Timestamp::from(SystemTime::now()); | ||
Self { | ||
inode: inode, | ||
parent_inode: parent_inode, | ||
name: name.into(), | ||
path: "".to_string(), | ||
size: 0, | ||
kind: FileType::Directory, | ||
perm: 0o755, | ||
atime: atime, | ||
mtime: atime, | ||
ctime: atime, | ||
nlink: 1, | ||
} | ||
} | ||
} | ||
|
||
/// Opened file for read or write, it is used to read or write the file content. | ||
#[derive(Clone, Debug)] | ||
pub(crate) struct OpenedFile { | ||
// file id | ||
pub(crate) file_id: u64, | ||
|
||
// file handle id, open a same file multiple times will have different handle id | ||
pub(crate) handle_id: u64, | ||
|
||
// file size | ||
pub(crate) size: u64, | ||
} | ||
|
||
/// File reader interface for read file content | ||
pub(crate) trait FileReader { | ||
fn file(&self) -> &OpenedFile; | ||
fn read(&mut self, offset: u64, size: u32) -> Vec<u8>; | ||
} | ||
|
||
/// File writer interface for write file content | ||
pub(crate) trait FileWriter { | ||
fn file(&self) -> &OpenedFile; | ||
fn write(&mut self, offset: u64, data: &[u8]) -> u32; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why the
compileDistribution
afterBuild and test Gravitino
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
compileDistribution
is use to running the integration test, build and test only run utsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you mean you mix fuseIT in compileDistribution?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, fuseITs depend on the package of compileDistribution
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what's the function of
-PenableFuse=true
hereThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
plz remove this and the below steps since it's unnecessary now