Skip to content
65 changes: 52 additions & 13 deletions source/sessions/snapshot-sessions.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,24 +63,28 @@ response. The `atClusterTime` field represents the timestamp of the read and is
## Specification

An application requests snapshot reads by creating a `ClientSession` with options that specify that snapshot reads are
desired. An application then passes the session as an argument to methods in the `MongoDatabase` and `MongoCollection`
classes. Read operations (find/aggregate/distinct) performed against that session will be read from the same snapshot.
desired and optionally specifying a `snapshotTime`. An application then passes the session as an argument to methods in
the `MongoDatabase` and `MongoCollection` classes. Read operations (find/aggregate/distinct) performed against that
session will be read from the same snapshot.

## High level summary of the API changes for snapshot reads

Snapshot reads are built on top of client sessions.

Applications will start a new client session for snapshot reads like this:
Applications will start a new client session for snapshot reads and possibly retrieve the snapshot time like this:

```typescript
options = new SessionOptions(snapshot = true);
options = new SessionOptions(snapshot = true, snapshotTime = timestampValue);
session = client.startSession(options);
snapshotTime = session.snapshotTime;
```

All read operations performed using this session will be read from the same snapshot.

If no value is provided for `snapshot` a value of false is implied. There are no MongoDatabase, MongoClient, or
MongoCollection API changes.
If no value is provided for `snapshot` a value of false is implied. `snapshotTime` is an optional parameter and if not
passed the snapshot time will be set internally after the first find/aggregate/distinct operation inside the session.

There are no MongoDatabase, MongoClient, or MongoCollection API changes.

## SessionOptions changes

Expand All @@ -89,14 +93,16 @@ MongoCollection API changes.
```typescript
class SessionOptions {
Optional<bool> snapshot;
Optional<BsonTimestamp> snapshotTime;

// other options defined by other specs
}
```

In order to support snapshot reads a new property named `snapshot` is added to `SessionOptions`. Applications set
`snapshot` when starting a client session to indicate whether they want snapshot reads. All read operations performed
using that client session will share the same snapshot.
In order to support snapshot reads two properties called `snapshot` and `snapshotTime` are added to `SessionOptions`.
Applications set `snapshot` when starting a client session to indicate whether they want snapshot reads and optionally
set `snapshotTime` to specify the desired snapshot time beforehand. All read operations performed using that client
session will share the same snapshot.

Each new member is documented below.

Expand All @@ -110,11 +116,41 @@ Snapshot reads and causal consistency are mutually exclusive. Therefore if `snap
`causalConsistency` must be false. Client MUST throw an error if both `snapshot` and `causalConsistency` are set to
true. Snapshot reads are supported on both primaries and secondaries.

### snapshotTime

Applications set `snapshotTime` when starting a snapshot session to specify the desired snapshot time.

Note that the `snapshotTime` property is optional. The default value of this property is null.

Client MUST throw an error if `snapshotTime` is set and `snapshot` is not set to true.

Note that when parsing `snapshotTime` from `sessionOptions` for
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a good place to describe this behaviour?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say we have to mention this in tests/README.md file.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense

[unified tests](https://github.com/mongodb/specifications/blob/master/source/unified-test-format/unified-test-format.md),
the parsed string is the name of the key for the actual value of `snapshotTime` to be found in the
[entity map](https://github.com/mongodb/specifications/blob/master/source/unified-test-format/unified-test-format.md#entity-map).

## ClientSession changes

A readonly property called `snapshotTime` will be added to `ClientSession` that allows applications to retrieve the
snapshot time of the session:

```typescript
class ClientSession {
readonly Optional<BsonTimestamp> snapshotTime;

// other options defined by other specs
}
```

Getting the value of `snapshotTime` on a non-snapshot session MUST raise an error.

Transactions are not allowed with snapshot sessions. Calling `session.startTransaction(options)` on a snapshot session
MUST raise an error.

Note that a new operation on session called `getSnapshotTime` must be supported for
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, move top tests/README.md

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

[unified tests](https://github.com/mongodb/specifications/blob/master/source/unified-test-format/unified-test-format.md).
This operation returns the value of `snapshotTime` on the session, so that it can be used in following operations.

## ReadConcern changes

`snapshot` added to [ReadConcernLevel enumeration](../read-write-concern/read-write-concern.md#read-concern).
Expand All @@ -123,10 +159,12 @@ MUST raise an error.

There are no new server commands related to snapshot reads. Instead, snapshot reads are implemented by:

1. Saving the `atClusterTime` returned by 5.0+ servers for the first find/aggregate/distinct operation in a private
`snapshotTime` property of the `ClientSession` object. Drivers MUST save `atClusterTime` in the `ClientSession`
object.
2. Passing that `snapshotTime` in the `atClusterTime` field of the `readConcern` field for subsequent snapshot read
1. If `snapshotTime` is specified in `SessionOptions`, saving the value in a `snapshotTime` property of the
`ClientSession`.
2. If `snapshotTime` is not specified in `SessionOptions`, saving the `atClusterTime` returned by 5.0+ servers for the
first find/aggregate/distinct operation in a `snapshotTime` property of the `ClientSession` object. Drivers MUST
save `atClusterTime` in the `ClientSession` object.
3. Passing that `snapshotTime` in the `atClusterTime` field of the `readConcern` field for subsequent snapshot read
operations (i.e. find/aggregate/distinct commands).

## Server Command Responses
Expand Down Expand Up @@ -241,6 +279,7 @@ C# driver will provide the reference implementation. The corresponding ticket is

## Changelog

- 2025-09-23: Exposed snapshotTime to applications.
- 2024-05-08: Migrated from reStructuredText to Markdown.
- 2021-06-15: Initial version.
- 2021-06-28: Raise client side error on < 5.0.
Expand Down
16 changes: 16 additions & 0 deletions source/sessions/tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,24 @@ and configure a `MongoClient` with default options.
- Run a ping command using C1 and assert that `$clusterTime` sent is the same as the `clusterTime` recorded earlier.
This assertion proves that C1's `$clusterTime` was not advanced by gossiping through SDAM.

### 21. Having `snapshotTime` set and `snapshot` set to false is not allowed

Snapshot sessions tests require server of version 5.0 or higher and replica set or a sharded cluster deployment.

- `client.startSession(snapshot = false, snapshotTime = new Timestamp(1))`
- Assert that an error was raised by driver

### 22. Retrieving `snapshotTime` on a non-snapshot session raises an error

Snapshot sessions tests require server of version 5.0 or higher and replica set or a sharded cluster deployment.

- `client.startSession(snapshot = false)`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to have more verbal steps:

- Start a session by calling `startSession` with `snapshot = false`.
- Try to access the session's snapshot time.
- Assert that client side error was raised.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

- `client.snapshotTime`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it suppose to be session, right?

- Assert that an error was raised by driver

## Changelog

- 2025-09-25: Added tests for snapshotTime.
- 2025-02-24: Test drivers do not gossip $clusterTime on SDAM.
- 2024-05-08: Migrated from reStructuredText to Markdown.
- 2019-05-15: Initial version.
Expand Down
Loading
Loading