github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/teams/loadkeycache.go (about)

     1  package teams
     2  
     3  import (
     4  	"github.com/keybase/client/go/libkb"
     5  	"github.com/keybase/client/go/protocol/keybase1"
     6  )
     7  
     8  type uvAndKey struct {
     9  	UV  keybase1.UserVersion
    10  	Key keybase1.PublicKeyV2NaCl
    11  }
    12  
    13  // loadKeyCache is a short-lived cache for loading keys and linkmaps for TeamLoader.
    14  // It must be short-lived since it has no expiration or eviction.
    15  // Not threadsafe.
    16  type loadKeyCache struct {
    17  	userKeyCache     map[keybase1.UID]map[keybase1.KID]uvAndKey
    18  	userLinkMapCache map[keybase1.UID]map[keybase1.Seqno]keybase1.LinkID
    19  	cacheHits        int64
    20  }
    21  
    22  func newLoadKeyCache() *loadKeyCache {
    23  	return &loadKeyCache{
    24  		userKeyCache:     make(map[keybase1.UID]map[keybase1.KID]uvAndKey),
    25  		userLinkMapCache: make(map[keybase1.UID]map[keybase1.Seqno]keybase1.LinkID),
    26  	}
    27  }
    28  
    29  func (c *loadKeyCache) loadKeyV2(mctx libkb.MetaContext, uid keybase1.UID, kid keybase1.KID) (
    30  	uv keybase1.UserVersion, pubKey *keybase1.PublicKeyV2NaCl, linkMap linkMapT, err error) {
    31  	mctx, tbs := mctx.WithTimeBuckets()
    32  	defer tbs.Record("loadKeyCache.loadKeyV2")()
    33  
    34  	// Look in the cache first
    35  	m2, ok := c.userKeyCache[uid]
    36  	if ok {
    37  		v, ok := m2[kid]
    38  		if ok {
    39  			c.cacheHits++
    40  			return v.UV, &v.Key, c.userLinkMapCache[uid], nil
    41  		}
    42  	}
    43  
    44  	// Load the user. LoadKeyV2 handles punching through the cache when needed.
    45  	user, upak, _, err := mctx.G().GetUPAKLoader().LoadKeyV2(mctx.Ctx(), uid, kid)
    46  	if err != nil {
    47  		return uv, pubKey, linkMap, err
    48  	}
    49  	if user == nil || upak == nil {
    50  		return uv, pubKey, linkMap, libkb.NotFoundError{}
    51  	}
    52  
    53  	// Put all the user's keys into the cache
    54  	c.userLinkMapCache[uid] = upak.SeqnoLinkIDs
    55  	if c.userKeyCache[uid] == nil {
    56  		c.userKeyCache[uid] = make(map[keybase1.KID]uvAndKey)
    57  	}
    58  	for _, user := range append(upak.PastIncarnations, upak.Current) {
    59  		pubKey, ok := user.DeviceKeys[kid]
    60  		if ok {
    61  			c.userKeyCache[uid][kid] = uvAndKey{
    62  				UV:  user.ToUserVersion(),
    63  				Key: pubKey,
    64  			}
    65  		}
    66  	}
    67  
    68  	// Get from the just-updated cache
    69  	v, ok := c.userKeyCache[uid][kid]
    70  	if !ok {
    71  		return uv, nil, nil, libkb.NotFoundError{Msg: "Not found: Key for user"}
    72  	}
    73  	return v.UV, &v.Key, c.userLinkMapCache[uid], nil
    74  }