github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/pkg/cluster/pool.go (about) 1 package cluster 2 3 import ( 4 model "github.com/cloudreve/Cloudreve/v3/models" 5 "github.com/cloudreve/Cloudreve/v3/pkg/balancer" 6 "github.com/cloudreve/Cloudreve/v3/pkg/util" 7 "sync" 8 ) 9 10 var Default *NodePool 11 12 // 需要分类的节点组 13 var featureGroup = []string{"aria2"} 14 15 // Pool 节点池 16 type Pool interface { 17 // Returns active node selected by given feature and load balancer 18 BalanceNodeByFeature(feature string, lb balancer.Balancer) (error, Node) 19 20 // Returns node by ID 21 GetNodeByID(id uint) Node 22 23 // Add given node into pool. If node existed, refresh node. 24 Add(node *model.Node) 25 26 // Delete and kill node from pool by given node id 27 Delete(id uint) 28 } 29 30 // NodePool 通用节点池 31 type NodePool struct { 32 active map[uint]Node 33 inactive map[uint]Node 34 35 featureMap map[string][]Node 36 37 lock sync.RWMutex 38 } 39 40 // Init 初始化从机节点池 41 func Init() { 42 Default = &NodePool{} 43 Default.Init() 44 if err := Default.initFromDB(); err != nil { 45 util.Log().Warning("Failed to initialize node pool: %s", err) 46 } 47 } 48 49 func (pool *NodePool) Init() { 50 pool.lock.Lock() 51 defer pool.lock.Unlock() 52 53 pool.featureMap = make(map[string][]Node) 54 pool.active = make(map[uint]Node) 55 pool.inactive = make(map[uint]Node) 56 } 57 58 func (pool *NodePool) buildIndexMap() { 59 pool.lock.Lock() 60 for _, feature := range featureGroup { 61 pool.featureMap[feature] = make([]Node, 0) 62 } 63 64 for _, v := range pool.active { 65 for _, feature := range featureGroup { 66 if v.IsFeatureEnabled(feature) { 67 pool.featureMap[feature] = append(pool.featureMap[feature], v) 68 } 69 } 70 } 71 pool.lock.Unlock() 72 } 73 74 func (pool *NodePool) GetNodeByID(id uint) Node { 75 pool.lock.RLock() 76 defer pool.lock.RUnlock() 77 78 if node, ok := pool.active[id]; ok { 79 return node 80 } 81 82 return pool.inactive[id] 83 } 84 85 func (pool *NodePool) nodeStatusChange(isActive bool, id uint) { 86 util.Log().Debug("Slave node [ID=%d] status changed to [Active=%t].", id, isActive) 87 var node Node 88 pool.lock.Lock() 89 if n, ok := pool.inactive[id]; ok { 90 node = n 91 delete(pool.inactive, id) 92 } else { 93 node = pool.active[id] 94 delete(pool.active, id) 95 } 96 97 if isActive { 98 pool.active[id] = node 99 } else { 100 pool.inactive[id] = node 101 } 102 pool.lock.Unlock() 103 104 pool.buildIndexMap() 105 } 106 107 func (pool *NodePool) initFromDB() error { 108 nodes, err := model.GetNodesByStatus(model.NodeActive) 109 if err != nil { 110 return err 111 } 112 113 pool.lock.Lock() 114 for i := 0; i < len(nodes); i++ { 115 pool.add(&nodes[i]) 116 } 117 pool.lock.Unlock() 118 119 pool.buildIndexMap() 120 return nil 121 } 122 123 func (pool *NodePool) add(node *model.Node) { 124 newNode := NewNodeFromDBModel(node) 125 if newNode.IsActive() { 126 pool.active[node.ID] = newNode 127 } else { 128 pool.inactive[node.ID] = newNode 129 } 130 131 // 订阅节点状态变更 132 newNode.SubscribeStatusChange(func(isActive bool, id uint) { 133 pool.nodeStatusChange(isActive, id) 134 }) 135 } 136 137 func (pool *NodePool) Add(node *model.Node) { 138 pool.lock.Lock() 139 defer pool.buildIndexMap() 140 defer pool.lock.Unlock() 141 142 var ( 143 old Node 144 ok bool 145 ) 146 if old, ok = pool.active[node.ID]; !ok { 147 old, ok = pool.inactive[node.ID] 148 } 149 if old != nil { 150 go old.Init(node) 151 return 152 } 153 154 pool.add(node) 155 } 156 157 func (pool *NodePool) Delete(id uint) { 158 pool.lock.Lock() 159 defer pool.buildIndexMap() 160 defer pool.lock.Unlock() 161 162 if node, ok := pool.active[id]; ok { 163 node.Kill() 164 delete(pool.active, id) 165 return 166 } 167 168 if node, ok := pool.inactive[id]; ok { 169 node.Kill() 170 delete(pool.inactive, id) 171 return 172 } 173 174 } 175 176 // BalanceNodeByFeature 根据 feature 和 LoadBalancer 取出节点 177 func (pool *NodePool) BalanceNodeByFeature(feature string, lb balancer.Balancer) (error, Node) { 178 pool.lock.RLock() 179 defer pool.lock.RUnlock() 180 if nodes, ok := pool.featureMap[feature]; ok { 181 err, res := lb.NextPeer(nodes) 182 if err == nil { 183 return nil, res.(Node) 184 } 185 186 return err, nil 187 } 188 189 return ErrFeatureNotExist, nil 190 }