@@ -20,7 +20,6 @@ import (
20
20
"bufio"
21
21
"encoding/json"
22
22
"fmt"
23
- "io/ioutil"
24
23
"os"
25
24
"path/filepath"
26
25
"sort"
@@ -75,13 +74,6 @@ type accountCache struct {
75
74
fileC fileCache
76
75
}
77
76
78
- // fileCache is a cache of files seen during scan of keystore
79
- type fileCache struct {
80
- all * set.SetNonTS // list of all files
81
- mtime time.Time // latest mtime seen
82
- mu sync.RWMutex
83
- }
84
-
85
77
func newAccountCache (keydir string ) (* accountCache , chan struct {}) {
86
78
ac := & accountCache {
87
79
keydir : keydir ,
@@ -236,66 +228,22 @@ func (ac *accountCache) close() {
236
228
ac .mu .Unlock ()
237
229
}
238
230
239
- // scanFiles performs a new scan on the given directory, compares against the already
240
- // cached filenames, and returns file sets: new, missing , modified
241
- func (fc * fileCache ) scanFiles (keyDir string ) (set.Interface , set.Interface , set.Interface , error ) {
242
- t0 := time .Now ()
243
- files , err := ioutil .ReadDir (keyDir )
244
- t1 := time .Now ()
245
- if err != nil {
246
- return nil , nil , nil , err
247
- }
248
- fc .mu .RLock ()
249
- prevMtime := fc .mtime
250
- fc .mu .RUnlock ()
251
-
252
- filesNow := set .NewNonTS ()
253
- moddedFiles := set .NewNonTS ()
254
- var newMtime time.Time
255
- for _ , fi := range files {
256
- modTime := fi .ModTime ()
257
- path := filepath .Join (keyDir , fi .Name ())
258
- if skipKeyFile (fi ) {
259
- log .Trace ("Ignoring file on account scan" , "path" , path )
260
- continue
261
- }
262
- filesNow .Add (path )
263
- if modTime .After (prevMtime ) {
264
- moddedFiles .Add (path )
265
- }
266
- if modTime .After (newMtime ) {
267
- newMtime = modTime
268
- }
269
- }
270
- t2 := time .Now ()
271
-
272
- fc .mu .Lock ()
273
- // Missing = previous - current
274
- missing := set .Difference (fc .all , filesNow )
275
- // New = current - previous
276
- newFiles := set .Difference (filesNow , fc .all )
277
- // Modified = modified - new
278
- modified := set .Difference (moddedFiles , newFiles )
279
- fc .all = filesNow
280
- fc .mtime = newMtime
281
- fc .mu .Unlock ()
282
- t3 := time .Now ()
283
- log .Debug ("FS scan times" , "list" , t1 .Sub (t0 ), "set" , t2 .Sub (t1 ), "diff" , t3 .Sub (t2 ))
284
- return newFiles , missing , modified , nil
285
- }
286
-
287
231
// scanAccounts checks if any changes have occurred on the filesystem, and
288
232
// updates the account cache accordingly
289
233
func (ac * accountCache ) scanAccounts () error {
290
- newFiles , missingFiles , modified , err := ac . fileC . scanFiles ( ac . keydir )
291
- t1 := time . Now ( )
234
+ // Scan the entire folder metadata for file changes
235
+ creates , deletes , updates , err := ac . fileC . scan ( ac . keydir )
292
236
if err != nil {
293
237
log .Debug ("Failed to reload keystore contents" , "err" , err )
294
238
return err
295
239
}
240
+ if creates .Size () == 0 && deletes .Size () == 0 && updates .Size () == 0 {
241
+ return nil
242
+ }
243
+ // Create a helper method to scan the contents of the key files
296
244
var (
297
- buf = new (bufio.Reader )
298
- keyJSON struct {
245
+ buf = new (bufio.Reader )
246
+ key struct {
299
247
Address string `json:"address"`
300
248
}
301
249
)
@@ -308,9 +256,9 @@ func (ac *accountCache) scanAccounts() error {
308
256
defer fd .Close ()
309
257
buf .Reset (fd )
310
258
// Parse the address.
311
- keyJSON .Address = ""
312
- err = json .NewDecoder (buf ).Decode (& keyJSON )
313
- addr := common .HexToAddress (keyJSON .Address )
259
+ key .Address = ""
260
+ err = json .NewDecoder (buf ).Decode (& key )
261
+ addr := common .HexToAddress (key .Address )
314
262
switch {
315
263
case err != nil :
316
264
log .Debug ("Failed to decode keystore key" , "path" , path , "err" , err )
@@ -321,47 +269,30 @@ func (ac *accountCache) scanAccounts() error {
321
269
}
322
270
return nil
323
271
}
272
+ // Process all the file diffs
273
+ start := time .Now ()
324
274
325
- for _ , p := range newFiles .List () {
326
- path , _ := p .(string )
327
- a := readAccount (path )
328
- if a != nil {
275
+ for _ , p := range creates .List () {
276
+ if a := readAccount (p .(string )); a != nil {
329
277
ac .add (* a )
330
278
}
331
279
}
332
- for _ , p := range missingFiles .List () {
333
- path , _ := p .(string )
334
- ac .deleteByFile (path )
280
+ for _ , p := range deletes .List () {
281
+ ac .deleteByFile (p .(string ))
335
282
}
336
-
337
- for _ , p := range modified .List () {
338
- path , _ := p .(string )
339
- a := readAccount (path )
283
+ for _ , p := range updates .List () {
284
+ path := p .(string )
340
285
ac .deleteByFile (path )
341
- if a != nil {
286
+ if a := readAccount ( path ); a != nil {
342
287
ac .add (* a )
343
288
}
344
289
}
345
-
346
- t2 := time .Now ()
290
+ end := time .Now ()
347
291
348
292
select {
349
293
case ac .notify <- struct {}{}:
350
294
default :
351
295
}
352
- log .Trace ("Handled keystore changes" , "time" , t2 .Sub (t1 ))
353
-
296
+ log .Trace ("Handled keystore changes" , "time" , end .Sub (start ))
354
297
return nil
355
298
}
356
-
357
- func skipKeyFile (fi os.FileInfo ) bool {
358
- // Skip editor backups and UNIX-style hidden files.
359
- if strings .HasSuffix (fi .Name (), "~" ) || strings .HasPrefix (fi .Name (), "." ) {
360
- return true
361
- }
362
- // Skip misc special files, directories (yes, symlinks too).
363
- if fi .IsDir () || fi .Mode ()& os .ModeType != 0 {
364
- return true
365
- }
366
- return false
367
- }
0 commit comments