@@ -63,41 +63,39 @@ func (b *Balancer) isAlive() bool {
6363 return true
6464}
6565
66- func (b * Balancer ) scanPartition (sign uint64 , part * partitions.Partition , owner discovery.Member ) {
66+ func (b * Balancer ) scanPartition (sign uint64 , part * partitions.Partition , owners ... discovery.Member ) bool {
67+ var clean = true
6768 part .Map ().Range (func (name , tmp interface {}) bool {
68- if ! b .isAlive () {
69- // Break the loop
70- return false
71- }
7269 u := tmp .(partitions.Fragment )
7370
74- b .log .V (2 ).Printf ("[INFO] Moving %s: %s (kind: %s) on PartID: %d to %s" , u .Name (), name , part .Kind (), part .Id (), owner )
75- err := u .Move (part .Id (), part .Kind (), name .(string ), owner )
76- if err != nil {
77- b .log .V (2 ).Printf ("[ERROR] Failed to move %s: %s on PartID: %d to %s: %v" , u .Name (), name , part .Id (), owner , err )
78- }
79- if err == nil {
80- // Delete the moved storage unit instance. GC will free the allocated memory.
81- part .Map ().Delete (name )
71+ for _ , owner := range owners {
72+ b .log .V (2 ).Printf ("[INFO] Moving %s: %s (kind: %s) on PartID: %d to %s" ,
73+ u .Name (), name , part .Kind (), part .Id (), owner )
74+
75+ err := u .Move (part .Id (), part .Kind (), name .(string ), owner )
76+
77+ if err != nil {
78+ b .log .V (2 ).Printf ("[ERROR] Failed to move %s: %s on PartID: %d to %s: %v" ,
79+ u .Name (), name , part .Id (), owner , err )
80+ clean = false
81+ }
8282 }
83+
8384 // if this returns true, the iteration continues
84- return sign == b . rt . Signature ( )
85+ return ! b . breakLoop ( sign )
8586 })
87+
88+ return clean
8689}
8790
8891func (b * Balancer ) primaryCopies () {
8992 sign := b .rt .Signature ()
9093 for partID := uint64 (0 ); partID < b .config .PartitionCount ; partID ++ {
91- if ! b .isAlive () {
92- break
93- }
94- if sign != b .rt .Signature () {
95- // Routing table is updated. Just quit. Another balancer goroutine
96- // will work on the new table immediately.
94+ if b .breakLoop (sign ) {
9795 break
9896 }
9997
100- part := b .primary .PartitionById (partID )
98+ part := b .primary .PartitionByID (partID )
10199 if part .Length () == 0 {
102100 // Empty partition. Skip it.
103101 continue
@@ -112,75 +110,75 @@ func (b *Balancer) primaryCopies() {
112110 // Already belongs to me.
113111 continue
114112 }
113+
115114 // This is a previous owner. Move the keys.
116- b .scanPartition (sign , part , owner )
115+ if b .scanPartition (sign , part , owner ) {
116+ part .Map ().Range (func (name , tmp interface {}) bool {
117+ // Delete the moved storage unit instance. GC will free the allocated memory.
118+ part .Map ().Delete (name )
119+ return true
120+ })
121+ }
117122 }
118123}
119124
125+ func (b * Balancer ) breakLoop (sign uint64 ) bool {
126+ if ! b .isAlive () {
127+ return true
128+ }
129+
130+ if sign != b .rt .Signature () {
131+ // Routing table is updated. Just quit. Another balancer goroutine
132+ // will work on the new table immediately.
133+ return true
134+ }
135+
136+ return false
137+ }
138+
120139func (b * Balancer ) backupCopies () {
121140 sign := b .rt .Signature ()
141+ LOOP:
122142 for partID := uint64 (0 ); partID < b .config .PartitionCount ; partID ++ {
123- if ! b . isAlive ( ) {
143+ if b . breakLoop ( sign ) {
124144 break
125145 }
126146
127- if sign != b .rt .Signature () {
128- // Routing table is updated. Just quit. Another balancer goroutine
129- // will work on the new table immediately.
130- break
131- }
132-
133- part := b .backup .PartitionById (partID )
134- if part .Length () == 0 {
135- // Empty partition. Skip it.
147+ part := b .backup .PartitionByID (partID )
148+ if part .Length () == 0 || part .OwnerCount () == 0 {
136149 continue
137150 }
138151
139- if part . OwnerCount () == 0 {
140- // This partition doesn't have any backup owner
141- continue
142- }
152+ var (
153+ counter = 1
154+ currentOwners []discovery. Member
155+ )
143156
144157 owners := part .Owners ()
145- if len (owners ) == b . config . ReplicaCount - 1 {
146- // Everything is ok
147- continue
148- }
158+ for i := len (owners ) - 1 ; i >= 0 ; i -- {
159+ if counter >= b . config . ReplicaCount - 1 {
160+ break
161+ }
149162
150- var ownerIDs []uint64
151- offset := len (owners ) - 1 - (b .config .ReplicaCount - 1 )
152- if offset <= 0 {
153- offset = - 1
154- }
155- for i := len (owners ) - 1 ; i > offset ; i -- {
163+ counter ++
156164 owner := owners [i ]
157165 // Here we don't use CompareById function because the routing table
158166 // is an eventually consistent data structure and a node can try to
159167 // move data to previous instance(the same name but a different birthdate)
160168 // of itself. So just check the name.
161169 if b .rt .This ().CompareByName (owner ) {
162170 // Already belongs to me.
163- continue
171+ continue LOOP
164172 }
165- ownerIDs = append (ownerIDs , owner . ID )
173+ currentOwners = append (currentOwners , owner )
166174 }
167175
168- for _ , ownerID := range ownerIDs {
169- if ! b .isAlive () {
170- break
171- }
172- if sign != b .rt .Signature () {
173- // Routing table is updated. Just quit. Another balancer goroutine
174- // will work on the new table immediately.
175- break
176- }
177-
178- owner , err := b .rt .Discovery ().FindMemberByID (ownerID )
179- if err != nil {
180- b .log .V (2 ).Printf ("[ERROR] Failed to get host by ownerId: %d: %v" , ownerID , err )
181- continue
182- }
183- b .scanPartition (sign , part , owner )
176+ if b .scanPartition (sign , part , currentOwners ... ) {
177+ part .Map ().Range (func (name , tmp interface {}) bool {
178+ // Delete the moved storage unit instance. GC will free the allocated memory.
179+ part .Map ().Delete (name )
180+ return true
181+ })
184182 }
185183 }
186184}
0 commit comments