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 }