Browse Source

Merge pull request #705 from unihorn/61

feat: set NOCOW for log directory when in btrfs
Xiang Li 11 years ago
parent
commit
0b790abd46
7 changed files with 119 additions and 6 deletions
  1. 1 2
      .gitignore
  2. 4 4
      build
  3. BIN
      pkg/btrfs/.util_linux.go.swp
  4. 72 0
      pkg/btrfs/btrfs.go
  5. 31 0
      pkg/btrfs/btrfs_test.go
  6. 8 0
      server/peer_server.go
  7. 3 0
      test.sh

+ 1 - 2
.gitignore

@@ -1,7 +1,6 @@
-/pkg
+/gopath
 /go-bindata
 /machine*
 /bin
-/src
 .vagrant
 *.etcd

+ 4 - 4
build

@@ -1,12 +1,12 @@
 #!/bin/sh -e
 
-if [ ! -h src/github.com/coreos/etcd ]; then
-	mkdir -p src/github.com/coreos/
-	ln -s ../../.. src/github.com/coreos/etcd
+if [ ! -h gopath/src/github.com/coreos/etcd ]; then
+	mkdir -p gopath/src/github.com/coreos/
+	ln -s ../../../.. gopath/src/github.com/coreos/etcd
 fi
 
 export GOBIN=${PWD}/bin
-export GOPATH=${PWD}
+export GOPATH=${PWD}/gopath
 export GOFMTPATH="./bench ./config ./discovery ./etcd ./error ./http ./log main.go ./metrics ./mod ./server ./store ./tests"
 
 # Don't surprise user by formatting their codes by stealth

BIN
pkg/btrfs/.util_linux.go.swp


+ 72 - 0
pkg/btrfs/btrfs.go

@@ -0,0 +1,72 @@
+package btrfs
+
+import (
+	"fmt"
+	"os"
+	"runtime"
+	"syscall"
+	"unsafe"
+
+	"github.com/coreos/etcd/log"
+)
+
+const (
+	// from Linux/include/uapi/linux/magic.h
+	BTRFS_SUPER_MAGIC = 0x9123683E
+
+	// from Linux/include/uapi/linux/fs.h
+	FS_NOCOW_FL = 0x00800000
+	FS_IOC_GETFLAGS = 0x80086601
+	FS_IOC_SETFLAGS = 0x40086602
+)
+
+// IsBtrfs checks whether the file is in btrfs
+func IsBtrfs(path string) bool {
+	// btrfs is linux-only filesystem
+	// exit on other platforms
+	if runtime.GOOS != "linux" {
+		return false
+	}
+	var buf syscall.Statfs_t
+	if err := syscall.Statfs(path, &buf); err != nil {
+		log.Warnf("Failed to statfs: %v", err)
+		return false
+	}
+	log.Debugf("The type of path %v is %v", path, buf.Type)
+	if buf.Type != BTRFS_SUPER_MAGIC {
+		return false
+	}
+	log.Infof("The path %v is in btrfs", path)
+	return true
+}
+
+// SetNOCOWFile sets NOCOW flag for file
+func SetNOCOWFile(path string) error {
+	file, err := os.Open(path)
+	if err != nil {
+		return err
+	}
+	defer file.Close()
+
+	fileinfo, err := file.Stat()
+	if err != nil {
+		return err
+	}
+	if fileinfo.IsDir() {
+		return fmt.Errorf("skip directory")
+	}
+	if fileinfo.Size() != 0 {
+		return fmt.Errorf("skip nonempty file")
+	}
+
+	var attr int
+	if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), FS_IOC_GETFLAGS, uintptr(unsafe.Pointer(&attr))); errno != 0 {
+		return errno
+	}
+	attr |= FS_NOCOW_FL
+	if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), FS_IOC_SETFLAGS, uintptr(unsafe.Pointer(&attr))); errno != 0 {
+		return errno
+	}
+	log.Infof("Set NOCOW to path %v succeeded", path)
+	return nil
+}

+ 31 - 0
pkg/btrfs/btrfs_test.go

@@ -0,0 +1,31 @@
+package btrfs
+
+import (
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"strings"
+	"testing"
+)
+
+func TestSetNOCOW(t *testing.T) {
+	f, err := ioutil.TempFile(".", "etcdtest")
+	if err != nil {
+		t.Fatal("Failed creating temp dir")
+	}
+	name := f.Name()
+	f.Close()
+	defer os.Remove(name)
+
+	if IsBtrfs(name) {
+		SetNOCOWFile(name)
+		cmd := exec.Command("lsattr", name)
+		out, err := cmd.Output()
+		if err != nil {
+			t.Fatal("Failed executing lsattr")
+		}
+		if !strings.Contains(string(out), "---------------C") {
+			t.Fatal("Failed setting NOCOW:\n", string(out))
+		}
+	}
+}

+ 8 - 0
server/peer_server.go

@@ -19,6 +19,7 @@ import (
 	etcdErr "github.com/coreos/etcd/error"
 	"github.com/coreos/etcd/log"
 	"github.com/coreos/etcd/metrics"
+	"github.com/coreos/etcd/pkg/btrfs"
 	"github.com/coreos/etcd/store"
 )
 
@@ -291,6 +292,13 @@ func (s *PeerServer) Start(snapshot bool, discoverURL string, peers []string) er
 
 	s.raftServer.Init()
 
+	// Set NOCOW for data directory in btrfs
+	if btrfs.IsBtrfs(s.raftServer.LogPath()) {
+		if err := btrfs.SetNOCOWFile(s.raftServer.LogPath()); err != nil {
+			log.Warnf("Failed setting NOCOW: %v", err)
+		}
+	}
+
 	s.findCluster(discoverURL, peers)
 
 	s.closeChan = make(chan bool)

+ 3 - 0
test.sh

@@ -23,6 +23,9 @@ go test -v ./server/v2/tests -race
 go test -i ./mod/lock/v2/tests
 go test -v ./mod/lock/v2/tests
 
+go test -i ./pkg/btrfs
+go test -v ./pkg/btrfs
+
 go test -i ./tests/functional
 ETCD_BIN_PATH=$(pwd)/bin/etcd go test -v ./tests/functional -race