Skip to content

Commit 3939682

Browse files
committed
lock MFS root in node
1 parent c00065c commit 3939682

File tree

6 files changed

+53
-4
lines changed

6 files changed

+53
-4
lines changed

core/commands/files.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
gopath "path"
1010
"sort"
1111
"strings"
12+
"time"
1213

1314
humanize "github.com/dustin/go-humanize"
1415
"github.com/ipfs/go-ipfs/core"
@@ -768,6 +769,8 @@ stat' on the file or any of its ancestors.
768769
cmds.BoolOption(filesTruncateOptionName, "t", "Truncate the file to size zero before writing."),
769770
cmds.Int64Option(filesCountOptionName, "n", "Maximum number of bytes to read."),
770771
cmds.BoolOption(filesRawLeavesOptionName, "Use raw blocks for newly created leaf nodes. (experimental)"),
772+
// FIXME: Fake lock for manual testing. Remove.
773+
cmds.IntOption("lock-time", "lt", "[TESTING] timeout to hold the MFS lock while copying").WithDefault(0),
771774
cidVersionOption,
772775
hashOption,
773776
},
@@ -792,20 +795,25 @@ stat' on the file or any of its ancestors.
792795
if err != nil {
793796
return err
794797
}
798+
filesRoot := nd.LockedFilesRoot.LockRoot()
799+
defer nd.LockedFilesRoot.UnlockRoot()
800+
// Keep the hold for a fake, arbitrary amount of time to test it manually.
801+
timeout, _ := req.Options["lock-time"].(int)
802+
defer time.Sleep(time.Duration(timeout) * time.Second)
795803

796804
offset, _ := req.Options[filesOffsetOptionName].(int64)
797805
if offset < 0 {
798806
return fmt.Errorf("cannot have negative write offset")
799807
}
800808

801809
if mkParents {
802-
err := ensureContainingDirectoryExists(nd.FilesRoot, path, prefix)
810+
err := ensureContainingDirectoryExists(filesRoot, path, prefix)
803811
if err != nil {
804812
return err
805813
}
806814
}
807815

808-
fi, err := getFileHandle(nd.FilesRoot, path, create, prefix)
816+
fi, err := getFileHandle(filesRoot, path, create, prefix)
809817
if err != nil {
810818
return err
811819
}

core/core.go

+1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ type IpfsNode struct {
8282
Reporter *metrics.BandwidthCounter `optional:"true"`
8383
Discovery mdns.Service `optional:"true"`
8484
FilesRoot *mfs.Root
85+
LockedFilesRoot *node.LockedFilesRoot
8586
RecordValidator record.Validator
8687

8788
// Online

core/corerepo/gc.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ func BestEffortRoots(filesRoot *mfs.Root) ([]cid.Cid, error) {
8484
}
8585

8686
func GarbageCollect(n *core.IpfsNode, ctx context.Context) error {
87-
roots, err := BestEffortRoots(n.FilesRoot)
87+
filesRoot := n.LockedFilesRoot.LockRoot()
88+
defer n.LockedFilesRoot.UnlockRoot()
89+
roots, err := BestEffortRoots(filesRoot)
8890
if err != nil {
8991
return err
9092
}
@@ -148,7 +150,9 @@ func (e *MultiError) Error() string {
148150
}
149151

150152
func GarbageCollectAsync(n *core.IpfsNode, ctx context.Context) <-chan gc.Result {
151-
roots, err := BestEffortRoots(n.FilesRoot)
153+
filesRoot := n.LockedFilesRoot.LockRoot()
154+
defer n.LockedFilesRoot.UnlockRoot()
155+
roots, err := BestEffortRoots(filesRoot)
152156
if err != nil {
153157
out := make(chan gc.Result)
154158
out <- gc.Result{Error: err}

core/node/core.go

+22
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package node
33
import (
44
"context"
55
"fmt"
6+
"sync"
67

78
"github.com/ipfs/go-blockservice"
89
"github.com/ipfs/go-cid"
@@ -168,3 +169,24 @@ func Files(mctx helpers.MetricsCtx, lc fx.Lifecycle, repo repo.Repo, dag format.
168169

169170
return root, err
170171
}
172+
173+
func LockedFiles(mctx helpers.MetricsCtx, lc fx.Lifecycle, root *mfs.Root) (*LockedFilesRoot, error) {
174+
return &LockedFilesRoot{
175+
root: root,
176+
lock: &sync.Mutex{},
177+
}, nil
178+
}
179+
180+
type LockedFilesRoot struct {
181+
root *mfs.Root
182+
lock *sync.Mutex
183+
}
184+
185+
func (lfr *LockedFilesRoot) LockRoot() *mfs.Root {
186+
lfr.lock.Lock()
187+
return lfr.root
188+
}
189+
190+
func (lfr *LockedFilesRoot) UnlockRoot() {
191+
lfr.lock.Unlock()
192+
}

core/node/groups.go

+1
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ var Core = fx.Options(
296296
fx.Provide(FetcherConfig),
297297
fx.Provide(Pinning),
298298
fx.Provide(Files),
299+
fx.Provide(LockedFiles),
299300
)
300301

301302
func Networked(bcfg *BuildCfg, cfg *config.Config) fx.Option {

test-mfs-lock.bash

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
set -x
2+
set -v
3+
4+
# The daemon needs to be running, otherwise the commands will compete on their
5+
# lock of the entire repo (not the MFS root) and fail.
6+
ipfs swarm addrs > /dev/null || (echo "daemon not running" && exit 1)
7+
8+
ipfs --version
9+
ipfs files mkdir /test-lock/
10+
ipfs files rm /test-lock/ -r
11+
((echo "content" | ./cmd/ipfs/ipfs files write --create --parents --truncate --lock-time 3 /test-lock/file) && echo "ipfs write lock released" &)
12+
ipfs repo gc
13+
# FIXME: This is a flaky test just to manually check the lock in ipfs write is blocking the GC.

0 commit comments

Comments
 (0)