|
@@ -20,7 +20,6 @@ import (
|
|
|
"bufio"
|
|
"bufio"
|
|
|
"encoding/json"
|
|
"encoding/json"
|
|
|
"fmt"
|
|
"fmt"
|
|
|
- "io/ioutil"
|
|
|
|
|
"os"
|
|
"os"
|
|
|
"path/filepath"
|
|
"path/filepath"
|
|
|
"sort"
|
|
"sort"
|
|
@@ -75,13 +74,6 @@ type accountCache struct {
|
|
|
fileC fileCache
|
|
fileC fileCache
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// fileCache is a cache of files seen during scan of keystore
|
|
|
|
|
-type fileCache struct {
|
|
|
|
|
- all *set.SetNonTS // list of all files
|
|
|
|
|
- mtime time.Time // latest mtime seen
|
|
|
|
|
- mu sync.RWMutex
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
func newAccountCache(keydir string) (*accountCache, chan struct{}) {
|
|
func newAccountCache(keydir string) (*accountCache, chan struct{}) {
|
|
|
ac := &accountCache{
|
|
ac := &accountCache{
|
|
|
keydir: keydir,
|
|
keydir: keydir,
|
|
@@ -236,66 +228,22 @@ func (ac *accountCache) close() {
|
|
|
ac.mu.Unlock()
|
|
ac.mu.Unlock()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// scanFiles performs a new scan on the given directory, compares against the already
|
|
|
|
|
-// cached filenames, and returns file sets: new, missing , modified
|
|
|
|
|
-func (fc *fileCache) scanFiles(keyDir string) (set.Interface, set.Interface, set.Interface, error) {
|
|
|
|
|
- t0 := time.Now()
|
|
|
|
|
- files, err := ioutil.ReadDir(keyDir)
|
|
|
|
|
- t1 := time.Now()
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return nil, nil, nil, err
|
|
|
|
|
- }
|
|
|
|
|
- fc.mu.RLock()
|
|
|
|
|
- prevMtime := fc.mtime
|
|
|
|
|
- fc.mu.RUnlock()
|
|
|
|
|
-
|
|
|
|
|
- filesNow := set.NewNonTS()
|
|
|
|
|
- moddedFiles := set.NewNonTS()
|
|
|
|
|
- var newMtime time.Time
|
|
|
|
|
- for _, fi := range files {
|
|
|
|
|
- modTime := fi.ModTime()
|
|
|
|
|
- path := filepath.Join(keyDir, fi.Name())
|
|
|
|
|
- if skipKeyFile(fi) {
|
|
|
|
|
- log.Trace("Ignoring file on account scan", "path", path)
|
|
|
|
|
- continue
|
|
|
|
|
- }
|
|
|
|
|
- filesNow.Add(path)
|
|
|
|
|
- if modTime.After(prevMtime) {
|
|
|
|
|
- moddedFiles.Add(path)
|
|
|
|
|
- }
|
|
|
|
|
- if modTime.After(newMtime) {
|
|
|
|
|
- newMtime = modTime
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- t2 := time.Now()
|
|
|
|
|
-
|
|
|
|
|
- fc.mu.Lock()
|
|
|
|
|
- // Missing = previous - current
|
|
|
|
|
- missing := set.Difference(fc.all, filesNow)
|
|
|
|
|
- // New = current - previous
|
|
|
|
|
- newFiles := set.Difference(filesNow, fc.all)
|
|
|
|
|
- // Modified = modified - new
|
|
|
|
|
- modified := set.Difference(moddedFiles, newFiles)
|
|
|
|
|
- fc.all = filesNow
|
|
|
|
|
- fc.mtime = newMtime
|
|
|
|
|
- fc.mu.Unlock()
|
|
|
|
|
- t3 := time.Now()
|
|
|
|
|
- log.Debug("FS scan times", "list", t1.Sub(t0), "set", t2.Sub(t1), "diff", t3.Sub(t2))
|
|
|
|
|
- return newFiles, missing, modified, nil
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
// scanAccounts checks if any changes have occurred on the filesystem, and
|
|
// scanAccounts checks if any changes have occurred on the filesystem, and
|
|
|
// updates the account cache accordingly
|
|
// updates the account cache accordingly
|
|
|
func (ac *accountCache) scanAccounts() error {
|
|
func (ac *accountCache) scanAccounts() error {
|
|
|
- newFiles, missingFiles, modified, err := ac.fileC.scanFiles(ac.keydir)
|
|
|
|
|
- t1 := time.Now()
|
|
|
|
|
|
|
+ // Scan the entire folder metadata for file changes
|
|
|
|
|
+ creates, deletes, updates, err := ac.fileC.scan(ac.keydir)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
log.Debug("Failed to reload keystore contents", "err", err)
|
|
log.Debug("Failed to reload keystore contents", "err", err)
|
|
|
return err
|
|
return err
|
|
|
}
|
|
}
|
|
|
|
|
+ if creates.Size() == 0 && deletes.Size() == 0 && updates.Size() == 0 {
|
|
|
|
|
+ return nil
|
|
|
|
|
+ }
|
|
|
|
|
+ // Create a helper method to scan the contents of the key files
|
|
|
var (
|
|
var (
|
|
|
- buf = new(bufio.Reader)
|
|
|
|
|
- keyJSON struct {
|
|
|
|
|
|
|
+ buf = new(bufio.Reader)
|
|
|
|
|
+ key struct {
|
|
|
Address string `json:"address"`
|
|
Address string `json:"address"`
|
|
|
}
|
|
}
|
|
|
)
|
|
)
|
|
@@ -308,9 +256,9 @@ func (ac *accountCache) scanAccounts() error {
|
|
|
defer fd.Close()
|
|
defer fd.Close()
|
|
|
buf.Reset(fd)
|
|
buf.Reset(fd)
|
|
|
// Parse the address.
|
|
// Parse the address.
|
|
|
- keyJSON.Address = ""
|
|
|
|
|
- err = json.NewDecoder(buf).Decode(&keyJSON)
|
|
|
|
|
- addr := common.HexToAddress(keyJSON.Address)
|
|
|
|
|
|
|
+ key.Address = ""
|
|
|
|
|
+ err = json.NewDecoder(buf).Decode(&key)
|
|
|
|
|
+ addr := common.HexToAddress(key.Address)
|
|
|
switch {
|
|
switch {
|
|
|
case err != nil:
|
|
case err != nil:
|
|
|
log.Debug("Failed to decode keystore key", "path", path, "err", err)
|
|
log.Debug("Failed to decode keystore key", "path", path, "err", err)
|
|
@@ -321,47 +269,30 @@ func (ac *accountCache) scanAccounts() error {
|
|
|
}
|
|
}
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
|
|
+ // Process all the file diffs
|
|
|
|
|
+ start := time.Now()
|
|
|
|
|
|
|
|
- for _, p := range newFiles.List() {
|
|
|
|
|
- path, _ := p.(string)
|
|
|
|
|
- a := readAccount(path)
|
|
|
|
|
- if a != nil {
|
|
|
|
|
|
|
+ for _, p := range creates.List() {
|
|
|
|
|
+ if a := readAccount(p.(string)); a != nil {
|
|
|
ac.add(*a)
|
|
ac.add(*a)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- for _, p := range missingFiles.List() {
|
|
|
|
|
- path, _ := p.(string)
|
|
|
|
|
- ac.deleteByFile(path)
|
|
|
|
|
|
|
+ for _, p := range deletes.List() {
|
|
|
|
|
+ ac.deleteByFile(p.(string))
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- for _, p := range modified.List() {
|
|
|
|
|
- path, _ := p.(string)
|
|
|
|
|
- a := readAccount(path)
|
|
|
|
|
|
|
+ for _, p := range updates.List() {
|
|
|
|
|
+ path := p.(string)
|
|
|
ac.deleteByFile(path)
|
|
ac.deleteByFile(path)
|
|
|
- if a != nil {
|
|
|
|
|
|
|
+ if a := readAccount(path); a != nil {
|
|
|
ac.add(*a)
|
|
ac.add(*a)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- t2 := time.Now()
|
|
|
|
|
|
|
+ end := time.Now()
|
|
|
|
|
|
|
|
select {
|
|
select {
|
|
|
case ac.notify <- struct{}{}:
|
|
case ac.notify <- struct{}{}:
|
|
|
default:
|
|
default:
|
|
|
}
|
|
}
|
|
|
- log.Trace("Handled keystore changes", "time", t2.Sub(t1))
|
|
|
|
|
-
|
|
|
|
|
|
|
+ log.Trace("Handled keystore changes", "time", end.Sub(start))
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-func skipKeyFile(fi os.FileInfo) bool {
|
|
|
|
|
- // Skip editor backups and UNIX-style hidden files.
|
|
|
|
|
- if strings.HasSuffix(fi.Name(), "~") || strings.HasPrefix(fi.Name(), ".") {
|
|
|
|
|
- return true
|
|
|
|
|
- }
|
|
|
|
|
- // Skip misc special files, directories (yes, symlinks too).
|
|
|
|
|
- if fi.IsDir() || fi.Mode()&os.ModeType != 0 {
|
|
|
|
|
- return true
|
|
|
|
|
- }
|
|
|
|
|
- return false
|
|
|
|
|
-}
|
|
|