diff options
| author | Jakob Unterwurzacher | 2021-06-04 22:16:41 +0200 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2021-06-04 22:17:13 +0200 | 
| commit | 3a1f009c1ad281f37a7643b32a63057dd9c2a16e (patch) | |
| tree | 7dd17ec627e684261729cb7204c228e1f834485c | |
| parent | 015cd066e1a857efd3d820a1ac29b89829ac72ed (diff) | |
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.
| -rwxr-xr-x | build.bash | 2 | ||||
| -rw-r--r-- | contrib/atomicrename/.gitignore | 1 | ||||
| -rw-r--r-- | contrib/atomicrename/main.go | 101 | 
3 files changed, 103 insertions, 1 deletions
| @@ -94,7 +94,7 @@ fi  # Actual "go build" call for gocryptfs  go build "-ldflags=$GO_LDFLAGS" "$@"  # 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" "$@")  done diff --git a/contrib/atomicrename/.gitignore b/contrib/atomicrename/.gitignore new file mode 100644 index 0000000..b91a212 --- /dev/null +++ b/contrib/atomicrename/.gitignore @@ -0,0 +1 @@ +/atomicrename diff --git a/contrib/atomicrename/main.go b/contrib/atomicrename/main.go new file mode 100644 index 0000000..67088b0 --- /dev/null +++ b/contrib/atomicrename/main.go @@ -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) +} | 
