github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/teams/storage/merkle.go (about) 1 package storage 2 3 import ( 4 "fmt" 5 lru "github.com/hashicorp/golang-lru" 6 "github.com/keybase/client/go/libkb" 7 "github.com/keybase/client/go/protocol/keybase1" 8 "log" 9 "sync" 10 ) 11 12 // Merkle stores when a team last polled merkle. Threadsafe. 13 type Merkle struct { 14 sync.Mutex 15 lru *lru.Cache 16 } 17 18 // Increment to invalidate the disk cache. 19 const merkleDiskStorageVersion = 1 20 const merkleMemCacheLRUSize = 2000 21 22 type merkleDiskStorageItem struct { 23 Version int `codec:"V"` 24 PolledAt keybase1.Time `codec:"T"` 25 } 26 27 func NewMerkle() *Merkle { 28 nlru, err := lru.New(merkleMemCacheLRUSize) 29 if err != nil { 30 // lru.New only panics if size <= 0 31 log.Panicf("Could not create lru cache: %v", err) 32 } 33 return &Merkle{ 34 lru: nlru, 35 } 36 } 37 38 func merkleKey(teamID keybase1.TeamID, public bool) libkb.DbKey { 39 key := genericStringKey(teamID, public) 40 dbKey := libkb.DbKey{ 41 Typ: libkb.DBTeamMerkleCheck, 42 Key: key, 43 } 44 return dbKey 45 } 46 47 func (s *Merkle) Put(mctx libkb.MetaContext, teamID keybase1.TeamID, public bool, time keybase1.Time) { 48 s.Lock() 49 defer s.Unlock() 50 key := merkleKey(teamID, public) 51 s.lru.Add(key.Key, time) 52 obj := merkleDiskStorageItem{ 53 Version: merkleDiskStorageVersion, 54 PolledAt: time, 55 } 56 mctx.VLogf(libkb.VLog0, "teams/storage.Merkle#Put(%s) <- %d", teamID, time) 57 err := mctx.G().LocalDb.PutObj(key, nil, obj) 58 if err != nil { 59 mctx.Warning("teams/storage.Merkle: Failed to put key %+v: %s", key, err.Error()) 60 } 61 } 62 63 func (s *Merkle) Get(mctx libkb.MetaContext, teamID keybase1.TeamID, public bool) (polledAt *keybase1.Time) { 64 s.Lock() 65 defer s.Unlock() 66 key := merkleKey(teamID, public) 67 68 report := func(res string, ret *keybase1.Time) { 69 var s string 70 if ret != nil { 71 s = fmt.Sprintf(" -> %d", *ret) 72 } 73 mctx.VLogf(libkb.VLog0, "teams/storage.Merkle#Get(%s) -> %s%s", teamID, res, s) 74 } 75 76 untyped, ok := s.lru.Get(key.Key) 77 if ok { 78 ret, ok := untyped.(keybase1.Time) 79 if ok { 80 report("hit mem", &ret) 81 return &ret 82 } 83 mctx.Warning("teams/storage.Merkle: Pulled object at %+v of wrong type: %T", key, untyped) 84 } 85 var tmp merkleDiskStorageItem 86 found, err := mctx.G().LocalDb.GetInto(&tmp, key) 87 if !found { 88 report("missed", nil) 89 return nil 90 } 91 if err != nil { 92 mctx.Warning("teams/storage.Merkle: error fetching %+v from disk: %s", key, err.Error()) 93 } 94 if tmp.Version != merkleDiskStorageVersion { 95 mctx.Debug("teams/storage.Merkle: skipping old version %d for key %+v", tmp.Version, key) 96 return nil 97 } 98 report("hit disk", &tmp.PolledAt) 99 return &tmp.PolledAt 100 }