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  }