Skip to content

Art integration#49

Open
aivillio wants to merge 34 commits into
acmpesuecc:devfrom
aivillio:art-integration
Open

Art integration#49
aivillio wants to merge 34 commits into
acmpesuecc:devfrom
aivillio:art-integration

Conversation

@aivillio

@aivillio aivillio commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

ART INTEGRATION

Context

integrating the ART data stricture with our file system

Description

Replace the hash map data structure used as a place holder and replace it with art and its crud operations

Changes

  • Added a new traverse() function that provides a generic mechanism to iterate over all key-value pairs stored in the ART
    And apply operations through a callback function.
  • Replaced hashmap-based operations in dir.go with their corresponding ART operations.

Tests

fs_test.go ran again; test suite works

Docs

Bhuviiiii-prog and others added 30 commits March 19, 2026 23:08
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
o
Merge branch 'artDev' of github.com:Bhuviiiii-prog/radFS into artDev
Copilot AI review requested due to automatic review settings June 9, 2026 12:06

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR replaces the directory-entry backing store in the FUSE filesystem from a Go map to an Adaptive Radix Tree (ART), while updating filesystem code to use RWMutex for improved concurrent read behavior.

Changes:

  • Replace Dir.Nodes (map) with Dir.tree (ART) and update filesystem operations/tests accordingly
  • Add a new internal/art package implementing Insert/Search/Delete/Traverse and node growth/shrink
  • Adjust locking in File/Dir to use sync.RWMutex and add an ART stress-test command

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
internal/fs/fs.go Initializes the root directory with an ART and inserts hello.txt; switches to RWMutex
internal/fs/dir.go Reworks Lookup/ReadDirAll/Create/Mkdir/Remove/Rename to use the ART API
internal/fs/file.go Switches Attr to RLock and fixes slice growth allocations to use int
internal/fs/fs_test.go Updates tests to validate entries via ART search instead of map access
internal/art/*.go Adds ART implementation (nodes, insert/search/delete, traversal, debug printing)
cmd/radFS/arttest/main.go Adds a manual stress-test program for ART grow/shrink correctness
docs/weekly/angelo/week_4.md Adds a weekly progress note related to ART implementation
Comments suppressed due to low confidence (2)

internal/fs/dir.go:1

  • Mkdir no longer updates the parent directory’s mtime/ctime after adding the new entry (the prior map-based version did). This is observable metadata behavior change for FUSE clients. After inserting into the tree, update d.mtime/d.ctime similarly to Remove.
package fs

internal/fs/dir.go:1

  • Create also no longer updates the parent directory’s mtime/ctime after creating/inserting the new file entry, which is a metadata regression from the previous implementation. Update d.mtime/d.ctime after the insert.
package fs

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/fs/fs.go
"time"

"bazil.org/fuse/fs"
"github.com/acmpesuecc/radFS/internal/art"
Comment thread internal/fs/fs.go
Comment on lines +45 to +46
uid: uint32(os.Getuid()), //permissions implemnet based on userid
gid: uint32(os.Getgid()), //permissions implement based on groupid
Comment thread internal/fs/fs.go
atime: time.Now(),
mtime: time.Now(),
ctime: time.Now(),
uid: uint32(os.Getuid()), //permissions implemnet based on userid
Comment thread internal/fs/dir.go
Comment on lines +58 to +61
d.mu.RLock()
defer d.mu.RUnlock()

node, ok := d.Nodes[name]
v, ok := d.tree.Search([]byte(name))
Comment thread internal/fs/dir.go
Comment on lines 66 to +68
d.atime = time.Now()

return node, nil
return v.(fs.Node), nil
Comment thread internal/fs/file.go
Comment on lines +88 to 90
newData := make([]byte, int(req.Size))
copy(newData, f.data)
f.data = newData
Comment thread internal/art/art.go
Comment on lines +17 to +23
func (t *Tree) Search(key []byte) (interface{}, bool) {
leaf := search(t.root, key, 0) // start from root and depth 0
if leaf != nil && isleaf(leaf) {
return leaf.leaf.values, true //Node->innerleaf->values
}
return "", false
}
Comment thread internal/art/search.go
Comment on lines +8 to +13
if isleaf(n) {
if string(n.leaf.key) == string(key) {
return n
}
return nil
}
Comment thread internal/art/delete.go
Comment on lines +8 to +13
if isleaf(n) {
if string(n.leaf.key) == string(key) {
return nil, true
}
return n, false
}
Comment thread internal/art/art.go
Comment on lines +13 to +37
func (t *Tree) Insert(key []byte, value interface{}) {
t.root = insert(t.root, value, key, 0)
}

func (t *Tree) Search(key []byte) (interface{}, bool) {
leaf := search(t.root, key, 0) // start from root and depth 0
if leaf != nil && isleaf(leaf) {
return leaf.leaf.values, true //Node->innerleaf->values
}
return "", false
}
func (t *Tree) Delete(key []byte) bool {
if t.root == nil {
return false
}

newRoot, deleted := deletekey(t.root, key, 0)

if deleted {
t.root = newRoot
return true
}

return false
}
Comment thread internal/fs/dir.go
if d == newParent {
d.mu.Lock()
defer d.mu.Unlock()
} else {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can deadlock when 2 concurrent processes using same 2 directories. For example: mv d1/f1 -> d2 and mv d2/f2 -> d1
i.e. an ABBA deadlock

Comment thread internal/fs/dir.go
d.mu.Lock()
defer d.mu.Unlock()
d.mu.RLock()
defer d.mu.RUnlock()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Directory level lock => No point of ART
Implement art.Node-wise locking instead

internal/art/search.go, internal/art/insert.go and internal/art/delete.go have to be rewritten to be iterative instead if implementing this

Comment thread internal/art/util.go

}

for i := 0; i < len(in.children); i++ { // find the free child

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is O(N) but should be O(1)
Maintain a bitmask with 1 being free and 0 being occupied and the position of the bit indicating the free child position.
Check for the first free index using math/bits.TrailingZeroes()

Comment thread internal/fs/dir.go
defer d.mu.RUnlock()

node, ok := d.Nodes[name]
v, ok := d.tree.Search([]byte(name))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Avoid casting string to []byte. Use the string directly

Comment thread internal/art/util.go
return n
}

func copymeta(n *Node, new_node *Node) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This can be a very frequently called function when doing operations so cap the internal/art/node.go meta struct at 8 bytes as described in the ART paper Section III.E and just copy by assignment

Comment thread internal/art/util.go

}

func deepcopy(source []byte) []byte {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not needed if internal/art/util.go line 304 is resolved

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.

4 participants