set.go 3.66 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"

11 12
	"github.com/syncthing/syncthing/lamport"
	"github.com/syncthing/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
	var nodeID protocol.NodeID
39
	ldbWithAllRepoTruncated(db, []byte(repo), func(node []byte, f protocol.FileInfoTruncated) bool {
Jakob Borg's avatar
Jakob Borg committed
40 41 42
		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
	s.localVersion[node] = ldbReplace(s.db, []byte(s.repo), node[:], fs)
62 63
}

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

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

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

func (s *Set) WithNeedTruncated(node protocol.NodeID, fn fileIterator) {
	if debug {
		l.Debugf("%s WithNeedTruncated(%v)", s.repo, node)
	}
	ldbWithNeed(s.db, []byte(s.repo), node[:], true, fn)
98 99
}

Jakob Borg's avatar
Jakob Borg committed
100
func (s *Set) WithHave(node protocol.NodeID, fn fileIterator) {
101
	if debug {
Jakob Borg's avatar
Jakob Borg committed
102
		l.Debugf("%s WithHave(%v)", s.repo, node)
103
	}
104 105 106 107 108 109 110 111
	ldbWithHave(s.db, []byte(s.repo), node[:], false, fn)
}

func (s *Set) WithHaveTruncated(node protocol.NodeID, fn fileIterator) {
	if debug {
		l.Debugf("%s WithHaveTruncated(%v)", s.repo, node)
	}
	ldbWithHave(s.db, []byte(s.repo), node[:], true, fn)
112 113
}

Jakob Borg's avatar
Jakob Borg committed
114 115 116 117 118 119 120
func (s *Set) WithGlobal(fn fileIterator) {
	if debug {
		l.Debugf("%s WithGlobal()", s.repo)
	}
	ldbWithGlobal(s.db, []byte(s.repo), false, fn)
}

121
func (s *Set) WithGlobalTruncated(fn fileIterator) {
122
	if debug {
Jakob Borg's avatar
Jakob Borg committed
123
		l.Debugf("%s WithGlobalTruncated()", s.repo)
124
	}
125
	ldbWithGlobal(s.db, []byte(s.repo), true, fn)
126 127
}

Jakob Borg's avatar
Jakob Borg committed
128
func (s *Set) Get(node protocol.NodeID, file string) protocol.FileInfo {
Jakob Borg's avatar
Jakob Borg committed
129
	return ldbGet(s.db, []byte(s.repo), node[:], []byte(file))
130 131
}

Jakob Borg's avatar
Jakob Borg committed
132
func (s *Set) GetGlobal(file string) protocol.FileInfo {
Jakob Borg's avatar
Jakob Borg committed
133
	return ldbGetGlobal(s.db, []byte(s.repo), []byte(file))
134 135
}

Jakob Borg's avatar
Jakob Borg committed
136 137
func (s *Set) Availability(file string) []protocol.NodeID {
	return ldbAvailability(s.db, []byte(s.repo), []byte(file))
138 139
}

140
func (s *Set) LocalVersion(node protocol.NodeID) uint64 {
141 142
	s.mutex.Lock()
	defer s.mutex.Unlock()
143
	return s.localVersion[node]
144
}