Skip to content

feat(meta): refactor inode memory tree to id-only model#776

Draft
lzjqsdd wants to merge 4 commits into
mainfrom
meta-opt-new
Draft

feat(meta): refactor inode memory tree to id-only model#776
lzjqsdd wants to merge 4 commits into
mainfrom
meta-opt-new

Conversation

@lzjqsdd
Copy link
Copy Markdown
Member

@lzjqsdd lzjqsdd commented Apr 2, 2026

Summary

  • Refactor inode memory tree to id-only model for reduced memory usage
  • DirEntry stores only inode id and children, InodeView holds rich metadata
  • Fix name storage: names stored in parent's children map key, not in InodeView
  • Save DirEntryRef in InodePath during resolve to avoid tree re-traversal
  • Implement recursive set_attr and free using DirEntry tree traversal

Changes

Core Refactoring

  • DirEntry struct: lightweight tree node with entry: InodeEntry (File/Dir id) and children
  • InodeView enum: rich metadata (File/Dir), name NOT stored inside
  • InodePath: stores both Vec<InodePtr> and Vec<DirEntryRef> for efficient navigation

Bug Fixes

  • Pass explicit child_name parameter to store methods (name not in InodeView)
  • Save DirEntryRef during resolve() to avoid re-traversing from root
  • Fix is_dir_empty() to use saved entries
  • Fix add_child_to_tree() and remove_child_to_tree() to use saved entries

Features

  • Implement recursive unprotected_set_attr using DirEntry tree
  • Implement recursive unprotected_free using DirEntry tree
  • Add find_entry_by_id() helper for safe tree traversal

Test Plan

  • All unit tests pass (cargo test -p curvine-server -- --test-threads=1)
  • Journal tests pass
  • Master filesystem tests pass
  • Idempotent operation tests pass

🤖 Generated with Claude Code

let parent_path = self.build_path_recursive(f.parent_id())?;
// Note: name is stored in parent's children key, not in InodeFile
// For now, use inode_id as placeholder
let name = format!("inode_{}", f.id());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This turns TTL path reconstruction into a placeholder path (/inode_<id>/...) instead of the real namespace path. execute_by_id() still calls filesystem.delete(&path, ...) / filesystem.free(&path, ...), so once this lands, expired inodes will start issuing operations against non-existent paths rather than the actual file or directory. Could we resolve the edge name from the parent DirEntry tree here instead of synthesizing a fake basename?

return Ok(());
}
let opts = curvine_common::state::MkdirOpts::with_create(true);
let inp = fs_dir.create_parent_dir(inp, opts)?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create_parent_dir() is a mutating helper from the normal write path, and it eventually goes through create_single_dir(), which calls journal_writer.log_mkdir(...). In other words, this replay path can now generate fresh journal entries while it is applying an old Mkdir / CreateFile record, if an ancestor is missing. That makes recovery semantics self-modifying and can append synthetic operations back into Raft instead of keeping replay side-effect free. Could we use a replay-only parent creation path here (or otherwise suppress journaling) before reusing create_parent_dir()?

lzjqsdd added 3 commits April 9, 2026 15:40
Refactor the master metadata tree to separate lightweight navigation
from rich metadata storage, solving memory waste from Rust enum variant
alignment.

Core changes:
- Add DirEntry as lightweight tree node struct (id + children)
- Add InodeEntry enum: File(id) | Dir(id)
- Remove FileEntry variant from InodeView enum
- Remove children field from InodeDir (now pure metadata)
- InodePath stores rich InodePtr data loaded from InodeStore

Tree navigation uses DirEntry (lightweight), business operations use
InodeView loaded from InodeStore on demand. Name is stored only in
parent's children map key, not duplicated in inode.
Tighten the inode rich-view write path and reuse the latest flushed file
blocks when FUSE refreshes concurrent readers.

Record the current investigation progress, validation status, and remaining
git clone risks in the regression document.

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants