set.go 3.1 KB
Newer Older
Jakob Borg's avatar
Jakob Borg committed
1 2 3
// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
// All rights reserved. Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
Jakob Borg's avatar
Jakob Borg committed
4

5 6 7 8 9 10
// Package files provides a set type to track local/remote files with newness checks.
package files

import (
	"sync"

Jakob Borg's avatar
Jakob Borg committed
11
	"github.com/calmh/syncthing/lamport"
12
	"github.com/calmh/syncthing/protocol"
Jakob Borg's avatar
Jakob Borg committed
13
	"github.com/syndtr/goleveldb/leveldb"
14 15 16
)

type fileRecord struct {
Jakob Borg's avatar
Jakob Borg committed
17
	File   protocol.FileInfo
18 19
	Usage  int
	Global bool
20 21 22 23 24
}

type bitset uint64

type Set struct {
25 26 27 28
	localVersion map[protocol.NodeID]uint64
	mutex        sync.Mutex
	repo         string
	db           *leveldb.DB
29 30
}

Jakob Borg's avatar
Jakob Borg committed
31 32
func NewSet(repo string, db *leveldb.DB) *Set {
	var s = Set{
33 34 35
		localVersion: make(map[protocol.NodeID]uint64),
		repo:         repo,
		db:           db,
36
	}
37

Jakob Borg's avatar
Jakob Borg committed
38 39 40 41 42
	var nodeID protocol.NodeID
	ldbWithAllRepo(db, []byte(repo), func(node []byte, f protocol.FileInfo) bool {
		copy(nodeID[:], node)
		if f.LocalVersion > s.localVersion[nodeID] {
			s.localVersion[nodeID] = f.LocalVersion
43
		}
Jakob Borg's avatar
Jakob Borg committed
44
		lamport.Default.Tick(f.Version)
45 46
		return true
	})
Jakob Borg's avatar
Jakob Borg committed
47 48 49 50
	if debug {
		l.Debugf("loaded localVersion for %q: %#v", repo, s.localVersion)
	}
	clock(s.localVersion[protocol.LocalNodeID])
51

Jakob Borg's avatar
Jakob Borg committed
52
	return &s
53 54
}

Jakob Borg's avatar
Jakob Borg committed
55
func (s *Set) Replace(node protocol.NodeID, fs []protocol.FileInfo) {
56
	if debug {
Jakob Borg's avatar
Jakob Borg committed
57
		l.Debugf("%s Replace(%v, [%d])", s.repo, node, len(fs))
58
	}
Jakob Borg's avatar
Jakob Borg committed
59 60
	s.mutex.Lock()
	defer s.mutex.Unlock()
61 62
	if lv := ldbReplace(s.db, []byte(s.repo), node[:], fs); lv > s.localVersion[node] {
		s.localVersion[node] = lv
63 64 65
	}
}

Jakob Borg's avatar
Jakob Borg committed
66
func (s *Set) ReplaceWithDelete(node protocol.NodeID, fs []protocol.FileInfo) {
67
	if debug {
Jakob Borg's avatar
Jakob Borg committed
68
		l.Debugf("%s ReplaceWithDelete(%v, [%d])", s.repo, node, len(fs))
69
	}
Jakob Borg's avatar
Jakob Borg committed
70 71
	s.mutex.Lock()
	defer s.mutex.Unlock()
72 73
	if lv := ldbReplaceWithDelete(s.db, []byte(s.repo), node[:], fs); lv > s.localVersion[node] {
		s.localVersion[node] = lv
74 75 76
	}
}

Jakob Borg's avatar
Jakob Borg committed
77
func (s *Set) Update(node protocol.NodeID, fs []protocol.FileInfo) {
78
	if debug {
Jakob Borg's avatar
Jakob Borg committed
79
		l.Debugf("%s Update(%v, [%d])", s.repo, node, len(fs))
80
	}
Jakob Borg's avatar
Jakob Borg committed
81 82
	s.mutex.Lock()
	defer s.mutex.Unlock()
83 84
	if lv := ldbUpdate(s.db, []byte(s.repo), node[:], fs); lv > s.localVersion[node] {
		s.localVersion[node] = lv
85 86 87
	}
}

Jakob Borg's avatar
Jakob Borg committed
88
func (s *Set) WithNeed(node protocol.NodeID, fn fileIterator) {
89
	if debug {
Jakob Borg's avatar
Jakob Borg committed
90
		l.Debugf("%s Need(%v)", s.repo, node)
91
	}
Jakob Borg's avatar
Jakob Borg committed
92
	ldbWithNeed(s.db, []byte(s.repo), node[:], fn)
93 94
}

Jakob Borg's avatar
Jakob Borg committed
95
func (s *Set) WithHave(node protocol.NodeID, fn fileIterator) {
96
	if debug {
Jakob Borg's avatar
Jakob Borg committed
97
		l.Debugf("%s WithHave(%v)", s.repo, node)
98
	}
Jakob Borg's avatar
Jakob Borg committed
99
	ldbWithHave(s.db, []byte(s.repo), node[:], fn)
100 101
}

Jakob Borg's avatar
Jakob Borg committed
102
func (s *Set) WithGlobal(fn fileIterator) {
103
	if debug {
Jakob Borg's avatar
Jakob Borg committed
104
		l.Debugf("%s WithGlobal()", s.repo)
105
	}
Jakob Borg's avatar
Jakob Borg committed
106
	ldbWithGlobal(s.db, []byte(s.repo), fn)
107 108
}

Jakob Borg's avatar
Jakob Borg committed
109
func (s *Set) Get(node protocol.NodeID, file string) protocol.FileInfo {
Jakob Borg's avatar
Jakob Borg committed
110
	return ldbGet(s.db, []byte(s.repo), node[:], []byte(file))
111 112
}

Jakob Borg's avatar
Jakob Borg committed
113
func (s *Set) GetGlobal(file string) protocol.FileInfo {
Jakob Borg's avatar
Jakob Borg committed
114
	return ldbGetGlobal(s.db, []byte(s.repo), []byte(file))
115 116
}

Jakob Borg's avatar
Jakob Borg committed
117 118
func (s *Set) Availability(file string) []protocol.NodeID {
	return ldbAvailability(s.db, []byte(s.repo), []byte(file))
119 120
}

121
func (s *Set) LocalVersion(node protocol.NodeID) uint64 {
122 123
	s.mutex.Lock()
	defer s.mutex.Unlock()
124
	return s.localVersion[node]
125
}