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