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
|
// 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
SessionTimeoutMinutes uint32
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
}
|