-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
lb: Perform round-robin load balancing in server list
The client will query the servers in a round-robin fashion with the order of the server list it receives. We order the server list differently for each client so that one-off calls do not hit always the same server. In order to increment the offset for each client we use an atomic operation the increments a counter and resets its value when it wraps around. The respective code is in the internal/atomic package.
- Loading branch information
Showing
8 changed files
with
143 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,6 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
) | ||
import "context" | ||
|
||
type Listener chan<- ServerList | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package atomic | ||
|
||
import "sync/atomic" | ||
|
||
// IncWrapInt64 atomically increments a 64-bit signed integer, wrapping around zero. | ||
// | ||
// Specifically if p points to a value of math.MaxInt64 the result of calling | ||
// IncWrapInt64 will be 0. | ||
func IncWrapInt64(p *int64) int64 { | ||
for { | ||
o := atomic.LoadInt64(p) | ||
n := o + 1 | ||
|
||
if n < 0 { | ||
n = 0 | ||
} | ||
|
||
if atomic.CompareAndSwapInt64(p, o, n) { | ||
return n | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package atomic | ||
|
||
import ( | ||
"math" | ||
"sync" | ||
"testing" | ||
) | ||
|
||
func TestIncWrapInt64(t *testing.T) { | ||
const n = 1000 | ||
const m = n - 1 | ||
|
||
var x int64 | ||
|
||
var wg sync.WaitGroup | ||
wg.Add(m) | ||
|
||
for i := 0; i < m; i++ { | ||
go func() { | ||
IncWrapInt64(&x) | ||
wg.Done() | ||
}() | ||
} | ||
|
||
wg.Wait() | ||
|
||
if y := IncWrapInt64(&x); y != n { | ||
t.Errorf("expected %d, got %d", n, y) | ||
} | ||
|
||
x = math.MaxInt64 - m | ||
wg.Add(m) | ||
|
||
for i := 0; i < m; i++ { | ||
go func() { | ||
IncWrapInt64(&x) | ||
wg.Done() | ||
}() | ||
} | ||
|
||
wg.Wait() | ||
|
||
if y := IncWrapInt64(&x); y != 0 { | ||
t.Errorf("expected %d, got %d", 0, y) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package main | ||
|
||
import ( | ||
"net" | ||
"testing" | ||
) | ||
|
||
func TestConvertServerList(t *testing.T) { | ||
l := ServerList{Server{net.IP{}, 1}, Server{net.IP{}, 2}, Server{net.IP{}, 3}} | ||
|
||
table := []struct { | ||
offset int | ||
want []int32 | ||
}{ | ||
{0, []int32{1, 2, 3}}, | ||
{1, []int32{2, 3, 1}}, | ||
{2, []int32{3, 1, 2}}, | ||
{3, []int32{1, 2, 3}}, | ||
{4, []int32{2, 3, 1}}, | ||
} | ||
|
||
for _, tt := range table { | ||
res := convertServerList(l, tt.offset) | ||
|
||
if len(res) != len(tt.want) { | ||
t.Errorf("expected len %d, got %d", len(tt.want), len(res)) | ||
continue | ||
} | ||
|
||
for i := range res { | ||
if res[i].Port != tt.want[i] { | ||
t.Errorf("expected %d at %d, got %d", tt.want[i], i, res[i].Port) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package main | ||
|
||
import "net" | ||
|
||
type ServerList []Server | ||
|
||
type Server struct { | ||
IP net.IP | ||
Port int32 | ||
} | ||
|
||
func (s Server) Equal(x Server) bool { | ||
return s.Port == x.Port && s.IP.Equal(x.IP) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters