Skip to content

Commit 00235ba

Browse files
Hanging query follow up (#7771)
* google-closure-library: git://github.com/google/closure-library.git#7818ff7 * Tests and hard asserts for hanging query issue - #7652 * Re-enable useFetchStreams * Create orange-pianos-push.md * Revert change to yarn.lock for rules-unit-testing/functions/ * git+https for google-closure-library * Update yarn.lock * Yarn.lock again * git+https in yarn.lock * Increase timeout setting up the repro for hanging queries. * Clean up error message for hardAssert based on peer feedback.
1 parent b782bb2 commit 00235ba

File tree

8 files changed

+2513
-2477
lines changed

8 files changed

+2513
-2477
lines changed

.changeset/orange-pianos-push.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@firebase/firestore": patch
3+
"@firebase/webchannel-wrapper": patch
4+
"firebase": patch
5+
---
6+
7+
Fix high memory usage of Firestore in browsers.

packages/firestore/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
"@firebase/component": "0.6.4",
100100
"@firebase/logger": "0.4.0",
101101
"@firebase/util": "1.9.3",
102-
"@firebase/webchannel-wrapper": "0.10.3",
102+
"@firebase/webchannel-wrapper": "0.10.4",
103103
"@grpc/grpc-js": "~1.9.0",
104104
"@grpc/proto-loader": "^0.7.8",
105105
"undici": "5.26.5",

packages/firestore/src/platform/browser/webchannel_connection.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ import {
2727
EventTarget,
2828
StatEvent,
2929
Event,
30-
Stat,
31-
FetchXmlHttpFactory
30+
Stat
3231
} from '@firebase/webchannel-wrapper';
3332

3433
import { Token } from '../../api/credentials';
@@ -209,8 +208,7 @@ export class WebChannelConnection extends RestConnection {
209208
}
210209

211210
if (this.useFetchStreams) {
212-
// TODO(b/307942499): switch to `useFetchStreams` once WebChannel is fixed.
213-
request.xmlHttpFactory = new FetchXmlHttpFactory({});
211+
request.useFetchStreams = true;
214212
}
215213

216214
this.modifyHeadersForRequest(

packages/firestore/src/remote/watch_change.ts

+7
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,13 @@ class TargetState {
240240

241241
recordTargetResponse(): void {
242242
this.pendingResponses -= 1;
243+
hardAssert(
244+
this.pendingResponses >= 0,
245+
'`pendingResponses` is less than 0. Actual value: ' +
246+
this.pendingResponses +
247+
'. This indicates that the SDK received more target acks from the ' +
248+
'server than expected. The SDK should not continue to operate.'
249+
);
243250
}
244251

245252
markCurrent(): void {

packages/firestore/test/integration/api/query.test.ts

+117-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ import {
5757
Timestamp,
5858
updateDoc,
5959
where,
60-
writeBatch
60+
writeBatch,
61+
CollectionReference,
62+
WriteBatch,
63+
Firestore
6164
} from '../util/firebase_export';
6265
import {
6366
apiDescribe,
@@ -2821,6 +2824,119 @@ apiDescribe('Queries', persistence => {
28212824
).timeout('90s');
28222825
});
28232826

2827+
apiDescribe('Hanging query issue - #7652', persistence => {
2828+
// Defines a collection that produces the hanging query issue.
2829+
const collectionDefinition = {
2830+
'totalDocs': 573,
2831+
'pageSize': 127,
2832+
'dataSizes': [
2833+
2578, 622, 3385, 0, 2525, 1084, 4192, 3940, 520, 0, 3675, 0, 2639, 1194,
2834+
0, 247, 0, 1618, 494, 1559, 0, 0, 2756, 250, 497, 0, 2071, 355, 3594,
2835+
3174, 2186, 1834, 2455, 226, 211, 2202, 3036, 0, 684, 3114, 0, 0, 1312,
2836+
758, 0, 0, 3582, 586, 1219, 0, 0, 3831, 2848, 1485, 4739, 0, 2632, 0,
2837+
1266, 2169, 0, 179, 1780, 4296, 2041, 3829, 2028, 5430, 0, 0, 5006, 2877,
2838+
0, 298, 538, 0, 3158, 1070, 3221, 652, 2946, 3600, 1716, 2308, 890, 784,
2839+
1332, 4530, 1727, 0, 653, 0, 386, 576, 0, 1908, 0, 5539, 1127, 0, 2340, 0,
2840+
1782, 0, 2153, 194, 0, 3432, 2881, 1016, 0, 941, 430, 5806, 1523, 3287,
2841+
2940, 196, 0, 418, 2012, 2616, 4264, 0, 3226, 1294, 1400, 2425, 0, 0,
2842+
4530, 466, 0, 1803, 2145, 1763, 0, 1190, 0, 0, 3729, 700, 3258, 132, 2307,
2843+
0, 1573, 38, 3209, 2564, 2835, 1554, 1035, 0, 2893, 2141, 2743, 0, 4443,
2844+
296, 0, 0, 576, 0, 770, 0, 3413, 694, 2779, 2541, 0, 0, 787, 3773, 862,
2845+
3311, 1012, 0, 0, 1924, 2511, 1512, 0, 0, 1348, 1327, 0, 0, 2629, 2933,
2846+
145, 457, 4270, 3629, 0, 0, 3060, 1404, 4841, 1657, 0, 1176, 0, 0, 1216,
2847+
1505, 449, 0, 2179, 1168, 0, 1305, 0, 2915, 2692, 1103, 2986, 1200, 1799,
2848+
2526, 827, 0, 2581, 6323, 400, 1377, 1306, 3043, 447, 1479, 520, 4572,
2849+
1883, 0, 6004, 345, 2126, 0, 1967, 3265, 1802, 0, 2986, 3979, 2493, 599,
2850+
3575, 86, 2062, 1596, 1676, 2026, 0, 861, 4938, 1734, 2598, 2503, 0, 0,
2851+
121, 0, 4068, 0, 1492, 0, 0, 0, 1947, 2352, 4353, 0, 0, 1036, 4161, 3142,
2852+
605, 144, 0, 2240, 0, 3382, 2947, 0, 4334, 3441, 5045, 2213, 3131, 0, 154,
2853+
2317, 2831, 0, 1608, 0, 2483, 0, 3992, 4915, 0, 3481, 0, 4369, 951, 2307,
2854+
430, 1510, 1079, 58, 0, 2752, 2782, 108, 0, 2309, 555, 2276, 1969, 0,
2855+
1708, 1282, 1870, 4300, 3909, 3801, 3216, 1240, 1303, 61, 3846, 0, 0,
2856+
3250, 203, 2969, 4053, 452, 1834, 2272, 1605, 3952, 0, 2685, 0, 773, 0,
2857+
2211, 0, 1049, 1076, 0, 18, 2919, 620, 2220, 1238, 0, 3557, 1879, 1264,
2858+
4030, 2001, 770, 1327, 0, 4036, 43, 5425, 0, 0, 1282, 1350, 1672, 1996,
2859+
2969, 275, 1429, 2504, 0, 160, 891, 1471, 5487, 1966, 1780, 0, 2265, 3753,
2860+
4226, 1710, 0, 1583, 5488, 3460, 3942, 2329, 2399, 0, 924, 1879, 0, 2476,
2861+
4164, 3064, 4950, 2464, 1268, 1621, 430, 0, 770, 0, 3807, 1946, 0, 1484,
2862+
3460, 674, 3089, 0, 0, 437, 2535, 0, 0, 2423, 1251, 2087, 2682, 2820, 239,
2863+
0, 1596, 34, 3823, 546, 0, 2495, 0, 3762, 887, 0, 0, 0, 3353, 0, 0, 3230,
2864+
5250, 3369, 4344, 50, 4180, 2033, 1475, 1498, 3402, 1, 900, 0, 4210, 1069,
2865+
0, 1595, 2444, 0, 3249, 3440, 0, 2572, 4686, 1586, 1395, 1890, 946, 0,
2866+
1052, 405, 1800, 0, 1482, 2041, 1416, 3639, 1795, 2380, 1502, 944, 3835,
2867+
688, 6986, 1187, 3572, 2997, 2580, 552, 52, 0, 2924, 0, 0, 1631, 283,
2868+
5936, 0, 3057, 2243, 45, 2944, 3417, 3645, 1800, 1958, 1428, 0, 5347, 186,
2869+
0, 4274, 1590, 2729, 4168, 4175, 0, 2234, 0, 2430, 0, 1751, 0, 0, 2847, 0,
2870+
3726, 728, 5645, 1666, 1900, 2835, 3925, 1425, 576, 0, 5067, 2202, 868,
2871+
2337, 4748, 2690, 0, 3289, 0, 0, 484, 1628, 0, 1195, 1883, 1114, 6103,
2872+
1055, 3794, 2030, 0, 0, 1124, 0, 0, 1353, 0, 3410, 0
2873+
]
2874+
};
2875+
let collPath: string;
2876+
2877+
// Recreates a collection that produces the hanging query issue.
2878+
async function generateTestData(
2879+
db: Firestore,
2880+
coll: CollectionReference
2881+
): Promise<void> {
2882+
let batch: WriteBatch | null = null;
2883+
for (let i = 1; i <= collectionDefinition.totalDocs; i++) {
2884+
if (batch == null) {
2885+
batch = writeBatch(db);
2886+
}
2887+
2888+
batch.set(doc(coll, i.toString()), {
2889+
id: i,
2890+
data: new Array(collectionDefinition.dataSizes[i]).fill(0).join(''),
2891+
createdClientTs: Date.now()
2892+
});
2893+
2894+
if (i % 100 === 0) {
2895+
await batch.commit();
2896+
batch = null;
2897+
}
2898+
}
2899+
2900+
if (batch != null) {
2901+
await batch.commit();
2902+
}
2903+
}
2904+
2905+
// Before all test iterations, create a collection that produces the
2906+
// hanging query issue.
2907+
before(function () {
2908+
this.timeout('90s');
2909+
return withTestCollection(persistence, {}, async (testCollection, db) => {
2910+
collPath = testCollection.path;
2911+
await generateTestData(db, testCollection);
2912+
});
2913+
});
2914+
2915+
// Run the test for 20 iteration to attempt to force a failure.
2916+
for (let i = 0; i < 20; i++) {
2917+
// Do not ignore timeouts for these tests. A timeout may indicate a
2918+
// regression. The test is attempting to reproduce hanging queries
2919+
// with a data set known to reproduce.
2920+
it(`iteration ${i}`, async () => {
2921+
return withTestDb(persistence, async db => {
2922+
const q = query(
2923+
collection(db, collPath)!,
2924+
orderBy('id'),
2925+
limit(collectionDefinition.pageSize)
2926+
);
2927+
2928+
// In issue #7652, this line will hang indefinitely.
2929+
// The root cause was addressed, and a hardAssert was
2930+
// added to catch any regressions, so this is no longer
2931+
// expected to hang.
2932+
const qSnap = await getDocs(q);
2933+
2934+
expect(qSnap.size).to.equal(collectionDefinition.pageSize);
2935+
});
2936+
});
2937+
}
2938+
});
2939+
28242940
function verifyDocumentChange<T>(
28252941
change: DocumentChange<T>,
28262942
id: string,

packages/firestore/test/unit/specs/listen_spec.test.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -954,17 +954,18 @@ describeSpec('Listens:', [], () => {
954954
);
955955

956956
// Reproduces b/249494921.
957+
// TODO(b/310241864) this test puts the SDK into an invalid state that is now
958+
// failing a hardAssert, so it is being ignored until it can be fixed.
957959
specTest(
958960
'Secondary client advances query state with global snapshot from primary',
959-
['multi-client'],
961+
['multi-client', 'no-web', 'no-ios', 'no-android'],
960962
() => {
961963
const query1 = query('collection');
962964
const docA = doc('collection/a', 1000, { key: '1' });
963965
const docADeleted = deletedDoc('collection/a', 2000);
964966
const docARecreated = doc('collection/a', 2000, {
965967
key: '2'
966968
}).setHasLocalMutations();
967-
968969
return (
969970
client(0)
970971
.becomeVisible()
@@ -990,6 +991,9 @@ describeSpec('Listens:', [], () => {
990991
})
991992
.client(0)
992993
.writeAcks('collection/a', 2000)
994+
// b/310241864: This line causes an add target ack without an add
995+
// target request. The unexpected ack puts the SDK into a bad state
996+
// which now fails a hardAssert.
993997
.watchAcksFull(query1, 2000, docADeleted)
994998
.client(1) // expects no event
995999
.client(0)

packages/webchannel-wrapper/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@firebase/webchannel-wrapper",
3-
"version": "0.10.3",
3+
"version": "0.10.4",
44
"description": "A wrapper of the webchannel packages from closure-library for use outside of a closure compiled application",
55
"author": "Firebase <[email protected]> (https://firebase.google.com/)",
66
"main": "dist/index.js",
@@ -28,7 +28,7 @@
2828
"devDependencies": {
2929
"@rollup/plugin-commonjs": "21.1.0",
3030
"google-closure-compiler": "20230228.0.0",
31-
"google-closure-library": "20230228.0.0",
31+
"google-closure-library": "git+https://github.com/google/closure-library.git#7818ff7",
3232
"gulp": "4.0.2",
3333
"gulp-sourcemaps": "3.0.0",
3434
"rollup": "2.79.1",

0 commit comments

Comments
 (0)