From: Sameer Ajmani Date: Mon, 6 Feb 2017 18:21:57 +0000 (-0500) Subject: os/user: cache the result of user.Current X-Git-Tag: go1.9beta1~1728 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=2ca5d105b00353d3f3aa4da023e405b0550117d0;p=gostls13.git 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 --- diff --git a/src/os/user/lookup.go b/src/os/user/lookup.go index 3b4421badd..2243a25788 100644 --- a/src/os/user/lookup.go +++ b/src/os/user/lookup.go @@ -4,20 +4,40 @@ package user +import "sync" + // Current returns the current user. func Current() (*User, error) { - return current() + cache.Do(func() { cache.u, cache.err = current() }) + if cache.err != nil { + return nil, cache.err + } + u := *cache.u // copy + return &u, nil +} + +// cache of the current user +var cache struct { + sync.Once + u *User + err error } // Lookup looks up a user by username. If the user cannot be found, the // returned error is of type UnknownUserError. func Lookup(username string) (*User, error) { + if u, err := Current(); err == nil && u.Username == username { + return u, err + } return lookupUser(username) } // LookupId looks up a user by userid. If the user cannot be found, the // returned error is of type UnknownUserIdError. func LookupId(uid string) (*User, error) { + if u, err := Current(); err == nil && u.Uid == uid { + return u, err + } return lookupUserId(uid) } diff --git a/src/os/user/user_test.go b/src/os/user/user_test.go index 9d8d94d8da..73e8ed8de7 100644 --- a/src/os/user/user_test.go +++ b/src/os/user/user_test.go @@ -31,6 +31,12 @@ func TestCurrent(t *testing.T) { } } +func BenchmarkCurrent(b *testing.B) { + for i := 0; i < b.N; i++ { + Current() + } +} + func compare(t *testing.T, want, got *User) { if want.Uid != got.Uid { t.Errorf("got Uid=%q; want %q", got.Uid, want.Uid)