virtualmtime.go 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  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. "encoding/binary"
  9. "fmt"
  10. "time"
  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 *Instance, folder string) *VirtualMtimeRepo {
  23. var prefix [5]byte // key type + 4 bytes folder idx number
  24. prefix[0] = KeyTypeVirtualMtime
  25. binary.BigEndian.PutUint32(prefix[1:], ldb.folderIdx.ID([]byte(folder)))
  26. return &VirtualMtimeRepo{
  27. ns: NewNamespacedKV(ldb, string(prefix[:])),
  28. }
  29. }
  30. func (r *VirtualMtimeRepo) UpdateMtime(path string, diskMtime, actualMtime time.Time) {
  31. l.Debugf("virtual mtime: storing values for path:%s disk:%v actual:%v", path, diskMtime, actualMtime)
  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. data, exists := r.ns.Bytes(path)
  39. if !exists {
  40. // Absence of debug print is significant enough in itself here
  41. return diskMtime
  42. }
  43. var mtime time.Time
  44. if err := mtime.UnmarshalBinary(data[:len(data)/2]); err != nil {
  45. panic(fmt.Sprintf("Can't unmarshal stored mtime at path %s: %v", path, err))
  46. }
  47. if mtime.Equal(diskMtime) {
  48. if err := mtime.UnmarshalBinary(data[len(data)/2:]); err != nil {
  49. panic(fmt.Sprintf("Can't unmarshal stored mtime at path %s: %v", path, err))
  50. }
  51. l.Debugf("virtual mtime: return %v instead of %v for path: %s", mtime, diskMtime, path)
  52. return mtime
  53. }
  54. l.Debugf("virtual mtime: record exists, but mismatch inDisk: %v dbDisk: %v for path: %s", diskMtime, mtime, path)
  55. return diskMtime
  56. }
  57. func (r *VirtualMtimeRepo) DeleteMtime(path string) {
  58. r.ns.Delete(path)
  59. }
  60. func (r *VirtualMtimeRepo) Drop() {
  61. r.ns.Reset()
  62. }