virtualmtime.go 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. // Copyright (C) 2015 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at http://mozilla.org/MPL/2.0/.
  6. package db
  7. import (
  8. "fmt"
  9. "time"
  10. "github.com/syndtr/goleveldb/leveldb"
  11. )
  12. // This type encapsulates a repository of mtimes for platforms where file mtimes
  13. // can't be set to arbitrary values. For this to work, we need to store both
  14. // the mtime we tried to set (the "actual" mtime) as well as the mtime the file
  15. // has when we're done touching it (the "disk" mtime) so that we can tell if it
  16. // was changed. So in GetMtime(), it's not sufficient that the record exists --
  17. // the argument must also equal the "disk" mtime in the record, otherwise it's
  18. // been touched locally and the "disk" mtime is actually correct.
  19. type VirtualMtimeRepo struct {
  20. ns *NamespacedKV
  21. }
  22. func NewVirtualMtimeRepo(ldb *leveldb.DB, folder string) *VirtualMtimeRepo {
  23. prefix := string(KeyTypeVirtualMtime) + folder
  24. return &VirtualMtimeRepo{
  25. ns: NewNamespacedKV(ldb, prefix),
  26. }
  27. }
  28. func (r *VirtualMtimeRepo) UpdateMtime(path string, diskMtime, actualMtime time.Time) {
  29. if debug {
  30. l.Debugf("virtual mtime: storing values for path:%s disk:%v actual:%v", path, diskMtime, actualMtime)
  31. }
  32. diskBytes, _ := diskMtime.MarshalBinary()
  33. actualBytes, _ := actualMtime.MarshalBinary()
  34. data := append(diskBytes, actualBytes...)
  35. r.ns.PutBytes(path, data)
  36. }
  37. func (r *VirtualMtimeRepo) GetMtime(path string, diskMtime time.Time) time.Time {
  38. var debugResult string
  39. if data, exists := r.ns.Bytes(path); exists {
  40. var mtime time.Time
  41. if err := mtime.UnmarshalBinary(data[:len(data)/2]); err != nil {
  42. panic(fmt.Sprintf("Can't unmarshal stored mtime at path %v: %v", path, err))
  43. }
  44. if mtime.Equal(diskMtime) {
  45. if err := mtime.UnmarshalBinary(data[len(data)/2:]); err != nil {
  46. panic(fmt.Sprintf("Can't unmarshal stored mtime at path %v: %v", path, err))
  47. }
  48. debugResult = "got it"
  49. diskMtime = mtime
  50. } else if debug {
  51. debugResult = fmt.Sprintf("record exists, but mismatch inDisk:%v dbDisk:%v", diskMtime, mtime)
  52. }
  53. } else {
  54. debugResult = "record does not exist"
  55. }
  56. if debug {
  57. l.Debugf("virtual mtime: value get result:%v path:%s", debugResult, path)
  58. }
  59. return diskMtime
  60. }
  61. func (r *VirtualMtimeRepo) DeleteMtime(path string) {
  62. r.ns.Delete(path)
  63. }
  64. func (r *VirtualMtimeRepo) Drop() {
  65. r.ns.Reset()
  66. }