Skip to content

Commit 2ca5d10

Browse files
committed
os/user: cache the result of user.Current
This has a notable impact on systems with very large passwd files. Before: BenchmarkCurrent-12 30000 42546 ns/op After: BenchmarkCurrent-12 20000000 77.5 ns/op Saved in perf dashboard: https://perf.golang.org/search?q=upload:20170206.1 Fixes #11625 Change-Id: Iebc9bf122cc64a4cab24ac06843c7b2bc450ded9 Reviewed-on: https://go-review.googlesource.com/36391 Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent fd37b8c commit 2ca5d10

File tree

2 files changed

+27
-1
lines changed

2 files changed

+27
-1
lines changed

src/os/user/lookup.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,40 @@
44

55
package user
66

7+
import "sync"
8+
79
// Current returns the current user.
810
func Current() (*User, error) {
9-
return current()
11+
cache.Do(func() { cache.u, cache.err = current() })
12+
if cache.err != nil {
13+
return nil, cache.err
14+
}
15+
u := *cache.u // copy
16+
return &u, nil
17+
}
18+
19+
// cache of the current user
20+
var cache struct {
21+
sync.Once
22+
u *User
23+
err error
1024
}
1125

1226
// Lookup looks up a user by username. If the user cannot be found, the
1327
// returned error is of type UnknownUserError.
1428
func Lookup(username string) (*User, error) {
29+
if u, err := Current(); err == nil && u.Username == username {
30+
return u, err
31+
}
1532
return lookupUser(username)
1633
}
1734

1835
// LookupId looks up a user by userid. If the user cannot be found, the
1936
// returned error is of type UnknownUserIdError.
2037
func LookupId(uid string) (*User, error) {
38+
if u, err := Current(); err == nil && u.Uid == uid {
39+
return u, err
40+
}
2141
return lookupUserId(uid)
2242
}
2343

src/os/user/user_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ func TestCurrent(t *testing.T) {
3131
}
3232
}
3333

34+
func BenchmarkCurrent(b *testing.B) {
35+
for i := 0; i < b.N; i++ {
36+
Current()
37+
}
38+
}
39+
3440
func compare(t *testing.T, want, got *User) {
3541
if want.Uid != got.Uid {
3642
t.Errorf("got Uid=%q; want %q", got.Uid, want.Uid)

0 commit comments

Comments
 (0)