-
Notifications
You must be signed in to change notification settings - Fork 883
/
topology.go
144 lines (126 loc) · 3.58 KB
/
topology.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package description
import (
"fmt"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
// Topology contains information about a MongoDB cluster.
type Topology struct {
Servers []Server
SetName string
Kind TopologyKind
// Deprecated: Use SessionTimeoutMinutesPtr instead.
SessionTimeoutMinutes uint32
SessionTimeoutMinutesPtr *int64
CompatibilityErr error
}
// String implements the Stringer interface.
func (t Topology) String() string {
var serversStr string
for _, s := range t.Servers {
serversStr += "{ " + s.String() + " }, "
}
return fmt.Sprintf("Type: %s, Servers: [%s]", t.Kind, serversStr)
}
// Equal compares two topology descriptions and returns true if they are equal.
func (t Topology) Equal(other Topology) bool {
if t.Kind != other.Kind {
return false
}
topoServers := make(map[string]Server)
for _, s := range t.Servers {
topoServers[s.Addr.String()] = s
}
otherServers := make(map[string]Server)
for _, s := range other.Servers {
otherServers[s.Addr.String()] = s
}
if len(topoServers) != len(otherServers) {
return false
}
for _, server := range topoServers {
otherServer := otherServers[server.Addr.String()]
if !server.Equal(otherServer) {
return false
}
}
return true
}
// HasReadableServer returns true if the topology contains a server suitable for reading.
//
// If the Topology's kind is Single or Sharded, the mode parameter is ignored and the function contains true if any of
// the servers in the Topology are of a known type.
//
// For replica sets, the function returns true if the cluster contains a server that matches the provided read
// preference mode.
func (t Topology) HasReadableServer(mode readpref.Mode) bool {
switch t.Kind {
case Single, Sharded:
return hasAvailableServer(t.Servers, 0)
case ReplicaSetWithPrimary:
return hasAvailableServer(t.Servers, mode)
case ReplicaSetNoPrimary, ReplicaSet:
if mode == readpref.PrimaryMode {
return false
}
// invalid read preference
if !mode.IsValid() {
return false
}
return hasAvailableServer(t.Servers, mode)
}
return false
}
// HasWritableServer returns true if a topology has a server available for writing.
//
// If the Topology's kind is Single or Sharded, this function returns true if any of the servers in the Topology are of
// a known type.
//
// For replica sets, the function returns true if the replica set contains a primary.
func (t Topology) HasWritableServer() bool {
return t.HasReadableServer(readpref.PrimaryMode)
}
// hasAvailableServer returns true if any servers are available based on the read preference.
func hasAvailableServer(servers []Server, mode readpref.Mode) bool {
switch mode {
case readpref.PrimaryMode:
for _, s := range servers {
if s.Kind == RSPrimary {
return true
}
}
return false
case readpref.PrimaryPreferredMode, readpref.SecondaryPreferredMode, readpref.NearestMode:
for _, s := range servers {
if s.Kind == RSPrimary || s.Kind == RSSecondary {
return true
}
}
return false
case readpref.SecondaryMode:
for _, s := range servers {
if s.Kind == RSSecondary {
return true
}
}
return false
}
// read preference is not specified
for _, s := range servers {
switch s.Kind {
case Standalone,
RSMember,
RSPrimary,
RSSecondary,
RSArbiter,
RSGhost,
Mongos:
return true
}
}
return false
}