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  }