Browse Source

Keep LocalSize data in RAM

Jakob Borg 10 years ago
parent
commit
d4f81e8791
3 changed files with 64 additions and 12 deletions
  1. 15 1
      lib/db/leveldb.go
  2. 48 1
      lib/db/set.go
  3. 1 10
      lib/model/model.go

+ 15 - 1
lib/db/leveldb.go

@@ -167,6 +167,10 @@ func globalKeyFolder(key []byte) []byte {
 	return folder[:izero]
 }
 
+func isLocalDevice(dev []byte) bool {
+	return bytes.Equal(dev, protocol.LocalDeviceID[:])
+}
+
 type deletionHandler func(db dbReader, batch dbWriter, folder, device, name []byte, dbi iterator.Iterator) int64
 
 func ldbGenericReplace(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo, deleteFn deletionHandler) int64 {
@@ -297,7 +301,7 @@ func ldbReplace(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo) i
 	})
 }
 
-func ldbUpdate(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo) int64 {
+func ldbUpdate(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo, size *sizeTracker) int64 {
 	runtime.GC()
 
 	batch := new(leveldb.Batch)
@@ -314,12 +318,17 @@ func ldbUpdate(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo) in
 
 	var maxLocalVer int64
 	var fk []byte
+	localDev := isLocalDevice(device)
 	for _, f := range fs {
 		name := []byte(f.Name)
 		fk = deviceKeyInto(fk[:cap(fk)], folder, device, name)
 		l.Debugf("snap.Get %p %x", snap, fk)
 		bs, err := snap.Get(fk, nil)
 		if err == leveldb.ErrNotFound {
+			if localDev {
+				size.addFile(f)
+			}
+
 			if lv := ldbInsert(batch, folder, device, f); lv > maxLocalVer {
 				maxLocalVer = lv
 			}
@@ -339,6 +348,11 @@ func ldbUpdate(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo) in
 		// Flags might change without the version being bumped when we set the
 		// invalid flag on an existing file.
 		if !ef.Version.Equal(f.Version) || ef.Flags != f.Flags {
+			if localDev {
+				size.removeFile(ef)
+				size.addFile(f)
+			}
+
 			if lv := ldbInsert(batch, folder, device, f); lv > maxLocalVer {
 				maxLocalVer = lv
 			}

+ 48 - 1
lib/db/set.go

@@ -13,6 +13,8 @@
 package db
 
 import (
+	stdsync "sync"
+
 	"github.com/syncthing/syncthing/lib/osutil"
 	"github.com/syncthing/syncthing/lib/protocol"
 	"github.com/syncthing/syncthing/lib/sync"
@@ -25,6 +27,7 @@ type FileSet struct {
 	folder       string
 	db           *leveldb.DB
 	blockmap     *BlockMap
+	sizeTracker
 }
 
 // FileIntf is the set of methods implemented by both protocol.FileInfo and
@@ -43,6 +46,47 @@ type FileIntf interface {
 // continue iteration, false to stop.
 type Iterator func(f FileIntf) bool
 
+type sizeTracker struct {
+	files   int
+	deleted int
+	bytes   int64
+	mut     stdsync.Mutex
+}
+
+func (s *sizeTracker) addFile(f FileIntf) {
+	if f.IsInvalid() {
+		return
+	}
+	s.mut.Lock()
+	if f.IsDeleted() {
+		s.deleted++
+	} else {
+		s.files++
+	}
+	s.bytes += f.Size()
+	s.mut.Unlock()
+}
+
+func (s *sizeTracker) removeFile(f FileIntf) {
+	if f.IsInvalid() {
+		return
+	}
+	s.mut.Lock()
+	if f.IsDeleted() {
+		s.deleted--
+	} else {
+		s.files--
+	}
+	s.bytes -= f.Size()
+	s.mut.Unlock()
+}
+
+func (s *sizeTracker) Size() (files, deleted int, bytes int64) {
+	s.mut.Lock()
+	defer s.mut.Unlock()
+	return s.files, s.deleted, s.bytes
+}
+
 func NewFileSet(folder string, db *leveldb.DB) *FileSet {
 	var s = FileSet{
 		localVersion: make(map[protocol.DeviceID]int64),
@@ -60,6 +104,9 @@ func NewFileSet(folder string, db *leveldb.DB) *FileSet {
 		if f.LocalVersion > s.localVersion[deviceID] {
 			s.localVersion[deviceID] = f.LocalVersion
 		}
+		if deviceID == protocol.LocalDeviceID {
+			s.addFile(f)
+		}
 		return true
 	})
 	l.Debugf("loaded localVersion for %q: %#v", folder, s.localVersion)
@@ -102,7 +149,7 @@ func (s *FileSet) Update(device protocol.DeviceID, fs []protocol.FileInfo) {
 		s.blockmap.Discard(discards)
 		s.blockmap.Update(updates)
 	}
-	if lv := ldbUpdate(s.db, []byte(s.folder), device[:], fs); lv > s.localVersion[device] {
+	if lv := ldbUpdate(s.db, []byte(s.folder), device[:], fs, &s.sizeTracker); lv > s.localVersion[device] {
 		s.localVersion[device] = lv
 	}
 }

+ 1 - 10
lib/model/model.go

@@ -406,16 +406,7 @@ func (m *Model) LocalSize(folder string) (nfiles, deleted int, bytes int64) {
 	m.fmut.RLock()
 	defer m.fmut.RUnlock()
 	if rf, ok := m.folderFiles[folder]; ok {
-		rf.WithHaveTruncated(protocol.LocalDeviceID, func(f db.FileIntf) bool {
-			if f.IsInvalid() {
-				return true
-			}
-			fs, de, by := sizeOfFile(f)
-			nfiles += fs
-			deleted += de
-			bytes += by
-			return true
-		})
+		nfiles, deleted, bytes = rf.Size()
 	}
 	return
 }