github.com/moby/docker@v26.1.3+incompatible/libnetwork/datastore/cache.go (about) 1 package datastore 2 3 import ( 4 "fmt" 5 "sync" 6 7 store "github.com/docker/docker/libnetwork/internal/kvstore" 8 ) 9 10 type kvMap map[string]KVObject 11 12 type cache struct { 13 mu sync.Mutex 14 kmm map[string]kvMap 15 ds store.Store 16 } 17 18 func newCache(ds store.Store) *cache { 19 return &cache{kmm: make(map[string]kvMap), ds: ds} 20 } 21 22 func (c *cache) kmap(kvObject KVObject) (kvMap, error) { 23 var err error 24 25 c.mu.Lock() 26 keyPrefix := Key(kvObject.KeyPrefix()...) 27 kmap, ok := c.kmm[keyPrefix] 28 c.mu.Unlock() 29 30 if ok { 31 return kmap, nil 32 } 33 34 kmap = kvMap{} 35 36 kvList, err := c.ds.List(keyPrefix) 37 if err != nil { 38 if err == store.ErrKeyNotFound { 39 // If the store doesn't have anything then there is nothing to 40 // populate in the cache. Just bail out. 41 goto out 42 } 43 44 return nil, fmt.Errorf("error while populating kmap: %v", err) 45 } 46 47 for _, kvPair := range kvList { 48 // Ignore empty kvPair values 49 if len(kvPair.Value) == 0 { 50 continue 51 } 52 53 dstO := kvObject.New() 54 err = dstO.SetValue(kvPair.Value) 55 if err != nil { 56 return nil, err 57 } 58 59 // Make sure the object has a correct view of the DB index in 60 // case we need to modify it and update the DB. 61 dstO.SetIndex(kvPair.LastIndex) 62 63 kmap[Key(dstO.Key()...)] = dstO 64 } 65 66 out: 67 // There may multiple go routines racing to fill the 68 // cache. The one which places the kmap in c.kmm first 69 // wins. The others should just use what the first populated. 70 c.mu.Lock() 71 kmapNew, ok := c.kmm[keyPrefix] 72 if ok { 73 c.mu.Unlock() 74 return kmapNew, nil 75 } 76 77 c.kmm[keyPrefix] = kmap 78 c.mu.Unlock() 79 80 return kmap, nil 81 } 82 83 func (c *cache) add(kvObject KVObject, atomic bool) error { 84 kmap, err := c.kmap(kvObject) 85 if err != nil { 86 return err 87 } 88 89 c.mu.Lock() 90 // If atomic is true, cache needs to maintain its own index 91 // for atomicity and the add needs to be atomic. 92 if atomic { 93 if prev, ok := kmap[Key(kvObject.Key()...)]; ok { 94 if prev.Index() != kvObject.Index() { 95 c.mu.Unlock() 96 return ErrKeyModified 97 } 98 } 99 100 // Increment index 101 index := kvObject.Index() 102 index++ 103 kvObject.SetIndex(index) 104 } 105 106 kmap[Key(kvObject.Key()...)] = kvObject 107 c.mu.Unlock() 108 return nil 109 } 110 111 func (c *cache) del(kvObject KVObject, atomic bool) error { 112 kmap, err := c.kmap(kvObject) 113 if err != nil { 114 return err 115 } 116 117 c.mu.Lock() 118 // If atomic is true, cache needs to maintain its own index 119 // for atomicity and del needs to be atomic. 120 if atomic { 121 if prev, ok := kmap[Key(kvObject.Key()...)]; ok { 122 if prev.Index() != kvObject.Index() { 123 c.mu.Unlock() 124 return ErrKeyModified 125 } 126 } 127 } 128 129 delete(kmap, Key(kvObject.Key()...)) 130 c.mu.Unlock() 131 return nil 132 } 133 134 func (c *cache) get(kvObject KVObject) error { 135 kmap, err := c.kmap(kvObject) 136 if err != nil { 137 return err 138 } 139 140 c.mu.Lock() 141 defer c.mu.Unlock() 142 143 o, ok := kmap[Key(kvObject.Key()...)] 144 if !ok { 145 return ErrKeyNotFound 146 } 147 148 return o.CopyTo(kvObject) 149 } 150 151 func (c *cache) list(kvObject KVObject) ([]KVObject, error) { 152 kmap, err := c.kmap(kvObject) 153 if err != nil { 154 return nil, err 155 } 156 157 c.mu.Lock() 158 defer c.mu.Unlock() 159 160 var kvol []KVObject 161 for _, v := range kmap { 162 kvol = append(kvol, v) 163 } 164 165 return kvol, nil 166 }