@@ -120,75 +120,151 @@ func (d *StateExists) UnmarshalJSON(bytes []byte) error {
120120 return nil
121121}
122122
123- type CollectionIterator func (db , col string , planCollection * StatePlanCollection , shard string , plan ShardServers , current ShardServers ) (skipRest bool )
123+ func (s State ) CountShards () int {
124+ count := 0
125+
126+ for _ , collections := range s .Plan .Collections {
127+ count += collections .CountShards ()
128+ }
129+
130+ return count
131+ }
132+
133+ func (s State ) PlanServers () []string {
134+ q := map [string ]bool {}
135+
136+ for _ , db := range s .Plan .Collections {
137+ for _ , col := range db {
138+ for _ , shards := range col .Shards {
139+ for _ , shard := range shards {
140+ q [shard ] = true
141+ }
142+ }
143+ }
144+ }
145+
146+ r := make ([]string , 0 , len (q ))
147+
148+ for k := range q {
149+ r = append (r , k )
150+ }
151+
152+ return r
153+ }
154+
155+ type CollectionShardDetails []CollectionShardDetail
156+
157+ type CollectionShardDetail struct {
158+ Database string
159+ Collection string
160+ Shard string
161+ }
162+
163+ type StateShardFilter func (s State , db , col , shard string ) bool
164+
165+ func NegateFilter (in StateShardFilter ) StateShardFilter {
166+ return func (s State , db , col , shard string ) bool {
167+ return ! in (s , db , col , shard )
168+ }
169+ }
170+
171+ func (s State ) Filter (f StateShardFilter ) CollectionShardDetails {
172+ shards := make (CollectionShardDetails , s .CountShards ())
173+ size := 0
124174
125- func (s State ) IterateOverCollections (i CollectionIterator ) {
126- dbsLoop:
127175 for db , collections := range s .Plan .Collections {
128176 for collection , details := range collections {
129- for shard , shardDetails := range details .Shards {
130- if currShard , ok := s .Current .Collections [db ][collection ][shard ]; ok {
131- if skipRest := i (db , collection , & details , shard , shardDetails , currShard .Servers ); skipRest {
132- break dbsLoop
177+ for shard := range details .Shards {
178+ if f (s , db , collection , shard ) {
179+ shards [size ] = CollectionShardDetail {
180+ Database : db ,
181+ Collection : collection ,
182+ Shard : shard ,
133183 }
184+ size ++
134185 }
135186 }
136187 }
137188 }
138- }
139189
140- func (s State ) IsDBServerInSync (serverID string ) bool {
141- isInSync := true
142- s .IterateOverCollections (func (db , col string , planCollection * StatePlanCollection , shard string , plan ShardServers , current ShardServers ) bool {
143- if ! plan .Contains (serverID ) {
144- return false
145- }
190+ if size == 0 {
191+ return nil
192+ }
146193
147- serverIsNotInSync := ! current .Contains (serverID )
148- wc := planCollection .GetWriteConcern (1 )
149- if serverIsNotInSync || wc > len (current ) {
150- isInSync = false
151- return true
152- }
153- return false
154- })
194+ return shards [0 :size ]
195+ }
155196
156- return isInSync
197+ func GetDBServerBlockingRestartShards (s State , serverID string ) CollectionShardDetails {
198+ return s .Filter (FilterDBServerShardRestart (serverID ))
157199}
158200
159- func (s State ) IsDBServerReadyToRestart (serverID string ) bool {
160- readyToRestart := true
201+ func FilterDBServerShardRestart (serverID string ) StateShardFilter {
202+ return NegateFilter (func (s State , db , col , shard string ) bool {
203+ // Filter all shards which are not blocking restart of server
204+ plan := s .Plan .Collections [db ][col ]
205+ planShard := plan .Shards [shard ]
161206
162- s . IterateOverCollections ( func ( db , col string , planCollection * StatePlanCollection , shard string , plan ShardServers , current ShardServers ) bool {
163- if ! plan . Contains ( serverID ) {
164- return false
207+ if ! planShard . Contains ( serverID ) {
208+ // This DBServer is not even in plan, restart possible
209+ return true
165210 }
166211
167- serverInSync := current .Contains (serverID )
168- if len (plan ) == 1 && serverInSync {
169- // The requested server is the only one in the plan
170- return false
212+ current := s .Current .Collections [db ][col ][shard ]
213+ currentShard := current .Servers .FilterBy (planShard )
214+
215+ serverInSync := currentShard .Contains (serverID )
216+
217+ if len (planShard ) == 1 && serverInSync {
218+ // The requested server is the only one in the plan, restart possible
219+ return true
171220 }
172221
173- wc := planCollection .GetWriteConcern (1 )
174- if wc >= len (plan ) && len (plan ) != 0 {
175- wc = len (plan ) - 1
222+ // If WriteConcern equals replicationFactor then downtime is always there
223+ wc := plan .GetWriteConcern (1 )
224+ if rf := plan .GetReplicationFactor (shard ); wc >= rf {
225+ wc = rf - 1
176226 }
177227
178- if len (current ) >= wc && ! serverInSync {
228+ if len (currentShard ) >= wc && ! serverInSync {
179229 // Current shard is not in sync, but it does not matter - we have enough replicas in sync
180230 // Restart of this DBServer won't affect WC
181- return false
231+ return true
182232 }
183233
184- if len (current ) <= wc {
185- // If we restart this server, write concern won't be satisfied
186- readyToRestart = false
234+ if len (currentShard ) > wc {
235+ // We are in plan, but restart is possible
187236 return true
188237 }
189238
239+ // If we restart this server, write concern won't be satisfied
190240 return false
191241 })
242+ }
192243
193- return readyToRestart
244+ func GetDBServerShardsNotInSync (s State , serverID string ) CollectionShardDetails {
245+ return s .Filter (FilterDBServerShardsNotInSync (serverID ))
246+ }
247+
248+ func FilterDBServerShardsNotInSync (serverID string ) StateShardFilter {
249+ return NegateFilter (func (s State , db , col , shard string ) bool {
250+ planShard := s .Plan .Collections [db ][col ].Shards [shard ]
251+
252+ if serverID != "*" && ! planShard .Contains (serverID ) {
253+ return true
254+ }
255+
256+ currentShard := s .Current .Collections [db ][col ][shard ]
257+
258+ if len (planShard ) != len (currentShard .Servers ) {
259+ return false
260+ }
261+
262+ for _ , s := range planShard {
263+ if ! currentShard .Servers .Contains (s ) {
264+ return false
265+ }
266+ }
267+
268+ return true
269+ })
194270}
0 commit comments