github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/libnetwork/datastore/cache.go (about)

     1  package datastore
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"sync"
     7  
     8  	"github.com/docker/libkv/store"
     9  )
    10  
    11  type kvMap map[string]KVObject
    12  
    13  type cache struct {
    14  	sync.Mutex
    15  	kmm map[string]kvMap
    16  	ds  *datastore
    17  }
    18  
    19  func newCache(ds *datastore) *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(key string, 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  }