mirror of
https://github.com/octoleo/syncthing.git
synced 2025-02-08 14:58:26 +00:00
Add mutex logging
This commit is contained in:
parent
9ee3541655
commit
433b923ea7
@ -22,7 +22,6 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/calmh/logger"
|
"github.com/calmh/logger"
|
||||||
@ -34,6 +33,7 @@ import (
|
|||||||
"github.com/syncthing/syncthing/internal/events"
|
"github.com/syncthing/syncthing/internal/events"
|
||||||
"github.com/syncthing/syncthing/internal/model"
|
"github.com/syncthing/syncthing/internal/model"
|
||||||
"github.com/syncthing/syncthing/internal/osutil"
|
"github.com/syncthing/syncthing/internal/osutil"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
"github.com/syncthing/syncthing/internal/upgrade"
|
"github.com/syncthing/syncthing/internal/upgrade"
|
||||||
"github.com/vitrun/qart/qr"
|
"github.com/vitrun/qart/qr"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
@ -45,16 +45,16 @@ type guiError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
configInSync = true
|
configInSync = true
|
||||||
guiErrors = []guiError{}
|
guiErrors = []guiError{}
|
||||||
guiErrorsMut sync.Mutex
|
guiErrorsMut sync.Mutex = sync.NewMutex()
|
||||||
startTime = time.Now()
|
startTime = time.Now()
|
||||||
eventSub *events.BufferedSubscription
|
eventSub *events.BufferedSubscription
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
lastEventRequest time.Time
|
lastEventRequest time.Time
|
||||||
lastEventRequestMut sync.Mutex
|
lastEventRequestMut sync.Mutex = sync.NewMutex()
|
||||||
)
|
)
|
||||||
|
|
||||||
func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) error {
|
func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) error {
|
||||||
@ -522,7 +522,7 @@ func flushResponse(s string, w http.ResponseWriter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var cpuUsagePercent [10]float64 // The last ten seconds
|
var cpuUsagePercent [10]float64 // The last ten seconds
|
||||||
var cpuUsageLock sync.RWMutex
|
var cpuUsageLock sync.RWMutex = sync.NewRWMutex()
|
||||||
|
|
||||||
func restGetSystemStatus(w http.ResponseWriter, r *http.Request) {
|
func restGetSystemStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
var m runtime.MemStats
|
var m runtime.MemStats
|
||||||
|
@ -12,16 +12,16 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/syncthing/syncthing/internal/config"
|
"github.com/syncthing/syncthing/internal/config"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
sessions = make(map[string]bool)
|
sessions = make(map[string]bool)
|
||||||
sessionsMut sync.Mutex
|
sessionsMut sync.Mutex = sync.NewMutex()
|
||||||
)
|
)
|
||||||
|
|
||||||
func basicAuthAndSessionMiddleware(cfg config.GUIConfiguration, next http.Handler) http.Handler {
|
func basicAuthAndSessionMiddleware(cfg config.GUIConfiguration, next http.Handler) http.Handler {
|
||||||
|
@ -12,14 +12,14 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/syncthing/syncthing/internal/osutil"
|
"github.com/syncthing/syncthing/internal/osutil"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var csrfTokens []string
|
var csrfTokens []string
|
||||||
var csrfMut sync.Mutex
|
var csrfMut sync.Mutex = sync.NewMutex()
|
||||||
|
|
||||||
// Check for CSRF token on /rest/ URLs. If a correct one is not given, reject
|
// Check for CSRF token on /rest/ URLs. If a correct one is not given, reject
|
||||||
// the request with 403. For / and /index.html, set a new CSRF cookie if none
|
// the request with 403. For / and /index.html, set a new CSRF cookie if none
|
||||||
|
@ -14,17 +14,17 @@ import (
|
|||||||
"os/signal"
|
"os/signal"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/syncthing/syncthing/internal/osutil"
|
"github.com/syncthing/syncthing/internal/osutil"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
stdoutFirstLines []string // The first 10 lines of stdout
|
stdoutFirstLines []string // The first 10 lines of stdout
|
||||||
stdoutLastLines []string // The last 50 lines of stdout
|
stdoutLastLines []string // The last 50 lines of stdout
|
||||||
stdoutMut sync.Mutex
|
stdoutMut sync.Mutex = sync.NewMutex()
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -7,11 +7,11 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/syncthing/syncthing/internal/events"
|
"github.com/syncthing/syncthing/internal/events"
|
||||||
"github.com/syncthing/syncthing/internal/model"
|
"github.com/syncthing/syncthing/internal/model"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
"github.com/thejerf/suture"
|
"github.com/thejerf/suture"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -37,6 +37,7 @@ func (c *folderSummarySvc) Serve() {
|
|||||||
c.stop = make(chan struct{})
|
c.stop = make(chan struct{})
|
||||||
c.folders = make(map[string]struct{})
|
c.folders = make(map[string]struct{})
|
||||||
c.srv = srv
|
c.srv = srv
|
||||||
|
c.foldersMut = sync.NewMutex()
|
||||||
|
|
||||||
srv.Serve()
|
srv.Serve()
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,11 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/syncthing/protocol"
|
"github.com/syncthing/protocol"
|
||||||
"github.com/syncthing/syncthing/internal/events"
|
"github.com/syncthing/syncthing/internal/events"
|
||||||
"github.com/syncthing/syncthing/internal/osutil"
|
"github.com/syncthing/syncthing/internal/osutil"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// An interface to handle configuration changes, and a wrapper type á la
|
// An interface to handle configuration changes, and a wrapper type á la
|
||||||
@ -49,7 +49,12 @@ type Wrapper struct {
|
|||||||
// Wrap wraps an existing Configuration structure and ties it to a file on
|
// Wrap wraps an existing Configuration structure and ties it to a file on
|
||||||
// disk.
|
// disk.
|
||||||
func Wrap(path string, cfg Configuration) *Wrapper {
|
func Wrap(path string, cfg Configuration) *Wrapper {
|
||||||
w := &Wrapper{cfg: cfg, path: path}
|
w := &Wrapper{
|
||||||
|
cfg: cfg,
|
||||||
|
path: path,
|
||||||
|
mut: sync.NewMutex(),
|
||||||
|
sMut: sync.NewMutex(),
|
||||||
|
}
|
||||||
w.replaces = make(chan Configuration)
|
w.replaces = make(chan Configuration)
|
||||||
go w.Serve()
|
go w.Serve()
|
||||||
return w
|
return w
|
||||||
|
@ -17,11 +17,11 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/syncthing/protocol"
|
"github.com/syncthing/protocol"
|
||||||
"github.com/syncthing/syncthing/internal/config"
|
"github.com/syncthing/syncthing/internal/config"
|
||||||
"github.com/syncthing/syncthing/internal/osutil"
|
"github.com/syncthing/syncthing/internal/osutil"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
|
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
"github.com/syndtr/goleveldb/leveldb/util"
|
"github.com/syndtr/goleveldb/leveldb/util"
|
||||||
@ -123,7 +123,8 @@ func NewBlockFinder(db *leveldb.DB, cfg *config.Wrapper) *BlockFinder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
f := &BlockFinder{
|
f := &BlockFinder{
|
||||||
db: db,
|
db: db,
|
||||||
|
mut: sync.NewRWMutex(),
|
||||||
}
|
}
|
||||||
f.Changed(cfg.Raw())
|
f.Changed(cfg.Raw())
|
||||||
cfg.Subscribe(f)
|
cfg.Subscribe(f)
|
||||||
|
@ -10,10 +10,11 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
|
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
"github.com/syndtr/goleveldb/leveldb/opt"
|
||||||
"github.com/syndtr/goleveldb/leveldb/util"
|
"github.com/syndtr/goleveldb/leveldb/util"
|
||||||
@ -132,7 +133,7 @@ func TestConcurrentSetClear(t *testing.T) {
|
|||||||
|
|
||||||
dur := 30 * time.Second
|
dur := 30 * time.Second
|
||||||
t0 := time.Now()
|
t0 := time.Now()
|
||||||
var wg sync.WaitGroup
|
wg := sync.NewWaitGroup()
|
||||||
|
|
||||||
os.RemoveAll("testdata/concurrent-set-clear.db")
|
os.RemoveAll("testdata/concurrent-set-clear.db")
|
||||||
db, err := leveldb.OpenFile("testdata/concurrent-set-clear.db", &opt.Options{OpenFilesCacheCapacity: 10})
|
db, err := leveldb.OpenFile("testdata/concurrent-set-clear.db", &opt.Options{OpenFilesCacheCapacity: 10})
|
||||||
@ -188,7 +189,7 @@ func TestConcurrentSetOnly(t *testing.T) {
|
|||||||
|
|
||||||
dur := 30 * time.Second
|
dur := 30 * time.Second
|
||||||
t0 := time.Now()
|
t0 := time.Now()
|
||||||
var wg sync.WaitGroup
|
wg := sync.NewWaitGroup()
|
||||||
|
|
||||||
os.RemoveAll("testdata/concurrent-set-only.db")
|
os.RemoveAll("testdata/concurrent-set-only.db")
|
||||||
db, err := leveldb.OpenFile("testdata/concurrent-set-only.db", &opt.Options{OpenFilesCacheCapacity: 10})
|
db, err := leveldb.OpenFile("testdata/concurrent-set-only.db", &opt.Options{OpenFilesCacheCapacity: 10})
|
||||||
|
@ -14,9 +14,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/syncthing/protocol"
|
"github.com/syncthing/protocol"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
"github.com/syndtr/goleveldb/leveldb/iterator"
|
"github.com/syndtr/goleveldb/leveldb/iterator"
|
||||||
"github.com/syndtr/goleveldb/leveldb/opt"
|
"github.com/syndtr/goleveldb/leveldb/opt"
|
||||||
@ -25,7 +25,7 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
clockTick int64
|
clockTick int64
|
||||||
clockMut sync.Mutex
|
clockMut sync.Mutex = sync.NewMutex()
|
||||||
)
|
)
|
||||||
|
|
||||||
func clock(v int64) int64 {
|
func clock(v int64) int64 {
|
||||||
|
@ -13,10 +13,9 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/syncthing/protocol"
|
"github.com/syncthing/protocol"
|
||||||
"github.com/syncthing/syncthing/internal/osutil"
|
"github.com/syncthing/syncthing/internal/osutil"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -50,6 +49,7 @@ func NewFileSet(folder string, db *leveldb.DB) *FileSet {
|
|||||||
folder: folder,
|
folder: folder,
|
||||||
db: db,
|
db: db,
|
||||||
blockmap: NewBlockMap(db, folder),
|
blockmap: NewBlockMap(db, folder),
|
||||||
|
mutex: sync.NewMutex(),
|
||||||
}
|
}
|
||||||
|
|
||||||
ldbCheckGlobals(db, []byte(folder))
|
ldbCheckGlobals(db, []byte(folder))
|
||||||
|
@ -9,12 +9,13 @@ package discover
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/syncthing/protocol"
|
"github.com/syncthing/protocol"
|
||||||
|
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var device protocol.DeviceID
|
var device protocol.DeviceID
|
||||||
@ -97,7 +98,7 @@ func TestUDP4Success(t *testing.T) {
|
|||||||
|
|
||||||
// Do a lookup in a separate routine
|
// Do a lookup in a separate routine
|
||||||
addrs := []string{}
|
addrs := []string{}
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.NewWaitGroup()
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
addrs = client.Lookup(device)
|
addrs = client.Lookup(device)
|
||||||
@ -193,7 +194,7 @@ func TestUDP4Failure(t *testing.T) {
|
|||||||
|
|
||||||
// Do a lookup in a separate routine
|
// Do a lookup in a separate routine
|
||||||
addrs := []string{}
|
addrs := []string{}
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.NewWaitGroup()
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
addrs = client.Lookup(device)
|
addrs = client.Lookup(device)
|
||||||
|
@ -12,16 +12,19 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/syncthing/protocol"
|
"github.com/syncthing/protocol"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
for _, proto := range []string{"udp", "udp4", "udp6"} {
|
for _, proto := range []string{"udp", "udp4", "udp6"} {
|
||||||
Register(proto, func(uri *url.URL, pkt *Announce) (Client, error) {
|
Register(proto, func(uri *url.URL, pkt *Announce) (Client, error) {
|
||||||
c := &UDPClient{}
|
c := &UDPClient{
|
||||||
|
wg: sync.NewWaitGroup(),
|
||||||
|
mut: sync.NewRWMutex(),
|
||||||
|
}
|
||||||
err := c.Start(uri, pkt)
|
err := c.Start(uri, pkt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -13,12 +13,12 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/syncthing/protocol"
|
"github.com/syncthing/protocol"
|
||||||
"github.com/syncthing/syncthing/internal/beacon"
|
"github.com/syncthing/syncthing/internal/beacon"
|
||||||
"github.com/syncthing/syncthing/internal/events"
|
"github.com/syncthing/syncthing/internal/events"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Discoverer struct {
|
type Discoverer struct {
|
||||||
@ -59,6 +59,8 @@ func NewDiscoverer(id protocol.DeviceID, addresses []string) *Discoverer {
|
|||||||
negCacheCutoff: 3 * time.Minute,
|
negCacheCutoff: 3 * time.Minute,
|
||||||
registry: make(map[protocol.DeviceID][]CacheEntry),
|
registry: make(map[protocol.DeviceID][]CacheEntry),
|
||||||
lastLookup: make(map[protocol.DeviceID]time.Time),
|
lastLookup: make(map[protocol.DeviceID]time.Time),
|
||||||
|
registryLock: sync.NewRWMutex(),
|
||||||
|
mut: sync.NewRWMutex(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +142,7 @@ func (d *Discoverer) StartGlobal(servers []string, extPort uint16) {
|
|||||||
|
|
||||||
d.extPort = extPort
|
d.extPort = extPort
|
||||||
pkt := d.announcementPkt()
|
pkt := d.announcementPkt()
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.NewWaitGroup()
|
||||||
clients := make(chan Client, len(servers))
|
clients := make(chan Client, len(servers))
|
||||||
for _, address := range servers {
|
for _, address := range servers {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
@ -216,7 +218,7 @@ func (d *Discoverer) Lookup(device protocol.DeviceID) []string {
|
|||||||
// server client and one local announcement interval has passed. This is
|
// server client and one local announcement interval has passed. This is
|
||||||
// to avoid finding local peers on their remote address at startup.
|
// to avoid finding local peers on their remote address at startup.
|
||||||
results := make(chan []string, len(d.clients))
|
results := make(chan []string, len(d.clients))
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.NewWaitGroup()
|
||||||
for _, client := range d.clients {
|
for _, client := range d.clients {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(c Client) {
|
go func(c Client) {
|
||||||
|
@ -9,8 +9,10 @@ package events
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"sync"
|
stdsync "sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EventType int
|
type EventType int
|
||||||
@ -113,7 +115,8 @@ var (
|
|||||||
|
|
||||||
func NewLogger() *Logger {
|
func NewLogger() *Logger {
|
||||||
return &Logger{
|
return &Logger{
|
||||||
subs: make(map[int]*Subscription),
|
subs: make(map[int]*Subscription),
|
||||||
|
mutex: sync.NewMutex(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,6 +153,7 @@ func (l *Logger) Subscribe(mask EventType) *Subscription {
|
|||||||
mask: mask,
|
mask: mask,
|
||||||
id: l.nextID,
|
id: l.nextID,
|
||||||
events: make(chan Event, BufferSize),
|
events: make(chan Event, BufferSize),
|
||||||
|
mutex: sync.NewMutex(),
|
||||||
}
|
}
|
||||||
l.nextID++
|
l.nextID++
|
||||||
l.subs[s.id] = s
|
l.subs[s.id] = s
|
||||||
@ -197,15 +201,16 @@ type BufferedSubscription struct {
|
|||||||
next int
|
next int
|
||||||
cur int
|
cur int
|
||||||
mut sync.Mutex
|
mut sync.Mutex
|
||||||
cond *sync.Cond
|
cond *stdsync.Cond
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBufferedSubscription(s *Subscription, size int) *BufferedSubscription {
|
func NewBufferedSubscription(s *Subscription, size int) *BufferedSubscription {
|
||||||
bs := &BufferedSubscription{
|
bs := &BufferedSubscription{
|
||||||
sub: s,
|
sub: s,
|
||||||
buf: make([]Event, size),
|
buf: make([]Event, size),
|
||||||
|
mut: sync.NewMutex(),
|
||||||
}
|
}
|
||||||
bs.cond = sync.NewCond(&bs.mut)
|
bs.cond = stdsync.NewCond(bs.mut)
|
||||||
go bs.pollingLoop()
|
go bs.pollingLoop()
|
||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
@ -16,10 +16,10 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/syncthing/syncthing/internal/fnmatch"
|
"github.com/syncthing/syncthing/internal/fnmatch"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Pattern struct {
|
type Pattern struct {
|
||||||
@ -48,6 +48,7 @@ func New(withCache bool) *Matcher {
|
|||||||
m := &Matcher{
|
m := &Matcher{
|
||||||
withCache: withCache,
|
withCache: withCache,
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
|
mut: sync.NewMutex(),
|
||||||
}
|
}
|
||||||
if withCache {
|
if withCache {
|
||||||
go m.clean(2 * time.Hour)
|
go m.clean(2 * time.Hour)
|
||||||
|
@ -7,9 +7,8 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/syncthing/protocol"
|
"github.com/syncthing/protocol"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// deviceActivity tracks the number of outstanding requests per device and can
|
// deviceActivity tracks the number of outstanding requests per device and can
|
||||||
@ -23,6 +22,7 @@ type deviceActivity struct {
|
|||||||
func newDeviceActivity() *deviceActivity {
|
func newDeviceActivity() *deviceActivity {
|
||||||
return &deviceActivity{
|
return &deviceActivity{
|
||||||
act: make(map[protocol.DeviceID]int),
|
act: make(map[protocol.DeviceID]int),
|
||||||
|
mut: sync.NewMutex(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/syncthing/syncthing/internal/events"
|
"github.com/syncthing/syncthing/internal/events"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type folderState int
|
type folderState int
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
stdsync "sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/syncthing/protocol"
|
"github.com/syncthing/protocol"
|
||||||
@ -30,6 +30,7 @@ import (
|
|||||||
"github.com/syncthing/syncthing/internal/scanner"
|
"github.com/syncthing/syncthing/internal/scanner"
|
||||||
"github.com/syncthing/syncthing/internal/stats"
|
"github.com/syncthing/syncthing/internal/stats"
|
||||||
"github.com/syncthing/syncthing/internal/symlinks"
|
"github.com/syncthing/syncthing/internal/symlinks"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
"github.com/syncthing/syncthing/internal/versioner"
|
"github.com/syncthing/syncthing/internal/versioner"
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
)
|
)
|
||||||
@ -85,7 +86,7 @@ type Model struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
SymlinkWarning = sync.Once{}
|
SymlinkWarning = stdsync.Once{}
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewModel creates and starts a new model. The model starts in read-only mode,
|
// NewModel creates and starts a new model. The model starts in read-only mode,
|
||||||
@ -113,6 +114,9 @@ func NewModel(cfg *config.Wrapper, id protocol.DeviceID, deviceName, clientName,
|
|||||||
protoConn: make(map[protocol.DeviceID]protocol.Connection),
|
protoConn: make(map[protocol.DeviceID]protocol.Connection),
|
||||||
rawConn: make(map[protocol.DeviceID]io.Closer),
|
rawConn: make(map[protocol.DeviceID]io.Closer),
|
||||||
deviceVer: make(map[protocol.DeviceID]string),
|
deviceVer: make(map[protocol.DeviceID]string),
|
||||||
|
|
||||||
|
fmut: sync.NewRWMutex(),
|
||||||
|
pmut: sync.NewRWMutex(),
|
||||||
}
|
}
|
||||||
if cfg.Options().ProgressUpdateIntervalS > -1 {
|
if cfg.Options().ProgressUpdateIntervalS > -1 {
|
||||||
go m.progressEmitter.Serve()
|
go m.progressEmitter.Serve()
|
||||||
@ -125,8 +129,8 @@ func NewModel(cfg *config.Wrapper, id protocol.DeviceID, deviceName, clientName,
|
|||||||
// the locks cannot be acquired in the given timeout period.
|
// the locks cannot be acquired in the given timeout period.
|
||||||
func (m *Model) StartDeadlockDetector(timeout time.Duration) {
|
func (m *Model) StartDeadlockDetector(timeout time.Duration) {
|
||||||
l.Infof("Starting deadlock detector with %v timeout", timeout)
|
l.Infof("Starting deadlock detector with %v timeout", timeout)
|
||||||
deadlockDetect(&m.fmut, timeout)
|
deadlockDetect(m.fmut, timeout)
|
||||||
deadlockDetect(&m.pmut, timeout)
|
deadlockDetect(m.pmut, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartRW starts read/write processing on the current model. When in
|
// StartRW starts read/write processing on the current model. When in
|
||||||
@ -1099,9 +1103,9 @@ func (m *Model) ScanFolders() map[string]error {
|
|||||||
m.fmut.RUnlock()
|
m.fmut.RUnlock()
|
||||||
|
|
||||||
errors := make(map[string]error, len(m.folderCfgs))
|
errors := make(map[string]error, len(m.folderCfgs))
|
||||||
var errorsMut sync.Mutex
|
errorsMut := sync.NewMutex()
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
wg := sync.NewWaitGroup()
|
||||||
wg.Add(len(folders))
|
wg.Add(len(folders))
|
||||||
for _, folder := range folders {
|
for _, folder := range folders {
|
||||||
folder := folder
|
folder := folder
|
||||||
|
@ -9,11 +9,11 @@ package model
|
|||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/syncthing/syncthing/internal/config"
|
"github.com/syncthing/syncthing/internal/config"
|
||||||
"github.com/syncthing/syncthing/internal/events"
|
"github.com/syncthing/syncthing/internal/events"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProgressEmitter struct {
|
type ProgressEmitter struct {
|
||||||
@ -35,6 +35,7 @@ func NewProgressEmitter(cfg *config.Wrapper) *ProgressEmitter {
|
|||||||
registry: make(map[string]*sharedPullerState),
|
registry: make(map[string]*sharedPullerState),
|
||||||
last: make(map[string]map[string]*pullerProgress),
|
last: make(map[string]map[string]*pullerProgress),
|
||||||
timer: time.NewTimer(time.Millisecond),
|
timer: time.NewTimer(time.Millisecond),
|
||||||
|
mut: sync.NewMutex(),
|
||||||
}
|
}
|
||||||
t.Changed(cfg.Raw())
|
t.Changed(cfg.Raw())
|
||||||
cfg.Subscribe(t)
|
cfg.Subscribe(t)
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/syncthing/syncthing/internal/config"
|
"github.com/syncthing/syncthing/internal/config"
|
||||||
"github.com/syncthing/syncthing/internal/events"
|
"github.com/syncthing/syncthing/internal/events"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var timeout = 10 * time.Millisecond
|
var timeout = 10 * time.Millisecond
|
||||||
@ -50,7 +51,9 @@ func TestProgressEmitter(t *testing.T) {
|
|||||||
|
|
||||||
expectTimeout(w, t)
|
expectTimeout(w, t)
|
||||||
|
|
||||||
s := sharedPullerState{}
|
s := sharedPullerState{
|
||||||
|
mut: sync.NewMutex(),
|
||||||
|
}
|
||||||
p.Register(&s)
|
p.Register(&s)
|
||||||
|
|
||||||
expectEvent(w, t, 1)
|
expectEvent(w, t, 1)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import "sync"
|
import "github.com/syncthing/syncthing/internal/sync"
|
||||||
|
|
||||||
type jobQueue struct {
|
type jobQueue struct {
|
||||||
progress []string
|
progress []string
|
||||||
@ -15,7 +15,9 @@ type jobQueue struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newJobQueue() *jobQueue {
|
func newJobQueue() *jobQueue {
|
||||||
return &jobQueue{}
|
return &jobQueue{
|
||||||
|
mut: sync.NewMutex(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *jobQueue) Push(file string) {
|
func (q *jobQueue) Push(file string) {
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type roFolder struct {
|
type roFolder struct {
|
||||||
@ -23,11 +25,14 @@ type roFolder struct {
|
|||||||
|
|
||||||
func newROFolder(model *Model, folder string, interval time.Duration) *roFolder {
|
func newROFolder(model *Model, folder string, interval time.Duration) *roFolder {
|
||||||
return &roFolder{
|
return &roFolder{
|
||||||
stateTracker: stateTracker{folder: folder},
|
stateTracker: stateTracker{
|
||||||
folder: folder,
|
folder: folder,
|
||||||
intv: interval,
|
mut: sync.NewMutex(),
|
||||||
model: model,
|
},
|
||||||
stop: make(chan struct{}),
|
folder: folder,
|
||||||
|
intv: interval,
|
||||||
|
model: model,
|
||||||
|
stop: make(chan struct{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/syncthing/protocol"
|
"github.com/syncthing/protocol"
|
||||||
@ -24,6 +23,7 @@ import (
|
|||||||
"github.com/syncthing/syncthing/internal/osutil"
|
"github.com/syncthing/syncthing/internal/osutil"
|
||||||
"github.com/syncthing/syncthing/internal/scanner"
|
"github.com/syncthing/syncthing/internal/scanner"
|
||||||
"github.com/syncthing/syncthing/internal/symlinks"
|
"github.com/syncthing/syncthing/internal/symlinks"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
"github.com/syncthing/syncthing/internal/versioner"
|
"github.com/syncthing/syncthing/internal/versioner"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -77,7 +77,10 @@ type rwFolder struct {
|
|||||||
|
|
||||||
func newRWFolder(m *Model, shortID uint64, cfg config.FolderConfiguration) *rwFolder {
|
func newRWFolder(m *Model, shortID uint64, cfg config.FolderConfiguration) *rwFolder {
|
||||||
return &rwFolder{
|
return &rwFolder{
|
||||||
stateTracker: stateTracker{folder: cfg.ID},
|
stateTracker: stateTracker{
|
||||||
|
folder: cfg.ID,
|
||||||
|
mut: sync.NewMutex(),
|
||||||
|
},
|
||||||
|
|
||||||
model: m,
|
model: m,
|
||||||
progressEmitter: m.progressEmitter,
|
progressEmitter: m.progressEmitter,
|
||||||
@ -279,10 +282,10 @@ func (p *rwFolder) pullerIteration(ignores *ignore.Matcher) int {
|
|||||||
copyChan := make(chan copyBlocksState)
|
copyChan := make(chan copyBlocksState)
|
||||||
finisherChan := make(chan *sharedPullerState)
|
finisherChan := make(chan *sharedPullerState)
|
||||||
|
|
||||||
var updateWg sync.WaitGroup
|
updateWg := sync.NewWaitGroup()
|
||||||
var copyWg sync.WaitGroup
|
copyWg := sync.NewWaitGroup()
|
||||||
var pullWg sync.WaitGroup
|
pullWg := sync.NewWaitGroup()
|
||||||
var doneWg sync.WaitGroup
|
doneWg := sync.NewWaitGroup()
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
l.Debugln(p, "c", p.copiers, "p", p.pullers)
|
l.Debugln(p, "c", p.copiers, "p", p.pullers)
|
||||||
@ -799,6 +802,7 @@ func (p *rwFolder) handleFile(file protocol.FileInfo, copyChan chan<- copyBlocks
|
|||||||
reused: reused,
|
reused: reused,
|
||||||
ignorePerms: p.ignorePerms,
|
ignorePerms: p.ignorePerms,
|
||||||
version: curFile.Version,
|
version: curFile.Version,
|
||||||
|
mut: sync.NewMutex(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
|
@ -10,10 +10,10 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/syncthing/protocol"
|
"github.com/syncthing/protocol"
|
||||||
"github.com/syncthing/syncthing/internal/db"
|
"github.com/syncthing/syncthing/internal/db"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A sharedPullerState is kept for each file that is being synced and is kept
|
// A sharedPullerState is kept for each file that is being synced and is kept
|
||||||
@ -59,8 +59,8 @@ type lockedWriterAt struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w lockedWriterAt) WriteAt(p []byte, off int64) (n int, err error) {
|
func (w lockedWriterAt) WriteAt(p []byte, off int64) (n int, err error) {
|
||||||
w.mut.Lock()
|
(*w.mut).Lock()
|
||||||
defer w.mut.Unlock()
|
defer (*w.mut).Unlock()
|
||||||
return w.wr.WriteAt(p, off)
|
return w.wr.WriteAt(p, off)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,11 +9,14 @@ package model
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSourceFileOK(t *testing.T) {
|
func TestSourceFileOK(t *testing.T) {
|
||||||
s := sharedPullerState{
|
s := sharedPullerState{
|
||||||
realName: "testdata/foo",
|
realName: "testdata/foo",
|
||||||
|
mut: sync.NewMutex(),
|
||||||
}
|
}
|
||||||
|
|
||||||
fd, err := s.sourceFile()
|
fd, err := s.sourceFile()
|
||||||
@ -42,6 +45,7 @@ func TestSourceFileOK(t *testing.T) {
|
|||||||
func TestSourceFileBad(t *testing.T) {
|
func TestSourceFileBad(t *testing.T) {
|
||||||
s := sharedPullerState{
|
s := sharedPullerState{
|
||||||
realName: "nonexistent",
|
realName: "nonexistent",
|
||||||
|
mut: sync.NewMutex(),
|
||||||
}
|
}
|
||||||
|
|
||||||
fd, err := s.sourceFile()
|
fd, err := s.sourceFile()
|
||||||
@ -67,6 +71,7 @@ func TestReadOnlyDir(t *testing.T) {
|
|||||||
|
|
||||||
s := sharedPullerState{
|
s := sharedPullerState{
|
||||||
tempName: "testdata/read_only_dir/.temp_name",
|
tempName: "testdata/read_only_dir/.temp_name",
|
||||||
|
mut: sync.NewMutex(),
|
||||||
}
|
}
|
||||||
|
|
||||||
fd, err := s.tempFile()
|
fd, err := s.tempFile()
|
||||||
|
@ -15,14 +15,15 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrNoHome = errors.New("No home directory found - set $HOME (or the platform equivalent).")
|
var ErrNoHome = errors.New("No home directory found - set $HOME (or the platform equivalent).")
|
||||||
|
|
||||||
// Try to keep this entire operation atomic-like. We shouldn't be doing this
|
// Try to keep this entire operation atomic-like. We shouldn't be doing this
|
||||||
// often enough that there is any contention on this lock.
|
// often enough that there is any contention on this lock.
|
||||||
var renameLock sync.Mutex
|
var renameLock sync.Mutex = sync.NewMutex()
|
||||||
|
|
||||||
// TryRename renames a file, leaving source file intact in case of failure.
|
// TryRename renames a file, leaving source file intact in case of failure.
|
||||||
// Tries hard to succeed on various systems by temporarily tweaking directory
|
// Tries hard to succeed on various systems by temporarily tweaking directory
|
||||||
|
@ -9,9 +9,9 @@ package scanner
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/syncthing/protocol"
|
"github.com/syncthing/protocol"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The parallell hasher reads FileInfo structures from the inbox, hashes the
|
// The parallell hasher reads FileInfo structures from the inbox, hashes the
|
||||||
@ -20,7 +20,7 @@ import (
|
|||||||
// is closed and all items handled.
|
// is closed and all items handled.
|
||||||
|
|
||||||
func newParallelHasher(dir string, blockSize, workers int, outbox, inbox chan protocol.FileInfo) {
|
func newParallelHasher(dir string, blockSize, workers int, outbox, inbox chan protocol.FileInfo) {
|
||||||
var wg sync.WaitGroup
|
wg := sync.NewWaitGroup()
|
||||||
wg.Add(workers)
|
wg.Add(workers)
|
||||||
|
|
||||||
for i := 0; i < workers; i++ {
|
for i := 0; i < workers; i++ {
|
||||||
|
31
internal/sync/debug.go
Normal file
31
internal/sync/debug.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright (C) 2015 The Syncthing Authors.
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/calmh/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
debug = strings.Contains(os.Getenv("STTRACE"), "locks") || os.Getenv("STTRACE") == "all"
|
||||||
|
threshold = time.Duration(100 * time.Millisecond)
|
||||||
|
l = logger.DefaultLogger
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if n, err := strconv.Atoi(os.Getenv("STLOCKTHRESHOLD")); debug && err == nil {
|
||||||
|
threshold = time.Duration(n) * time.Millisecond
|
||||||
|
}
|
||||||
|
if debug {
|
||||||
|
l.Debugf("Enabling lock logging at %v threshold", threshold)
|
||||||
|
}
|
||||||
|
}
|
123
internal/sync/sync.go
Normal file
123
internal/sync/sync.go
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
// Copyright (C) 2015 The Syncthing Authors.
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mutex interface {
|
||||||
|
Lock()
|
||||||
|
Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
type RWMutex interface {
|
||||||
|
Mutex
|
||||||
|
RLock()
|
||||||
|
RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
type WaitGroup interface {
|
||||||
|
Add(int)
|
||||||
|
Done()
|
||||||
|
Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMutex() Mutex {
|
||||||
|
if debug {
|
||||||
|
return &loggedMutex{}
|
||||||
|
}
|
||||||
|
return &sync.Mutex{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRWMutex() RWMutex {
|
||||||
|
if debug {
|
||||||
|
return &loggedRWMutex{}
|
||||||
|
}
|
||||||
|
return &sync.RWMutex{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWaitGroup() WaitGroup {
|
||||||
|
if debug {
|
||||||
|
return &loggedWaitGroup{}
|
||||||
|
}
|
||||||
|
return &sync.WaitGroup{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type loggedMutex struct {
|
||||||
|
sync.Mutex
|
||||||
|
start time.Time
|
||||||
|
lockedAt string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *loggedMutex) Lock() {
|
||||||
|
m.Mutex.Lock()
|
||||||
|
m.start = time.Now()
|
||||||
|
m.lockedAt = getCaller()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *loggedMutex) Unlock() {
|
||||||
|
duration := time.Now().Sub(m.start)
|
||||||
|
if duration >= threshold {
|
||||||
|
l.Debugf("Mutex held for %v. Locked at %s unlocked at %s", duration, m.lockedAt, getCaller())
|
||||||
|
}
|
||||||
|
m.Mutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
type loggedRWMutex struct {
|
||||||
|
sync.RWMutex
|
||||||
|
start time.Time
|
||||||
|
lockedAt string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *loggedRWMutex) Lock() {
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
m.RWMutex.Lock()
|
||||||
|
|
||||||
|
m.start = time.Now()
|
||||||
|
duration := m.start.Sub(start)
|
||||||
|
|
||||||
|
m.lockedAt = getCaller()
|
||||||
|
if duration > threshold {
|
||||||
|
l.Debugf("RWMutex took %v to lock. Locked at %s", duration, m.lockedAt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *loggedRWMutex) Unlock() {
|
||||||
|
duration := time.Now().Sub(m.start)
|
||||||
|
if duration >= threshold {
|
||||||
|
l.Debugf("RWMutex held for %v. Locked at %s: unlocked at %s", duration, m.lockedAt, getCaller())
|
||||||
|
}
|
||||||
|
m.RWMutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
type loggedWaitGroup struct {
|
||||||
|
sync.WaitGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wg *loggedWaitGroup) Done() {
|
||||||
|
start := time.Now()
|
||||||
|
wg.WaitGroup.Done()
|
||||||
|
duration := time.Now().Sub(start)
|
||||||
|
if duration > threshold {
|
||||||
|
l.Debugf("WaitGroup took %v at %s", duration, getCaller())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCaller() string {
|
||||||
|
pc := make([]uintptr, 10)
|
||||||
|
runtime.Callers(3, pc)
|
||||||
|
f := runtime.FuncForPC(pc[0])
|
||||||
|
file, line := f.FileLine(pc[0])
|
||||||
|
file = filepath.Join(filepath.Base(filepath.Dir(file)), filepath.Base(file))
|
||||||
|
return fmt.Sprintf("%s:%d", file, line)
|
||||||
|
}
|
@ -22,8 +22,9 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A container for relevant properties of a UPnP InternetGatewayDevice.
|
// A container for relevant properties of a UPnP InternetGatewayDevice.
|
||||||
@ -129,7 +130,7 @@ func Discover(timeout time.Duration) []IGD {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
wg := sync.NewWaitGroup()
|
||||||
for _, intf := range interfaces {
|
for _, intf := range interfaces {
|
||||||
for _, deviceType := range []string{"urn:schemas-upnp-org:device:InternetGatewayDevice:1", "urn:schemas-upnp-org:device:InternetGatewayDevice:2"} {
|
for _, deviceType := range []string{"urn:schemas-upnp-org:device:InternetGatewayDevice:1", "urn:schemas-upnp-org:device:InternetGatewayDevice:2"} {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
@ -11,10 +11,10 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/syncthing/syncthing/internal/osutil"
|
"github.com/syncthing/syncthing/internal/osutil"
|
||||||
|
"github.com/syncthing/syncthing/internal/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -33,7 +33,7 @@ type Staggered struct {
|
|||||||
cleanInterval int64
|
cleanInterval int64
|
||||||
folderPath string
|
folderPath string
|
||||||
interval [4]Interval
|
interval [4]Interval
|
||||||
mutex *sync.Mutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rename versions with old version format
|
// Rename versions with old version format
|
||||||
@ -87,7 +87,6 @@ func NewStaggered(folderID, folderPath string, params map[string]string) Version
|
|||||||
versionsDir = params["versionsPath"]
|
versionsDir = params["versionsPath"]
|
||||||
}
|
}
|
||||||
|
|
||||||
var mutex sync.Mutex
|
|
||||||
s := Staggered{
|
s := Staggered{
|
||||||
versionsPath: versionsDir,
|
versionsPath: versionsDir,
|
||||||
cleanInterval: cleanInterval,
|
cleanInterval: cleanInterval,
|
||||||
@ -98,7 +97,7 @@ func NewStaggered(folderID, folderPath string, params map[string]string) Version
|
|||||||
{86400, 592000}, // next 30 days -> 1 day between versions
|
{86400, 592000}, // next 30 days -> 1 day between versions
|
||||||
{604800, maxAge}, // next year -> 1 week between versions
|
{604800, maxAge}, // next year -> 1 week between versions
|
||||||
},
|
},
|
||||||
mutex: &mutex,
|
mutex: sync.NewMutex(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user