Skip to content

Commit e9a79e7

Browse files
DRIVERS-2868 Guard server round trips from timeout
1 parent ee212da commit e9a79e7

File tree

9 files changed

+849
-38
lines changed

9 files changed

+849
-38
lines changed

internal/driverutil/operation.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66

77
package driverutil
88

9+
import (
10+
"context"
11+
"fmt"
12+
"math"
13+
"time"
14+
)
15+
916
// Operation Names should be sourced from the command reference documentation:
1017
// https://www.mongodb.com/docs/manual/reference/command/
1118
const (
@@ -30,3 +37,35 @@ const (
3037
UpdateOp = "update" // UpdateOp is the name for updating
3138
BulkWriteOp = "bulkWrite" // BulkWriteOp is the name for client-level bulk write
3239
)
40+
41+
func CalculateMaxTimeMS(ctx context.Context, rttMin time.Duration, rttStats string, err error) (int64, error) {
42+
deadline, ok := ctx.Deadline()
43+
if !ok {
44+
return 0, nil
45+
}
46+
47+
remainingTimeout := time.Until(deadline)
48+
49+
// Always round up to the next millisecond value so we never truncate the calculated
50+
// maxTimeMS value (e.g. 400 microseconds evaluates to 1ms, not 0ms).
51+
maxTimeMS := int64((remainingTimeout - rttMin + time.Millisecond - 1) / time.Millisecond)
52+
if maxTimeMS <= 0 {
53+
return 0, fmt.Errorf(
54+
"remaining time %v until context deadline is less than or equal to min network round-trip time %v (%v): %w",
55+
remainingTimeout,
56+
rttMin,
57+
rttStats,
58+
err)
59+
}
60+
61+
// The server will return a "BadValue" error if maxTimeMS is greater
62+
// than the maximum positive int32 value (about 24.9 days). If the
63+
// user specified a timeout value greater than that, omit maxTimeMS
64+
// and let the client-side timeout handle cancelling the op if the
65+
// timeout is ever reached.
66+
if maxTimeMS > math.MaxInt32 {
67+
return 0, nil
68+
}
69+
70+
return maxTimeMS, nil
71+
}

internal/integration/unified/collection_operation_execution.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"context"
1111
"errors"
1212
"fmt"
13+
"strings"
1314
"time"
1415

1516
"go.mongodb.org/mongo-driver/v2/bson"
@@ -1485,6 +1486,22 @@ func createFindCursor(ctx context.Context, operation *operation) (*cursorResult,
14851486
opts.SetSkip(int64(val.Int32()))
14861487
case "sort":
14871488
opts.SetSort(val.Document())
1489+
case "timeoutMode":
1490+
return nil, newSkipTestError(fmt.Sprintf("timeoutMode is not supported"))
1491+
case "cursorType":
1492+
fmt.Println("cursorType check", val.String(), strings.ToLower(val.String()), val.String() == "tailableAwait")
1493+
switch strings.ToLower(val.StringValue()) {
1494+
case "tailable":
1495+
opts.SetCursorType(options.Tailable)
1496+
case "tailableawait":
1497+
fmt.Println("gottem")
1498+
opts.SetCursorType(options.TailableAwait)
1499+
case "nontailable":
1500+
opts.SetCursorType(options.NonTailable)
1501+
}
1502+
case "maxAwaitTimeMS":
1503+
maxAwaitTimeMS := time.Duration(val.Int32()) * time.Millisecond
1504+
opts.SetMaxAwaitTime(maxAwaitTimeMS)
14881505
default:
14891506
return nil, fmt.Errorf("unrecognized find option %q", key)
14901507
}

internal/integration/unified/cursor_operation_execution.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,24 @@ func executeIterateOnce(ctx context.Context, operation *operation) (*operationRe
1919
return nil, err
2020
}
2121

22+
fmt.Println("iterate once")
23+
2224
// TryNext will attempt to get the next document, potentially issuing a single 'getMore'.
2325
if cursor.TryNext(ctx) {
2426
// We don't expect the server to return malformed documents, so any errors from Decode here are treated
2527
// as fatal.
2628
var res bson.Raw
2729
if err := cursor.Decode(&res); err != nil {
30+
fmt.Println("err:", err)
2831
return nil, fmt.Errorf("error decoding cursor result: %w", err)
2932
}
3033

34+
fmt.Println("err:", cursor.Err())
35+
3136
return newDocumentResult(res, nil), nil
3237
}
38+
39+
fmt.Println("err:", cursor.Err())
3340
return newErrorResult(cursor.Err()), nil
3441
}
3542

internal/integration/unified/unified_spec_runner.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ var (
7878
"operation is retried multiple times for non-zero timeoutMS - aggregate on collection": "maxTimeMS is disabled on find and aggregate. See DRIVERS-2722.",
7979
"operation is retried multiple times for non-zero timeoutMS - aggregate on database": "maxTimeMS is disabled on find and aggregate. See DRIVERS-2722.",
8080
"timeoutMS applied to find command": "maxTimeMS is disabled on find and aggregate. See DRIVERS-2722.",
81+
"timeoutMS applied to find": "maxTimeMS is disabled on find and aggregate. See DRIVERS-2722.",
82+
"timeoutMS is refreshed for getMore if maxAwaitTimeMS is not set": "maxTimeMS is disabled on find and aggregate. See DRIVERS-2722.",
83+
"timeoutMS is refreshed for getMore if maxAwaitTimeMS is set": "maxTimeMS is disabled on find and aggregate. See DRIVERS-2722.",
84+
"timeoutMS is refreshed for getMore - failure": "maxTimeMS is disabled on find and aggregate. See DRIVERS-2722.",
8185

8286
// DRIVERS-2953: This test requires that the driver sends a "getMore"
8387
// with "maxTimeMS" set. However, "getMore" can only include "maxTimeMS"
@@ -178,14 +182,14 @@ func runTestFile(t *testing.T, filepath string, expectValidFail bool, opts ...*O
178182
mt.Skip("Skipping CSOT spec test because SKIP_CSOT_TESTS=true")
179183
}
180184

181-
defer func() {
182-
// catch panics from looking up elements and fail if it's unexpected
183-
if r := recover(); r != nil {
184-
if !expectValidFail {
185-
mt.Fatal(r)
186-
}
187-
}
188-
}()
185+
//defer func() {
186+
// // catch panics from looking up elements and fail if it's unexpected
187+
// if r := recover(); r != nil {
188+
// if !expectValidFail {
189+
// mt.Fatal(r)
190+
// }
191+
// }
192+
//}()
189193
err := testCase.Run(mt)
190194
if expectValidFail {
191195
if err != nil {

0 commit comments

Comments
 (0)