]> Cypherpunks repositories - gostls13.git/commitdiff
os/user: cache the result of user.Current
authorSameer Ajmani <sameer@golang.org>
Mon, 6 Feb 2017 18:21:57 +0000 (13:21 -0500)
committerSameer Ajmani <sameer@golang.org>
Mon, 6 Feb 2017 18:49:52 +0000 (18:49 +0000)
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 <iant@golang.org>
src/os/user/lookup.go
src/os/user/user_test.go

index 3b4421badd5d336bfebe265f2a1607ddf4337c52..2243a25788aed0bb65130d3227d62a1d056cb06f 100644 (file)
@@ -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)
 }
 
index 9d8d94d8dae2243f8deeeebf660317f075cf1980..73e8ed8de732c5040a3089017dab7d87be69365f 100644 (file)
@@ -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)