github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/appparts/impl.go (about) 1 /* 2 * Copyright (c) 2021-present Sigma-Soft, Ltd. 3 * @author: Nikolay Nikitin 4 */ 5 6 package appparts 7 8 import ( 9 "context" 10 "errors" 11 "sync" 12 "time" 13 14 "github.com/voedger/voedger/pkg/appdef" 15 "github.com/voedger/voedger/pkg/iextengine" 16 "github.com/voedger/voedger/pkg/istructs" 17 coreutils "github.com/voedger/voedger/pkg/utils" 18 ) 19 20 type apps struct { 21 structs istructs.IAppStructsProvider 22 syncActualizerFactory SyncActualizerFactory 23 extEngineFactories iextengine.ExtensionEngineFactories 24 apps map[istructs.AppQName]*app 25 mx sync.RWMutex 26 } 27 28 func newAppPartitions(asp istructs.IAppStructsProvider, saf SyncActualizerFactory, eef iextengine.ExtensionEngineFactories) (ap IAppPartitions, cleanup func(), err error) { 29 a := &apps{ 30 structs: asp, 31 syncActualizerFactory: saf, 32 extEngineFactories: eef, 33 apps: map[istructs.AppQName]*app{}, 34 mx: sync.RWMutex{}, 35 } 36 return a, func() {}, err 37 } 38 39 func (aps *apps) DeployApp(name istructs.AppQName, def appdef.IAppDef, partsCount istructs.NumAppPartitions, engines [ProcessorKind_Count]int) { 40 aps.mx.Lock() 41 defer aps.mx.Unlock() 42 43 if _, ok := aps.apps[name]; ok { 44 panic(errAppCannotBeRedeployed(name)) 45 } 46 47 a := newApplication(aps, name, partsCount) 48 aps.apps[name] = a 49 50 appStructs, err := aps.structs.AppStructsByDef(name, def) 51 if err != nil { 52 panic(err) 53 } 54 55 a.deploy(def, appStructs, engines) 56 } 57 58 func (aps *apps) DeployAppPartitions(appName istructs.AppQName, partIDs []istructs.PartitionID) { 59 aps.mx.Lock() 60 defer aps.mx.Unlock() 61 62 a, ok := aps.apps[appName] 63 if !ok { 64 panic(errAppNotFound(appName)) 65 } 66 67 for _, id := range partIDs { 68 p := newPartition(a, id) 69 a.parts[id] = p 70 } 71 } 72 73 func (aps *apps) AppDef(appName istructs.AppQName) (appdef.IAppDef, error) { 74 aps.mx.Lock() 75 defer aps.mx.Unlock() 76 77 app, ok := aps.apps[appName] 78 if !ok { 79 return nil, errAppNotFound(appName) 80 } 81 return app.def, nil 82 } 83 84 // Returns _total_ application partitions count. 85 // 86 // This is a configuration value for the application, independent of how many sections are currently deployed. 87 func (aps *apps) AppPartsCount(appName istructs.AppQName) (istructs.NumAppPartitions, error) { 88 aps.mx.Lock() 89 defer aps.mx.Unlock() 90 91 app, ok := aps.apps[appName] 92 if !ok { 93 return 0, errAppNotFound(appName) 94 } 95 return app.partsCount, nil 96 } 97 98 func (aps *apps) Borrow(appName istructs.AppQName, partID istructs.PartitionID, proc ProcessorKind) (IAppPartition, error) { 99 aps.mx.RLock() 100 defer aps.mx.RUnlock() 101 102 app, ok := aps.apps[appName] 103 if !ok { 104 return nil, errAppNotFound(appName) 105 } 106 107 part, ok := app.parts[partID] 108 if !ok { 109 return nil, errPartitionNotFound(appName, partID) 110 } 111 112 borrowed, err := part.borrow(proc) 113 if err != nil { 114 return nil, err 115 } 116 117 return borrowed, nil 118 } 119 120 func (aps *apps) AppWorkspacePartitionID(appName istructs.AppQName, ws istructs.WSID) (istructs.PartitionID, error) { 121 pc, err := aps.AppPartsCount(appName) 122 if err != nil { 123 return 0, err 124 } 125 return coreutils.AppPartitionID(ws, pc), nil 126 } 127 128 func (aps *apps) WaitForBorrow(ctx context.Context, appName istructs.AppQName, partID istructs.PartitionID, proc ProcessorKind) (IAppPartition, error) { 129 for ctx.Err() == nil { 130 ap, err := aps.Borrow(appName, partID, proc) 131 if err == nil { 132 return ap, nil 133 } 134 if errors.Is(err, ErrNotAvailableEngines) { 135 time.Sleep(AppPartitionBorrowRetryDelay) 136 continue 137 } 138 return nil, err 139 } 140 return nil, ctx.Err() 141 }