From 2ca5d105b00353d3f3aa4da023e405b0550117d0 Mon Sep 17 00:00:00 2001 From: Sameer Ajmani Date: Mon, 6 Feb 2017 13:21:57 -0500 Subject: [PATCH] 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 --- src/os/user/lookup.go | 22 +++++++++++++++++++++- src/os/user/user_test.go | 6 ++++++ 2 files changed, 27 insertions(+), 1 deletion(-) 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) -- 2.50.0