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