Skip to content
This repository was archived by the owner on Dec 20, 2024. It is now read-only.

Commit f2a016c

Browse files
committed
bugfix: avoid creating dup-process of dfget server.
Signed-off-by: zhouchencheng <[email protected]>
1 parent 7300a6b commit f2a016c

File tree

3 files changed

+162
-0
lines changed

3 files changed

+162
-0
lines changed

dfget/core/uploader/peer_server_executor.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ import (
2121
"io"
2222
"os"
2323
"os/exec"
24+
"path/filepath"
2425
"strconv"
2526
"strings"
2627
"sync/atomic"
2728
"time"
2829

2930
"github.com/dragonflyoss/Dragonfly/dfget/config"
31+
"github.com/dragonflyoss/Dragonfly/pkg/fileutils"
3032
"github.com/dragonflyoss/Dragonfly/version"
3133

3234
"github.com/sirupsen/logrus"
@@ -74,6 +76,12 @@ func (pe *peerServerExecutor) StartPeerServerProcess(cfg *config.Config) (port i
7476
return port, nil
7577
}
7678

79+
fileLock := fileutils.NewFileLock(filepath.Dir(cfg.RV.MetaPath))
80+
if err = fileLock.Lock(); err != nil {
81+
return 0, err
82+
}
83+
defer fileLock.Unlock()
84+
7785
cmd := exec.Command(os.Args[0], "server",
7886
"--ip", cfg.RV.LocalIP,
7987
"--port", strconv.Itoa(cfg.RV.PeerPort),

pkg/fileutils/filelock.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright The Dragonfly Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package fileutils
18+
19+
import (
20+
"fmt"
21+
"os"
22+
"syscall"
23+
24+
"github.com/pkg/errors"
25+
)
26+
27+
// FileLock defines a file lock implemented by syscall.Flock
28+
type FileLock struct {
29+
fileName string
30+
fd *os.File
31+
}
32+
33+
// NewFileLock create a FileLock instance
34+
func NewFileLock(name string) *FileLock {
35+
return &FileLock{
36+
fileName: name,
37+
}
38+
}
39+
40+
// Lock locks file.
41+
// If the file is already locked, the calling goroutine blocks until the file is unlocked.
42+
// If lock has been invoked without unlock, lock again will return an error.
43+
func (l *FileLock) Lock() error {
44+
var (
45+
fd *os.File
46+
err error
47+
)
48+
49+
if l.fd != nil {
50+
return fmt.Errorf("file %s has already been locked", l.fileName)
51+
}
52+
53+
if fd, err = os.Open(l.fileName); err != nil {
54+
return err
55+
}
56+
l.fd = fd
57+
58+
if err := syscall.Flock(int(l.fd.Fd()), syscall.LOCK_EX); err != nil {
59+
return errors.Wrapf(err, "file %s lock failed", l.fileName)
60+
}
61+
return nil
62+
}
63+
64+
// Unlock unlocks file.
65+
// If lock has not been invoked before unlock, unlock will return an error.
66+
func (l *FileLock) Unlock() error {
67+
if l.fd == nil {
68+
return fmt.Errorf("file %s descriptor is nil", l.fileName)
69+
}
70+
fd := l.fd
71+
l.fd = nil
72+
73+
defer fd.Close()
74+
if err := syscall.Flock(int(fd.Fd()), syscall.LOCK_UN); err != nil {
75+
return errors.Wrapf(err, "file %s unlock failed", l.fileName)
76+
}
77+
return nil
78+
}

pkg/fileutils/filelock_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright The Dragonfly Authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package fileutils
18+
19+
import (
20+
"fmt"
21+
"io/ioutil"
22+
"os"
23+
"time"
24+
25+
"github.com/go-check/check"
26+
)
27+
28+
type FileLockTestSuite struct {
29+
tmpDir string
30+
flockA *FileLock
31+
flockB *FileLock
32+
}
33+
34+
func init() {
35+
check.Suite(&FileLockTestSuite{})
36+
}
37+
38+
func (s *FileLockTestSuite) SetUpSuite(c *check.C) {
39+
tmpDir, _ := ioutil.TempDir("/tmp", "dfget-FileLockTestSuite-")
40+
os.Create(tmpDir)
41+
s.tmpDir = tmpDir
42+
s.flockA = NewFileLock(tmpDir)
43+
s.flockB = NewFileLock(tmpDir)
44+
}
45+
46+
func (s *FileLockTestSuite) TearDownSuite(c *check.C) {
47+
if s.tmpDir != "" {
48+
if err := os.RemoveAll(s.tmpDir); err != nil {
49+
fmt.Printf("remove path:%s error", s.tmpDir)
50+
}
51+
}
52+
}
53+
54+
func (s *FileLockTestSuite) TestFileLock(c *check.C) {
55+
err := s.flockA.Lock()
56+
c.Assert(err, check.IsNil)
57+
58+
err = s.flockA.Lock()
59+
c.Assert(err, check.NotNil)
60+
61+
err = s.flockA.Unlock()
62+
c.Assert(err, check.IsNil)
63+
64+
err = s.flockA.Unlock()
65+
c.Assert(err, check.NotNil)
66+
67+
s.flockA.Lock()
68+
start := time.Now()
69+
go func() {
70+
time.Sleep(time.Second)
71+
s.flockA.Unlock()
72+
}()
73+
s.flockB.Lock()
74+
c.Assert(time.Since(start) >= time.Second, check.Equals, true)
75+
s.flockB.Unlock()
76+
}

0 commit comments

Comments
 (0)