Skip to content

Commit 24c1ee9

Browse files
Allow shared usage of Transaction (#3114)
1 parent ef5fb1b commit 24c1ee9

File tree

4 files changed

+21
-14
lines changed

4 files changed

+21
-14
lines changed

packages/firestore/src/core/component_provider.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ export class MemoryComponentProvider implements ComponentProvider {
162162
return new SyncEngine(
163163
this.localStore,
164164
this.remoteStore,
165+
cfg.datastore,
165166
this.sharedClientState,
166167
cfg.initialUser,
167168
cfg.maxConcurrentLimboResolutions
@@ -219,6 +220,7 @@ export class IndexedDbComponentProvider extends MemoryComponentProvider {
219220
const syncEngine = new MultiTabSyncEngine(
220221
this.localStore,
221222
this.remoteStore,
223+
cfg.datastore,
222224
this.sharedClientState,
223225
cfg.initialUser,
224226
cfg.maxConcurrentLimboResolutions

packages/firestore/src/core/sync_engine.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ import {
7474
import { ViewSnapshot } from './view_snapshot';
7575
import { AsyncQueue, wrapInUserErrorIfRecoverable } from '../util/async_queue';
7676
import { TransactionRunner } from './transaction_runner';
77+
import { Datastore } from '../remote/datastore';
7778

7879
const LOG_TAG = 'SyncEngine';
7980

@@ -185,6 +186,7 @@ export class SyncEngine implements RemoteSyncer {
185186
constructor(
186187
protected localStore: LocalStore,
187188
protected remoteStore: RemoteStore,
189+
protected datastore: Datastore,
188190
// PORTING NOTE: Manages state synchronization in multi-tab environments.
189191
protected sharedClientState: SharedClientState,
190192
private currentUser: User,
@@ -390,7 +392,7 @@ export class SyncEngine implements RemoteSyncer {
390392
): void {
391393
new TransactionRunner<T>(
392394
asyncQueue,
393-
this.remoteStore,
395+
this.datastore,
394396
updateFunction,
395397
deferred
396398
).run();
@@ -924,13 +926,15 @@ export class MultiTabSyncEngine extends SyncEngine
924926
constructor(
925927
protected localStore: MultiTabLocalStore,
926928
remoteStore: RemoteStore,
929+
datastore: Datastore,
927930
sharedClientState: SharedClientState,
928931
currentUser: User,
929932
maxConcurrentLimboResolutions: number
930933
) {
931934
super(
932935
localStore,
933936
remoteStore,
937+
datastore,
934938
sharedClientState,
935939
currentUser,
936940
maxConcurrentLimboResolutions

packages/firestore/src/core/transaction.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
*/
1717

1818
import { ParsedSetData, ParsedUpdateData } from '../api/user_data_reader';
19-
import { documentVersionMap } from '../model/collections';
2019
import { Document, MaybeDocument, NoDocument } from '../model/document';
2120

2221
import { DocumentKey } from '../model/document_key';
@@ -34,14 +33,15 @@ import {
3433
import { fail, debugAssert } from '../util/assert';
3534
import { Code, FirestoreError } from '../util/error';
3635
import { SnapshotVersion } from './snapshot_version';
36+
import { ResourcePath } from '../model/path';
3737

3838
/**
3939
* Internal transaction object responsible for accumulating the mutations to
4040
* perform and the base versions for any documents read.
4141
*/
4242
export class Transaction {
4343
// The version of each document that was read during this transaction.
44-
private readVersions = documentVersionMap();
44+
private readVersions = new Map</* path */ string, SnapshotVersion>();
4545
private mutations: Mutation[] = [];
4646
private committed = false;
4747

@@ -106,14 +106,15 @@ export class Transaction {
106106
if (this.lastWriteError) {
107107
throw this.lastWriteError;
108108
}
109-
let unwritten = this.readVersions;
109+
const unwritten = this.readVersions;
110110
// For each mutation, note that the doc was written.
111111
this.mutations.forEach(mutation => {
112-
unwritten = unwritten.remove(mutation.key);
112+
unwritten.delete(mutation.key.toString());
113113
});
114114
// For each document that was read but not written to, we want to perform
115115
// a `verify` operation.
116-
unwritten.forEach((key, _version) => {
116+
unwritten.forEach((_, path) => {
117+
const key = new DocumentKey(ResourcePath.fromString(path));
117118
this.mutations.push(new VerifyMutation(key, this.precondition(key)));
118119
});
119120
await invokeCommitRpc(this.datastore, this.mutations);
@@ -132,8 +133,8 @@ export class Transaction {
132133
throw fail('Document in a transaction was a ' + doc.constructor.name);
133134
}
134135

135-
const existingVersion = this.readVersions.get(doc.key);
136-
if (existingVersion !== null) {
136+
const existingVersion = this.readVersions.get(doc.key.toString());
137+
if (existingVersion) {
137138
if (!docVersion.isEqual(existingVersion)) {
138139
// This transaction will fail no matter what.
139140
throw new FirestoreError(
@@ -142,7 +143,7 @@ export class Transaction {
142143
);
143144
}
144145
} else {
145-
this.readVersions = this.readVersions.insert(doc.key, docVersion);
146+
this.readVersions.set(doc.key.toString(), docVersion);
146147
}
147148
}
148149

@@ -151,7 +152,7 @@ export class Transaction {
151152
* as a precondition, or no precondition if it was not read.
152153
*/
153154
private precondition(key: DocumentKey): Precondition {
154-
const version = this.readVersions.get(key);
155+
const version = this.readVersions.get(key.toString());
155156
if (!this.writtenDocs.has(key) && version) {
156157
return Precondition.updateTime(version);
157158
} else {
@@ -163,7 +164,7 @@ export class Transaction {
163164
* Returns the precondition for a document if the operation is an update.
164165
*/
165166
private preconditionForUpdate(key: DocumentKey): Precondition {
166-
const version = this.readVersions.get(key);
167+
const version = this.readVersions.get(key.toString());
167168
// The first time a document is written, we want to take into account the
168169
// read time and existence
169170
if (!this.writtenDocs.has(key) && version) {

packages/firestore/src/core/transaction_runner.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { Deferred } from '../util/promise';
1919
import { TimerId, AsyncQueue } from '../util/async_queue';
2020
import { ExponentialBackoff } from '../remote/backoff';
2121
import { Transaction } from './transaction';
22-
import { RemoteStore } from '../remote/remote_store';
22+
import { Datastore } from '../remote/datastore';
2323
import { isNullOrUndefined } from '../util/types';
2424
import { isPermanentError } from '../remote/rpc_error';
2525
import { FirestoreError } from '../util/error';
@@ -36,7 +36,7 @@ export class TransactionRunner<T> {
3636

3737
constructor(
3838
private readonly asyncQueue: AsyncQueue,
39-
private readonly remoteStore: RemoteStore,
39+
private readonly datastore: Datastore,
4040
private readonly updateFunction: (transaction: Transaction) => Promise<T>,
4141
private readonly deferred: Deferred<T>
4242
) {
@@ -53,7 +53,7 @@ export class TransactionRunner<T> {
5353

5454
private runWithBackOff(): void {
5555
this.backoff.backoffAndRun(async () => {
56-
const transaction = this.remoteStore.createTransaction();
56+
const transaction = new Transaction(this.datastore);
5757
const userPromise = this.tryRunUpdateFunction(transaction);
5858
if (userPromise) {
5959
userPromise

0 commit comments

Comments
 (0)