Add contrib/atomicrename
$ ./contrib/atomicrename/atomicrename -h atomicrename creates 100 "src" files in the current directory, renames them in random order over a single "dst" file while reading the "dst" file concurrently in a loop. Progress and errors are reported as they occour in addition to a summary printed at the end. cifs and fuse filesystems are known to fail, local filesystems and nfs seem ok. See https://github.com/hanwen/go-fuse/issues/398 for background info.
This commit is contained in:
parent
015cd066e1
commit
3a1f009c1a
@ -94,7 +94,7 @@ fi
|
|||||||
# Actual "go build" call for gocryptfs
|
# Actual "go build" call for gocryptfs
|
||||||
go build "-ldflags=$GO_LDFLAGS" "$@"
|
go build "-ldflags=$GO_LDFLAGS" "$@"
|
||||||
# Additional binaries
|
# Additional binaries
|
||||||
for d in gocryptfs-xray contrib/statfs contrib/findholes ; do
|
for d in gocryptfs-xray contrib/statfs contrib/findholes contrib/atomicrename ; do
|
||||||
(cd "$d"; go build "-ldflags=$GO_LDFLAGS" "$@")
|
(cd "$d"; go build "-ldflags=$GO_LDFLAGS" "$@")
|
||||||
done
|
done
|
||||||
|
|
||||||
|
1
contrib/atomicrename/.gitignore
vendored
Normal file
1
contrib/atomicrename/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/atomicrename
|
101
contrib/atomicrename/main.go
Normal file
101
contrib/atomicrename/main.go
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync/atomic"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
const fileCount = 100
|
||||||
|
|
||||||
|
type stats struct {
|
||||||
|
renameOk int
|
||||||
|
renameError int
|
||||||
|
readOk int
|
||||||
|
readError int
|
||||||
|
readContentMismatch int
|
||||||
|
}
|
||||||
|
|
||||||
|
func usage() {
|
||||||
|
fmt.Printf(`atomicrename creates %d "src" files in the current directory, renames
|
||||||
|
them in random order over a single "dst" file while reading the "dst"
|
||||||
|
file concurrently in a loop.
|
||||||
|
|
||||||
|
Progress and errors are reported as they occour in addition to a summary
|
||||||
|
printed at the end. cifs and fuse filesystems are known to fail, local
|
||||||
|
filesystems and nfs seem ok.
|
||||||
|
|
||||||
|
See https://github.com/hanwen/go-fuse/issues/398 for background info.
|
||||||
|
`, fileCount)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Usage = usage
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
hello := []byte("hello world")
|
||||||
|
srcFiles := make(map[string]struct{})
|
||||||
|
|
||||||
|
// prepare source files
|
||||||
|
fmt.Print("creating files")
|
||||||
|
for i := 0; i < fileCount; i++ {
|
||||||
|
srcName := fmt.Sprintf("src.atomicrename.%d", i)
|
||||||
|
srcFiles[srcName] = struct{}{}
|
||||||
|
buf := bytes.Repeat([]byte("_"), i)
|
||||||
|
buf = append(buf, hello...)
|
||||||
|
if err := ioutil.WriteFile(srcName, buf, 0600); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Print(".")
|
||||||
|
}
|
||||||
|
fmt.Print("\n")
|
||||||
|
|
||||||
|
// prepare destination file
|
||||||
|
const dstName = "dst.atomicrename"
|
||||||
|
if err := ioutil.WriteFile(dstName, hello, 0600); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var running int32 = 1
|
||||||
|
|
||||||
|
stats := stats{}
|
||||||
|
|
||||||
|
// read thread
|
||||||
|
go func() {
|
||||||
|
for atomic.LoadInt32(&running) == 1 {
|
||||||
|
have, err := ioutil.ReadFile(dstName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
stats.readError++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(string(have), string(hello)) {
|
||||||
|
fmt.Printf("content mismatch: have %q\n", have)
|
||||||
|
stats.readContentMismatch++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Printf("content ok len=%d\n", len(have))
|
||||||
|
stats.readOk++
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// rename thread = main thread
|
||||||
|
for srcName := range srcFiles {
|
||||||
|
if err := os.Rename(srcName, dstName); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
stats.renameError++
|
||||||
|
}
|
||||||
|
stats.renameOk++
|
||||||
|
}
|
||||||
|
// Signal the Read goroutine to stop when loop is done
|
||||||
|
atomic.StoreInt32(&running, 0)
|
||||||
|
|
||||||
|
syscall.Unlink(dstName)
|
||||||
|
fmt.Printf("stats: %#v\n", stats)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user