gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/virtcontainers/factory/cache/cache.go (about)

     1  // Copyright (c) 2018 HyperHQ Inc.
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  //
     5  // cache implements base vm factory on top of other base vm factory.
     6  
     7  package cache
     8  
     9  import (
    10  	"context"
    11  	"fmt"
    12  	"sync"
    13  
    14  	pb "github.com/kata-containers/runtime/protocols/cache"
    15  	vc "github.com/kata-containers/runtime/virtcontainers"
    16  	"github.com/kata-containers/runtime/virtcontainers/factory/base"
    17  )
    18  
    19  type cache struct {
    20  	base base.FactoryBase
    21  
    22  	cacheCh   chan *vc.VM
    23  	closed    chan<- int
    24  	wg        sync.WaitGroup
    25  	closeOnce sync.Once
    26  
    27  	vmm     map[*vc.VM]interface{}
    28  	vmmLock sync.RWMutex
    29  }
    30  
    31  // New creates a new cached vm factory.
    32  func New(ctx context.Context, count uint, b base.FactoryBase) base.FactoryBase {
    33  	if count < 1 {
    34  		return b
    35  	}
    36  
    37  	cacheCh := make(chan *vc.VM)
    38  	closed := make(chan int, count)
    39  	c := cache{
    40  		base:    b,
    41  		cacheCh: cacheCh,
    42  		closed:  closed,
    43  		vmm:     make(map[*vc.VM]interface{}),
    44  	}
    45  	for i := 0; i < int(count); i++ {
    46  		c.wg.Add(1)
    47  		go func() {
    48  			for {
    49  				vm, err := b.GetBaseVM(ctx, c.Config())
    50  				if err != nil {
    51  					c.wg.Done()
    52  					c.CloseFactory(ctx)
    53  					return
    54  				}
    55  				c.addToVmm(vm)
    56  
    57  				select {
    58  				case cacheCh <- vm:
    59  					// Because vm will not be relased or changed
    60  					// by cacheServer.GetBaseVM or removeFromVmm.
    61  					// So removeFromVmm can be called after vm send to cacheCh.
    62  					c.removeFromVmm(vm)
    63  				case <-closed:
    64  					c.removeFromVmm(vm)
    65  					vm.Stop()
    66  					vm.Disconnect()
    67  					c.wg.Done()
    68  					return
    69  				}
    70  			}
    71  		}()
    72  	}
    73  	return &c
    74  }
    75  
    76  func (c *cache) addToVmm(vm *vc.VM) {
    77  	c.vmmLock.Lock()
    78  	defer c.vmmLock.Unlock()
    79  
    80  	c.vmm[vm] = nil
    81  }
    82  
    83  func (c *cache) removeFromVmm(vm *vc.VM) {
    84  	c.vmmLock.Lock()
    85  	defer c.vmmLock.Unlock()
    86  
    87  	delete(c.vmm, vm)
    88  }
    89  
    90  // Config returns cache vm factory's base factory config.
    91  func (c *cache) Config() vc.VMConfig {
    92  	return c.base.Config()
    93  }
    94  
    95  // GetVMStatus returns the status of the cached VMs.
    96  func (c *cache) GetVMStatus() []*pb.GrpcVMStatus {
    97  	vs := []*pb.GrpcVMStatus{}
    98  
    99  	c.vmmLock.RLock()
   100  	defer c.vmmLock.RUnlock()
   101  
   102  	for vm := range c.vmm {
   103  		vs = append(vs, vm.GetVMStatus())
   104  	}
   105  
   106  	return vs
   107  }
   108  
   109  // GetBaseVM returns a base VM from cache factory's base factory.
   110  func (c *cache) GetBaseVM(ctx context.Context, config vc.VMConfig) (*vc.VM, error) {
   111  	vm, ok := <-c.cacheCh
   112  	if ok {
   113  		return vm, nil
   114  	}
   115  	return nil, fmt.Errorf("cache factory is closed")
   116  }
   117  
   118  // CloseFactory closes the cache factory.
   119  func (c *cache) CloseFactory(ctx context.Context) {
   120  	c.closeOnce.Do(func() {
   121  		for len(c.closed) < cap(c.closed) { // send sufficient closed signal
   122  			c.closed <- 0
   123  		}
   124  		c.wg.Wait()
   125  		close(c.cacheCh)
   126  		c.base.CloseFactory(ctx)
   127  	})
   128  }