blob: e31877ce6cfdaf58688a292b2e6aa1d1a9ccf168 [file] [log] [blame]
Don Newton379ae252019-04-01 12:17:06 -04001// Copyright (C) MongoDB, Inc. 2017-present.
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
7package driver
8
9import (
10 "context"
11
12 "github.com/mongodb/mongo-go-driver/bson"
13 "github.com/mongodb/mongo-go-driver/mongo/readpref"
14 "github.com/mongodb/mongo-go-driver/x/mongo/driver/session"
15 "github.com/mongodb/mongo-go-driver/x/mongo/driver/topology"
16 "github.com/mongodb/mongo-go-driver/x/mongo/driver/uuid"
17 "github.com/mongodb/mongo-go-driver/x/network/command"
18 "github.com/mongodb/mongo-go-driver/x/network/description"
19)
20
21// Read handles the full cycle dispatch and execution of a read command against the provided
22// topology.
23func Read(
24 ctx context.Context,
25 cmd command.Read,
26 topo *topology.Topology,
27 selector description.ServerSelector,
28 clientID uuid.UUID,
29 pool *session.Pool,
30) (bson.Raw, error) {
31
32 ss, err := topo.SelectServer(ctx, selector)
33 if err != nil {
34 return nil, err
35 }
36
37 conn, err := ss.Connection(ctx)
38 if err != nil {
39 return nil, err
40 }
41 defer conn.Close()
42
43 if cmd.Session != nil && cmd.Session.TransactionRunning() {
44 // When command.read is directly used, this implies an operation level
45 // read preference, so we do not override it with the transaction read pref.
46 err = checkTransactionReadPref(cmd.ReadPref)
47
48 if err != nil {
49 return nil, err
50 }
51 }
52
53 // If no explicit session and deployment supports sessions, start implicit session.
54 if cmd.Session == nil && topo.SupportsSessions() {
55 cmd.Session, err = session.NewClientSession(pool, clientID, session.Implicit)
56 if err != nil {
57 return nil, err
58 }
59 defer cmd.Session.EndSession()
60 }
61
62 return cmd.RoundTrip(ctx, ss.Description(), conn)
63}
64
65func getReadPrefBasedOnTransaction(current *readpref.ReadPref, sess *session.Client) (*readpref.ReadPref, error) {
66 if sess != nil && sess.TransactionRunning() {
67 // Transaction's read preference always takes priority
68 current = sess.CurrentRp
69 err := checkTransactionReadPref(current)
70 if err != nil {
71 return nil, err
72 }
73 }
74 return current, nil
75}
76
77func checkTransactionReadPref(pref *readpref.ReadPref) error {
78 if pref != nil && (pref.Mode() == readpref.SecondaryMode ||
79 pref.Mode() == readpref.SecondaryPreferredMode ||
80 pref.Mode() == readpref.NearestMode ||
81 pref.Mode() == readpref.PrimaryPreferredMode) {
82 return command.ErrNonPrimaryRP
83 }
84 return nil
85}