Skip to content

Commit 47e035f

Browse files
Tree-Shake EventQueue (#4462)
1 parent 7772426 commit 47e035f

File tree

2 files changed

+131
-97
lines changed

2 files changed

+131
-97
lines changed

packages/database/src/core/Repo.ts

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,32 @@ import { SparseSnapshotTree } from './SparseSnapshotTree';
2626
import { SyncTree } from './SyncTree';
2727
import { SnapshotHolder } from './SnapshotHolder';
2828
import {
29-
stringify,
30-
map,
31-
isEmpty,
3229
assert,
3330
contains,
34-
safeGet
31+
isEmpty,
32+
map,
33+
safeGet,
34+
stringify
3535
} from '@firebase/util';
3636
import {
3737
beingCrawled,
3838
each,
3939
exceptionGuard,
40-
warn,
4140
log,
42-
LUIDGenerator
41+
LUIDGenerator,
42+
warn
4343
} from './util/util';
4444

4545
import { AuthTokenProvider } from './AuthTokenProvider';
4646
import { StatsManager } from './stats/StatsManager';
4747
import { StatsReporter } from './stats/StatsReporter';
4848
import { StatsListener } from './stats/StatsListener';
49-
import { EventQueue } from './view/EventQueue';
49+
import {
50+
EventQueue,
51+
eventQueueQueueEvents,
52+
eventQueueRaiseEventsAtPath,
53+
eventQueueRaiseEventsForChangedPath
54+
} from './view/EventQueue';
5055
import { PersistentConnection } from './PersistentConnection';
5156
import { ReadonlyRestClient } from './ReadonlyRestClient';
5257
import { RepoInfo } from './RepoInfo';
@@ -234,7 +239,11 @@ export class Repo {
234239
startListening: (query, tag, currentHashFn, onComplete) => {
235240
this.server_.listen(query, currentHashFn, tag, (status, data) => {
236241
const events = onComplete(status, data);
237-
this.eventQueue_.raiseEventsForChangedPath(query.path, events);
242+
eventQueueRaiseEventsForChangedPath(
243+
this.eventQueue_,
244+
query.path,
245+
events
246+
);
238247
});
239248
// No synchronous events for network-backed sync trees
240249
return [];
@@ -332,7 +341,7 @@ export class Repo {
332341
// is a proxy for some change having occurred.
333342
affectedPath = this.rerunTransactions_(path);
334343
}
335-
this.eventQueue_.raiseEventsForChangedPath(affectedPath, events);
344+
eventQueueRaiseEventsForChangedPath(this.eventQueue_, affectedPath, events);
336345
}
337346

338347
// TODO: This should be @private but it's used by test_access.js and internal.js
@@ -358,7 +367,7 @@ export class Repo {
358367
const newNode = nodeFromJSON(value);
359368
this.infoData_.updateSnapshot(path, newNode);
360369
const events = this.infoSyncTree_.applyServerOverwrite(path, newNode);
361-
this.eventQueue_.raiseEventsForChangedPath(path, events);
370+
eventQueueRaiseEventsForChangedPath(this.eventQueue_, path, events);
362371
}
363372

364373
private getNextWriteId_(): number {
@@ -399,7 +408,7 @@ export class Repo {
399408
query.path,
400409
node
401410
);
402-
this.eventQueue_.raiseEventsAtPath(query.path, events);
411+
eventQueueRaiseEventsAtPath(this.eventQueue_, query.path, events);
403412
return Promise.resolve(
404413
new DataSnapshot(
405414
node,
@@ -445,7 +454,7 @@ export class Repo {
445454
writeId,
446455
true
447456
);
448-
this.eventQueue_.queueEvents(events);
457+
eventQueueQueueEvents(this.eventQueue_, events);
449458
this.server_.put(
450459
path.toString(),
451460
newNodeUnresolved.val(/*export=*/ true),
@@ -459,14 +468,18 @@ export class Repo {
459468
writeId,
460469
!success
461470
);
462-
this.eventQueue_.raiseEventsForChangedPath(path, clearEvents);
471+
eventQueueRaiseEventsForChangedPath(
472+
this.eventQueue_,
473+
path,
474+
clearEvents
475+
);
463476
this.callOnCompleteCallback(onComplete, status, errorReason);
464477
}
465478
);
466479
const affectedPath = this.abortTransactions_(path);
467480
this.rerunTransactions_(affectedPath);
468481
// We queued the events above, so just flush the queue here
469-
this.eventQueue_.raiseEventsForChangedPath(affectedPath, []);
482+
eventQueueRaiseEventsForChangedPath(this.eventQueue_, affectedPath, []);
470483
}
471484

472485
update(
@@ -497,7 +510,7 @@ export class Repo {
497510
changedChildren,
498511
writeId
499512
);
500-
this.eventQueue_.queueEvents(events);
513+
eventQueueQueueEvents(this.eventQueue_, events);
501514
this.server_.merge(
502515
path.toString(),
503516
childrenToMerge,
@@ -513,7 +526,11 @@ export class Repo {
513526
);
514527
const affectedPath =
515528
clearEvents.length > 0 ? this.rerunTransactions_(path) : path;
516-
this.eventQueue_.raiseEventsForChangedPath(affectedPath, clearEvents);
529+
eventQueueRaiseEventsForChangedPath(
530+
this.eventQueue_,
531+
affectedPath,
532+
clearEvents
533+
);
517534
this.callOnCompleteCallback(onComplete, status, errorReason);
518535
}
519536
);
@@ -524,7 +541,7 @@ export class Repo {
524541
});
525542

526543
// We queued the events above, so just flush the queue here
527-
this.eventQueue_.raiseEventsForChangedPath(path, []);
544+
eventQueueRaiseEventsForChangedPath(this.eventQueue_, path, []);
528545
} else {
529546
log("update() called with empty data. Don't do anything.");
530547
this.callOnCompleteCallback(onComplete, 'ok');
@@ -559,7 +576,7 @@ export class Repo {
559576
});
560577

561578
this.onDisconnect_ = new SparseSnapshotTree();
562-
this.eventQueue_.raiseEventsForChangedPath(Path.Empty, events);
579+
eventQueueRaiseEventsForChangedPath(this.eventQueue_, Path.Empty, events);
563580
}
564581

565582
onDisconnectCancel(
@@ -652,7 +669,7 @@ export class Repo {
652669
eventRegistration
653670
);
654671
}
655-
this.eventQueue_.raiseEventsAtPath(query.path, events);
672+
eventQueueRaiseEventsAtPath(this.eventQueue_, query.path, events);
656673
}
657674

658675
removeEventCallbackForQuery(
@@ -673,7 +690,7 @@ export class Repo {
673690
eventRegistration
674691
);
675692
}
676-
this.eventQueue_.raiseEventsAtPath(query.path, events);
693+
eventQueueRaiseEventsAtPath(this.eventQueue_, query.path, events);
677694
}
678695

679696
interrupt() {
@@ -885,7 +902,7 @@ export class Repo {
885902
transaction.currentWriteId,
886903
transaction.applyLocally
887904
);
888-
this.eventQueue_.raiseEventsForChangedPath(path, events);
905+
eventQueueRaiseEventsForChangedPath(this.eventQueue_, path, events);
889906

890907
this.sendReadyTransactions_();
891908
}
@@ -1013,7 +1030,7 @@ export class Repo {
10131030
// There may be pending transactions that we can now send.
10141031
this.sendReadyTransactions_();
10151032

1016-
this.eventQueue_.raiseEventsForChangedPath(path, events);
1033+
eventQueueRaiseEventsForChangedPath(this.eventQueue_, path, events);
10171034

10181035
// Finally, trigger onComplete callbacks.
10191036
for (let i = 0; i < callbacks.length; i++) {
@@ -1178,7 +1195,7 @@ export class Repo {
11781195
}
11791196
}
11801197
}
1181-
this.eventQueue_.raiseEventsForChangedPath(path, events);
1198+
eventQueueRaiseEventsForChangedPath(this.eventQueue_, path, events);
11821199
events = [];
11831200
if (abortTransaction) {
11841201
// Abort.
@@ -1392,7 +1409,11 @@ export class Repo {
13921409
}
13931410

13941411
// Now fire the callbacks.
1395-
this.eventQueue_.raiseEventsForChangedPath(node.path(), events);
1412+
eventQueueRaiseEventsForChangedPath(
1413+
this.eventQueue_,
1414+
node.path(),
1415+
events
1416+
);
13961417
for (let i = 0; i < callbacks.length; i++) {
13971418
exceptionGuard(callbacks[i]);
13981419
}

packages/database/src/core/view/EventQueue.ts

Lines changed: 86 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -33,96 +33,109 @@ import { Event } from './Event';
3333
*
3434
*/
3535
export class EventQueue {
36-
private eventLists_: EventList[] = [];
36+
eventLists_: EventList[] = [];
3737

3838
/**
3939
* Tracks recursion depth of raiseQueuedEvents_, for debugging purposes.
4040
*/
41-
private recursionDepth_ = 0;
42-
43-
/**
44-
* @param eventDataList The new events to queue.
45-
*/
46-
queueEvents(eventDataList: Event[]) {
47-
// We group events by path, storing them in a single EventList, to make it easier to skip over them quickly.
48-
let currList: EventList | null = null;
49-
for (let i = 0; i < eventDataList.length; i++) {
50-
const data = eventDataList[i];
51-
const path = data.getPath();
52-
if (currList !== null && !path.equals(currList.path)) {
53-
this.eventLists_.push(currList);
54-
currList = null;
55-
}
56-
57-
if (currList === null) {
58-
currList = { events: [], path };
59-
}
41+
recursionDepth_ = 0;
42+
}
6043

61-
currList.events.push(data);
44+
/**
45+
* @param eventDataList The new events to queue.
46+
*/
47+
export function eventQueueQueueEvents(
48+
eventQueue: EventQueue,
49+
eventDataList: Event[]
50+
) {
51+
// We group events by path, storing them in a single EventList, to make it easier to skip over them quickly.
52+
let currList: EventList | null = null;
53+
for (let i = 0; i < eventDataList.length; i++) {
54+
const data = eventDataList[i];
55+
const path = data.getPath();
56+
if (currList !== null && !path.equals(currList.path)) {
57+
eventQueue.eventLists_.push(currList);
58+
currList = null;
6259
}
63-
if (currList) {
64-
this.eventLists_.push(currList);
60+
61+
if (currList === null) {
62+
currList = { events: [], path };
6563
}
66-
}
6764

68-
/**
69-
* Queues the specified events and synchronously raises all events (including previously queued ones)
70-
* for the specified path.
71-
*
72-
* It is assumed that the new events are all for the specified path.
73-
*
74-
* @param path The path to raise events for.
75-
* @param eventDataList The new events to raise.
76-
*/
77-
raiseEventsAtPath(path: Path, eventDataList: Event[]) {
78-
this.queueEvents(eventDataList);
79-
this.raiseQueuedEventsMatchingPredicate_((eventPath: Path) =>
80-
eventPath.equals(path)
81-
);
65+
currList.events.push(data);
66+
}
67+
if (currList) {
68+
eventQueue.eventLists_.push(currList);
8269
}
70+
}
8371

84-
/**
85-
* Queues the specified events and synchronously raises all events (including previously queued ones) for
86-
* locations related to the specified change path (i.e. all ancestors and descendants).
87-
*
88-
* It is assumed that the new events are all related (ancestor or descendant) to the specified path.
89-
*
90-
* @param changedPath The path to raise events for.
91-
* @param eventDataList The events to raise
92-
*/
93-
raiseEventsForChangedPath(changedPath: Path, eventDataList: Event[]) {
94-
this.queueEvents(eventDataList);
72+
/**
73+
* Queues the specified events and synchronously raises all events (including previously queued ones)
74+
* for the specified path.
75+
*
76+
* It is assumed that the new events are all for the specified path.
77+
*
78+
* @param path The path to raise events for.
79+
* @param eventDataList The new events to raise.
80+
*/
81+
export function eventQueueRaiseEventsAtPath(
82+
eventQueue: EventQueue,
83+
path: Path,
84+
eventDataList: Event[]
85+
) {
86+
eventQueueQueueEvents(eventQueue, eventDataList);
87+
eventQueueRaiseQueuedEventsMatchingPredicate(eventQueue, eventPath =>
88+
eventPath.equals(path)
89+
);
90+
}
9591

96-
this.raiseQueuedEventsMatchingPredicate_((eventPath: Path) => {
97-
return eventPath.contains(changedPath) || changedPath.contains(eventPath);
98-
});
99-
}
92+
/**
93+
* Queues the specified events and synchronously raises all events (including previously queued ones) for
94+
* locations related to the specified change path (i.e. all ancestors and descendants).
95+
*
96+
* It is assumed that the new events are all related (ancestor or descendant) to the specified path.
97+
*
98+
* @param changedPath The path to raise events for.
99+
* @param eventDataList The events to raise
100+
*/
101+
export function eventQueueRaiseEventsForChangedPath(
102+
eventQueue: EventQueue,
103+
changedPath: Path,
104+
eventDataList: Event[]
105+
) {
106+
eventQueueQueueEvents(eventQueue, eventDataList);
107+
eventQueueRaiseQueuedEventsMatchingPredicate(
108+
eventQueue,
109+
eventPath =>
110+
eventPath.contains(changedPath) || changedPath.contains(eventPath)
111+
);
112+
}
100113

101-
private raiseQueuedEventsMatchingPredicate_(
102-
predicate: (path: Path) => boolean
103-
) {
104-
this.recursionDepth_++;
114+
function eventQueueRaiseQueuedEventsMatchingPredicate(
115+
eventQueue: EventQueue,
116+
predicate: (path: Path) => boolean
117+
) {
118+
eventQueue.recursionDepth_++;
105119

106-
let sentAll = true;
107-
for (let i = 0; i < this.eventLists_.length; i++) {
108-
const eventList = this.eventLists_[i];
109-
if (eventList) {
110-
const eventPath = eventList.path;
111-
if (predicate(eventPath)) {
112-
eventListRaise(this.eventLists_[i]);
113-
this.eventLists_[i] = null;
114-
} else {
115-
sentAll = false;
116-
}
120+
let sentAll = true;
121+
for (let i = 0; i < eventQueue.eventLists_.length; i++) {
122+
const eventList = eventQueue.eventLists_[i];
123+
if (eventList) {
124+
const eventPath = eventList.path;
125+
if (predicate(eventPath)) {
126+
eventListRaise(eventQueue.eventLists_[i]);
127+
eventQueue.eventLists_[i] = null;
128+
} else {
129+
sentAll = false;
117130
}
118131
}
132+
}
119133

120-
if (sentAll) {
121-
this.eventLists_ = [];
122-
}
123-
124-
this.recursionDepth_--;
134+
if (sentAll) {
135+
eventQueue.eventLists_ = [];
125136
}
137+
138+
eventQueue.recursionDepth_--;
126139
}
127140

128141
interface EventList {

0 commit comments

Comments
 (0)