Skip to content

Commit b1cd906

Browse files
authored
GODRIVER-3043 Use default write/read concerns in the index search commands. (#1563)
1 parent be7fa88 commit b1cd906

File tree

9 files changed

+148
-139
lines changed

9 files changed

+148
-139
lines changed

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ evg-test-load-balancers:
158158

159159
.PHONY: evg-test-search-index
160160
evg-test-search-index:
161-
go test ./mongo/integration -run TestSearchIndexProse -v -timeout $(TEST_TIMEOUT)s >> test.suite
161+
# Double the timeout to wait for the responses from the server.
162+
go test ./mongo/integration -run TestSearchIndexProse -v -timeout $(shell echo "$$(( $(TEST_TIMEOUT) * 2))")s >> test.suite
162163

163164
.PHONY: evg-test-ocsp
164165
evg-test-ocsp:

mongo/collection.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1801,8 +1801,11 @@ func (coll *Collection) Indexes() IndexView {
18011801

18021802
// SearchIndexes returns a SearchIndexView instance that can be used to perform operations on the search indexes for the collection.
18031803
func (coll *Collection) SearchIndexes() SearchIndexView {
1804+
c, _ := coll.Clone() // Clone() always return a nil error.
1805+
c.readConcern = nil
1806+
c.writeConcern = nil
18041807
return SearchIndexView{
1805-
coll: coll,
1808+
coll: c,
18061809
}
18071810
}
18081811

mongo/integration/search_index_prose_test.go

Lines changed: 88 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package integration
88

99
import (
10+
"bytes"
1011
"context"
1112
"os"
1213
"sync"
@@ -20,6 +21,8 @@ import (
2021
"go.mongodb.org/mongo-driver/mongo"
2122
"go.mongodb.org/mongo-driver/mongo/integration/mtest"
2223
"go.mongodb.org/mongo-driver/mongo/options"
24+
"go.mongodb.org/mongo-driver/mongo/readconcern"
25+
"go.mongodb.org/mongo-driver/mongo/writeconcern"
2326
)
2427

2528
func TestSearchIndexProse(t *testing.T) {
@@ -61,15 +64,16 @@ func TestSearchIndexProse(t *testing.T) {
6164
if !cursor.Next(ctx) {
6265
break
6366
}
64-
if cursor.Current.Lookup("queryable").Boolean() {
67+
name := cursor.Current.Lookup("name").StringValue()
68+
queryable := cursor.Current.Lookup("queryable").Boolean()
69+
if name == searchName && queryable {
6570
doc = cursor.Current
6671
} else {
6772
t.Logf("cursor: %s, sleep 5 seconds...", cursor.Current.String())
6873
time.Sleep(5 * time.Second)
6974
}
7075
}
7176
require.NotNil(mt, doc, "got empty document")
72-
assert.Equal(mt, searchName, doc.Lookup("name").StringValue(), "unmatched name")
7377
expected, err := bson.Marshal(definition)
7478
require.NoError(mt, err, "failed to marshal definition")
7579
actual := doc.Lookup("latestDefinition").Value
@@ -110,7 +114,9 @@ func TestSearchIndexProse(t *testing.T) {
110114
if !cursor.Next(ctx) {
111115
return nil
112116
}
113-
if cursor.Current.Lookup("queryable").Boolean() {
117+
name := cursor.Current.Lookup("name").StringValue()
118+
queryable := cursor.Current.Lookup("queryable").Boolean()
119+
if name == *opts.Name && queryable {
114120
return cursor.Current
115121
}
116122
t.Logf("cursor: %s, sleep 5 seconds...", cursor.Current.String())
@@ -126,7 +132,6 @@ func TestSearchIndexProse(t *testing.T) {
126132

127133
doc := getDocument(opts)
128134
require.NotNil(mt, doc, "got empty document")
129-
assert.Equal(mt, *opts.Name, doc.Lookup("name").StringValue(), "unmatched name")
130135
expected, err := bson.Marshal(definition)
131136
require.NoError(mt, err, "failed to marshal definition")
132137
actual := doc.Lookup("latestDefinition").Value
@@ -162,15 +167,16 @@ func TestSearchIndexProse(t *testing.T) {
162167
if !cursor.Next(ctx) {
163168
break
164169
}
165-
if cursor.Current.Lookup("queryable").Boolean() {
170+
name := cursor.Current.Lookup("name").StringValue()
171+
queryable := cursor.Current.Lookup("queryable").Boolean()
172+
if name == searchName && queryable {
166173
doc = cursor.Current
167174
} else {
168175
t.Logf("cursor: %s, sleep 5 seconds...", cursor.Current.String())
169176
time.Sleep(5 * time.Second)
170177
}
171178
}
172179
require.NotNil(mt, doc, "got empty document")
173-
require.Equal(mt, searchName, doc.Lookup("name").StringValue(), "unmatched name")
174180

175181
err = view.DropOne(ctx, searchName)
176182
require.NoError(mt, err, "failed to drop index")
@@ -204,37 +210,49 @@ func TestSearchIndexProse(t *testing.T) {
204210
require.NoError(mt, err, "failed to create index")
205211
require.Equal(mt, searchName, index, "unmatched name")
206212

207-
getDocument := func() bson.Raw {
208-
for {
209-
cursor, err := view.List(ctx, opts)
210-
require.NoError(mt, err, "failed to list")
213+
var doc bson.Raw
214+
for doc == nil {
215+
cursor, err := view.List(ctx, opts)
216+
require.NoError(mt, err, "failed to list")
211217

212-
if !cursor.Next(ctx) {
213-
return nil
214-
}
215-
if cursor.Current.Lookup("queryable").Boolean() {
216-
return cursor.Current
217-
}
218+
if !cursor.Next(ctx) {
219+
break
220+
}
221+
name := cursor.Current.Lookup("name").StringValue()
222+
queryable := cursor.Current.Lookup("queryable").Boolean()
223+
if name == searchName && queryable {
224+
doc = cursor.Current
225+
} else {
218226
t.Logf("cursor: %s, sleep 5 seconds...", cursor.Current.String())
219227
time.Sleep(5 * time.Second)
220228
}
221229
}
222-
223-
doc := getDocument()
224230
require.NotNil(mt, doc, "got empty document")
225-
require.Equal(mt, searchName, doc.Lookup("name").StringValue(), "unmatched name")
226231

227232
definition = bson.D{{"mappings", bson.D{{"dynamic", true}}}}
228-
err = view.UpdateOne(ctx, searchName, definition)
229-
require.NoError(mt, err, "failed to drop index")
230-
doc = getDocument()
231-
require.NotNil(mt, doc, "got empty document")
232-
assert.Equal(mt, searchName, doc.Lookup("name").StringValue(), "unmatched name")
233-
assert.Equal(mt, "READY", doc.Lookup("status").StringValue(), "unexpected status")
234233
expected, err := bson.Marshal(definition)
235234
require.NoError(mt, err, "failed to marshal definition")
236-
actual := doc.Lookup("latestDefinition").Value
237-
assert.Equal(mt, expected, actual, "unmatched definition")
235+
err = view.UpdateOne(ctx, searchName, definition)
236+
require.NoError(mt, err, "failed to update index")
237+
for doc == nil {
238+
cursor, err := view.List(ctx, opts)
239+
require.NoError(mt, err, "failed to list")
240+
241+
if !cursor.Next(ctx) {
242+
break
243+
}
244+
name := cursor.Current.Lookup("name").StringValue()
245+
queryable := cursor.Current.Lookup("queryable").Boolean()
246+
status := cursor.Current.Lookup("status").StringValue()
247+
latestDefinition := doc.Lookup("latestDefinition").Value
248+
if name == searchName && queryable && status == "READY" && bytes.Equal(latestDefinition, expected) {
249+
doc = cursor.Current
250+
} else {
251+
t.Logf("cursor: %s, sleep 5 seconds...", cursor.Current.String())
252+
time.Sleep(5 * time.Second)
253+
}
254+
}
255+
require.NotNil(mt, doc, "got empty document")
238256
})
239257

240258
mt.Run("case 5: dropSearchIndex suppresses namespace not found errors", func(mt *mtest.T) {
@@ -250,4 +268,47 @@ func TestSearchIndexProse(t *testing.T) {
250268
err = collection.SearchIndexes().DropOne(ctx, "foo")
251269
require.NoError(mt, err)
252270
})
271+
272+
mt.RunOpts("case 6: Driver can successfully create and list search indexes with non-default readConcern and writeConcern",
273+
mtest.NewOptions().CollectionOptions(options.Collection().SetWriteConcern(writeconcern.New(writeconcern.W(1))).SetReadConcern(readconcern.Majority())),
274+
func(mt *mtest.T) {
275+
ctx := context.Background()
276+
277+
_, err := mt.Coll.InsertOne(ctx, bson.D{})
278+
require.NoError(mt, err, "failed to insert")
279+
280+
view := mt.Coll.SearchIndexes()
281+
282+
definition := bson.D{{"mappings", bson.D{{"dynamic", false}}}}
283+
const searchName = "test-search-index-case6"
284+
opts := options.SearchIndexes().SetName(searchName)
285+
index, err := view.CreateOne(ctx, mongo.SearchIndexModel{
286+
Definition: definition,
287+
Options: opts,
288+
})
289+
require.NoError(mt, err, "failed to create index")
290+
require.Equal(mt, searchName, index, "unmatched name")
291+
var doc bson.Raw
292+
for doc == nil {
293+
cursor, err := view.List(ctx, opts)
294+
require.NoError(mt, err, "failed to list")
295+
296+
if !cursor.Next(ctx) {
297+
break
298+
}
299+
name := cursor.Current.Lookup("name").StringValue()
300+
queryable := cursor.Current.Lookup("queryable").Boolean()
301+
if name == searchName && queryable {
302+
doc = cursor.Current
303+
} else {
304+
t.Logf("cursor: %s, sleep 5 seconds...", cursor.Current.String())
305+
time.Sleep(5 * time.Second)
306+
}
307+
}
308+
require.NotNil(mt, doc, "got empty document")
309+
expected, err := bson.Marshal(definition)
310+
require.NoError(mt, err, "failed to marshal definition")
311+
actual := doc.Lookup("latestDefinition").Value
312+
assert.Equal(mt, expected, actual, "unmatched definition")
313+
})
253314
}

mongo/search_index_view.go

Lines changed: 8 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313

1414
"go.mongodb.org/mongo-driver/bson"
1515
"go.mongodb.org/mongo-driver/mongo/options"
16-
"go.mongodb.org/mongo-driver/mongo/writeconcern"
1716
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
1817
"go.mongodb.org/mongo-driver/x/mongo/driver"
1918
"go.mongodb.org/mongo-driver/x/mongo/driver/operation"
@@ -134,20 +133,13 @@ func (siv SearchIndexView) CreateMany(
134133
return nil, err
135134
}
136135

137-
wc := siv.coll.writeConcern
138-
if sess.TransactionRunning() {
139-
wc = nil
140-
}
141-
if !writeconcern.AckWrite(wc) {
142-
sess = nil
143-
}
144-
145136
selector := makePinnedSelector(sess, siv.coll.writeSelector)
146137

147138
op := operation.NewCreateSearchIndexes(indexes).
148-
Session(sess).WriteConcern(wc).ClusterClock(siv.coll.client.clock).
149-
Database(siv.coll.db.name).Collection(siv.coll.name).CommandMonitor(siv.coll.client.monitor).
150-
Deployment(siv.coll.client.deployment).ServerSelector(selector).ServerAPI(siv.coll.client.serverAPI).
139+
Session(sess).CommandMonitor(siv.coll.client.monitor).
140+
ServerSelector(selector).ClusterClock(siv.coll.client.clock).
141+
Collection(siv.coll.name).Database(siv.coll.db.name).
142+
Deployment(siv.coll.client.deployment).ServerAPI(siv.coll.client.serverAPI).
151143
Timeout(siv.coll.client.timeout)
152144

153145
err = op.Execute(ctx)
@@ -196,20 +188,12 @@ func (siv SearchIndexView) DropOne(
196188
return err
197189
}
198190

199-
wc := siv.coll.writeConcern
200-
if sess.TransactionRunning() {
201-
wc = nil
202-
}
203-
if !writeconcern.AckWrite(wc) {
204-
sess = nil
205-
}
206-
207191
selector := makePinnedSelector(sess, siv.coll.writeSelector)
208192

209193
op := operation.NewDropSearchIndex(name).
210-
Session(sess).WriteConcern(wc).CommandMonitor(siv.coll.client.monitor).
194+
Session(sess).CommandMonitor(siv.coll.client.monitor).
211195
ServerSelector(selector).ClusterClock(siv.coll.client.clock).
212-
Database(siv.coll.db.name).Collection(siv.coll.name).
196+
Collection(siv.coll.name).Database(siv.coll.db.name).
213197
Deployment(siv.coll.client.deployment).ServerAPI(siv.coll.client.serverAPI).
214198
Timeout(siv.coll.client.timeout)
215199

@@ -258,20 +242,12 @@ func (siv SearchIndexView) UpdateOne(
258242
return err
259243
}
260244

261-
wc := siv.coll.writeConcern
262-
if sess.TransactionRunning() {
263-
wc = nil
264-
}
265-
if !writeconcern.AckWrite(wc) {
266-
sess = nil
267-
}
268-
269245
selector := makePinnedSelector(sess, siv.coll.writeSelector)
270246

271247
op := operation.NewUpdateSearchIndex(name, indexDefinition).
272-
Session(sess).WriteConcern(wc).CommandMonitor(siv.coll.client.monitor).
248+
Session(sess).CommandMonitor(siv.coll.client.monitor).
273249
ServerSelector(selector).ClusterClock(siv.coll.client.clock).
274-
Database(siv.coll.db.name).Collection(siv.coll.name).
250+
Collection(siv.coll.name).Database(siv.coll.db.name).
275251
Deployment(siv.coll.client.deployment).ServerAPI(siv.coll.client.serverAPI).
276252
Timeout(siv.coll.client.timeout)
277253

testdata/index-management/searchIndexIgnoresReadWriteConcern.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
]
9696
},
9797
{
98-
"description": "createSearchIndex ignores read and write concern",
98+
"description": "createSearchIndexes ignores read and write concern",
9999
"operations": [
100100
{
101101
"name": "createSearchIndexes",

testdata/index-management/searchIndexIgnoresReadWriteConcern.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ tests:
4949
writeConcern: { $$exists: false }
5050
readConcern: { $$exists: false }
5151

52-
- description: "createSearchIndex ignores read and write concern"
52+
- description: "createSearchIndexes ignores read and write concern"
5353
operations:
5454
- name: createSearchIndexes
5555
object: *collection0
56-
arguments:
56+
arguments:
5757
models: []
5858
expectError:
5959
# This test always errors in a non-Atlas environment. The test functions as a unit test by asserting

x/mongo/driver/operation/create_search_indexes.go

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,25 @@ import (
1515
"go.mongodb.org/mongo-driver/bson"
1616
"go.mongodb.org/mongo-driver/event"
1717
"go.mongodb.org/mongo-driver/mongo/description"
18-
"go.mongodb.org/mongo-driver/mongo/writeconcern"
1918
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
2019
"go.mongodb.org/mongo-driver/x/mongo/driver"
2120
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
2221
)
2322

2423
// CreateSearchIndexes performs a createSearchIndexes operation.
2524
type CreateSearchIndexes struct {
26-
indexes bsoncore.Document
27-
session *session.Client
28-
clock *session.ClusterClock
29-
collection string
30-
monitor *event.CommandMonitor
31-
crypt driver.Crypt
32-
database string
33-
deployment driver.Deployment
34-
selector description.ServerSelector
35-
writeConcern *writeconcern.WriteConcern
36-
result CreateSearchIndexesResult
37-
serverAPI *driver.ServerAPIOptions
38-
timeout *time.Duration
25+
indexes bsoncore.Document
26+
session *session.Client
27+
clock *session.ClusterClock
28+
collection string
29+
monitor *event.CommandMonitor
30+
crypt driver.Crypt
31+
database string
32+
deployment driver.Deployment
33+
selector description.ServerSelector
34+
result CreateSearchIndexesResult
35+
serverAPI *driver.ServerAPIOptions
36+
timeout *time.Duration
3937
}
4038

4139
// CreateSearchIndexResult represents a single search index result in CreateSearchIndexesResult.
@@ -109,9 +107,15 @@ func (csi *CreateSearchIndexes) Execute(ctx context.Context) error {
109107
return driver.Operation{
110108
CommandFn: csi.command,
111109
ProcessResponseFn: csi.processResponse,
110+
Client: csi.session,
111+
Clock: csi.clock,
112112
CommandMonitor: csi.monitor,
113+
Crypt: csi.crypt,
113114
Database: csi.database,
114115
Deployment: csi.deployment,
116+
Selector: csi.selector,
117+
ServerAPI: csi.serverAPI,
118+
Timeout: csi.timeout,
115119
}.Execute(ctx)
116120

117121
}
@@ -214,16 +218,6 @@ func (csi *CreateSearchIndexes) ServerSelector(selector description.ServerSelect
214218
return csi
215219
}
216220

217-
// WriteConcern sets the write concern for this operation.
218-
func (csi *CreateSearchIndexes) WriteConcern(writeConcern *writeconcern.WriteConcern) *CreateSearchIndexes {
219-
if csi == nil {
220-
csi = new(CreateSearchIndexes)
221-
}
222-
223-
csi.writeConcern = writeConcern
224-
return csi
225-
}
226-
227221
// ServerAPI sets the server API version for this operation.
228222
func (csi *CreateSearchIndexes) ServerAPI(serverAPI *driver.ServerAPIOptions) *CreateSearchIndexes {
229223
if csi == nil {

0 commit comments

Comments
 (0)