X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/740d71d2b7a797bb2dd2e1e427c12e84c86b9ce6..32e4350b4ea4c111ae95d9a99712fb86bf0ecb86:/services/keepstore/volume_unix.go diff --git a/services/keepstore/volume_unix.go b/services/keepstore/volume_unix.go index ddddd5abf9..75a75229a6 100644 --- a/services/keepstore/volume_unix.go +++ b/services/keepstore/volume_unix.go @@ -97,6 +97,30 @@ func (v *UnixVolume) Put(loc string, block []byte) error { return response.err } +func (v *UnixVolume) Touch(loc string) error { + p := v.blockPath(loc) + f, err := os.OpenFile(p, os.O_RDWR|os.O_APPEND, 0644) + if err != nil { + return err + } + if e := lockfile(f); e != nil { + return e + } + defer unlockfile(f) + now := time.Now().Unix() + utime := syscall.Utimbuf{now, now} + return syscall.Utime(p, &utime) +} + +func (v *UnixVolume) Mtime(loc string) (time.Time, error) { + p := v.blockPath(loc) + if fi, err := os.Stat(p); err != nil { + return time.Time{}, err + } else { + return fi.ModTime(), nil + } +} + // Read retrieves a block identified by the locator string "loc", and // returns its contents as a byte slice. // @@ -230,7 +254,29 @@ func (v *UnixVolume) Index(prefix string) (output string) { } func (v *UnixVolume) Delete(loc string) error { - return os.Remove(v.blockPath(loc)) + p := v.blockPath(loc) + f, err := os.OpenFile(p, os.O_RDWR|os.O_APPEND, 0644) + if err != nil { + return err + } + if e := lockfile(f); e != nil { + return e + } + defer unlockfile(f) + + // If the block has been PUT more recently than -permission_ttl, + // return success without removing the block. This guards against + // a race condition where a block is old enough that Data Manager + // has added it to the trash list, but the user submitted a PUT + // for the block since then. + if fi, err := os.Stat(p); err != nil { + return err + } else { + if time.Since(fi.ModTime()) < permission_ttl { + return nil + } + } + return os.Remove(p) } // blockDir returns the fully qualified directory name for the directory @@ -293,3 +339,12 @@ func (v *UnixVolume) FreeDiskSpace() (free uint64, err error) { func (v *UnixVolume) String() string { return fmt.Sprintf("[UnixVolume %s]", v.root) } + +// lockfile and unlockfile use flock(2) to manage kernel file locks. +func lockfile(f *os.File) error { + return syscall.Flock(int(f.Fd()), syscall.LOCK_EX) +} + +func unlockfile(f *os.File) error { + return syscall.Flock(int(f.Fd()), syscall.LOCK_UN) +}