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  }