...

Source file src/helm.sh/helm/v3/pkg/storage/driver/memory.go

Documentation: helm.sh/helm/v3/pkg/storage/driver

     1  /*
     2  Copyright The Helm Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package driver
    18  
    19  import (
    20  	"strconv"
    21  	"strings"
    22  	"sync"
    23  
    24  	rspb "helm.sh/helm/v3/pkg/release"
    25  )
    26  
    27  var _ Driver = (*Memory)(nil)
    28  
    29  const (
    30  	// MemoryDriverName is the string name of this driver.
    31  	MemoryDriverName = "Memory"
    32  
    33  	defaultNamespace = "default"
    34  )
    35  
    36  // A map of release names to list of release records
    37  type memReleases map[string]records
    38  
    39  // Memory is the in-memory storage driver implementation.
    40  type Memory struct {
    41  	sync.RWMutex
    42  	namespace string
    43  	// A map of namespaces to releases
    44  	cache map[string]memReleases
    45  }
    46  
    47  // NewMemory initializes a new memory driver.
    48  func NewMemory() *Memory {
    49  	return &Memory{cache: map[string]memReleases{}, namespace: "default"}
    50  }
    51  
    52  // SetNamespace sets a specific namespace in which releases will be accessed.
    53  // An empty string indicates all namespaces (for the list operation)
    54  func (mem *Memory) SetNamespace(ns string) {
    55  	mem.namespace = ns
    56  }
    57  
    58  // Name returns the name of the driver.
    59  func (mem *Memory) Name() string {
    60  	return MemoryDriverName
    61  }
    62  
    63  // Get returns the release named by key or returns ErrReleaseNotFound.
    64  func (mem *Memory) Get(key string) (*rspb.Release, error) {
    65  	defer unlock(mem.rlock())
    66  
    67  	keyWithoutPrefix := strings.TrimPrefix(key, "sh.helm.release.v1.")
    68  	switch elems := strings.Split(keyWithoutPrefix, ".v"); len(elems) {
    69  	case 2:
    70  		name, ver := elems[0], elems[1]
    71  		if _, err := strconv.Atoi(ver); err != nil {
    72  			return nil, ErrInvalidKey
    73  		}
    74  		if recs, ok := mem.cache[mem.namespace][name]; ok {
    75  			if r := recs.Get(key); r != nil {
    76  				return r.rls, nil
    77  			}
    78  		}
    79  		return nil, ErrReleaseNotFound
    80  	default:
    81  		return nil, ErrInvalidKey
    82  	}
    83  }
    84  
    85  // List returns the list of all releases such that filter(release) == true
    86  func (mem *Memory) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) {
    87  	defer unlock(mem.rlock())
    88  
    89  	var ls []*rspb.Release
    90  	for namespace := range mem.cache {
    91  		if mem.namespace != "" {
    92  			// Should only list releases of this namespace
    93  			namespace = mem.namespace
    94  		}
    95  		for _, recs := range mem.cache[namespace] {
    96  			recs.Iter(func(_ int, rec *record) bool {
    97  				if filter(rec.rls) {
    98  					ls = append(ls, rec.rls)
    99  				}
   100  				return true
   101  			})
   102  		}
   103  		if mem.namespace != "" {
   104  			// Should only list releases of this namespace
   105  			break
   106  		}
   107  	}
   108  	return ls, nil
   109  }
   110  
   111  // Query returns the set of releases that match the provided set of labels
   112  func (mem *Memory) Query(keyvals map[string]string) ([]*rspb.Release, error) {
   113  	defer unlock(mem.rlock())
   114  
   115  	var lbs labels
   116  
   117  	lbs.init()
   118  	lbs.fromMap(keyvals)
   119  
   120  	var ls []*rspb.Release
   121  	for namespace := range mem.cache {
   122  		if mem.namespace != "" {
   123  			// Should only query releases of this namespace
   124  			namespace = mem.namespace
   125  		}
   126  		for _, recs := range mem.cache[namespace] {
   127  			recs.Iter(func(_ int, rec *record) bool {
   128  				// A query for a release name that doesn't exist (has been deleted)
   129  				// can cause rec to be nil.
   130  				if rec == nil {
   131  					return false
   132  				}
   133  				if rec.lbs.match(lbs) {
   134  					ls = append(ls, rec.rls)
   135  				}
   136  				return true
   137  			})
   138  		}
   139  		if mem.namespace != "" {
   140  			// Should only query releases of this namespace
   141  			break
   142  		}
   143  	}
   144  
   145  	if len(ls) == 0 {
   146  		return nil, ErrReleaseNotFound
   147  	}
   148  
   149  	return ls, nil
   150  }
   151  
   152  // Create creates a new release or returns ErrReleaseExists.
   153  func (mem *Memory) Create(key string, rls *rspb.Release) error {
   154  	defer unlock(mem.wlock())
   155  
   156  	// For backwards compatibility, we protect against an unset namespace
   157  	namespace := rls.Namespace
   158  	if namespace == "" {
   159  		namespace = defaultNamespace
   160  	}
   161  	mem.SetNamespace(namespace)
   162  
   163  	if _, ok := mem.cache[namespace]; !ok {
   164  		mem.cache[namespace] = memReleases{}
   165  	}
   166  
   167  	if recs, ok := mem.cache[namespace][rls.Name]; ok {
   168  		if err := recs.Add(newRecord(key, rls)); err != nil {
   169  			return err
   170  		}
   171  		mem.cache[namespace][rls.Name] = recs
   172  		return nil
   173  	}
   174  	mem.cache[namespace][rls.Name] = records{newRecord(key, rls)}
   175  	return nil
   176  }
   177  
   178  // Update updates a release or returns ErrReleaseNotFound.
   179  func (mem *Memory) Update(key string, rls *rspb.Release) error {
   180  	defer unlock(mem.wlock())
   181  
   182  	// For backwards compatibility, we protect against an unset namespace
   183  	namespace := rls.Namespace
   184  	if namespace == "" {
   185  		namespace = defaultNamespace
   186  	}
   187  	mem.SetNamespace(namespace)
   188  
   189  	if _, ok := mem.cache[namespace]; ok {
   190  		if rs, ok := mem.cache[namespace][rls.Name]; ok && rs.Exists(key) {
   191  			rs.Replace(key, newRecord(key, rls))
   192  			return nil
   193  		}
   194  	}
   195  	return ErrReleaseNotFound
   196  }
   197  
   198  // Delete deletes a release or returns ErrReleaseNotFound.
   199  func (mem *Memory) Delete(key string) (*rspb.Release, error) {
   200  	defer unlock(mem.wlock())
   201  
   202  	keyWithoutPrefix := strings.TrimPrefix(key, "sh.helm.release.v1.")
   203  	elems := strings.Split(keyWithoutPrefix, ".v")
   204  
   205  	if len(elems) != 2 {
   206  		return nil, ErrInvalidKey
   207  	}
   208  
   209  	name, ver := elems[0], elems[1]
   210  	if _, err := strconv.Atoi(ver); err != nil {
   211  		return nil, ErrInvalidKey
   212  	}
   213  	if _, ok := mem.cache[mem.namespace]; ok {
   214  		if recs, ok := mem.cache[mem.namespace][name]; ok {
   215  			if r := recs.Remove(key); r != nil {
   216  				// recs.Remove changes the slice reference, so we have to re-assign it.
   217  				mem.cache[mem.namespace][name] = recs
   218  				return r.rls, nil
   219  			}
   220  		}
   221  	}
   222  	return nil, ErrReleaseNotFound
   223  }
   224  
   225  // wlock locks mem for writing
   226  func (mem *Memory) wlock() func() {
   227  	mem.Lock()
   228  	return func() { mem.Unlock() }
   229  }
   230  
   231  // rlock locks mem for reading
   232  func (mem *Memory) rlock() func() {
   233  	mem.RLock()
   234  	return func() { mem.RUnlock() }
   235  }
   236  
   237  // unlock calls fn which reverses a mem.rlock or mem.wlock. e.g:
   238  // ```defer unlock(mem.rlock())```, locks mem for reading at the
   239  // call point of defer and unlocks upon exiting the block.
   240  func unlock(fn func()) { fn() }
   241  

View as plain text