diff --git a/api/dbv1/media_link.go b/api/dbv1/media_link.go index 402924cf..e782c416 100644 --- a/api/dbv1/media_link.go +++ b/api/dbv1/media_link.go @@ -25,8 +25,7 @@ type Id3Tags struct { } func mediaLink(cid string, trackId int32, userId int32, id3Tags *Id3Tags) (*MediaLink, error) { - first, rest := rendezvous.GlobalHasher.ReplicaSet3(cid) - rest = append(config.Cfg.StoreAllNodes, rest...) + first, rest := rendezvous.GlobalHasher.Select(cid) timestamp := time.Now().Unix() * 1000 data := map[string]interface{}{ diff --git a/api/dbv1/users.go b/api/dbv1/users.go index d65f2379..b58c2ddf 100644 --- a/api/dbv1/users.go +++ b/api/dbv1/users.go @@ -6,7 +6,6 @@ import ( "fmt" "strings" - "api.audius.co/config" "api.audius.co/rendezvous" "api.audius.co/trashid" "github.com/jackc/pgx/v5/pgtype" @@ -64,8 +63,7 @@ func (q *Queries) UsersKeyed(ctx context.Context, arg GetUsersParams) (map[int32 if cid != "" { // rendezvous for cid - first, rest := rendezvous.GlobalHasher.ReplicaSet3(cid) - rest = append(rest, config.Cfg.StoreAllNodes...) + first, rest := rendezvous.GlobalHasher.Select(cid) coverPhoto = &RectangleImage{ X640: fmt.Sprintf("%s/content/%s/640x.jpg", first, cid), X2000: fmt.Sprintf("%s/content/%s/2000x.jpg", first, cid), @@ -126,8 +124,7 @@ func squareImageStruct(maybeCids ...pgtype.Text) *SquareImage { } // rendezvous for cid - first, rest := rendezvous.GlobalHasher.ReplicaSet3(cid) - rest = append(rest, config.Cfg.StoreAllNodes...) + first, rest := rendezvous.GlobalHasher.Select(cid) return &SquareImage{ X150x150: fmt.Sprintf("%s/content/%s/150x150.jpg", first, cid), diff --git a/api/v1_rendezvous.go b/api/v1_rendezvous.go index f05753c7..018f1171 100644 --- a/api/v1_rendezvous.go +++ b/api/v1_rendezvous.go @@ -20,7 +20,7 @@ func (app *ApiServer) v1Rendezvous(c *fiber.Ctx) error { for i, node := range nodes { endpoints[i] = node.Endpoint } - first, rest := rendezvous.GlobalHasher.ReplicaSet3(cid) + first, rest := rendezvous.GlobalHasher.Select(cid) return c.JSON(fiber.Map{ "first": first, diff --git a/rendezvous/rendezvous.go b/rendezvous/rendezvous.go index 75b2597a..cce6398c 100644 --- a/rendezvous/rendezvous.go +++ b/rendezvous/rendezvous.go @@ -94,8 +94,8 @@ func (rh *RendezvousHasher) Rank(key string) []string { return result } -// Get a replica set of 3 nodes with random order -func (rh *RendezvousHasher) ReplicaSet3(key string) (string, []string) { +// Select returns a primary node and mirror nodes for the given key. +func (rh *RendezvousHasher) Select(key string) (string, []string) { ranked := rh.Rank(key) n := min(len(ranked), 3) if n == 0 { @@ -103,7 +103,13 @@ func (rh *RendezvousHasher) ReplicaSet3(key string) (string, []string) { } candidates := append([]string(nil), ranked[:n]...) - rand.Shuffle(n, func(i, j int) { + for _, h := range config.Cfg.StoreAllNodes { + if !slices.Contains(candidates, h) { + candidates = append(candidates, h) + } + } + + rand.Shuffle(len(candidates), func(i, j int) { candidates[i], candidates[j] = candidates[j], candidates[i] }) diff --git a/rendezvous/rendezvous_test.go b/rendezvous/rendezvous_test.go index c1ade0a3..a26014bb 100644 --- a/rendezvous/rendezvous_test.go +++ b/rendezvous/rendezvous_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestReplicaSet3(t *testing.T) { +func TestSelect(t *testing.T) { hosts := []string{ "https://host1.com", "https://host2.com", @@ -16,7 +16,7 @@ func TestReplicaSet3(t *testing.T) { } hasher := NewRendezvousHasher(hosts) - first, rest := hasher.ReplicaSet3("test-key") + first, rest := hasher.Select("test-key") ranked := hasher.Rank("test-key") assert.Equal(t, 2, len(rest))