1
+ from copy import copy
1
2
import logging
2
3
from itertools import izip_longest
3
4
4
5
import redis
5
6
6
7
from .cluster import Cluster , ClusterNode
7
- from .distribute import gen_distribution
8
+ from .distribute import gen_distribution , NodeWrapper
8
9
9
10
10
11
logger = logging .getLogger (__name__ )
@@ -16,13 +17,43 @@ def __init__(self, cluster, new_nodes):
16
17
self .cluster = cluster
17
18
self .new_nodes = new_nodes
18
19
self .result = None
20
+ self .dis = gen_distribution (self .cluster .nodes , new_nodes )
19
21
20
22
def get_distribution (self ):
21
- return gen_distribution (self .cluster .nodes , self .new_nodes )
23
+ hosts = map (copy , self .dis ['hosts' ])
24
+ masters = self .dis ['masters' ]
25
+ slaves = self .dis ['slaves' ]
26
+ result = self .peek_result ()
27
+ plan = result ['plan' ]
28
+ deleted_masters = [p ['master' ] for p in plan ]
29
+ new_slaves = []
30
+ new_masters = []
31
+ for p in plan :
32
+ m = copy (p ['master' ])
33
+ s = copy (p ['slave' ])
34
+ # After failover, their roles will change
35
+ m .slaves = []
36
+ m .master = s
37
+ s .slaves .append (m )
38
+ s .master = None
39
+ new_masters .append (s )
40
+ new_slaves .append (m )
41
+ new_slaves = NodeWrapper .divide_by_host (new_slaves , len (hosts ))
42
+ new_masters = NodeWrapper .divide_by_host (new_masters , len (hosts ))
43
+
44
+ masters = [list (set (m ) - set (deleted_masters )) for m in masters ]
45
+ masters = [o + n for o , n in zip (masters , new_masters )]
46
+ slaves = [o + n for o , n in zip (slaves , new_slaves )]
47
+ return {
48
+ 'hosts' : hosts ,
49
+ 'masters' : masters ,
50
+ 'slaves' : slaves ,
51
+ 'frees' : NodeWrapper .divide_by_host ([], len (hosts )),
52
+ }
22
53
23
54
def peek_result (self ):
24
55
if self .result :
25
- return result
56
+ return self . result
26
57
return self .gen_plan (self .new_nodes )
27
58
28
59
def move_masters_to_new_hosts (self , fast_mode = False ):
@@ -64,24 +95,35 @@ def promote_new_masters(self, plan):
64
95
65
96
def gen_plan (self , new_nodes ):
66
97
plan = []
67
- dis = gen_distribution (self .cluster .nodes , new_nodes )
68
- masters = dis ['masters' ]
69
- frees = filter (None , dis ['frees' ])
70
- hosts_len = len (dis ['hosts' ])
98
+ masters = map (copy , self .dis ['masters' ])
99
+ frees = filter (None , map (copy , self .dis ['frees' ]))
100
+ hosts_len = len (self .dis ['hosts' ])
71
101
masters_sum = len (sum (masters , []))
72
102
aver = (masters_sum + hosts_len - 1 ) / hosts_len
73
- failover_masters = sum ([h [aver :] for h in masters ], [])
74
- # merge [[a,b], [c], [d,e,f]] to [a,c,e,b,e,f] for example
103
+ new_hosts_num = len (set (n .host_index for n in sum (frees , [])))
104
+ num_in_old_hosts = masters_sum / \
105
+ hosts_len * (hosts_len - new_hosts_num ) + masters_sum % hosts_len
106
+ moved_masters = masters_sum - num_in_old_hosts
107
+ # merge [[a,b], [c], [d,e,f]] to [a,c,d,b,e,f] for example
75
108
frees = filter (None , sum (map (list , izip_longest (* frees )), []))
76
- while len (failover_masters ) > 0 and len (frees ) > 0 :
77
- m = failover_masters .pop ()
78
- f = frees .pop ()
109
+ while moved_masters > 0 and len (frees ) > 0 :
110
+ m = self .select_master (masters )
111
+ f = frees .pop (0 )
112
+ f .master = m
113
+ m .slaves .append (f )
79
114
plan .append ({
80
115
'slave' : f ,
81
116
'master' : m ,
82
117
})
118
+ moved_masters -= 1
83
119
self .result = {
84
120
'plan' : plan ,
85
121
'frees' : frees ,
86
122
}
87
123
return self .result
124
+
125
+ def select_master (self , masters ):
126
+ nums = map (len , masters )
127
+ m = max (nums )
128
+ i = nums .index (m )
129
+ return masters [i ].pop ()
0 commit comments