util.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // Copyright (C) 2014 Jakob Borg and other contributors. All rights reserved.
  2. // Use of this source code is governed by an MIT-style license that can be
  3. // found in the LICENSE file.
  4. package model
  5. import (
  6. "fmt"
  7. "path/filepath"
  8. "sync"
  9. "time"
  10. "github.com/calmh/syncthing/protocol"
  11. "github.com/calmh/syncthing/scanner"
  12. )
  13. func fileFromFileInfo(f protocol.FileInfo) scanner.File {
  14. var blocks = make([]scanner.Block, len(f.Blocks))
  15. var offset int64
  16. for i, b := range f.Blocks {
  17. blocks[i] = scanner.Block{
  18. Offset: offset,
  19. Size: b.Size,
  20. Hash: b.Hash,
  21. }
  22. offset += int64(b.Size)
  23. }
  24. return scanner.File{
  25. // Name is with native separator and normalization
  26. Name: filepath.FromSlash(f.Name),
  27. Size: offset,
  28. Flags: f.Flags &^ protocol.FlagInvalid,
  29. Modified: f.Modified,
  30. Version: f.Version,
  31. Blocks: blocks,
  32. Suppressed: f.Flags&protocol.FlagInvalid != 0,
  33. }
  34. }
  35. func fileInfoFromFile(f scanner.File) protocol.FileInfo {
  36. var blocks = make([]protocol.BlockInfo, len(f.Blocks))
  37. for i, b := range f.Blocks {
  38. blocks[i] = protocol.BlockInfo{
  39. Size: b.Size,
  40. Hash: b.Hash,
  41. }
  42. }
  43. pf := protocol.FileInfo{
  44. Name: filepath.ToSlash(f.Name),
  45. Flags: f.Flags,
  46. Modified: f.Modified,
  47. Version: f.Version,
  48. Blocks: blocks,
  49. }
  50. if f.Suppressed {
  51. pf.Flags |= protocol.FlagInvalid
  52. }
  53. return pf
  54. }
  55. func cmMap(cm protocol.ClusterConfigMessage) map[string]map[protocol.NodeID]uint32 {
  56. m := make(map[string]map[protocol.NodeID]uint32)
  57. for _, repo := range cm.Repositories {
  58. m[repo.ID] = make(map[protocol.NodeID]uint32)
  59. for _, node := range repo.Nodes {
  60. var id protocol.NodeID
  61. copy(id[:], node.ID)
  62. m[repo.ID][id] = node.Flags
  63. }
  64. }
  65. return m
  66. }
  67. type ClusterConfigMismatch error
  68. // compareClusterConfig returns nil for two equivalent configurations,
  69. // otherwise a descriptive error
  70. func compareClusterConfig(local, remote protocol.ClusterConfigMessage) error {
  71. lm := cmMap(local)
  72. rm := cmMap(remote)
  73. for repo, lnodes := range lm {
  74. _ = lnodes
  75. if rnodes, ok := rm[repo]; ok {
  76. for node, lflags := range lnodes {
  77. if rflags, ok := rnodes[node]; ok {
  78. if lflags&protocol.FlagShareBits != rflags&protocol.FlagShareBits {
  79. return ClusterConfigMismatch(fmt.Errorf("remote has different sharing flags for node %q in repository %q", node, repo))
  80. }
  81. }
  82. }
  83. }
  84. }
  85. return nil
  86. }
  87. func deadlockDetect(mut sync.Locker, timeout time.Duration) {
  88. go func() {
  89. for {
  90. time.Sleep(timeout / 4)
  91. ok := make(chan bool, 2)
  92. go func() {
  93. mut.Lock()
  94. mut.Unlock()
  95. ok <- true
  96. }()
  97. go func() {
  98. time.Sleep(timeout)
  99. ok <- false
  100. }()
  101. if r := <-ok; !r {
  102. panic("deadlock detected")
  103. }
  104. }
  105. }()
  106. }