From b58e756df39508ecd07666a60ca67f4887f64d4b Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Tue, 17 Jan 2023 10:29:20 -0800 Subject: [PATCH 01/22] Update protos to include bloom filter (#4564) --- firebase-abt/CHANGELOG.md | 2 + .../firebase/abt/FirebaseABTesting.java | 63 ++++++------ .../firebase/abt/FirebaseABTestingTest.java | 98 +++++++++++++++---- .../google/firestore/v1/bloom_filter.proto | 73 ++++++++++++++ .../proto/google/firestore/v1/firestore.proto | 10 ++ .../src/proto/google/firestore/v1/write.proto | 15 +++ 6 files changed, 214 insertions(+), 47 deletions(-) create mode 100644 firebase-firestore/src/proto/google/firestore/v1/bloom_filter.proto diff --git a/firebase-abt/CHANGELOG.md b/firebase-abt/CHANGELOG.md index 931ae65ff4d..d54afdaa8e6 100644 --- a/firebase-abt/CHANGELOG.md +++ b/firebase-abt/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased +* [changed] Internal changes to improve experiment reporting. + # 21.1.0 * [changed] Internal changes to ensure functionality alignment with other SDK releases. diff --git a/firebase-abt/src/main/java/com/google/firebase/abt/FirebaseABTesting.java b/firebase-abt/src/main/java/com/google/firebase/abt/FirebaseABTesting.java index 15ce789b78d..d3f89e99bbf 100644 --- a/firebase-abt/src/main/java/com/google/firebase/abt/FirebaseABTesting.java +++ b/firebase-abt/src/main/java/com/google/firebase/abt/FirebaseABTesting.java @@ -30,10 +30,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Deque; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; /** * Manages Firebase A/B Testing Experiments. @@ -144,11 +142,11 @@ public void removeAllExperiments() throws AbtException { } /** - * Gets the origin service's list of experiments in the app. + * Gets the origin service's list of experiments in the app via the Analytics SDK. * *

Note: This is a blocking call and therefore should be called from a worker thread. * - * @return the origin service's list of experiments in the app. + * @return the origin service's list of experiments in the app as {@link AbtExperimentInfo}s. * @throws AbtException If there is no Analytics SDK. */ @WorkerThread @@ -204,12 +202,10 @@ public void reportActiveExperiment(AbtExperimentInfo activeExperiment) throws Ab public void validateRunningExperiments(List runningExperiments) throws AbtException { throwAbtExceptionIfAnalyticsIsNull(); - Set runningExperimentIds = new HashSet<>(); - for (AbtExperimentInfo runningExperiment : runningExperiments) { - runningExperimentIds.add(runningExperiment.getExperimentId()); - } + + // Get all experiments in Analytics and remove the ones that aren't running. List experimentsToRemove = - getExperimentsToRemove(getAllExperimentsInAnalytics(), runningExperimentIds); + getExperimentsToRemove(getAllExperiments(), runningExperiments); removeExperiments(experimentsToRemove); } @@ -245,34 +241,29 @@ private void replaceAllExperimentsWith(List replacementExperi return; } - Set replacementExperimentIds = new HashSet<>(); - for (AbtExperimentInfo replacementExperiment : replacementExperiments) { - replacementExperimentIds.add(replacementExperiment.getExperimentId()); - } - - List experimentsInAnalytics = getAllExperimentsInAnalytics(); - Set idsOfExperimentsInAnalytics = new HashSet<>(); - for (ConditionalUserProperty experimentInAnalytics : experimentsInAnalytics) { - idsOfExperimentsInAnalytics.add(experimentInAnalytics.name); - } + // Get all experiments in Analytics. + List experimentsInAnalytics = getAllExperiments(); + // Remove experiments no longer assigned. List experimentsToRemove = - getExperimentsToRemove(experimentsInAnalytics, replacementExperimentIds); + getExperimentsToRemove(experimentsInAnalytics, replacementExperiments); removeExperiments(experimentsToRemove); + // Add newly assigned or updated (changed variant id). List experimentsToAdd = - getExperimentsToAdd(replacementExperiments, idsOfExperimentsInAnalytics); + getExperimentsToAdd(replacementExperiments, experimentsInAnalytics); addExperiments(experimentsToAdd); } /** Returns this origin's experiments in Analytics that are no longer assigned to this App. */ private ArrayList getExperimentsToRemove( - List experimentsInAnalytics, Set replacementExperimentIds) { + List experimentsInAnalytics, + List replacementExperiments) { ArrayList experimentsToRemove = new ArrayList<>(); - for (ConditionalUserProperty experimentInAnalytics : experimentsInAnalytics) { - if (!replacementExperimentIds.contains(experimentInAnalytics.name)) { - experimentsToRemove.add(experimentInAnalytics); + for (AbtExperimentInfo experimentInAnalytics : experimentsInAnalytics) { + if (!experimentsListContainsExperiment(replacementExperiments, experimentInAnalytics)) { + experimentsToRemove.add(experimentInAnalytics.toConditionalUserProperty(originService)); } } return experimentsToRemove; @@ -283,17 +274,33 @@ private ArrayList getExperimentsToRemove( * to this origin's list of experiments in Analytics. */ private ArrayList getExperimentsToAdd( - List replacementExperiments, Set idsOfExperimentsInAnalytics) { + List replacementExperiments, + List experimentInfoFromAnalytics) { ArrayList experimentsToAdd = new ArrayList<>(); for (AbtExperimentInfo replacementExperiment : replacementExperiments) { - if (!idsOfExperimentsInAnalytics.contains(replacementExperiment.getExperimentId())) { + if (!experimentsListContainsExperiment(experimentInfoFromAnalytics, replacementExperiment)) { experimentsToAdd.add(replacementExperiment); } } return experimentsToAdd; } + private boolean experimentsListContainsExperiment( + List experiments, AbtExperimentInfo experiment) { + String experimentId = experiment.getExperimentId(); + String variantId = experiment.getVariantId(); + + for (AbtExperimentInfo experimentInfo : experiments) { + if (experimentInfo.getExperimentId().equals(experimentId) + && experimentInfo.getVariantId().equals(variantId)) { + return true; + } + } + + return false; + } + /** Adds the given experiments to the origin's list in Analytics. */ private void addExperiments(List experimentsToAdd) { @@ -369,7 +376,7 @@ private int getMaxUserPropertiesInAnalytics() { * Returns a list of all this origin's experiments in this App's Analytics SDK. * *

The list is sorted chronologically by the experiment start time, with the oldest experiment - * at index 0. + * at index 0. Experiments are stored as {@link ConditionalUserProperty}s in Analytics. */ @WorkerThread private List getAllExperimentsInAnalytics() { diff --git a/firebase-abt/src/test/java/com/google/firebase/abt/FirebaseABTestingTest.java b/firebase-abt/src/test/java/com/google/firebase/abt/FirebaseABTestingTest.java index a98c05f317f..c8e2c6d8fdd 100644 --- a/firebase-abt/src/test/java/com/google/firebase/abt/FirebaseABTestingTest.java +++ b/firebase-abt/src/test/java/com/google/firebase/abt/FirebaseABTestingTest.java @@ -54,14 +54,27 @@ public class FirebaseABTestingTest { private static final String TEST_EXPERIMENT_1_ID = "1"; private static final String TEST_EXPERIMENT_2_ID = "2"; + private static final String TEST_VARIANT_ID_A = "VARIANT_A"; + private static final String TEST_VARIANT_ID_B = "VARIANT_B"; + private static final AbtExperimentInfo TEST_ABT_EXPERIMENT_1 = createExperimentInfo( TEST_EXPERIMENT_1_ID, + TEST_VARIANT_ID_A, /*triggerEventName=*/ "", /*experimentStartTimeInEpochMillis=*/ 1000L); - private static final AbtExperimentInfo TEST_ABT_EXPERIMENT_2 = + private static final AbtExperimentInfo TEST_ABT_EXPERIMENT_2_VARIANT_A = + createExperimentInfo( + TEST_EXPERIMENT_2_ID, + TEST_VARIANT_ID_A, + "trigger_event_2", + /*experimentStartTimeInEpochMillis=*/ 2000L); + private static final AbtExperimentInfo TEST_ABT_EXPERIMENT_2_VARIANT_B = createExperimentInfo( - TEST_EXPERIMENT_2_ID, "trigger_event_2", /*experimentStartTimeInEpochMillis=*/ 2000L); + TEST_EXPERIMENT_2_ID, + TEST_VARIANT_ID_B, + "trigger_event_2", + /*experimentStartTimeInEpochMillis=*/ 2000L); private static final int MAX_ALLOWED_EXPERIMENTS_IN_ANALYTICS = 100; @@ -91,7 +104,7 @@ public void replaceAllExperiments_noExperimentsInAnalytics_experimentsCorrectlyS firebaseAbt.replaceAllExperiments( Lists.newArrayList( - TEST_ABT_EXPERIMENT_1.toStringMap(), TEST_ABT_EXPERIMENT_2.toStringMap())); + TEST_ABT_EXPERIMENT_1.toStringMap(), TEST_ABT_EXPERIMENT_2_VARIANT_A.toStringMap())); ArgumentCaptor analyticsExperimentArgumentCaptor = ArgumentCaptor.forClass(ConditionalUserProperty.class); @@ -107,7 +120,8 @@ public void replaceAllExperiments_noExperimentsInAnalytics_experimentsCorrectlyS // Validates that TEST_ABT_EXPERIMENT_1 and TEST_ABT_EXPERIMENT_2 have been set in Analytics. assertThat(analyticsExperiment1.toStringMap()).isEqualTo(TEST_ABT_EXPERIMENT_1.toStringMap()); - assertThat(analyticsExperiment2.toStringMap()).isEqualTo(TEST_ABT_EXPERIMENT_2.toStringMap()); + assertThat(analyticsExperiment2.toStringMap()) + .isEqualTo(TEST_ABT_EXPERIMENT_2_VARIANT_A.toStringMap()); } @Test @@ -117,10 +131,11 @@ public void replaceAllExperiments_existExperimentsInAnalytics_experimentsCorrect .thenReturn( Lists.newArrayList( TEST_ABT_EXPERIMENT_1.toConditionalUserProperty(ORIGIN_SERVICE), - TEST_ABT_EXPERIMENT_2.toConditionalUserProperty(ORIGIN_SERVICE))); + TEST_ABT_EXPERIMENT_2_VARIANT_A.toConditionalUserProperty(ORIGIN_SERVICE))); - AbtExperimentInfo newExperiment3 = createExperimentInfo("3", "", 1000L); - AbtExperimentInfo newExperiment4 = createExperimentInfo("4", "trigger_event_4", 1000L); + AbtExperimentInfo newExperiment3 = createExperimentInfo("3", TEST_VARIANT_ID_A, "", 1000L); + AbtExperimentInfo newExperiment4 = + createExperimentInfo("4", TEST_VARIANT_ID_A, "trigger_event_4", 1000L); // Simulates the case where experiment 1 is assigned (as before), experiment 2 is no longer // assigned; experiment 3 and experiment 4 are newly assigned. @@ -146,6 +161,47 @@ public void replaceAllExperiments_existExperimentsInAnalytics_experimentsCorrect .isEqualTo(newExperiment4.toStringMap()); } + @Test + public void + replaceAllExperiments_existExperimentsInAnalyticsWithDifferentVariants_experimentsCorrectlySetInAnalytics() + throws Exception { + when(mockAnalyticsConnector.getConditionalUserProperties(ORIGIN_SERVICE, "")) + .thenReturn( + Lists.newArrayList( + TEST_ABT_EXPERIMENT_1.toConditionalUserProperty(ORIGIN_SERVICE), + TEST_ABT_EXPERIMENT_2_VARIANT_A.toConditionalUserProperty(ORIGIN_SERVICE))); + + AbtExperimentInfo newExperiment3 = createExperimentInfo("3", "b", "", 1000L); + AbtExperimentInfo newExperiment4 = createExperimentInfo("4", "a", "trigger_event_4", 1000L); + + // Simulates the case where experiments 1 and 2 are removed, + // experiment 2 is re-set with a new variant, and experiments 3 and 4 are newly added. + firebaseAbt.replaceAllExperiments( + Lists.newArrayList( + TEST_ABT_EXPERIMENT_2_VARIANT_B.toStringMap(), + newExperiment3.toStringMap(), + newExperiment4.toStringMap())); + + // Validates that experiment 1 is cleared, experiment 2 is updated, + // and experiment 3 and experiment 4 are set in Analytics. + ArgumentCaptor analyticsExperimentArgumentCaptor = + ArgumentCaptor.forClass(ConditionalUserProperty.class); + verify(mockAnalyticsConnector, times(1)) + .clearConditionalUserProperty(TEST_EXPERIMENT_1_ID, null, null); + verify(mockAnalyticsConnector, times(1)) + .clearConditionalUserProperty(TEST_EXPERIMENT_2_ID, null, null); + verify(mockAnalyticsConnector, times(3)) + .setConditionalUserProperty(analyticsExperimentArgumentCaptor.capture()); + + List actualValues = analyticsExperimentArgumentCaptor.getAllValues(); + assertThat(AbtExperimentInfo.fromConditionalUserProperty(actualValues.get(0)).toStringMap()) + .isEqualTo(TEST_ABT_EXPERIMENT_2_VARIANT_B.toStringMap()); + assertThat(AbtExperimentInfo.fromConditionalUserProperty(actualValues.get(1)).toStringMap()) + .isEqualTo(newExperiment3.toStringMap()); + assertThat(AbtExperimentInfo.fromConditionalUserProperty(actualValues.get(2)).toStringMap()) + .isEqualTo(newExperiment4.toStringMap()); + } + @Test public void replaceAllExperiments_totalExperimentsExceedsAnalyticsLimit_oldExperimentsDiscarded() throws Exception { @@ -155,17 +211,18 @@ public void replaceAllExperiments_totalExperimentsExceedsAnalyticsLimit_oldExper .thenReturn( Lists.newArrayList( TEST_ABT_EXPERIMENT_1.toConditionalUserProperty(ORIGIN_SERVICE), - TEST_ABT_EXPERIMENT_2.toConditionalUserProperty(ORIGIN_SERVICE))); + TEST_ABT_EXPERIMENT_2_VARIANT_A.toConditionalUserProperty(ORIGIN_SERVICE))); - AbtExperimentInfo newExperiment3 = createExperimentInfo("3", "", 1000L); - AbtExperimentInfo newExperiment4 = createExperimentInfo("4", "trigger_event_4", 1000L); + AbtExperimentInfo newExperiment3 = createExperimentInfo("3", TEST_VARIANT_ID_A, "", 1000L); + AbtExperimentInfo newExperiment4 = + createExperimentInfo("4", TEST_VARIANT_ID_A, "trigger_event_4", 1000L); // Simulates the case where experiment 1 and 2 are assigned (as before), experiment 3 and // experiment 4 are newly assigned. firebaseAbt.replaceAllExperiments( Lists.newArrayList( TEST_ABT_EXPERIMENT_1.toStringMap(), - TEST_ABT_EXPERIMENT_2.toStringMap(), + TEST_ABT_EXPERIMENT_2_VARIANT_A.toStringMap(), newExperiment3.toStringMap(), newExperiment4.toStringMap())); @@ -231,7 +288,7 @@ public void removeAllExperiments_existExperimentsInAnalytics_experimentsClearedF .thenReturn( Lists.newArrayList( TEST_ABT_EXPERIMENT_1.toConditionalUserProperty(ORIGIN_SERVICE), - TEST_ABT_EXPERIMENT_2.toConditionalUserProperty(ORIGIN_SERVICE))); + TEST_ABT_EXPERIMENT_2_VARIANT_A.toConditionalUserProperty(ORIGIN_SERVICE))); firebaseAbt.removeAllExperiments(); @@ -266,7 +323,7 @@ public void getAllExperiments_existExperimentsInAnalytics_returnAllExperiments() .thenReturn( Lists.newArrayList( TEST_ABT_EXPERIMENT_1.toConditionalUserProperty(ORIGIN_SERVICE), - TEST_ABT_EXPERIMENT_2.toConditionalUserProperty(ORIGIN_SERVICE))); + TEST_ABT_EXPERIMENT_2_VARIANT_A.toConditionalUserProperty(ORIGIN_SERVICE))); List abtExperimentInfoList = firebaseAbt.getAllExperiments(); @@ -274,7 +331,7 @@ public void getAllExperiments_existExperimentsInAnalytics_returnAllExperiments() assertThat(abtExperimentInfoList.get(0).toStringMap()) .isEqualTo(TEST_ABT_EXPERIMENT_1.toStringMap()); assertThat(abtExperimentInfoList.get(1).toStringMap()) - .isEqualTo(TEST_ABT_EXPERIMENT_2.toStringMap()); + .isEqualTo(TEST_ABT_EXPERIMENT_2_VARIANT_A.toStringMap()); } @Test @@ -298,7 +355,7 @@ public void getAllExperiments_analyticsSdkUnavailable_throwsAbtException() { .thenReturn( Lists.newArrayList( TEST_ABT_EXPERIMENT_1.toConditionalUserProperty(ORIGIN_SERVICE), - TEST_ABT_EXPERIMENT_2.toConditionalUserProperty(ORIGIN_SERVICE))); + TEST_ABT_EXPERIMENT_2_VARIANT_A.toConditionalUserProperty(ORIGIN_SERVICE))); // Update to just one experiment running firebaseAbt.validateRunningExperiments(Lists.newArrayList(TEST_ABT_EXPERIMENT_1)); @@ -315,11 +372,11 @@ public void validateRunningExperiments_noinactiveExperimentsInAnalytics_cleansUp .thenReturn( Lists.newArrayList( TEST_ABT_EXPERIMENT_1.toConditionalUserProperty(ORIGIN_SERVICE), - TEST_ABT_EXPERIMENT_2.toConditionalUserProperty(ORIGIN_SERVICE))); + TEST_ABT_EXPERIMENT_2_VARIANT_A.toConditionalUserProperty(ORIGIN_SERVICE))); // Update still says the same two experiments are running firebaseAbt.validateRunningExperiments( - Lists.newArrayList(TEST_ABT_EXPERIMENT_1, TEST_ABT_EXPERIMENT_2)); + Lists.newArrayList(TEST_ABT_EXPERIMENT_1, TEST_ABT_EXPERIMENT_2_VARIANT_A)); // Verify nothing cleared verify(mockAnalyticsConnector, never()).clearConditionalUserProperty(any(), any(), any()); @@ -346,11 +403,14 @@ public void reportActiveExperiment_setsNullTriggerCondition() throws Exception { } private static AbtExperimentInfo createExperimentInfo( - String experimentId, String triggerEventName, long experimentStartTimeInEpochMillis) { + String experimentId, + String variantId, + String triggerEventName, + long experimentStartTimeInEpochMillis) { return new AbtExperimentInfo( experimentId, - VARIANT_ID_VALUE, + variantId, triggerEventName, new Date(experimentStartTimeInEpochMillis), TRIGGER_TIMEOUT_IN_MILLIS_VALUE, diff --git a/firebase-firestore/src/proto/google/firestore/v1/bloom_filter.proto b/firebase-firestore/src/proto/google/firestore/v1/bloom_filter.proto new file mode 100644 index 00000000000..9487e3036fe --- /dev/null +++ b/firebase-firestore/src/proto/google/firestore/v1/bloom_filter.proto @@ -0,0 +1,73 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.firestore.v1; + +option csharp_namespace = "Google.Cloud.Firestore.V1"; +option go_package = "google.golang.org/genproto/googleapis/firestore/v1;firestore"; +option java_multiple_files = true; +option java_outer_classname = "BloomFilterProto"; +option java_package = "com.google.firestore.v1"; +option objc_class_prefix = "GCFS"; +option php_namespace = "Google\\Cloud\\Firestore\\V1"; +option ruby_package = "Google::Cloud::Firestore::V1"; + +// A sequence of bits, encoded in a byte array. +// +// Each byte in the `bitmap` byte array stores 8 bits of the sequence. The only +// exception is the last byte, which may store 8 _or fewer_ bits. The `padding` +// defines the number of bits of the last byte to be ignored as "padding". The +// values of these "padding" bits are unspecified and must be ignored. +// +// To retrieve the first bit, bit 0, calculate: (bitmap[0] & 0x01) != 0. +// To retrieve the second bit, bit 1, calculate: (bitmap[0] & 0x02) != 0. +// To retrieve the third bit, bit 2, calculate: (bitmap[0] & 0x04) != 0. +// To retrieve the fourth bit, bit 3, calculate: (bitmap[0] & 0x08) != 0. +// To retrieve bit n, calculate: (bitmap[n / 8] & (0x01 << (n % 8))) != 0. +// +// The "size" of a `BitSequence` (the number of bits it contains) is calculated +// by this formula: (bitmap.length * 8) - padding. +message BitSequence { + // The bytes that encode the bit sequence. + // May have a length of zero. + bytes bitmap = 1; + + // The number of bits of the last byte in `bitmap` to ignore as "padding". + // If the length of `bitmap` is zero, then this value must be 0. + // Otherwise, this value must be between 0 and 7, inclusive. + int32 padding = 2; +} + +// A bloom filter (https://en.wikipedia.org/wiki/Bloom_filter). +// +// The bloom filter hashes the entries with MD5 and treats the resulting 128-bit +// hash as 2 distinct 64-bit hash values, interpreted as unsigned integers +// using 2's complement encoding. +// +// These two hash values, named h1 and h2, are then used to compute the +// `hash_count` hash values using the formula, starting at i=0: +// +// h(i) = h1 + (i * h2) +// +// These resulting values are then taken modulo the number of bits in the bloom +// filter to get the bits of the bloom filter to test for the given entry. +message BloomFilter { + // The bloom filter data. + BitSequence bits = 1; + + // The number of hashes used by the algorithm. + int32 hash_count = 2; +} \ No newline at end of file diff --git a/firebase-firestore/src/proto/google/firestore/v1/firestore.proto b/firebase-firestore/src/proto/google/firestore/v1/firestore.proto index dda4721596c..1bf75ea3c15 100644 --- a/firebase-firestore/src/proto/google/firestore/v1/firestore.proto +++ b/firebase-firestore/src/proto/google/firestore/v1/firestore.proto @@ -25,6 +25,7 @@ import "google/firestore/v1/query.proto"; import "google/firestore/v1/write.proto"; import "google/protobuf/empty.proto"; import "google/protobuf/timestamp.proto"; +import "google/protobuf/wrappers.proto"; import "google/rpc/status.proto"; option csharp_namespace = "Google.Cloud.Firestore.V1"; @@ -746,6 +747,15 @@ message Target { // If the target should be removed once it is current and consistent. bool once = 6; + + // The number of documents that last matched the query at the resume token or + // read time. + // + // This value is only relevant when a `resume_type` is provided. This value + // being present and greater than zero signals that the client wants + // `ExistenceFilter.unchanged_names` to be included in the response. + // + google.protobuf.Int32Value expected_count = 12; } // Targets being watched have changed. diff --git a/firebase-firestore/src/proto/google/firestore/v1/write.proto b/firebase-firestore/src/proto/google/firestore/v1/write.proto index 59b2dafe4fd..49acae6ebf6 100644 --- a/firebase-firestore/src/proto/google/firestore/v1/write.proto +++ b/firebase-firestore/src/proto/google/firestore/v1/write.proto @@ -18,6 +18,7 @@ syntax = "proto3"; package google.firestore.v1; import "google/api/annotations.proto"; +import "google/firestore/v1/bloom_filter.proto"; import "google/firestore/v1/common.proto"; import "google/firestore/v1/document.proto"; import "google/protobuf/timestamp.proto"; @@ -261,4 +262,18 @@ message ExistenceFilter { // If different from the count of documents in the client that match, the // client must manually determine which documents no longer match the target. int32 count = 2; + + // A bloom filter that contains the UTF-8 byte encodings of the resource names + // of the documents that match [target_id][google.firestore.v1.ExistenceFilter.target_id], in the + // form `projects/{project_id}/databases/{database_id}/documents/{document_path}` + // that have NOT changed since the query results indicated by the resume token + // or timestamp given in `Target.resume_type`. + // + // This bloom filter may be omitted at the server's discretion, such as if it + // is deemed that the client will not make use of it or if it is too + // computationally expensive to calculate or transmit. Clients must gracefully + // handle this field being absent by falling back to the logic used before + // this field existed; that is, re-add the target without a resume token to + // figure out which documents in the client's cache are out of sync. + BloomFilter unchanged_names = 3; } From b30613582c3876b6e095107533a5124054ca4a5b Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Fri, 20 Jan 2023 10:25:31 -0800 Subject: [PATCH 02/22] Implement BloomFilter class (#4524) --- .../firestore/remote/BloomFilter.java | 167 ++++++++++ .../firestore/remote/BloomFilterTest.java | 285 ++++++++++++++++++ ...terTest_MD5_1_0001_bloom_filter_proto.json | 1 + ...est_MD5_1_0001_membership_test_result.json | 1 + ...ilterTest_MD5_1_01_bloom_filter_proto.json | 1 + ...rTest_MD5_1_01_membership_test_result.json | 1 + ...FilterTest_MD5_1_1_bloom_filter_proto.json | 1 + ...erTest_MD5_1_1_membership_test_result.json | 1 + ...est_MD5_50000_0001_bloom_filter_proto.json | 7 + ...MD5_50000_0001_membership_test_result.json | 1 + ...rTest_MD5_50000_01_bloom_filter_proto.json | 1 + ...t_MD5_50000_01_membership_test_result.json | 1 + ...erTest_MD5_50000_1_bloom_filter_proto.json | 1 + ...st_MD5_50000_1_membership_test_result.json | 1 + ...Test_MD5_5000_0001_bloom_filter_proto.json | 1 + ..._MD5_5000_0001_membership_test_result.json | 1 + ...erTest_MD5_5000_01_bloom_filter_proto.json | 1 + ...st_MD5_5000_01_membership_test_result.json | 1 + ...terTest_MD5_5000_1_bloom_filter_proto.json | 1 + ...est_MD5_5000_1_membership_test_result.json | 1 + ...rTest_MD5_500_0001_bloom_filter_proto.json | 1 + ...t_MD5_500_0001_membership_test_result.json | 1 + ...terTest_MD5_500_01_bloom_filter_proto.json | 1 + ...est_MD5_500_01_membership_test_result.json | 1 + ...lterTest_MD5_500_1_bloom_filter_proto.json | 1 + ...Test_MD5_500_1_membership_test_result.json | 1 + 26 files changed, 482 insertions(+) create mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java create mode 100644 firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_membership_test_result.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_membership_test_result.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_bloom_filter_proto.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_membership_test_result.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_bloom_filter_proto.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_membership_test_result.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_membership_test_result.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_membership_test_result.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_bloom_filter_proto.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_membership_test_result.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_membership_test_result.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_membership_test_result.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_membership_test_result.json diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java new file mode 100644 index 00000000000..9eba0f3f07b --- /dev/null +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java @@ -0,0 +1,167 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.firestore.remote; + +import android.util.Base64; +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class BloomFilter { + private final int bitCount; + private final byte[] bitmap; + private final int hashCount; + private final MessageDigest md5HashMessageDigest; + + public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount) { + if (bitmap == null) { + throw new NullPointerException("Bitmap cannot be null."); + } + if (padding < 0 || padding >= 8) { + throw new IllegalArgumentException("Invalid padding: " + padding); + } + if (hashCount < 0) { + throw new IllegalArgumentException("Invalid hash count: " + hashCount); + } + if (bitmap.length > 0 && hashCount == 0) { + // Only empty bloom filter can have 0 hash count. + throw new IllegalArgumentException("Invalid hash count: " + hashCount); + } + if (bitmap.length == 0) { + // Empty bloom filter should have 0 padding. + if (padding != 0) { + throw new IllegalArgumentException( + "Expected padding of 0 when bitmap length is 0, but got " + padding); + } + } + + this.bitmap = bitmap; + this.hashCount = hashCount; + this.bitCount = bitmap.length * 8 - padding; + this.md5HashMessageDigest = createMd5HashMessageDigest(); + } + + @VisibleForTesting + int getBitCount() { + return this.bitCount; + } + + /** + * Check whether the given string is a possible member of the bloom filter. It might return false + * positive result, ie, the given string is not a member of the bloom filter, but the method + * returned true. + * + * @param value the string to be tested for membership. + * @return true if the given string might be contained in the bloom filter, or false if the given + * string is definitely not contained in the bloom filter. + */ + public boolean mightContain(@NonNull String value) { + // Empty bitmap should return false on membership check. + if (this.bitCount == 0) { + return false; + } + + byte[] hashedValue = md5HashDigest(value); + if (hashedValue.length != 16) { + throw new RuntimeException( + "Invalid md5 hash array length: " + hashedValue.length + " (expected 16)"); + } + + long hash1 = getLongLittleEndian(hashedValue, 0); + long hash2 = getLongLittleEndian(hashedValue, 8); + + for (int i = 0; i < this.hashCount; i++) { + int index = this.getBitIndex(hash1, hash2, i); + if (!this.isBitSet(index)) { + return false; + } + } + return true; + } + + /** Hash a string using md5 hashing algorithm, and return an array of 16 bytes. */ + @NonNull + private byte[] md5HashDigest(@NonNull String value) { + return md5HashMessageDigest.digest(value.getBytes(StandardCharsets.UTF_8)); + } + + @NonNull + private static MessageDigest createMd5HashMessageDigest() { + try { + return MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("Missing MD5 MessageDigest provider: ", e); + } + } + + /** Interpret 8 bytes into a long, using little endian 2’s complement. */ + private static long getLongLittleEndian(@NonNull byte[] bytes, int offset) { + long result = 0; + for (int i = 0; i < 8; i++) { + result |= (bytes[offset + i] & 0xFFL) << (i * 8); + } + return result; + } + + /** + * Calculate the ith hash value based on the hashed 64 bit unsigned integers, and calculate its + * corresponding bit index in the bitmap to be checked. + */ + private int getBitIndex(long hash1, long hash2, int hashIndex) { + // Calculate hashed value h(i) = h1 + (i * h2). + // Even though we are interpreting hash1 and hash2 as unsigned, the addition and multiplication + // operators still perform the correct operation and give the desired overflow behavior. + long combinedHash = hash1 + (hash2 * hashIndex); + long modulo = unsignedRemainder(combinedHash, this.bitCount); + return (int) modulo; + } + + /** + * Calculate modulo, where the dividend and divisor are treated as unsigned 64-bit longs. + * + *

The implementation is taken from Guava, + * simplified to our needs. + * + *

+ */ + private static long unsignedRemainder(long dividend, long divisor) { + long quotient = ((dividend >>> 1) / divisor) << 1; + long remainder = dividend - quotient * divisor; + return remainder - (remainder >= divisor ? divisor : 0); + } + + /** Return whether the bit at the given index in the bitmap is set to 1. */ + private boolean isBitSet(int index) { + // To retrieve bit n, calculate: (bitmap[n / 8] & (0x01 << (n % 8))). + byte byteAtIndex = this.bitmap[index / 8]; + int offset = index % 8; + return (byteAtIndex & (0x01 << offset)) != 0; + } + + @Override + public String toString() { + return "BloomFilter{" + + "hashCount=" + + hashCount + + ", size=" + + bitCount + + ", bitmap=\"" + + Base64.encodeToString(bitmap, Base64.NO_WRAP) + + "\"}"; + } +} diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java new file mode 100644 index 00000000000..0e851a0fc4f --- /dev/null +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java @@ -0,0 +1,285 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.firestore.remote; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.stream.Stream; +import org.json.JSONObject; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class BloomFilterTest { + private static final String GOLDEN_DOCUMENT_PREFIX = + "projects/project-1/databases/database-1/documents/coll/doc"; + private static final String GOLDEN_TEST_LOCATION = + "src/test/resources/bloom_filter_golden_test_data/"; + + @Test + public void instantiateEmptyBloomFilter() { + BloomFilter bloomFilter = new BloomFilter(new byte[0], 0, 0); + assertEquals(bloomFilter.getBitCount(), 0); + } + + @Test + public void instantiateNonEmptyBloomFilter() { + { + BloomFilter bloomFilter1 = new BloomFilter(new byte[] {1}, 0, 1); + assertEquals(bloomFilter1.getBitCount(), 8); + } + { + BloomFilter bloomFilter2 = new BloomFilter(new byte[] {1}, 7, 1); + assertEquals(bloomFilter2.getBitCount(), 1); + } + } + + @Test + public void constructorShouldThrowNPEOnNullBitmap() { + { + NullPointerException emptyBloomFilterException = + assertThrows(NullPointerException.class, () -> new BloomFilter(null, 0, 0)); + assertThat(emptyBloomFilterException).hasMessageThat().contains("Bitmap cannot be null."); + } + { + NullPointerException nonEmptyBloomFilterException = + assertThrows(NullPointerException.class, () -> new BloomFilter(null, 1, 1)); + assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Bitmap cannot be null."); + } + } + + @Test + public void constructorShouldThrowIAEOnEmptyBloomFilterWithNonZeroPadding() { + IllegalArgumentException exception = + assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 1, 0)); + assertThat(exception) + .hasMessageThat() + .contains("Expected padding of 0 when bitmap length is 0, but got 1"); + } + + @Test + public void constructorShouldThrowIAEOnNonEmptyBloomFilterWithZeroHashCount() { + IllegalArgumentException zeroHashCountException = + assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 1, 0)); + assertThat(zeroHashCountException).hasMessageThat().contains("Invalid hash count: 0"); + } + + @Test + public void constructorShouldThrowIAEOnNegativePadding() { + { + IllegalArgumentException emptyBloomFilterException = + assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], -1, 0)); + assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1"); + } + { + IllegalArgumentException nonEmptyBloomFilterException = + assertThrows( + IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, -1, 1)); + assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1"); + } + } + + @Test + public void constructorShouldThrowIAEOnNegativeHashCount() { + { + IllegalArgumentException emptyBloomFilterException = + assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 0, -1)); + assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1"); + } + { + IllegalArgumentException nonEmptyBloomFilterException = + assertThrows( + IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 1, -1)); + assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1"); + } + } + + @Test + public void constructorShouldThrowIAEIfPaddingIsTooLarge() { + IllegalArgumentException exception = + assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 8, 1)); + assertThat(exception).hasMessageThat().contains("Invalid padding: 8"); + } + + @Test + public void mightContainCanProcessNonStandardCharacters() { + // A non-empty BloomFilter object with 1 insertion : "ÀÒ∑" + BloomFilter bloomFilter = new BloomFilter(new byte[] {(byte) 237, 5}, 5, 8); + assertTrue(bloomFilter.mightContain("ÀÒ∑")); + assertFalse(bloomFilter.mightContain("Ò∑À")); + } + + @Test + public void mightContainOnEmptyBloomFilterShouldReturnFalse() { + BloomFilter bloomFilter = new BloomFilter(new byte[0], 0, 0); + assertFalse(bloomFilter.mightContain("")); + assertFalse(bloomFilter.mightContain("a")); + } + + @Test + public void mightContainWithEmptyStringMightReturnFalsePositiveResult() { + { + BloomFilter bloomFilter1 = new BloomFilter(new byte[] {1}, 1, 1); + assertFalse(bloomFilter1.mightContain("")); + } + { + BloomFilter bloomFilter2 = new BloomFilter(new byte[] {(byte) 255}, 0, 16); + assertTrue(bloomFilter2.mightContain("")); + } + } + + @Test + public void bloomFilterToString() { + { + BloomFilter emptyBloomFilter = new BloomFilter(new byte[0], 0, 0); + assertEquals(emptyBloomFilter.toString(), "BloomFilter{hashCount=0, size=0, bitmap=\"\"}"); + } + { + BloomFilter nonEmptyBloomFilter = new BloomFilter(new byte[] {1}, 1, 1); + assertEquals( + nonEmptyBloomFilter.toString(), "BloomFilter{hashCount=1, size=7, bitmap=\"AQ==\"}"); + } + } + + /** + * Golden tests are generated by backend based on inserting n number of document paths into a + * bloom filter. + * + *

Full document path is generated by concatenating documentPrefix and number n, eg, + * projects/project-1/databases/database-1/documents/coll/doc12. + * + *

The test result is generated by checking the membership of documents from documentPrefix+0 + * to documentPrefix+2n. The membership results from 0 to n is expected to be true, and the + * membership results from n to 2n is expected to be false with some false positive results. + */ + private static void runGoldenTest(String testFile) throws Exception { + String resultFile = testFile.replace("bloom_filter_proto", "membership_test_result"); + if (resultFile.equals(testFile)) { + throw new IllegalArgumentException("Cannot find corresponding result file for " + testFile); + } + + JSONObject testJson = readJsonFile(testFile); + JSONObject resultJSON = readJsonFile(resultFile); + + JSONObject bits = testJson.getJSONObject("bits"); + String bitmap = bits.getString("bitmap"); + int padding = bits.getInt("padding"); + int hashCount = testJson.getInt("hashCount"); + BloomFilter bloomFilter = + new BloomFilter(Base64.getDecoder().decode(bitmap), padding, hashCount); + + String membershipTestResults = resultJSON.getString("membershipTestResults"); + + // Run and compare mightContain result with the expectation. + for (int i = 0; i < membershipTestResults.length(); i++) { + boolean expectedResult = membershipTestResults.charAt(i) == '1'; + boolean mightContainResult = bloomFilter.mightContain(GOLDEN_DOCUMENT_PREFIX + i); + assertEquals( + "For document " + + GOLDEN_DOCUMENT_PREFIX + + i + + " mightContain() returned " + + mightContainResult + + ", but expected " + + expectedResult, + mightContainResult, + expectedResult); + } + } + + private static JSONObject readJsonFile(String fileName) throws Exception { + StringBuilder builder = new StringBuilder(); + InputStreamReader streamReader = + new InputStreamReader( + new FileInputStream(GOLDEN_TEST_LOCATION + fileName), StandardCharsets.UTF_8); + BufferedReader reader = new BufferedReader(streamReader); + Stream lines = reader.lines(); + lines.forEach(builder::append); + String json = builder.toString(); + return new JSONObject(json); + } + + @Test + public void goldenTest_1Document_1FalsePositiveRate() throws Exception { + runGoldenTest("Validation_BloomFilterTest_MD5_1_1_bloom_filter_proto.json"); + } + + @Test + public void goldenTest_1Document_01FalsePositiveRate() throws Exception { + runGoldenTest("Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json"); + } + + @Test + public void goldenTest_1Document_0001FalsePositiveRate() throws Exception { + runGoldenTest("Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json"); + } + + @Test + public void goldenTest_500Document_1FalsePositiveRate() throws Exception { + runGoldenTest("Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json"); + } + + @Test + public void goldenTest_500Document_01FalsePositiveRate() throws Exception { + runGoldenTest("Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json"); + } + + @Test + public void goldenTest_500Document_0001FalsePositiveRate() throws Exception { + runGoldenTest("Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json"); + } + + @Test + public void goldenTest_5000Document_1FalsePositiveRate() throws Exception { + runGoldenTest("Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json"); + } + + @Test + public void goldenTest_5000Document_01FalsePositiveRate() throws Exception { + runGoldenTest("Validation_BloomFilterTest_MD5_5000_01_bloom_filter_proto.json"); + } + + @Test + public void goldenTest_5000Document_0001FalsePositiveRate() throws Exception { + runGoldenTest("Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json"); + } + + @Test + public void goldenTest_50000Document_1FalsePositiveRate() throws Exception { + runGoldenTest("Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json"); + } + + @Test + public void goldenTest_50000Document_01FalsePositiveRate() throws Exception { + runGoldenTest("Validation_BloomFilterTest_MD5_50000_01_bloom_filter_proto.json"); + } + + @Test + public void goldenTest_50000Document_0001FalsePositiveRate() throws Exception { + runGoldenTest("Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json"); + } +} diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json new file mode 100644 index 00000000000..23f0f12b267 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json @@ -0,0 +1 @@ +{ "bits": { "bitmap": "RswZ", "padding": 1 }, "hashCount": 16 } diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_membership_test_result.json new file mode 100644 index 00000000000..5a41f842376 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_membership_test_result.json @@ -0,0 +1 @@ +{"membershipTestResults" : "10"} diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json new file mode 100644 index 00000000000..43d07db5e6d --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json @@ -0,0 +1 @@ +{"bits":{"bitmap":"mwE=","padding":5},"hashCount":8} \ No newline at end of file diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_membership_test_result.json new file mode 100644 index 00000000000..5a41f842376 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_membership_test_result.json @@ -0,0 +1 @@ +{"membershipTestResults" : "10"} diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_bloom_filter_proto.json new file mode 100644 index 00000000000..c03535eafc3 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_bloom_filter_proto.json @@ -0,0 +1 @@ +{"bits":{"bitmap":"","padding":0},"hashCount":0} \ No newline at end of file diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_membership_test_result.json new file mode 100644 index 00000000000..fcbc34d14ac --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_membership_test_result.json @@ -0,0 +1 @@ +{"membershipTestResults" : "00"} \ No newline at end of file diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json new file mode 100644 index 00000000000..04b77bf83ab --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json @@ -0,0 +1,7 @@ +{ + "bits": { + "bitmap": "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", + "padding": 1 + }, + "hashCount": 13 +} diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json new file mode 100644 index 00000000000..25628a9889d --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json @@ -0,0 +1 @@ +{"membershipTestResults" : "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"} \ No newline at end of file diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_bloom_filter_proto.json new file mode 100644 index 00000000000..d1448123cdc --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_bloom_filter_proto.json @@ -0,0 +1 @@ +{"bits":{"bitmap":"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","padding":1},"hashCount":7} \ No newline at end of file diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_membership_test_result.json new file mode 100644 index 00000000000..c8bef092c6b --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_membership_test_result.json @@ -0,0 +1 @@ +{"membershipTestResults" : "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000100000000000000000000000000000000000000000000000000100000000000000000000000000000000000010000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000010010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000010000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000001000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000100000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000100000000000000000000000000000000001000000000000000000000000101000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000100000000001000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000100000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000010000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000010000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000001000000001000000000000000000000000000000000000000000000000000000001000000000000000000001000000000000001000000000000100000000000000000000000000000000000000001100000000010000000000000000000000000000000000000000000000000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000100000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000010000000000000000000010000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000100000000000000000100100000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000001000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000010000000000000000000010000000000000000000000000000000000000000000000000000000000000000000001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000100000000000000000000000000000100000010000000000000000000000000000000000001000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000001000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000001000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000010000000000001000000000000000000000000000010000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000100000001000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000010000000000000000000000000100000000000000000000000000000000000000000000000100000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000001000000000000000000000000000000000000001000000000000000000000000010000000000000000000000000000000000000001000000000000000000000000000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000010010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000100000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100001000000000000000000010000000000000000000000000000000000000000000000001000001000000000000000000000000000000000000000000001000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000010000000000010000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000001000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000001000000000000000000000100000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000010000000000010010000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010100000000001000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000010010000000010000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100100000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000100000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000001000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100100000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000010000000000000000000000000000000000000100000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000010000000000000000000000000000000000000000000001000010000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000000000000010000000000000000010000000000000000000000000000000000000000000000000000001000000000000000000000000001000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000100000000000100000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000001000000000000000000000000000000000000000000000000000001000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000100000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000010000000001000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000010000000000000000000000000000010000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000010010000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000001000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000"} diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json new file mode 100644 index 00000000000..c03535eafc3 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json @@ -0,0 +1 @@ +{"bits":{"bitmap":"","padding":0},"hashCount":0} \ No newline at end of file diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_membership_test_result.json new file mode 100644 index 00000000000..8872f804c6c --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_membership_test_result.json @@ -0,0 +1 @@ +{"membershipTestResults" : "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"} \ No newline at end of file diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json new file mode 100644 index 00000000000..41f4c45b813 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json @@ -0,0 +1 @@ +{"bits":{"bitmap":"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","padding":7},"hashCount":13} diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_membership_test_result.json new file mode 100644 index 00000000000..e93415cc7e6 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_membership_test_result.json @@ -0,0 +1 @@ +{"membershipTestResults" : "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"} diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_bloom_filter_proto.json new file mode 100644 index 00000000000..0cd630436d1 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_bloom_filter_proto.json @@ -0,0 +1 @@ +{"bits":{"bitmap":"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","padding":3},"hashCount":7} diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_membership_test_result.json new file mode 100644 index 00000000000..416b190ec53 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_membership_test_result.json @@ -0,0 +1 @@ +{"membershipTestResults" : "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000100000000000000000000000000000000110000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000001000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000010000000000000000000000000100000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000001000000000000000000000000000000000000000000000010100000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000010000000000000000000000000000000000000000000000000100000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000"} \ No newline at end of file diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json new file mode 100644 index 00000000000..c03535eafc3 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json @@ -0,0 +1 @@ +{"bits":{"bitmap":"","padding":0},"hashCount":0} \ No newline at end of file diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_membership_test_result.json new file mode 100644 index 00000000000..d568ff095e5 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_membership_test_result.json @@ -0,0 +1 @@ +{"membershipTestResults" : "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"} diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json new file mode 100644 index 00000000000..b206a483c54 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json @@ -0,0 +1 @@ +{"bits":{"bitmap":"vusW6Yc2oIsxmEapab4xh7Qqznx2LAVmFrA3SquH85kFR8l+/MpCIokPAAMuIAmKqcrwBtx/I8ds9Uw9ApHW2KZ/BMTbijPDac2Hm0oQvWFkUjycX7gNQrkjDIsRBdO/IaYDwAh74QwofDQLYxrSNgAdT+stIC7UKnpxZl1tRKTnIa0JQXrRChmxvO4r6WQI9QR76uk55KNZFQ5YmgvT6uYeTafiJEZb61Q9V3OOks44hV83F/8/rgPvRoweLHFJ+ezSJ04P9A+a1DHlMtpriDsxVIAgJm/CKuPkBC1jitppF9CagnLPidC65F1OPSE+8RAzHaEfuic32yNJEuQZfb1hq4pwE62hQ0/ulczuNFsQykikNcGBAWWDHWK4ur6dwjQSP7tOq3m4fLK3xYQt41OpIdPzPfn1Y4NC+BFdKQZUhIxEpTX2TPFoGsW9iSqRvF2zzWstAjcOyvT/yJ36ijEjVV9O+/NWfZvxUft26/NNDRPhpnxXHFGei10qKGMYym/seFr5+Hm2bpczLfpZtfQt/IHKg8Lyr8uMoAK5YhYrTqKY5DDo2jCPGnIbgwYJUDQRL34Eegvnd6T0A6XaU0y+SXbbfbk2vHybVZwuGEobTYZabE2bNg0rmdYx4LJvODl2ZFN7WZ5isyUAtBJJa16Py2PfLBxfrCScVpQJr6Xdka6eUrHA4wAT7V+r3NCZslUJyQky4lDjtacCVsRo2ONMGuWkUh9xqynRCQ85d21St+xAo4pl/V0ld1FeU6sOVGzV5oHosji3S4DFZZ+UZbKdAQwqR+UY+DRN0Vt51MZheZ1YYJd80ZX4DTshs6feSJpktuOBWJGftFzdbIIclJG29KKbwSpR25wGKnFafI2rwItNizCTVkxa/aQnTYF4PGhBmLu0zfEpaIz3pmpMUO7TPE1aYjyV8xakSJA4iDMQI3Z7n/6eF7PFxy/qUNuzHzmV3PoyvOjIC8GNnWaUdw9SlwTr/2LUzQ4fhucCykIAHcgawtcD/7whga1Z/LfOPROF1JfKw7a8H0vERX3WC427LHjbvbhAw0KnSfyIPMok49H20i3oZOdHQE0wxYj/1APD8JfU/TlMW1umRVARZ8ohWLF0oZcohEqexajnKREArfVvvBroyFvI5yRgR4vQapTI0RPCmi4tNbw11Zgy43snKG2pVYR2S4I/Dg9rcK4Plr301TIbFRAT0CE+vqUAjg56lkxcDnUxMW/p9qDU2bILaypkXyr16SiZxc9bMvYEVVBztcbyU6uI+JLFruiPl4mHHv6IylJIc7HJ1vL1gnRTP3bBBvw5qyEl0KS6woregx1RAbPszwxRrTR+zfxV9tUKuC59BZHlmpC5YFAK2wLyU1d5rQyhMN4ySA8POYD6rj80DEZHXQzoTvfQIitPp42unEQRGMKQt/PqljT8A/lBU5DZcc8M3hkFklDpDyIXKuwLkd1zuiPrwzkC27GZ0SZEvQvUi3xVefevyFdY8lAeAlP17z57E+vKDjG9Guo+sX7I1qByNUBpMSO4UkOMP9otRBToRjxD1Rb+lEdGCUwcFm677KL6hR9e3Om9PWkZF6LpWqH+qnt9+lPVxgY=","padding":5},"hashCount":13} diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json new file mode 100644 index 00000000000..3bcbf418c24 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json @@ -0,0 +1 @@ +{"membershipTestResults" : "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"} \ No newline at end of file diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json new file mode 100644 index 00000000000..35de64eee0a --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json @@ -0,0 +1 @@ +{"bits":{"bitmap":"n+36qf4UgWXLxRabHwqwva8jpXlZ7yfdCjRNwHQ5MBmgc35tGNWFvTgrWyfmznuz1j0wMabH29pR84MjjWGgAxLhDXU3dyYTY505812+BYTO5GXEAyGoUZhcBlUZPK+RAqSZ+9e3q9Gxpmoes/4iCbxJFc5eew0+95v5Z0h5fvlF2Y9iRBDu2PWC1pVGuc/j3W+34+5IwPtDLPbtfvYhnohTfXP02vsf2/77YqEtfmMVFfIMZJ5e7uLOA+rcmQC5fFfxjubJfKR5R+Rzw/UWd0Eg3gi+FCUIk/WUP5938R4tPH3fnrtQjclvsZhtj5dak7WWw1Ph4ZFdJE2XdFBH1JSvggI5tFKH5WUeIBlHYj+V3HomQ2gDrwMXGsIJokcwQi1qTUjECnwYGlOl/FRjZQg7h3QoSkyxgBnp6w7XKttc/EJf+279WLkvm6K/sTuQiFsOGqdQQ+c6osu9SzICn7Rtu4+RzmfxgCx1i2rX1OvVt+DLWa8/K5TlLvVM7GqXiHeaLuvkaz4uR754T1Iurp8/Ps2yJdXYHLyGndJa+7DJ1BPsGK8ZYbYFN7jGamHF9de+3K/syp1raDltsNUxUGAaMBghK1nIRDtHLSHBtVkuxvUkP3iVIkm6pEp0K/2npYUEAsbYVkug4Iv7qhnLTGwMUXP3piTMySLLoZ9bGY0k13FMX7h/s79dJDcIIf4fR9S0SN6fWXKdZOBLFzyXGcxbD+o0o3NO/UOZDgmTet2or8rvipr4tGDyGluUnW1o/fWPlGvEIo/7Ep6avGyw7jilLKYiunAA","padding":7},"hashCount":7} \ No newline at end of file diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_membership_test_result.json new file mode 100644 index 00000000000..2a851465e72 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_membership_test_result.json @@ -0,0 +1 @@ +{"membershipTestResults" : "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"} diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json new file mode 100644 index 00000000000..c03535eafc3 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json @@ -0,0 +1 @@ +{"bits":{"bitmap":"","padding":0},"hashCount":0} \ No newline at end of file diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_membership_test_result.json new file mode 100644 index 00000000000..d59b3592362 --- /dev/null +++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_membership_test_result.json @@ -0,0 +1 @@ +{"membershipTestResults" : "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"} \ No newline at end of file From 2139f5e7c72ab77189141b4b5e0364705eda7381 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Fri, 27 Jan 2023 13:38:11 -0800 Subject: [PATCH 03/22] Add expected count to target (#4574) --- .../firebase/firestore/core/SyncEngine.java | 3 +- .../firestore/local/LocalSerializer.java | 3 +- .../firebase/firestore/local/TargetData.java | 46 +- .../firestore/remote/RemoteSerializer.java | 7 + .../firestore/remote/RemoteStore.java | 6 + .../firestore/local/LocalSerializerTest.java | 3 +- .../firestore/local/TargetCacheTestCase.java | 3 +- .../firebase/firestore/spec/SpecTestCase.java | 7 + .../test/resources/json/listen_spec_test.json | 671 ++++++++++++++++++ 9 files changed, 739 insertions(+), 10 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/SyncEngine.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/SyncEngine.java index c7da9e27e18..b8655d91656 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/SyncEngine.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/SyncEngine.java @@ -203,13 +203,14 @@ public int listen(Query query) { hardAssert(!queryViewsByQuery.containsKey(query), "We already listen to query: %s", query); TargetData targetData = localStore.allocateTarget(query.toTarget()); - remoteStore.listen(targetData); ViewSnapshot viewSnapshot = initializeViewAndComputeSnapshot( query, targetData.getTargetId(), targetData.getResumeToken()); syncEngineListener.onViewSnapshots(Collections.singletonList(viewSnapshot)); + remoteStore.listen(targetData); + return targetData.getTargetId(); } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalSerializer.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalSerializer.java index fb4e476b411..98fb7230821 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalSerializer.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalSerializer.java @@ -260,7 +260,8 @@ TargetData decodeTargetData(com.google.firebase.firestore.proto.Target targetPro QueryPurpose.LISTEN, version, lastLimboFreeSnapshotVersion, - resumeToken); + resumeToken, + null); } public com.google.firestore.bundle.BundledQuery encodeBundledQuery(BundledQuery bundledQuery) { diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java index 18375731fe0..ff2e3274cee 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java @@ -16,10 +16,12 @@ import static com.google.firebase.firestore.util.Preconditions.checkNotNull; +import androidx.annotation.Nullable; import com.google.firebase.firestore.core.Target; import com.google.firebase.firestore.model.SnapshotVersion; import com.google.firebase.firestore.remote.WatchStream; import com.google.protobuf.ByteString; +import java.util.Objects; /** An immutable set of metadata that the store will need to keep track of for each target. */ public final class TargetData { @@ -30,6 +32,7 @@ public final class TargetData { private final SnapshotVersion snapshotVersion; private final SnapshotVersion lastLimboFreeSnapshotVersion; private final ByteString resumeToken; + private final @Nullable Integer expectedCount; /** * Creates a new TargetData with the given values. @@ -45,6 +48,9 @@ public final class TargetData { * @param resumeToken An opaque, server-assigned token that allows watching a target to be resumed * after disconnecting without retransmitting all the data that matches the target. The resume * token essentially identifies a point in time from which the server should resume sending + * @param expectedCount The number of documents that last matched the query at the resume token or + * read time. Documents are counted only when making a listen request with resume token or + * read time, otherwise, keep it null. */ TargetData( Target target, @@ -53,7 +59,8 @@ public final class TargetData { QueryPurpose purpose, SnapshotVersion snapshotVersion, SnapshotVersion lastLimboFreeSnapshotVersion, - ByteString resumeToken) { + ByteString resumeToken, + @Nullable Integer expectedCount) { this.target = checkNotNull(target); this.targetId = targetId; this.sequenceNumber = sequenceNumber; @@ -61,6 +68,7 @@ public final class TargetData { this.purpose = purpose; this.snapshotVersion = checkNotNull(snapshotVersion); this.resumeToken = checkNotNull(resumeToken); + this.expectedCount = expectedCount; } /** Convenience constructor for use when creating a TargetData for the first time. */ @@ -72,7 +80,8 @@ public TargetData(Target target, int targetId, long sequenceNumber, QueryPurpose purpose, SnapshotVersion.NONE, SnapshotVersion.NONE, - WatchStream.EMPTY_RESUME_TOKEN); + WatchStream.EMPTY_RESUME_TOKEN, + null); } /** Creates a new target data instance with an updated sequence number. */ @@ -84,7 +93,8 @@ public TargetData withSequenceNumber(long sequenceNumber) { purpose, snapshotVersion, lastLimboFreeSnapshotVersion, - resumeToken); + resumeToken, + /* expectedCount= */ null); } /** Creates a new target data instance with an updated resume token and snapshot version. */ @@ -96,7 +106,21 @@ public TargetData withResumeToken(ByteString resumeToken, SnapshotVersion snapsh purpose, snapshotVersion, lastLimboFreeSnapshotVersion, - resumeToken); + resumeToken, + expectedCount); + } + + /** Creates a new target data instance with an updated expected count. */ + public TargetData withExpectedCount(@Nullable Integer expectedCount) { + return new TargetData( + target, + targetId, + sequenceNumber, + purpose, + snapshotVersion, + lastLimboFreeSnapshotVersion, + resumeToken, + expectedCount); } /** Creates a new target data instance with an updated last limbo free snapshot version number. */ @@ -108,7 +132,8 @@ public TargetData withLastLimboFreeSnapshotVersion(SnapshotVersion lastLimboFree purpose, snapshotVersion, lastLimboFreeSnapshotVersion, - resumeToken); + resumeToken, + expectedCount); } public Target getTarget() { @@ -135,6 +160,11 @@ public ByteString getResumeToken() { return resumeToken; } + @Nullable + public Integer getExpectedCount() { + return expectedCount; + } + /** * Returns the last snapshot version for which the associated view contained no limbo documents. */ @@ -158,7 +188,8 @@ public boolean equals(Object o) { && purpose.equals(targetData.purpose) && snapshotVersion.equals(targetData.snapshotVersion) && lastLimboFreeSnapshotVersion.equals(targetData.lastLimboFreeSnapshotVersion) - && resumeToken.equals(targetData.resumeToken); + && resumeToken.equals(targetData.resumeToken) + && Objects.equals(expectedCount, targetData.expectedCount); } @Override @@ -170,6 +201,7 @@ public int hashCode() { result = 31 * result + snapshotVersion.hashCode(); result = 31 * result + lastLimboFreeSnapshotVersion.hashCode(); result = 31 * result + resumeToken.hashCode(); + result = 31 * result + Objects.hashCode(expectedCount); return result; } @@ -190,6 +222,8 @@ public String toString() { + lastLimboFreeSnapshotVersion + ", resumeToken=" + resumeToken + + ", expectedCount=" + + expectedCount + '}'; } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java index 57f51a7b8cc..7f1f7781045 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java @@ -499,6 +499,13 @@ public Target encodeTarget(TargetData targetData) { builder.setResumeToken(targetData.getResumeToken()); } + // TODO(Mila) Incorporate this into the if statement above. + if (targetData.getExpectedCount() != null + && (!targetData.getResumeToken().isEmpty() + || targetData.getSnapshotVersion().compareTo(SnapshotVersion.NONE) > 0)) { + builder.setExpectedCount(Int32Value.newBuilder().setValue(targetData.getExpectedCount())); + } + return builder.build(); } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java index 3999f22a939..965ceee35da 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java @@ -369,6 +369,12 @@ public void listen(TargetData targetData) { private void sendWatchRequest(TargetData targetData) { watchChangeAggregator.recordPendingTargetRequest(targetData.getTargetId()); + if (!targetData.getResumeToken().isEmpty() + || targetData.getSnapshotVersion().compareTo(SnapshotVersion.NONE) > 0) { + int expectedCount = this.getRemoteKeysForTarget(targetData.getTargetId()).size(); + targetData = targetData.withExpectedCount(expectedCount); + } + watchStream.watchQuery(targetData); } diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java index 124727f5681..20223e78dec 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java @@ -378,7 +378,8 @@ public void testEncodesTargetData() { QueryPurpose.LISTEN, snapshotVersion, limboFreeVersion, - resumeToken); + resumeToken, + null); // Let the RPC serializer test various permutations of query serialization. com.google.firestore.v1.Target.QueryTarget queryTarget = diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/local/TargetCacheTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/local/TargetCacheTestCase.java index e098f7666f1..58a3a57ba69 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/local/TargetCacheTestCase.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/local/TargetCacheTestCase.java @@ -331,7 +331,8 @@ private TargetData newTargetData(Query query, int targetId, long version) { QueryPurpose.LISTEN, version(version), version(version), - resumeToken(version)); + resumeToken(version), + null); } /** Adds the given query data to the targetCache under test, committing immediately. */ diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java index cf136ab45d8..7be9479da3b 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java @@ -1006,6 +1006,9 @@ private void validateExpectedState(@Nullable JSONObject expectedState) throws JS targetData.withResumeToken( ByteString.EMPTY, version(queryDataJson.getInt("readTime"))); } + if (queryDataJson.has("expectedCount")) { + targetData = targetData.withExpectedCount(queryDataJson.getInt("expectedCount")); + } expectedActiveTargets.get(targetId).add(targetData); } @@ -1144,6 +1147,10 @@ private void validateActiveTargets() { expectedTarget.getResumeToken().toStringUtf8(), actualTarget.getResumeToken().toStringUtf8()); + if (expectedTarget.getExpectedCount() != null) { + assertEquals(expectedTarget.getExpectedCount(), actualTarget.getExpectedCount()); + } + actualTargets.remove(expected.getKey()); } diff --git a/firebase-firestore/src/test/resources/json/listen_spec_test.json b/firebase-firestore/src/test/resources/json/listen_spec_test.json index 5755019b048..85170a91d71 100644 --- a/firebase-firestore/src/test/resources/json/listen_spec_test.json +++ b/firebase-firestore/src/test/resources/json/listen_spec_test.json @@ -3337,6 +3337,158 @@ } ] }, + "ExpectedCount in listen request should work after coming back online": { + "describeName": "Listens:", + "itName": "ExpectedCount in listen request should work after coming back online", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": false + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "enableNetwork": false, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + }, + "enqueuedLimboDocs": [ + ] + } + }, + { + "enableNetwork": true, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "resume-token-1000", + "expectedCount": 1 + } + } + } + } + ] + }, "Ignores update from inactive target": { "describeName": "Listens:", "itName": "Ignores update from inactive target", @@ -12409,6 +12561,525 @@ } ] }, + "Resuming a query should specify expectedCount that does not include pending mutations": { + "describeName": "Listens:", + "itName": "Resuming a query should specify expectedCount that does not include pending mutations", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": false + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "userUnlisten": [ + 2, + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "expectedState": { + "activeTargets": { + } + } + }, + { + "userSet": [ + "collection/b", + { + "key": "b" + } + ] + }, + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + }, + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": true + }, + "value": { + "key": "b" + }, + "version": 0 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": true, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "resume-token-1000", + "expectedCount": 1 + } + } + } + } + ] + }, + "Resuming a query should specify expectedCount when adding the target": { + "describeName": "Listens:", + "itName": "Resuming a query should specify expectedCount when adding the target", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": false + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "userUnlisten": [ + 2, + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "expectedState": { + "activeTargets": { + } + } + }, + { + "watchRemove": { + "targetIds": [ + 2 + ] + } + }, + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "resume-token-1000", + "expectedCount": 0 + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + }, + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b" + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-2000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + }, + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "userUnlisten": [ + 2, + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "expectedState": { + "activeTargets": { + } + } + }, + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + }, + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "resume-token-2000", + "expectedCount": 2 + } + } + } + } + ] + }, "Secondary client advances query state with global snapshot from primary": { "describeName": "Listens:", "itName": "Secondary client advances query state with global snapshot from primary", From 078c4144ea38fbed2e05c7c08ad8ce7dc7725974 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Wed, 8 Feb 2023 20:50:48 -0800 Subject: [PATCH 04/22] Apply bloom filter on existence filter mismatch (#4601) --- .../firestore/remote/BloomFilter.java | 18 +- .../remote/BloomFilterException.java | 23 + .../firestore/remote/ExistenceFilter.java | 16 +- .../firestore/remote/RemoteSerializer.java | 4 +- .../firestore/remote/RemoteStore.java | 6 + .../remote/WatchChangeAggregator.java | 79 +- .../firestore/remote/BloomFilterTest.java | 42 +- .../firebase/firestore/spec/SpecTestCase.java | 51 +- .../json/existence_filter_spec_test.json | 6904 +++++++++++++++-- .../test/resources/json/limbo_spec_test.json | 402 +- .../test/resources/json/limit_spec_test.json | 12 +- .../testutil/TestTargetMetadataProvider.java | 6 + .../firebase/firestore/testutil/TestUtil.java | 19 +- 13 files changed, 6798 insertions(+), 784 deletions(-) create mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java index 9eba0f3f07b..e51a89906c7 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java @@ -32,21 +32,19 @@ public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount) { throw new NullPointerException("Bitmap cannot be null."); } if (padding < 0 || padding >= 8) { - throw new IllegalArgumentException("Invalid padding: " + padding); + throw new BloomFilterException("Invalid padding: " + padding); } if (hashCount < 0) { - throw new IllegalArgumentException("Invalid hash count: " + hashCount); + throw new BloomFilterException("Invalid hash count: " + hashCount); } if (bitmap.length > 0 && hashCount == 0) { // Only empty bloom filter can have 0 hash count. - throw new IllegalArgumentException("Invalid hash count: " + hashCount); + throw new BloomFilterException("Invalid hash count: " + hashCount); } - if (bitmap.length == 0) { + if (bitmap.length == 0 && padding != 0) { // Empty bloom filter should have 0 padding. - if (padding != 0) { - throw new IllegalArgumentException( - "Expected padding of 0 when bitmap length is 0, but got " + padding); - } + throw new BloomFilterException( + "Expected padding of 0 when bitmap length is 0, but got " + padding); } this.bitmap = bitmap; @@ -133,8 +131,8 @@ private int getBitIndex(long hash1, long hash2, int hashIndex) { /** * Calculate modulo, where the dividend and divisor are treated as unsigned 64-bit longs. * - *

The implementation is taken from Guava, + *

The implementation is taken from Guava, * simplified to our needs. * *

diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java new file mode 100644 index 00000000000..429b501ed47 --- /dev/null +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java @@ -0,0 +1,23 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.firestore.remote; + +import androidx.annotation.NonNull; + +public class BloomFilterException extends RuntimeException { + public BloomFilterException(@NonNull String detailMessage) { + super(detailMessage); + } +} diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java index 7be1ca4744a..06d2d5f924e 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java @@ -14,20 +14,34 @@ package com.google.firebase.firestore.remote; +import androidx.annotation.Nullable; +import com.google.firestore.v1.BloomFilter; + /** Simplest form of existence filter */ public final class ExistenceFilter { private final int count; + private BloomFilter unchangedNames; public ExistenceFilter(int count) { this.count = count; } + public ExistenceFilter(int count, @Nullable BloomFilter unchangedNames) { + this.count = count; + this.unchangedNames = unchangedNames; + } + public int getCount() { return count; } + @Nullable + public BloomFilter getUnchangedNames() { + return unchangedNames; + } + @Override public String toString() { - return "ExistenceFilter{count=" + count + '}'; + return "ExistenceFilter{count=" + count + ", unchangedNames=" + unchangedNames + '}'; } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java index 7f1f7781045..655842a73af 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java @@ -945,8 +945,8 @@ public WatchChange decodeWatchChange(ListenResponse protoChange) { break; case FILTER: com.google.firestore.v1.ExistenceFilter protoFilter = protoChange.getFilter(); - // TODO: implement existence filter parsing (see b/33076578) - ExistenceFilter filter = new ExistenceFilter(protoFilter.getCount()); + ExistenceFilter filter = + new ExistenceFilter(protoFilter.getCount(), protoFilter.getUnchangedNames()); int targetId = protoFilter.getTargetId(); watchChange = new ExistenceFilterWatchChange(targetId, filter); break; diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java index 965ceee35da..1f5ad514b46 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java @@ -28,6 +28,7 @@ import com.google.firebase.firestore.local.LocalStore; import com.google.firebase.firestore.local.QueryPurpose; import com.google.firebase.firestore.local.TargetData; +import com.google.firebase.firestore.model.DatabaseId; import com.google.firebase.firestore.model.DocumentKey; import com.google.firebase.firestore.model.SnapshotVersion; import com.google.firebase.firestore.model.mutation.MutationBatch; @@ -758,6 +759,11 @@ public TargetData getTargetDataForTarget(int targetId) { return this.listenTargets.get(targetId); } + @Override + public DatabaseId getDatabaseId() { + return this.datastore.getDatabaseInfo().getDatabaseId(); + } + public Task runCountQuery(Query query) { if (canUseNetwork()) { return datastore.runCountQuery(query); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java index 1086af504db..435cbca9e24 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java @@ -23,12 +23,14 @@ import com.google.firebase.firestore.core.Target; import com.google.firebase.firestore.local.QueryPurpose; import com.google.firebase.firestore.local.TargetData; +import com.google.firebase.firestore.model.DatabaseId; import com.google.firebase.firestore.model.DocumentKey; import com.google.firebase.firestore.model.MutableDocument; import com.google.firebase.firestore.model.SnapshotVersion; import com.google.firebase.firestore.remote.WatchChange.DocumentChange; import com.google.firebase.firestore.remote.WatchChange.ExistenceFilterWatchChange; import com.google.firebase.firestore.remote.WatchChange.WatchTargetChange; +import com.google.firebase.firestore.util.Logger; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -56,6 +58,9 @@ public interface TargetMetadataProvider { */ @Nullable TargetData getTargetDataForTarget(int targetId); + + /** Returns the database ID of the Firestore instance. */ + DatabaseId getDatabaseId(); } private final TargetMetadataProvider targetMetadataProvider; @@ -75,6 +80,9 @@ public interface TargetMetadataProvider { */ private Set pendingTargetResets = new HashSet<>(); + /** The log tag to use for this class. */ + private static final String LOG_TAG = "WatchChangeAggregator"; + public WatchChangeAggregator(TargetMetadataProvider targetMetadataProvider) { this.targetMetadataProvider = targetMetadataProvider; } @@ -196,17 +204,78 @@ public void handleExistenceFilter(ExistenceFilterWatchChange watchChange) { expectedCount == 1, "Single document existence filter with count: %d", expectedCount); } } else { - long currentSize = getCurrentDocumentCountForTarget(targetId); + int currentSize = getCurrentDocumentCountForTarget(targetId); if (currentSize != expectedCount) { - // Existence filter mismatch: We reset the mapping and raise a new snapshot with - // `isFromCache:true`. - resetTarget(targetId); - pendingTargetResets.add(targetId); + + // Apply bloom filter to identify and mark removed documents. + boolean bloomFilterApplied = this.applyBloomFilter(watchChange, currentSize); + + if (!bloomFilterApplied) { + // If bloom filter application fails, we reset the mapping and + // trigger re-run of the query. + resetTarget(targetId); + pendingTargetResets.add(targetId); + } } } } } + /** Returns whether a bloom filter removed the deleted documents successfully. */ + private boolean applyBloomFilter(ExistenceFilterWatchChange watchChange, int currentCount) { + int expectedCount = watchChange.getExistenceFilter().getCount(); + com.google.firestore.v1.BloomFilter unchangedNames = + watchChange.getExistenceFilter().getUnchangedNames(); + + if (unchangedNames == null || !unchangedNames.hasBits()) { + return false; + } + + byte[] bitmap = unchangedNames.getBits().getBitmap().toByteArray(); + BloomFilter bloomFilter; + + try { + bloomFilter = + new BloomFilter( + bitmap, unchangedNames.getBits().getPadding(), unchangedNames.getHashCount()); + } catch (BloomFilterException e) { + Logger.warn( + LOG_TAG, + "Decoding the base64 bloom filter in existence filter failed (" + + e.getMessage() + + "); ignoring the bloom filter and falling back to full re-query."); + return false; + } + + int removedDocumentCount = this.filterRemovedDocuments(bloomFilter, watchChange.getTargetId()); + + return expectedCount == (currentCount - removedDocumentCount); + } + + /** + * Filter out removed documents based on bloom filter membership result and return number of + * documents removed. + */ + private int filterRemovedDocuments(BloomFilter bloomFilter, int targetId) { + ImmutableSortedSet existingKeys = + targetMetadataProvider.getRemoteKeysForTarget(targetId); + int removalCount = 0; + for (DocumentKey key : existingKeys) { + DatabaseId databaseId = targetMetadataProvider.getDatabaseId(); + String documentPath = + "projects/" + + databaseId.getProjectId() + + "/databases/" + + databaseId.getDatabaseId() + + "/documents/" + + key.getPath().canonicalString(); + if (!bloomFilter.mightContain(documentPath)) { + this.removeDocumentFromTarget(targetId, key, /*updatedDocument=*/ null); + removalCount++; + } + } + return removalCount; + } /** * Converts the currently accumulated state into a remote event at the provided snapshot version. * Resets the accumulated changes before returning. diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java index 0e851a0fc4f..c2ba39c4d7f 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java @@ -73,55 +73,53 @@ public void constructorShouldThrowNPEOnNullBitmap() { } @Test - public void constructorShouldThrowIAEOnEmptyBloomFilterWithNonZeroPadding() { - IllegalArgumentException exception = - assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 1, 0)); + public void constructorShouldThrowBFEOnEmptyBloomFilterWithNonZeroPadding() { + BloomFilterException exception = + assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[0], 1, 0)); assertThat(exception) .hasMessageThat() .contains("Expected padding of 0 when bitmap length is 0, but got 1"); } @Test - public void constructorShouldThrowIAEOnNonEmptyBloomFilterWithZeroHashCount() { - IllegalArgumentException zeroHashCountException = - assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 1, 0)); + public void constructorShouldThrowBFEOnNonEmptyBloomFilterWithZeroHashCount() { + BloomFilterException zeroHashCountException = + assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, 1, 0)); assertThat(zeroHashCountException).hasMessageThat().contains("Invalid hash count: 0"); } @Test - public void constructorShouldThrowIAEOnNegativePadding() { + public void constructorShouldThrowBFEOnNegativePadding() { { - IllegalArgumentException emptyBloomFilterException = - assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], -1, 0)); + BloomFilterException emptyBloomFilterException = + assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[0], -1, 0)); assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1"); } { - IllegalArgumentException nonEmptyBloomFilterException = - assertThrows( - IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, -1, 1)); + BloomFilterException nonEmptyBloomFilterException = + assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, -1, 1)); assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1"); } } @Test - public void constructorShouldThrowIAEOnNegativeHashCount() { + public void constructorShouldThrowBFEOnNegativeHashCount() { { - IllegalArgumentException emptyBloomFilterException = - assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 0, -1)); + BloomFilterException emptyBloomFilterException = + assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[0], 0, -1)); assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1"); } { - IllegalArgumentException nonEmptyBloomFilterException = - assertThrows( - IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 1, -1)); + BloomFilterException nonEmptyBloomFilterException = + assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, 1, -1)); assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1"); } } @Test - public void constructorShouldThrowIAEIfPaddingIsTooLarge() { - IllegalArgumentException exception = - assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 8, 1)); + public void constructorShouldThrowBFEIfPaddingIsTooLarge() { + BloomFilterException exception = + assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, 8, 1)); assertThat(exception).hasMessageThat().contains("Invalid padding: 8"); } @@ -179,7 +177,7 @@ public void bloomFilterToString() { private static void runGoldenTest(String testFile) throws Exception { String resultFile = testFile.replace("bloom_filter_proto", "membership_test_result"); if (resultFile.equals(testFile)) { - throw new IllegalArgumentException("Cannot find corresponding result file for " + testFile); + throw new BloomFilterException("Cannot find corresponding result file for " + testFile); } JSONObject testJson = readJsonFile(testFile); diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java index 7be9479da3b..42f570711b1 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java @@ -31,6 +31,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import android.util.Base64; import android.util.Pair; import androidx.test.core.app.ApplicationProvider; import com.google.android.gms.tasks.Task; @@ -81,6 +82,8 @@ import com.google.firebase.firestore.util.Assert; import com.google.firebase.firestore.util.AsyncQueue; import com.google.firebase.firestore.util.AsyncQueue.TimerId; +import com.google.firestore.v1.BitSequence; +import com.google.firestore.v1.BloomFilter; import com.google.protobuf.ByteString; import io.grpc.Status; import java.io.BufferedReader; @@ -468,6 +471,24 @@ private List parseIntList(@Nullable JSONArray arr) throws JSONException return result; } + /** Deeply parses a JSONObject into a bloom filter proto type. */ + private BloomFilter parseBloomFilter(JSONObject obj) throws JSONException { + BitSequence.Builder bitSequence = BitSequence.newBuilder(); + JSONObject bits = obj.getJSONObject("bits"); + if (bits.has("padding")) { + bitSequence.setPadding(bits.getInt("padding")); + } + bitSequence.setBitmap( + ByteString.copyFrom(Base64.decode(bits.getString("bitmap"), Base64.DEFAULT))); + + BloomFilter.Builder bloomFilter = BloomFilter.newBuilder(); + bloomFilter.setBits(bitSequence); + if (obj.has("hashCount")) { + bloomFilter.setHashCount(obj.getInt("hashCount")); + } + return bloomFilter.build(); + } + // // Methods for doing the steps of the spec test. // @@ -654,15 +675,19 @@ private void doWatchEntity(JSONObject watchEntity) throws Exception { } } - private void doWatchFilter(JSONArray watchFilter) throws Exception { - List targets = parseIntList(watchFilter.getJSONArray(0)); + private void doWatchFilter(JSONObject watchFilter) throws Exception { + List targets = parseIntList(watchFilter.getJSONArray("targetIds")); + Assert.hardAssert( targets.size() == 1, "ExistenceFilters currently support exactly one target only."); - int keyCount = watchFilter.length() == 0 ? 0 : watchFilter.length() - 1; + int keyCount = watchFilter.getJSONArray("keys").length(); + BloomFilter bloomFilterProto = + watchFilter.has("bloomFilter") + ? parseBloomFilter(watchFilter.getJSONObject("bloomFilter")) + : null; - // TODO: extend this with different existence filters over time. - ExistenceFilter filter = new ExistenceFilter(keyCount); + ExistenceFilter filter = new ExistenceFilter(keyCount, bloomFilterProto); ExistenceFilterWatchChange change = new ExistenceFilterWatchChange(targets.get(0), filter); writeWatchChange(change, SnapshotVersion.NONE); } @@ -713,7 +738,7 @@ private void doWriteAck(JSONObject writeAckSpec) throws Exception { validateNextWriteSent(write.first); MutationResult mutationResult = - new MutationResult(version(version), /*transformResults=*/ Collections.emptyList()); + new MutationResult(version(version), /* transformResults= */ Collections.emptyList()); queue.runSync(() -> datastore.ackWrite(version(version), singletonList(mutationResult))); } @@ -830,7 +855,7 @@ private void doStep(JSONObject step) throws Exception { } else if (step.has("watchEntity")) { doWatchEntity(step.getJSONObject("watchEntity")); } else if (step.has("watchFilter")) { - doWatchFilter(step.getJSONArray("watchFilter")); + doWatchFilter(step.getJSONObject("watchFilter")); } else if (step.has("watchReset")) { doWatchReset(step.getJSONArray("watchReset")); } else if (step.has("watchSnapshot")) { @@ -899,7 +924,17 @@ private void assertEventMatches(JSONObject expected, QueryEvent actual) throws J for (int i = 0; metadata != null && i < metadata.length(); ++i) { expectedChanges.add(parseChange(metadata.getJSONObject(i), Type.METADATA)); } - assertEquals(expectedChanges, actual.view.getChanges()); + + List sortedActualChanges = + actual.view.getChanges().stream() + .sorted((a, b) -> a.getDocument().getKey().compareTo(b.getDocument().getKey())) + .collect(Collectors.toList()); + List sortedExpectedChanges = + expectedChanges.stream() + .sorted((a, b) -> a.getDocument().getKey().compareTo(b.getDocument().getKey())) + .collect(Collectors.toList()); + + assertEquals(sortedExpectedChanges, sortedActualChanges); boolean expectedHasPendingWrites = expected.optBoolean("hasPendingWrites", false); boolean expectedFromCache = expected.optBoolean("fromCache", false); diff --git a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json index 3083b762224..a66a08bce17 100644 --- a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json +++ b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json @@ -1,9 +1,8 @@ { - "Existence filter clears resume token": { + "Bloom filter can process special characters in document name": { "describeName": "Existence Filters:", - "itName": "Existence filter clears resume token", + "itName": "Bloom filter can process special characters in document name", "tags": [ - "durable-persistence" ], "config": { "numClients": 1, @@ -47,7 +46,7 @@ "watchEntity": { "docs": [ { - "key": "collection/1", + "key": "collection/ÀÒ∑", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -58,13 +57,13 @@ "version": 1000 }, { - "key": "collection/2", + "key": "collection/À∑Ò", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, "version": 1000 } @@ -92,7 +91,7 @@ { "added": [ { - "key": "collection/1", + "key": "collection/ÀÒ∑", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -103,13 +102,13 @@ "version": 1000 }, { - "key": "collection/2", + "key": "collection/À∑Ò", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, "version": 1000 } @@ -128,12 +127,21 @@ ] }, { - "watchFilter": [ - [ - 2 + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "IIAAIIAIIAAIIAIIAA==", + "padding": 4 + }, + "hashCount": 10 + }, + "keys": [ + "collection/ÀÒ∑" ], - "collection/1" - ] + "targetIds": [ + 2 + ] + } }, { "watchSnapshot": { @@ -154,19 +162,51 @@ "path": "collection" } } - ] - }, - { - "restart": true, + ], "expectedState": { "activeLimboDocs": [ + "collection/À∑Ò" ], "activeTargets": { - }, - "enqueuedLimboDocs": [ - ] + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/À∑Ò" + } + ], + "resumeToken": "" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } } - }, + } + ] + }, + "Bloom filter fills in default values for undefined padding and hashCount": { + "describeName": "Existence Filters:", + "itName": "Bloom filter fills in default values for undefined padding and hashCount", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": true + }, + "steps": [ { "userListen": { "query": { @@ -178,11 +218,78 @@ }, "targetId": 2 }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, "expectedSnapshotEvents": [ { "added": [ { - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -193,7 +300,7 @@ "version": 1000 }, { - "key": "collection/2", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -204,6 +311,42 @@ "version": 1000 } ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "AhAAApAAAIAEBIAABA==" + } + }, + "keys": [ + "collection/a" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { "errorCode": 0, "fromCache": true, "hasPendingWrites": false, @@ -235,9 +378,9 @@ } ] }, - "Existence filter handled at global snapshot": { + "Bloom filter is handled at global snapshot": { "describeName": "Existence Filters:", - "itName": "Existence filter handled at global snapshot", + "itName": "Bloom filter is handled at global snapshot", "tags": [ ], "config": { @@ -282,7 +425,7 @@ "watchEntity": { "docs": [ { - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -291,6 +434,17 @@ "v": 1 }, "version": 1000 + }, + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 } ], "targets": [ @@ -316,7 +470,7 @@ { "added": [ { - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -325,6 +479,17 @@ "v": 1 }, "version": 1000 + }, + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 } ], "errorCode": 0, @@ -341,19 +506,27 @@ ] }, { - "watchFilter": [ - [ - 2 + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "AhAAApAAAIAEBIAABA==", + "padding": 4 + }, + "hashCount": 10 + }, + "keys": [ + "collection/a" ], - "collection/1", - "collection/2" - ] + "targetIds": [ + 2 + ] + } }, { "watchEntity": { "docs": [ { - "key": "collection/3", + "key": "collection/c", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -379,7 +552,7 @@ { "added": [ { - "key": "collection/3", + "key": "collection/c", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -403,7 +576,22 @@ } ], "expectedState": { + "activeLimboDocs": [ + "collection/b" + ], "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/b" + } + ], + "resumeToken": "" + }, "2": { "queries": [ { @@ -418,12 +606,45 @@ } } } - }, + } + ] + }, + "Bloom filter limbo resolution is denied": { + "describeName": "Existence Filters:", + "itName": "Bloom filter limbo resolution is denied", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": true + }, + "steps": [ { - "watchRemove": { - "targetIds": [ - 2 - ] + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } } }, { @@ -435,7 +656,7 @@ "watchEntity": { "docs": [ { - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -446,26 +667,15 @@ "version": 1000 }, { - "key": "collection/2", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, - "version": 2000 - }, - { - "key": "collection/3", - "options": { - "hasCommittedMutations": false, - "hasLocalMutations": false - }, - "value": { - "v": 3 - }, - "version": 3000 + "version": 1000 } ], "targets": [ @@ -478,135 +688,39 @@ [ 2 ], - "resume-token-3000" + "resume-token-1000" ] }, { "watchSnapshot": { "targetIds": [ ], - "version": 3000 + "version": 1000 }, "expectedSnapshotEvents": [ { "added": [ { - "key": "collection/2", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, - "version": 2000 - } - ], - "errorCode": 0, - "fromCache": false, - "hasPendingWrites": false, - "query": { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } - } - ] - } - ] - }, - "Existence filter ignored with pending target": { - "describeName": "Existence Filters:", - "itName": "Existence filter ignored with pending target", - "tags": [ - ], - "config": { - "numClients": 1, - "useGarbageCollection": false - }, - "steps": [ - { - "userListen": { - "query": { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - }, - "targetId": 2 - }, - "expectedState": { - "activeTargets": { - "2": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } - ], - "resumeToken": "" - } - } - } - }, - { - "watchAck": [ - 2 - ] - }, - { - "watchEntity": { - "docs": [ - { - "key": "collection/1", - "options": { - "hasCommittedMutations": false, - "hasLocalMutations": false - }, - "value": { - "v": 2 + "version": 1000 }, - "version": 2000 - } - ], - "targets": [ - 2 - ] - } - }, - { - "watchCurrent": [ - [ - 2 - ], - "resume-token-1000" - ] - }, - { - "watchSnapshot": { - "targetIds": [ - ], - "version": 1000 - }, - "expectedSnapshotEvents": [ - { - "added": [ { - "key": "collection/1", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, - "version": 2000 + "version": 1000 } ], "errorCode": 0, @@ -623,47 +737,30 @@ ] }, { - "userUnlisten": [ - 2, - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } - ], - "expectedState": { - "activeTargets": { - } + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "AhAAApAAAIAEBIAABA==", + "padding": 4 + }, + "hashCount": 10 + }, + "keys": [ + "collection/a" + ], + "targetIds": [ + 2 + ] } }, { - "userListen": { - "query": { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - }, - "targetId": 2 + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 }, "expectedSnapshotEvents": [ { - "added": [ - { - "key": "collection/1", - "options": { - "hasCommittedMutations": false, - "hasLocalMutations": false - }, - "value": { - "v": 2 - }, - "version": 2000 - } - ], "errorCode": 0, "fromCache": true, "hasPendingWrites": false, @@ -677,7 +774,22 @@ } ], "expectedState": { + "activeLimboDocs": [ + "collection/b" + ], "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/b" + } + ], + "resumeToken": "" + }, "2": { "queries": [ { @@ -688,43 +800,19 @@ "path": "collection" } ], - "resumeToken": "resume-token-1000" + "resumeToken": "" } } } }, - { - "watchFilter": [ - [ - 2 - ] - ] - }, { "watchRemove": { + "cause": { + "code": 7 + }, "targetIds": [ - 2 + 1 ] - } - }, - { - "watchAck": [ - 2 - ] - }, - { - "watchCurrent": [ - [ - 2 - ], - "resume-token-2000" - ] - }, - { - "watchSnapshot": { - "targetIds": [ - ], - "version": 2000 }, "expectedSnapshotEvents": [ { @@ -737,15 +825,46 @@ "orderBys": [ ], "path": "collection" + }, + "removed": [ + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ] + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" } } - ] + } } ] }, - "Existence filter limbo resolution is denied": { + "Bloom filter with large size works as expected": { "describeName": "Existence Filters:", - "itName": "Existence filter limbo resolution is denied", + "itName": "Bloom filter with large size works as expected", "tags": [ ], "config": { @@ -790,7 +909,7 @@ "watchEntity": { "docs": [ { - "key": "collection/1", + "key": "collection/doc0", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -801,27 +920,4388 @@ "version": 1000 }, { - "key": "collection/2", + "key": "collection/doc1", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, "version": 1000 - } - ], - "targets": [ - 2 - ] - } - }, - { - "watchCurrent": [ - [ - 2 - ], + }, + { + "key": "collection/doc2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc4", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc5", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc6", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc7", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc8", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc9", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc10", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc11", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc12", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc13", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc14", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc15", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc16", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc17", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc18", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc19", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc20", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc21", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc22", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc23", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc24", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc25", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc26", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc27", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc28", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc29", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc30", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc31", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc32", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc33", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc34", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc35", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc36", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc37", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc38", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc39", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc40", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc41", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc42", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc43", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc44", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc45", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc46", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc47", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc48", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc49", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc50", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc51", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc52", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc53", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc54", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc55", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc56", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc57", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc58", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc59", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc60", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc61", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc62", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc63", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc64", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc65", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc66", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc67", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc68", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc69", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc70", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc71", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc72", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc73", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc74", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc75", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc76", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc77", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc78", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc79", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc80", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc81", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc82", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc83", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc84", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc85", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc86", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc87", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc88", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc89", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc90", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc91", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc92", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc93", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc94", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc95", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc96", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc97", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc98", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc99", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/doc0", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc4", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc5", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc6", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc7", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc8", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc9", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc10", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc11", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc12", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc13", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc14", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc15", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc16", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc17", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc18", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc19", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc20", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc21", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc22", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc23", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc24", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc25", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc26", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc27", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc28", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc29", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc30", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc31", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc32", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc33", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc34", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc35", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc36", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc37", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc38", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc39", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc40", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc41", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc42", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc43", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc44", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc45", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc46", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc47", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc48", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc49", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc50", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc51", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc52", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc53", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc54", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc55", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc56", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc57", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc58", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc59", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc60", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc61", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc62", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc63", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc64", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc65", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc66", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc67", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc68", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc69", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc70", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc71", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc72", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc73", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc74", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc75", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc76", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc77", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc78", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc79", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc80", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc81", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc82", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc83", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc84", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc85", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc86", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc87", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc88", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc89", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc90", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc91", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc92", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc93", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc94", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc95", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc96", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc97", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc98", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/doc99", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "+9oMQXUptl274DOaET8sfebQ4aCu0Roiddbja3z8TfadKuyPV/9XWV5Ksv+vywRXTfZSNIn8z+xk/oq1+cbOPepeNvbXVOF6H92fCOAz/KiS3Mcw338R9tXE3Y7QB1L2kbvbvVHW3Kn/k3Vx8k9Oa19eWX6RYE97Q+oCcVU=", + "padding": 0 + }, + "hashCount": 16 + }, + "keys": [ + "collection/doc0", + "collection/doc1", + "collection/doc2", + "collection/doc3", + "collection/doc4", + "collection/doc5", + "collection/doc6", + "collection/doc7", + "collection/doc8", + "collection/doc9", + "collection/doc10", + "collection/doc11", + "collection/doc12", + "collection/doc13", + "collection/doc14", + "collection/doc15", + "collection/doc16", + "collection/doc17", + "collection/doc18", + "collection/doc19", + "collection/doc20", + "collection/doc21", + "collection/doc22", + "collection/doc23", + "collection/doc24", + "collection/doc25", + "collection/doc26", + "collection/doc27", + "collection/doc28", + "collection/doc29", + "collection/doc30", + "collection/doc31", + "collection/doc32", + "collection/doc33", + "collection/doc34", + "collection/doc35", + "collection/doc36", + "collection/doc37", + "collection/doc38", + "collection/doc39", + "collection/doc40", + "collection/doc41", + "collection/doc42", + "collection/doc43", + "collection/doc44", + "collection/doc45", + "collection/doc46", + "collection/doc47", + "collection/doc48", + "collection/doc49" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeLimboDocs": [ + "collection/doc50", + "collection/doc51", + "collection/doc52", + "collection/doc53", + "collection/doc54", + "collection/doc55", + "collection/doc56", + "collection/doc57", + "collection/doc58", + "collection/doc59", + "collection/doc60", + "collection/doc61", + "collection/doc62", + "collection/doc63", + "collection/doc64", + "collection/doc65", + "collection/doc66", + "collection/doc67", + "collection/doc68", + "collection/doc69", + "collection/doc70", + "collection/doc71", + "collection/doc72", + "collection/doc73", + "collection/doc74", + "collection/doc75", + "collection/doc76", + "collection/doc77", + "collection/doc78", + "collection/doc79", + "collection/doc80", + "collection/doc81", + "collection/doc82", + "collection/doc83", + "collection/doc84", + "collection/doc85", + "collection/doc86", + "collection/doc87", + "collection/doc88", + "collection/doc89", + "collection/doc90", + "collection/doc91", + "collection/doc92", + "collection/doc93", + "collection/doc94", + "collection/doc95", + "collection/doc96", + "collection/doc97", + "collection/doc98", + "collection/doc99" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc50" + } + ], + "resumeToken": "" + }, + "11": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc55" + } + ], + "resumeToken": "" + }, + "13": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc56" + } + ], + "resumeToken": "" + }, + "15": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc57" + } + ], + "resumeToken": "" + }, + "17": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc58" + } + ], + "resumeToken": "" + }, + "19": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc59" + } + ], + "resumeToken": "" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + }, + "21": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc60" + } + ], + "resumeToken": "" + }, + "23": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc61" + } + ], + "resumeToken": "" + }, + "25": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc62" + } + ], + "resumeToken": "" + }, + "27": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc63" + } + ], + "resumeToken": "" + }, + "29": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc64" + } + ], + "resumeToken": "" + }, + "3": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc51" + } + ], + "resumeToken": "" + }, + "31": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc65" + } + ], + "resumeToken": "" + }, + "33": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc66" + } + ], + "resumeToken": "" + }, + "35": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc67" + } + ], + "resumeToken": "" + }, + "37": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc68" + } + ], + "resumeToken": "" + }, + "39": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc69" + } + ], + "resumeToken": "" + }, + "41": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc70" + } + ], + "resumeToken": "" + }, + "43": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc71" + } + ], + "resumeToken": "" + }, + "45": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc72" + } + ], + "resumeToken": "" + }, + "47": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc73" + } + ], + "resumeToken": "" + }, + "49": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc74" + } + ], + "resumeToken": "" + }, + "5": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc52" + } + ], + "resumeToken": "" + }, + "51": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc75" + } + ], + "resumeToken": "" + }, + "53": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc76" + } + ], + "resumeToken": "" + }, + "55": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc77" + } + ], + "resumeToken": "" + }, + "57": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc78" + } + ], + "resumeToken": "" + }, + "59": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc79" + } + ], + "resumeToken": "" + }, + "61": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc80" + } + ], + "resumeToken": "" + }, + "63": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc81" + } + ], + "resumeToken": "" + }, + "65": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc82" + } + ], + "resumeToken": "" + }, + "67": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc83" + } + ], + "resumeToken": "" + }, + "69": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc84" + } + ], + "resumeToken": "" + }, + "7": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc53" + } + ], + "resumeToken": "" + }, + "71": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc85" + } + ], + "resumeToken": "" + }, + "73": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc86" + } + ], + "resumeToken": "" + }, + "75": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc87" + } + ], + "resumeToken": "" + }, + "77": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc88" + } + ], + "resumeToken": "" + }, + "79": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc89" + } + ], + "resumeToken": "" + }, + "81": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc90" + } + ], + "resumeToken": "" + }, + "83": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc91" + } + ], + "resumeToken": "" + }, + "85": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc92" + } + ], + "resumeToken": "" + }, + "87": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc93" + } + ], + "resumeToken": "" + }, + "89": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc94" + } + ], + "resumeToken": "" + }, + "9": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc54" + } + ], + "resumeToken": "" + }, + "91": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc95" + } + ], + "resumeToken": "" + }, + "93": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc96" + } + ], + "resumeToken": "" + }, + "95": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc97" + } + ], + "resumeToken": "" + }, + "97": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc98" + } + ], + "resumeToken": "" + }, + "99": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc99" + } + ], + "resumeToken": "" + } + } + } + } + ] + }, + "Existence filter clears resume token": { + "describeName": "Existence Filters:", + "itName": "Existence filter clears resume token", + "tags": [ + "durable-persistence" + ], + "config": { + "numClients": 1, + "useGarbageCollection": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "keys": [ + "collection/1" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "restart": true, + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + }, + "enqueuedLimboDocs": [ + ] + } + }, + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + } + ] + }, + "Existence filter handled at global snapshot": { + "describeName": "Existence Filters:", + "itName": "Existence filter handled at global snapshot", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "keys": [ + "collection/1", + "collection/2" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 3 + }, + "version": 3000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 3 + }, + "version": 3000 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchRemove": { + "targetIds": [ + 2 + ] + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 + }, + { + "key": "collection/3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 3 + }, + "version": 3000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-3000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 3000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + } + ] + }, + "Existence filter ignored with pending target": { + "describeName": "Existence Filters:", + "itName": "Existence filter ignored with pending target", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": false + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "userUnlisten": [ + 2, + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "expectedState": { + "activeTargets": { + } + } + }, + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "resume-token-1000" + } + } + } + }, + { + "watchFilter": { + "keys": [ + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchRemove": { + "targetIds": [ + 2 + ] + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-2000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + } + ] + }, + "Existence filter limbo resolution is denied": { + "describeName": "Existence Filters:", + "itName": "Existence filter limbo resolution is denied", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "keys": [ + "collection/1" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchRemove": { + "targetIds": [ + 2 + ] + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-2000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedState": { + "activeLimboDocs": [ + "collection/2" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/2" + } + ], + "resumeToken": "" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchRemove": { + "cause": { + "code": 7 + }, + "targetIds": [ + 1 + ] + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "removed": [ + { + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ] + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + } + ] + }, + "Existence filter match": { + "describeName": "Existence Filters:", + "itName": "Existence filter match", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "keys": [ + "collection/1" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + } + } + ] + }, + "Existence filter match after pending update": { + "describeName": "Existence Filters:", + "itName": "Existence filter match after pending update", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchFilter": { + "keys": [ + "collection/1" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + } + ] + }, + "Existence filter mismatch triggers re-run of query": { + "describeName": "Existence Filters:", + "itName": "Existence filter mismatch triggers re-run of query", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], "resume-token-1000" ] }, @@ -829,30 +5309,676 @@ "watchSnapshot": { "targetIds": [ ], - "version": 1000 + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "keys": [ + "collection/1" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchRemove": { + "targetIds": [ + 2 + ] + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-2000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedState": { + "activeLimboDocs": [ + "collection/2" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/2" + } + ], + "resumeToken": "" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 1 + ] + }, + { + "watchCurrent": [ + [ + 1 + ], + "resume-token-2000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "removed": [ + { + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ] + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + } + ] + }, + "Existence filter mismatch will drop resume token": { + "describeName": "Existence Filters:", + "itName": "Existence filter mismatch will drop resume token", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "existence-filter-resume-token" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchStreamClose": { + "error": { + "code": 14, + "message": "Simulated Backend Error" + }, + "runBackoffTimer": true + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "existence-filter-resume-token" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchFilter": { + "keys": [ + "collection/1" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchRemove": { + "targetIds": [ + 2 + ] + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-2000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedState": { + "activeLimboDocs": [ + "collection/2" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/2" + } + ], + "resumeToken": "" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 1 + ] + }, + { + "watchCurrent": [ + [ + 1 + ], + "resume-token-2000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 }, "expectedSnapshotEvents": [ { - "added": [ + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "removed": [ { - "key": "collection/1", + "key": "collection/2", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 1 + "v": 2 }, "version": 1000 + } + ] + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + } + ] + }, + "Existence filter synthesizes deletes": { + "describeName": "Existence Filters:", + "itName": "Existence filter synthesizes deletes", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/a" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/a" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ { - "key": "collection/2", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, "version": 1000 } @@ -865,18 +5991,19 @@ ], "orderBys": [ ], - "path": "collection" + "path": "collection/a" } } ] }, { - "watchFilter": [ - [ - 2 + "watchFilter": { + "keys": [ ], - "collection/1" - ] + "targetIds": [ + 2 + ] + } }, { "watchSnapshot": { @@ -887,17 +6014,54 @@ "expectedSnapshotEvents": [ { "errorCode": 0, - "fromCache": true, + "fromCache": false, "hasPendingWrites": false, "query": { "filters": [ ], "orderBys": [ ], - "path": "collection" - } + "path": "collection/a" + }, + "removed": [ + { + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ] } - ], + ] + } + ] + }, + "Existence filter with empty target": { + "describeName": "Existence Filters:", + "itName": "Existence filter with empty target", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, "expectedState": { "activeTargets": { "2": { @@ -915,44 +6079,17 @@ } } }, - { - "watchRemove": { - "targetIds": [ - 2 - ] - } - }, { "watchAck": [ 2 ] }, - { - "watchEntity": { - "docs": [ - { - "key": "collection/1", - "options": { - "hasCommittedMutations": false, - "hasLocalMutations": false - }, - "value": { - "v": 1 - }, - "version": 1000 - } - ], - "targets": [ - 2 - ] - } - }, { "watchCurrent": [ [ 2 ], - "resume-token-2000" + "resume-token-1000" ] }, { @@ -961,51 +6098,41 @@ ], "version": 2000 }, - "expectedState": { - "activeLimboDocs": [ - "collection/2" - ], - "activeTargets": { - "1": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection/2" - } + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ ], - "resumeToken": "" - }, - "2": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } + "orderBys": [ ], - "resumeToken": "" + "path": "collection" } } - } + ] }, { - "watchRemove": { - "cause": { - "code": 7 - }, + "watchFilter": { + "keys": [ + "collection/1" + ], "targetIds": [ - 1 + 2 ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 }, "expectedSnapshotEvents": [ { "errorCode": 0, - "fromCache": false, + "fromCache": true, "hasPendingWrites": false, "query": { "filters": [ @@ -1013,46 +6140,15 @@ "orderBys": [ ], "path": "collection" - }, - "removed": [ - { - "key": "collection/2", - "options": { - "hasCommittedMutations": false, - "hasLocalMutations": false - }, - "value": { - "v": 2 - }, - "version": 1000 - } - ] - } - ], - "expectedState": { - "activeLimboDocs": [ - ], - "activeTargets": { - "2": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } - ], - "resumeToken": "" } } - } + ] } ] }, - "Existence filter match": { + "Full re-query is skipped when bloom filter can identify documents deleted": { "describeName": "Existence Filters:", - "itName": "Existence filter match", + "itName": "Full re-query is skipped when bloom filter can identify documents deleted", "tags": [ ], "config": { @@ -1097,7 +6193,7 @@ "watchEntity": { "docs": [ { - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1106,6 +6202,17 @@ "v": 1 }, "version": 1000 + }, + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 } ], "targets": [ @@ -1131,7 +6238,7 @@ { "added": [ { - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1140,6 +6247,17 @@ "v": 1 }, "version": 1000 + }, + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 } ], "errorCode": 0, @@ -1156,11 +6274,85 @@ ] }, { - "watchFilter": [ - [ + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "AhAAApAAAIAEBIAABA==", + "padding": 4 + }, + "hashCount": 10 + }, + "keys": [ + "collection/a" + ], + "targetIds": [ 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeLimboDocs": [ + "collection/b" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/b" + } + ], + "resumeToken": "" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 1 + ] + }, + { + "watchCurrent": [ + [ + 1 ], - "collection/1" + "resume-token-2000" ] }, { @@ -1168,14 +6360,61 @@ "targetIds": [ ], "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "removed": [ + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ] + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } } } ] }, - "Existence filter match after pending update": { + "Full re-query is triggered when bloom filter bitmap is invalid": { "describeName": "Existence Filters:", - "itName": "Existence filter match after pending update", + "itName": "Full re-query is triggered when bloom filter bitmap is invalid", "tags": [ + "no-ios", + "no-android" ], "config": { "numClients": 1, @@ -1215,48 +6454,30 @@ 2 ] }, - { - "watchCurrent": [ - [ - 2 - ], - "resume-token-1000" - ] - }, - { - "watchSnapshot": { - "targetIds": [ - ], - "version": 2000 - }, - "expectedSnapshotEvents": [ - { - "errorCode": 0, - "fromCache": false, - "hasPendingWrites": false, - "query": { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } - } - ] - }, { "watchEntity": { "docs": [ { - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, - "version": 2000 + "version": 1000 + }, + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 } ], "targets": [ @@ -1265,32 +6486,43 @@ } }, { - "watchFilter": [ + "watchCurrent": [ [ 2 ], - "collection/1" + "resume-token-1000" ] }, { "watchSnapshot": { "targetIds": [ ], - "version": 2000 + "version": 1000 }, "expectedSnapshotEvents": [ { "added": [ { - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, - "version": 2000 + "version": 1000 + }, + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 } ], "errorCode": 0, @@ -1305,12 +6537,66 @@ } } ] + }, + { + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "INVALID_BASE_64", + "padding": 4 + }, + "hashCount": 10 + }, + "keys": [ + "collection/a" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } } ] }, - "Existence filter mismatch triggers re-run of query": { + "Full re-query is triggered when bloom filter can not identify documents deleted": { "describeName": "Existence Filters:", - "itName": "Existence filter mismatch triggers re-run of query", + "itName": "Full re-query is triggered when bloom filter can not identify documents deleted", "tags": [ ], "config": { @@ -1355,7 +6641,7 @@ "watchEntity": { "docs": [ { - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1366,7 +6652,18 @@ "version": 1000 }, { - "key": "collection/2", + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + }, + { + "key": "collection/c", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1400,7 +6697,7 @@ { "added": [ { - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1411,7 +6708,18 @@ "version": 1000 }, { - "key": "collection/2", + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + }, + { + "key": "collection/c", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1436,12 +6744,21 @@ ] }, { - "watchFilter": [ - [ - 2 + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "AxBIApBIAIAWBoCQBA==", + "padding": 4 + }, + "hashCount": 10 + }, + "keys": [ + "collection/a" ], - "collection/1" - ] + "targetIds": [ + 2 + ] + } }, { "watchSnapshot": { @@ -1462,7 +6779,14 @@ "path": "collection" } } - ], + ] + }, + { + "watchRemove": { + "targetIds": [ + 2 + ] + }, "expectedState": { "activeTargets": { "2": { @@ -1479,12 +6803,45 @@ } } } - }, + } + ] + }, + "Full re-query is triggered when bloom filter hashCount is invalid": { + "describeName": "Existence Filters:", + "itName": "Full re-query is triggered when bloom filter hashCount is invalid", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": true + }, + "steps": [ { - "watchRemove": { - "targetIds": [ - 2 - ] + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } } }, { @@ -1496,7 +6853,7 @@ "watchEntity": { "docs": [ { - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1505,80 +6862,64 @@ "v": 1 }, "version": 1000 - } - ], - "targets": [ - 2 - ] - } - }, - { - "watchCurrent": [ - [ - 2 - ], - "resume-token-2000" - ] - }, - { - "watchSnapshot": { - "targetIds": [ - ], - "version": 2000 - }, - "expectedState": { - "activeLimboDocs": [ - "collection/2" - ], - "activeTargets": { - "1": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection/2" - } - ], - "resumeToken": "" }, - "2": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } - ], - "resumeToken": "" + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 } - } + ], + "targets": [ + 2 + ] } }, - { - "watchAck": [ - 1 - ] - }, { "watchCurrent": [ [ - 1 + 2 ], - "resume-token-2000" + "resume-token-1000" ] }, { "watchSnapshot": { "targetIds": [ ], - "version": 2000 + "version": 1000 }, "expectedSnapshotEvents": [ { + "added": [ + { + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], "errorCode": 0, "fromCache": false, "hasPendingWrites": false, @@ -1588,25 +6929,48 @@ "orderBys": [ ], "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "AhAAApAAAIAEBIAABA==", + "padding": 4 }, - "removed": [ - { - "key": "collection/2", - "options": { - "hasCommittedMutations": false, - "hasLocalMutations": false - }, - "value": { - "v": 2 - }, - "version": 1000 - } - ] + "hashCount": -1 + }, + "keys": [ + "collection/a" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } } ], "expectedState": { - "activeLimboDocs": [ - ], "activeTargets": { "2": { "queries": [ @@ -1625,9 +6989,9 @@ } ] }, - "Existence filter mismatch will drop resume token": { + "Full re-query is triggered when bloom filter is empty": { "describeName": "Existence Filters:", - "itName": "Existence filter mismatch will drop resume token", + "itName": "Full re-query is triggered when bloom filter is empty", "tags": [ ], "config": { @@ -1672,7 +7036,7 @@ "watchEntity": { "docs": [ { - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1683,13 +7047,13 @@ "version": 1000 }, { - "key": "collection/2", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, "version": 1000 } @@ -1704,7 +7068,7 @@ [ 2 ], - "existence-filter-resume-token" + "resume-token-1000" ] }, { @@ -1717,7 +7081,7 @@ { "added": [ { - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1728,13 +7092,13 @@ "version": 1000 }, { - "key": "collection/2", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, "version": 1000 } @@ -1753,42 +7117,21 @@ ] }, { - "watchStreamClose": { - "error": { - "code": 14, - "message": "Simulated Backend Error" + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "", + "padding": 0 + }, + "hashCount": 0 }, - "runBackoffTimer": true - }, - "expectedState": { - "activeTargets": { - "2": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } - ], - "resumeToken": "existence-filter-resume-token" - } - } - } - }, - { - "watchAck": [ - 2 - ] - }, - { - "watchFilter": [ - [ - 2 + "keys": [ + "collection/a" ], - "collection/1" - ] + "targetIds": [ + 2 + ] + } }, { "watchSnapshot": { @@ -1826,12 +7169,55 @@ } } } - }, + } + ] + }, + "Same documents can have different bloom filters": { + "describeName": "Existence Filters:", + "itName": "Same documents can have different bloom filters", + "tags": [ + ], + "config": { + "numClients": 1, + "useGarbageCollection": true + }, + "steps": [ { - "watchRemove": { - "targetIds": [ - 2 - ] + "userListen": { + "query": { + "filters": [ + [ + "v", + "<=", + 2 + ] + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + [ + "v", + "<=", + 2 + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } } }, { @@ -1843,7 +7229,7 @@ "watchEntity": { "docs": [ { - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1852,6 +7238,17 @@ "v": 1 }, "version": 1000 + }, + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 } ], "targets": [ @@ -1864,81 +7261,80 @@ [ 2 ], - "resume-token-2000" - ] - }, - { - "watchSnapshot": { - "targetIds": [ - ], - "version": 2000 - }, - "expectedState": { - "activeLimboDocs": [ - "collection/2" - ], - "activeTargets": { - "1": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection/2" - } - ], - "resumeToken": "" - }, - "2": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } - ], - "resumeToken": "" - } - } - } - }, - { - "watchAck": [ - 1 - ] - }, - { - "watchCurrent": [ - [ - 1 - ], - "resume-token-2000" + "resume-token-1000" ] }, { "watchSnapshot": { "targetIds": [ ], - "version": 2000 + "version": 1000 }, "expectedSnapshotEvents": [ { + "added": [ + { + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], "errorCode": 0, "fromCache": false, "hasPendingWrites": false, "query": { "filters": [ + [ + "v", + "<=", + 2 + ] ], "orderBys": [ ], "path": "collection" - }, - "removed": [ + } + } + ] + }, + { + "userListen": { + "query": { + "filters": [ + [ + "v", + ">=", + 2 + ] + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 4 + }, + "expectedSnapshotEvents": [ + { + "added": [ { - "key": "collection/2", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1948,17 +7344,35 @@ }, "version": 1000 } - ] + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + [ + "v", + ">=", + 2 + ] + ], + "orderBys": [ + ], + "path": "collection" + } } ], "expectedState": { - "activeLimboDocs": [ - ], "activeTargets": { "2": { "queries": [ { "filters": [ + [ + "v", + "<=", + 2 + ] ], "orderBys": [ ], @@ -1966,43 +7380,20 @@ } ], "resumeToken": "" - } - } - } - } - ] - }, - "Existence filter synthesizes deletes": { - "describeName": "Existence Filters:", - "itName": "Existence filter synthesizes deletes", - "tags": [ - ], - "config": { - "numClients": 1, - "useGarbageCollection": true - }, - "steps": [ - { - "userListen": { - "query": { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection/a" - }, - "targetId": 2 - }, - "expectedState": { - "activeTargets": { - "2": { + }, + "4": { "queries": [ { "filters": [ + [ + "v", + ">=", + 2 + ] ], "orderBys": [ ], - "path": "collection/a" + "path": "collection" } ], "resumeToken": "" @@ -2012,54 +7403,65 @@ }, { "watchAck": [ - 2 + 4 ] }, { "watchEntity": { "docs": [ { - "key": "collection/a", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 1 + "v": 2 + }, + "version": 1000 + }, + { + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 3 }, "version": 1000 } ], "targets": [ - 2 + 4 ] } }, { "watchCurrent": [ [ - 2 + 4 ], - "resume-token-1000" + "resume-token-1001" ] }, { "watchSnapshot": { "targetIds": [ ], - "version": 1000 + "version": 1001 }, "expectedSnapshotEvents": [ { "added": [ { - "key": "collection/a", + "key": "collection/c", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 1 + "v": 3 }, "version": 1000 } @@ -2069,20 +7471,35 @@ "hasPendingWrites": false, "query": { "filters": [ + [ + "v", + ">=", + 2 + ] ], "orderBys": [ ], - "path": "collection/a" + "path": "collection" } } ] }, { - "watchFilter": [ - [ + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "CQ==", + "padding": 3 + }, + "hashCount": 2 + }, + "keys": [ + "collection/b" + ], + "targetIds": [ 2 ] - ] + } }, { "watchSnapshot": { @@ -2093,60 +7510,65 @@ "expectedSnapshotEvents": [ { "errorCode": 0, - "fromCache": false, + "fromCache": true, "hasPendingWrites": false, "query": { "filters": [ + [ + "v", + "<=", + 2 + ] ], "orderBys": [ ], - "path": "collection/a" - }, - "removed": [ - { - "key": "collection/a", - "options": { - "hasCommittedMutations": false, - "hasLocalMutations": false - }, - "value": { - "v": 1 - }, - "version": 1000 - } - ] + "path": "collection" + } } - ] - } - ] - }, - "Existence filter with empty target": { - "describeName": "Existence Filters:", - "itName": "Existence filter with empty target", - "tags": [ - ], - "config": { - "numClients": 1, - "useGarbageCollection": true - }, - "steps": [ - { - "userListen": { - "query": { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - }, - "targetId": 2 - }, + ], "expectedState": { + "activeLimboDocs": [ + "collection/a" + ], "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/a" + } + ], + "resumeToken": "" + }, "2": { "queries": [ { "filters": [ + [ + "v", + "<=", + 2 + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + }, + "4": { + "queries": [ + { + "filters": [ + [ + "v", + ">=", + 2 + ] ], "orderBys": [ ], @@ -2159,67 +7581,113 @@ } }, { - "watchAck": [ - 2 - ] - }, - { - "watchCurrent": [ - [ - 2 + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "CA==", + "padding": 4 + }, + "hashCount": 1 + }, + "keys": [ + "collection/b" ], - "resume-token-1000" - ] + "targetIds": [ + 4 + ] + } }, { "watchSnapshot": { "targetIds": [ ], - "version": 2000 + "version": 3000 }, "expectedSnapshotEvents": [ { "errorCode": 0, - "fromCache": false, + "fromCache": true, "hasPendingWrites": false, "query": { "filters": [ + [ + "v", + ">=", + 2 + ] ], "orderBys": [ ], "path": "collection" } } - ] - }, - { - "watchFilter": [ - [ - 2 - ], - "collection/1" - ] - }, - { - "watchSnapshot": { - "targetIds": [ + ], + "expectedState": { + "activeLimboDocs": [ + "collection/a", + "collection/c" ], - "version": 2000 - }, - "expectedSnapshotEvents": [ - { - "errorCode": 0, - "fromCache": true, - "hasPendingWrites": false, - "query": { - "filters": [ + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/a" + } ], - "orderBys": [ + "resumeToken": "" + }, + "2": { + "queries": [ + { + "filters": [ + [ + "v", + "<=", + 2 + ] + ], + "orderBys": [ + ], + "path": "collection" + } ], - "path": "collection" + "resumeToken": "" + }, + "3": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/c" + } + ], + "resumeToken": "" + }, + "4": { + "queries": [ + { + "filters": [ + [ + "v", + ">=", + 2 + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" } } - ] + } } ] } diff --git a/firebase-firestore/src/test/resources/json/limbo_spec_test.json b/firebase-firestore/src/test/resources/json/limbo_spec_test.json index 0b6abe08a2b..7babd7364f5 100644 --- a/firebase-firestore/src/test/resources/json/limbo_spec_test.json +++ b/firebase-firestore/src/test/resources/json/limbo_spec_test.json @@ -3386,11 +3386,13 @@ ] }, { - "watchFilter": [ - [ + "watchFilter": { + "keys": [ + ], + "targetIds": [ 1 ] - ] + } }, { "watchCurrent": [ @@ -7794,9 +7796,9 @@ } ] }, - "Limbo resolution throttling with existence filter mismatch": { + "Limbo resolution throttling with bloom filter application": { "describeName": "Limbo Documents:", - "itName": "Limbo resolution throttling with existence filter mismatch", + "itName": "Limbo resolution throttling with bloom filter application", "tags": [ ], "config": { @@ -8036,15 +8038,397 @@ } }, { - "watchFilter": [ + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "yABCEAeZURNRGAkgAQ==", + "padding": 4 + }, + "hashCount": 10 + }, + "keys": [ + "collection/b1", + "collection/b2", + "collection/b3" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1001 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/b1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b1" + }, + "version": 1000 + }, + { + "key": "collection/b2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b2" + }, + "version": 1000 + }, + { + "key": "collection/b3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b3" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1002" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1002 + }, + "expectedState": { + "activeLimboDocs": [ + "collection/a1", + "collection/a2" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/a1" + } + ], + "resumeToken": "" + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "resume-token-1000" + }, + "3": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/a2" + } + ], + "resumeToken": "" + } + }, + "enqueuedLimboDocs": [ + "collection/a3" + ] + } + } + ] + }, + "Limbo resolution throttling with existence filter mismatch": { + "describeName": "Limbo Documents:", + "itName": "Limbo resolution throttling with existence filter mismatch", + "tags": [ + ], + "config": { + "maxConcurrentLimboResolutions": 2, + "numClients": 1, + "useGarbageCollection": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/a1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a1" + }, + "version": 1000 + }, + { + "key": "collection/a2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a2" + }, + "version": 1000 + }, + { + "key": "collection/a3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a3" + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ [ 2 ], - "collection/b1", - "collection/b2", - "collection/b3" + "resume-token-1000" ] }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "key": "collection/a1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a1" + }, + "version": 1000 + }, + { + "key": "collection/a2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a2" + }, + "version": 1000 + }, + { + "key": "collection/a3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a3" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "enableNetwork": false, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + }, + "enqueuedLimboDocs": [ + ] + } + }, + { + "enableNetwork": true, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "resume-token-1000" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "key": "collection/b1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b1" + }, + "version": 1000 + }, + { + "key": "collection/b2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b2" + }, + "version": 1000 + }, + { + "key": "collection/b3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b3" + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchFilter": { + "keys": [ + "collection/b1", + "collection/b2", + "collection/b3" + ], + "targetIds": [ + 2 + ] + } + }, { "watchSnapshot": { "targetIds": [ diff --git a/firebase-firestore/src/test/resources/json/limit_spec_test.json b/firebase-firestore/src/test/resources/json/limit_spec_test.json index 40e48205956..856e0505d91 100644 --- a/firebase-firestore/src/test/resources/json/limit_spec_test.json +++ b/firebase-firestore/src/test/resources/json/limit_spec_test.json @@ -5455,12 +5455,14 @@ } }, { - "watchFilter": [ - [ - 2 + "watchFilter": { + "keys": [ + "collection/b" ], - "collection/b" - ] + "targetIds": [ + 2 + ] + } }, { "watchSnapshot": { diff --git a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java index 71cb84b9de8..21394a90269 100644 --- a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java +++ b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java @@ -16,6 +16,7 @@ import com.google.firebase.database.collection.ImmutableSortedSet; import com.google.firebase.firestore.local.TargetData; +import com.google.firebase.firestore.model.DatabaseId; import com.google.firebase.firestore.model.DocumentKey; import com.google.firebase.firestore.remote.WatchChangeAggregator; import java.util.HashMap; @@ -41,6 +42,11 @@ public TargetData getTargetDataForTarget(int targetId) { return queryData.get(targetId); } + @Override + public DatabaseId getDatabaseId() { + return DatabaseId.forProject("test-project"); + } + /** Sets or replaces the local state for the provided query data. */ public void setSyncedKeys(TargetData targetData, ImmutableSortedSet keys) { this.queryData.put(targetData.getTargetId(), targetData); diff --git a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java index 55f846f9270..daf64c9b3e3 100644 --- a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java +++ b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java @@ -108,6 +108,8 @@ public class TestUtil { public static final long ARBITRARY_SEQUENCE_NUMBER = 2; + private static final DatabaseId TEST_PROJECT = DatabaseId.forProject("project"); + @SuppressWarnings("unchecked") public static Map map(Object... entries) { Map res = new LinkedHashMap<>(); @@ -140,8 +142,7 @@ public static FieldMask fieldMask(String... fields) { public static final Map EMPTY_MAP = new HashMap<>(); public static Value wrap(Object value) { - DatabaseId databaseId = DatabaseId.forProject("project"); - UserDataReader dataReader = new UserDataReader(databaseId); + UserDataReader dataReader = new UserDataReader(TEST_PROJECT); // HACK: We use parseQueryValue() since it accepts scalars as well as arrays / objects, and // our tests currently use wrap() pretty generically so we don't know the intent. return dataReader.parseQueryValue(value); @@ -488,6 +489,11 @@ public TargetData getTargetDataForTarget(int targetId) { ResourcePath collectionPath = docs.get(0).getKey().getCollectionPath(); return targetData(targetId, QueryPurpose.LISTEN, collectionPath.toString()); } + + @Override + public DatabaseId getDatabaseId() { + return TEST_PROJECT; + } }); SnapshotVersion version = SnapshotVersion.NONE; @@ -535,13 +541,18 @@ public TargetData getTargetDataForTarget(int targetId) { ? targetData(targetId, QueryPurpose.LISTEN, doc.getKey().toString()) : null; } + + @Override + public DatabaseId getDatabaseId() { + return TEST_PROJECT; + } }); aggregator.handleDocumentChange(change); return aggregator.createRemoteEvent(doc.getVersion()); } public static SetMutation setMutation(String path, Map values) { - UserDataReader dataReader = new UserDataReader(DatabaseId.forProject("project")); + UserDataReader dataReader = new UserDataReader(TEST_PROJECT); ParsedSetData parsed = dataReader.parseSetData(values); // The order of the transforms doesn't matter, but we sort them so tests can assume a particular @@ -574,7 +585,7 @@ private static PatchMutation patchMutationHelper( } } - UserDataReader dataReader = new UserDataReader(DatabaseId.forProject("project")); + UserDataReader dataReader = new UserDataReader(TEST_PROJECT); ParsedUpdateData parsed = dataReader.parseUpdateData(values); // `mergeMutation()` provides an update mask for the merged fields, whereas `patchMutation()` From 7ea3c34477506376deeaeb1fb9ac70e7d9181934 Mon Sep 17 00:00:00 2001 From: milaGGL <107142260+milaGGL@users.noreply.github.com> Date: Mon, 27 Feb 2023 11:14:42 -0800 Subject: [PATCH 05/22] Update TargetData.java --- .../java/com/google/firebase/firestore/local/TargetData.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java index ff2e3274cee..6d0dda95678 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java @@ -94,7 +94,7 @@ public TargetData withSequenceNumber(long sequenceNumber) { snapshotVersion, lastLimboFreeSnapshotVersion, resumeToken, - /* expectedCount= */ null); + expectedCount); } /** Creates a new target data instance with an updated resume token and snapshot version. */ @@ -107,7 +107,7 @@ public TargetData withResumeToken(ByteString resumeToken, SnapshotVersion snapsh snapshotVersion, lastLimboFreeSnapshotVersion, resumeToken, - expectedCount); + /* expectedCount= */ null); } /** Creates a new target data instance with an updated expected count. */ From 8696c17766c71ceda3a08d3f590065a93aabddf5 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Mon, 27 Feb 2023 18:11:20 -0800 Subject: [PATCH 06/22] Add integration test for bloom filter (#4696) --- .../google/firebase/firestore/QueryTest.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java index 08ffc043d35..9202fe0376e 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java @@ -14,6 +14,7 @@ package com.google.firebase.firestore; +import static com.google.firebase.firestore.testutil.IntegrationTestUtil.isRunningAgainstEmulator; import static com.google.firebase.firestore.testutil.IntegrationTestUtil.nullList; import static com.google.firebase.firestore.testutil.IntegrationTestUtil.querySnapshotToIds; import static com.google.firebase.firestore.testutil.IntegrationTestUtil.querySnapshotToValues; @@ -29,6 +30,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.gms.tasks.Task; @@ -37,6 +39,7 @@ import com.google.firebase.firestore.testutil.EventAccumulator; import com.google.firebase.firestore.testutil.IntegrationTestUtil; import java.util.ArrayList; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -1029,6 +1032,46 @@ public void testMultipleUpdatesWhileOffline() { assertEquals(asList(map("foo", "zzyzx", "bar", "2")), querySnapshotToValues(snapshot2)); } + @Test + public void resumingQueryShouldRemoveDeletedDocumentsIndicatedByExistenceFilter() + throws InterruptedException { + assumeFalse( + "Skip this test when running against the Firestore emulator as there is a bug related to " + + "sending existence filter in response: b/270731363.", + isRunningAgainstEmulator()); + + Map> testData = new HashMap<>(); + for (int i = 1; i <= 100; i++) { + testData.put("doc" + i, map("key", i)); + } + CollectionReference collection = testCollectionWithDocs(testData); + + // Populate the cache and save the resume token. + QuerySnapshot snapshot1 = waitFor(collection.get()); + assertEquals(snapshot1.size(), 100); + List documents = snapshot1.getDocuments(); + + // Delete 50 docs in transaction so that it doesn't affect local cache. + waitFor( + collection + .getFirestore() + .runTransaction( + transaction -> { + for (int i = 1; i <= 50; i++) { + DocumentReference docRef = documents.get(i).getReference(); + transaction.delete(docRef); + } + return null; + })); + + // Wait 10 seconds, during which Watch will stop tracking the query + // and will send an existence filter rather than "delete" events. + Thread.sleep(10000); + + QuerySnapshot snapshot2 = waitFor(collection.get()); + assertEquals(snapshot2.size(), 50); + } + // TODO(orquery): Enable this test when prod supports OR queries. @Ignore @Test From 9f66dea732654b368d280572f7f5cd30b471dfb8 Mon Sep 17 00:00:00 2001 From: milaGGL <107142260+milaGGL@users.noreply.github.com> Date: Thu, 9 Mar 2023 14:36:59 -0800 Subject: [PATCH 07/22] fromat --- .../java/com/google/firebase/firestore/QueryTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java index 3db947ec439..f77e4630578 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java @@ -31,6 +31,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; + import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.gms.tasks.Task; import com.google.common.collect.Lists; From 70326ee533be48012b76c87e29e8f83d217aa033 Mon Sep 17 00:00:00 2001 From: milaGGL <107142260+milaGGL@users.noreply.github.com> Date: Thu, 9 Mar 2023 17:31:55 -0800 Subject: [PATCH 08/22] Update MockDatastore.java --- .../com/google/firebase/firestore/remote/MockDatastore.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/MockDatastore.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/MockDatastore.java index e37e7069b0e..91077548585 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/MockDatastore.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/MockDatastore.java @@ -94,6 +94,11 @@ public void watchQuery(TargetData targetData) { // Snapshot version is ignored on the wire TargetData sentTargetData = targetData.withResumeToken(targetData.getResumeToken(), SnapshotVersion.NONE); + + if (targetData.getExpectedCount() != null) { + sentTargetData = sentTargetData.withExpectedCount(targetData.getExpectedCount()); + } + watchStreamRequestCount += 1; this.activeTargets.put(targetData.getTargetId(), sentTargetData); } From 97dafeec42dd854209086cecb221f6a131cb2734 Mon Sep 17 00:00:00 2001 From: milaGGL <107142260+milaGGL@users.noreply.github.com> Date: Tue, 14 Mar 2023 12:33:56 -0700 Subject: [PATCH 09/22] Update WatchChangeAggregator.java --- .../google/firebase/firestore/remote/WatchChangeAggregator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java index 435cbca9e24..b6f9441b3d0 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java @@ -241,7 +241,7 @@ private boolean applyBloomFilter(ExistenceFilterWatchChange watchChange, int cur } catch (BloomFilterException e) { Logger.warn( LOG_TAG, - "Decoding the base64 bloom filter in existence filter failed (" + "Applying bloom filter failed: (" + e.getMessage() + "); ignoring the bloom filter and falling back to full re-query."); return false; From 1bbf61be8276fde083aef321aeb7709747b9b308 Mon Sep 17 00:00:00 2001 From: milaGGL <107142260+milaGGL@users.noreply.github.com> Date: Tue, 14 Mar 2023 16:28:16 -0700 Subject: [PATCH 10/22] update queryTest to be consistent with master --- .../java/com/google/firebase/firestore/QueryTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java index f77e4630578..67713bb696d 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java @@ -31,6 +31,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.gms.tasks.Task; @@ -1071,8 +1072,6 @@ public void resumingQueryShouldRemoveDeletedDocumentsIndicatedByExistenceFilter( assertEquals(snapshot2.size(), 50); } - // TODO(orquery): Enable this test when prod supports OR queries. - @Ignore @Test public void testOrQueries() { Map> testDocs = From 06479a02ecf8635667ffe5bc9ef4e921264d6d52 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Thu, 16 Mar 2023 10:46:17 -0700 Subject: [PATCH 11/22] Add new goog-listen-tag for bloom filter (#4777) --- .../firebase/firestore/core/SyncEngine.java | 2 +- .../firebase/firestore/local/LocalStore.java | 2 +- .../firestore/local/QueryPurpose.java | 5 + .../firestore/remote/RemoteEvent.java | 11 +- .../firestore/remote/RemoteSerializer.java | 2 + .../firestore/remote/RemoteStore.java | 5 +- .../remote/WatchChangeAggregator.java | 46 +- .../test/resources/json/bundle_spec_test.json | 2 +- .../json/existence_filter_spec_test.json | 497 ++++++++++-------- .../test/resources/json/limbo_spec_test.json | 122 ++--- .../test/resources/json/limit_spec_test.json | 20 +- .../resources/json/offline_spec_test.json | 6 +- .../resources/json/recovery_spec_test.json | 8 +- 13 files changed, 409 insertions(+), 319 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/SyncEngine.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/SyncEngine.java index b8655d91656..1cda1f721c5 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/SyncEngine.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/SyncEngine.java @@ -428,7 +428,7 @@ public void handleRejectedListen(int targetId, Status error) { new RemoteEvent( SnapshotVersion.NONE, /* targetChanges= */ Collections.emptyMap(), - /* targetMismatches= */ Collections.emptySet(), + /* targetMismatches= */ Collections.emptyMap(), documentUpdates, limboDocuments); handleRemoteEvent(event); diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalStore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalStore.java index 2d9f24c14e6..81b7dd13455 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalStore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalStore.java @@ -425,7 +425,7 @@ public ImmutableSortedMap applyRemoteEvent(RemoteEvent re targetCache.addMatchingKeys(change.getAddedDocuments(), targetId); TargetData newTargetData = oldTargetData.withSequenceNumber(sequenceNumber); - if (remoteEvent.getTargetMismatches().contains(targetId)) { + if (remoteEvent.getTargetMismatches().containsKey(targetId)) { newTargetData = newTargetData .withResumeToken(ByteString.EMPTY, SnapshotVersion.NONE) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/QueryPurpose.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/QueryPurpose.java index e56f0cf4e66..7595592ba8e 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/QueryPurpose.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/QueryPurpose.java @@ -22,6 +22,11 @@ public enum QueryPurpose { /** The query was used to refill a query after an existence filter mismatch. */ EXISTENCE_FILTER_MISMATCH, + /** + * The query target was used if the query is the result of a false positive in the bloom filter. + */ + EXISTENCE_FILTER_MISMATCH_BLOOM, + /** The query was used to resolve a limbo document. */ LIMBO_RESOLUTION, } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteEvent.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteEvent.java index e890574ba8a..443ee13ecea 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteEvent.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteEvent.java @@ -14,6 +14,7 @@ package com.google.firebase.firestore.remote; +import com.google.firebase.firestore.local.QueryPurpose; import com.google.firebase.firestore.model.DocumentKey; import com.google.firebase.firestore.model.MutableDocument; import com.google.firebase.firestore.model.SnapshotVersion; @@ -27,14 +28,14 @@ public final class RemoteEvent { private final SnapshotVersion snapshotVersion; private final Map targetChanges; - private final Set targetMismatches; + private final Map targetMismatches; private final Map documentUpdates; private final Set resolvedLimboDocuments; public RemoteEvent( SnapshotVersion snapshotVersion, Map targetChanges, - Set targetMismatches, + Map targetMismatches, Map documentUpdates, Set resolvedLimboDocuments) { this.snapshotVersion = snapshotVersion; @@ -55,10 +56,10 @@ public Map getTargetChanges() { } /** - * Returns a set of targets that is known to be inconsistent. Listens for these targets should be - * re-established without resume tokens. + * Returns a map of targets that is known to be inconsistent, and the purpose for re-listening. + * Listens for these targets should be re-established without resume tokens. */ - public Set getTargetMismatches() { + public Map getTargetMismatches() { return targetMismatches; } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java index 655842a73af..9a352000f6b 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java @@ -471,6 +471,8 @@ private String encodeLabel(QueryPurpose purpose) { return null; case EXISTENCE_FILTER_MISMATCH: return "existence-filter-mismatch"; + case EXISTENCE_FILTER_MISMATCH_BLOOM: + return "existence-filter-mismatch-bloom"; case LIMBO_RESOLUTION: return "limbo-document"; default: diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java index 1f5ad514b46..15f132d6d1b 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java @@ -547,7 +547,8 @@ private void raiseWatchSnapshot(SnapshotVersion snapshotVersion) { // Re-establish listens for the targets that have been invalidated by existence filter // mismatches. - for (int targetId : remoteEvent.getTargetMismatches()) { + for (Map.Entry entry : remoteEvent.getTargetMismatches().entrySet()) { + int targetId = entry.getKey(); TargetData targetData = this.listenTargets.get(targetId); // A watched target might have been removed already. if (targetData != null) { @@ -569,7 +570,7 @@ private void raiseWatchSnapshot(SnapshotVersion snapshotVersion) { targetData.getTarget(), targetId, targetData.getSequenceNumber(), - QueryPurpose.EXISTENCE_FILTER_MISMATCH); + /*purpose=*/ entry.getValue()); this.sendWatchRequest(requestTargetData); } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java index b6f9441b3d0..dc29f2633f1 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java @@ -75,14 +75,21 @@ public interface TargetMetadataProvider { private Map> pendingDocumentTargetMapping = new HashMap<>(); /** - * A list of targets with existence filter mismatches. These targets are known to be inconsistent + * A map of targets with existence filter mismatches. These targets are known to be inconsistent * and their listens needs to be re-established by RemoteStore. */ - private Set pendingTargetResets = new HashSet<>(); + private Map pendingTargetResets = new HashMap<>(); /** The log tag to use for this class. */ private static final String LOG_TAG = "WatchChangeAggregator"; + /** The bloom filter application status while handling existence filter mismatch. */ + private enum BloomFilterApplicationStatus { + SUCCESS, + SKIPPED, + FALSE_POSITIVE + } + public WatchChangeAggregator(TargetMetadataProvider targetMetadataProvider) { this.targetMetadataProvider = targetMetadataProvider; } @@ -208,27 +215,34 @@ public void handleExistenceFilter(ExistenceFilterWatchChange watchChange) { if (currentSize != expectedCount) { // Apply bloom filter to identify and mark removed documents. - boolean bloomFilterApplied = this.applyBloomFilter(watchChange, currentSize); + BloomFilterApplicationStatus status = this.applyBloomFilter(watchChange, currentSize); - if (!bloomFilterApplied) { + if (status != BloomFilterApplicationStatus.SUCCESS) { // If bloom filter application fails, we reset the mapping and // trigger re-run of the query. resetTarget(targetId); - pendingTargetResets.add(targetId); + + QueryPurpose purpose = + status == BloomFilterApplicationStatus.FALSE_POSITIVE + ? QueryPurpose.EXISTENCE_FILTER_MISMATCH_BLOOM + : QueryPurpose.EXISTENCE_FILTER_MISMATCH; + + pendingTargetResets.put(targetId, purpose); } } } } } - /** Returns whether a bloom filter removed the deleted documents successfully. */ - private boolean applyBloomFilter(ExistenceFilterWatchChange watchChange, int currentCount) { + /** Apply bloom filter to remove the deleted documents, and return the application status. */ + private BloomFilterApplicationStatus applyBloomFilter( + ExistenceFilterWatchChange watchChange, int currentCount) { int expectedCount = watchChange.getExistenceFilter().getCount(); com.google.firestore.v1.BloomFilter unchangedNames = watchChange.getExistenceFilter().getUnchangedNames(); if (unchangedNames == null || !unchangedNames.hasBits()) { - return false; + return BloomFilterApplicationStatus.SKIPPED; } byte[] bitmap = unchangedNames.getBits().getBitmap().toByteArray(); @@ -244,12 +258,20 @@ private boolean applyBloomFilter(ExistenceFilterWatchChange watchChange, int cur "Applying bloom filter failed: (" + e.getMessage() + "); ignoring the bloom filter and falling back to full re-query."); - return false; + return BloomFilterApplicationStatus.SKIPPED; + } + + if (bloomFilter.getBitCount() == 0) { + return BloomFilterApplicationStatus.SKIPPED; } int removedDocumentCount = this.filterRemovedDocuments(bloomFilter, watchChange.getTargetId()); - return expectedCount == (currentCount - removedDocumentCount); + if (expectedCount != (currentCount - removedDocumentCount)) { + return BloomFilterApplicationStatus.FALSE_POSITIVE; + } + + return BloomFilterApplicationStatus.SUCCESS; } /** @@ -341,14 +363,14 @@ public RemoteEvent createRemoteEvent(SnapshotVersion snapshotVersion) { new RemoteEvent( snapshotVersion, Collections.unmodifiableMap(targetChanges), - Collections.unmodifiableSet(pendingTargetResets), + Collections.unmodifiableMap(pendingTargetResets), Collections.unmodifiableMap(pendingDocumentUpdates), Collections.unmodifiableSet(resolvedLimboDocuments)); // Re-initialize the current state to ensure that we do not modify the generated RemoteEvent. pendingDocumentUpdates = new HashMap<>(); pendingDocumentTargetMapping = new HashMap<>(); - pendingTargetResets = new HashSet<>(); + pendingTargetResets = new HashMap<>(); return remoteEvent; } diff --git a/firebase-firestore/src/test/resources/json/bundle_spec_test.json b/firebase-firestore/src/test/resources/json/bundle_spec_test.json index 94bc9cc0da1..617f5946d5f 100644 --- a/firebase-firestore/src/test/resources/json/bundle_spec_test.json +++ b/firebase-firestore/src/test/resources/json/bundle_spec_test.json @@ -1166,7 +1166,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ diff --git a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json index 16442ba1702..131d47cd4a1 100644 --- a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json +++ b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json @@ -91,7 +91,7 @@ { "added": [ { - "key": "collection/ÀÒ∑", + "key": "collection/ÀÒ∑", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -102,7 +102,7 @@ "version": 1000 }, { - "key": "collection/À∑Ò", + "key": "collection/À∑Ò", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -178,7 +178,8 @@ "path": "collection/À∑Ò" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "2": { "queries": [ @@ -289,7 +290,7 @@ { "added": [ { - "key": "collection/a", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -300,7 +301,7 @@ "version": 1000 }, { - "key": "collection/b", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -371,7 +372,8 @@ "path": "collection" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 1 } } } @@ -470,7 +472,7 @@ { "added": [ { - "key": "collection/a", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -481,7 +483,7 @@ "version": 1000 }, { - "key": "collection/b", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -552,7 +554,7 @@ { "added": [ { - "key": "collection/c", + "key": "collection/c", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -590,7 +592,8 @@ "path": "collection/b" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "2": { "queries": [ @@ -701,7 +704,7 @@ { "added": [ { - "key": "collection/a", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -712,7 +715,7 @@ "version": 1000 }, { - "key": "collection/b", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -788,7 +791,8 @@ "path": "collection/b" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "2": { "queries": [ @@ -828,7 +832,7 @@ }, "removed": [ { - "key": "collection/b", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2032,7 +2036,7 @@ { "added": [ { - "key": "collection/doc0", + "key": "collection/doc0", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2043,7 +2047,7 @@ "version": 1000 }, { - "key": "collection/doc1", + "key": "collection/doc1", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2054,7 +2058,7 @@ "version": 1000 }, { - "key": "collection/doc2", + "key": "collection/doc2", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2065,7 +2069,7 @@ "version": 1000 }, { - "key": "collection/doc3", + "key": "collection/doc3", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2076,7 +2080,7 @@ "version": 1000 }, { - "key": "collection/doc4", + "key": "collection/doc4", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2087,7 +2091,7 @@ "version": 1000 }, { - "key": "collection/doc5", + "key": "collection/doc5", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2098,7 +2102,7 @@ "version": 1000 }, { - "key": "collection/doc6", + "key": "collection/doc6", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2109,7 +2113,7 @@ "version": 1000 }, { - "key": "collection/doc7", + "key": "collection/doc7", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2120,7 +2124,7 @@ "version": 1000 }, { - "key": "collection/doc8", + "key": "collection/doc8", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2131,7 +2135,7 @@ "version": 1000 }, { - "key": "collection/doc9", + "key": "collection/doc9", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2142,7 +2146,7 @@ "version": 1000 }, { - "key": "collection/doc10", + "key": "collection/doc10", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2153,7 +2157,7 @@ "version": 1000 }, { - "key": "collection/doc11", + "key": "collection/doc11", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2164,7 +2168,7 @@ "version": 1000 }, { - "key": "collection/doc12", + "key": "collection/doc12", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2175,7 +2179,7 @@ "version": 1000 }, { - "key": "collection/doc13", + "key": "collection/doc13", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2186,7 +2190,7 @@ "version": 1000 }, { - "key": "collection/doc14", + "key": "collection/doc14", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2197,7 +2201,7 @@ "version": 1000 }, { - "key": "collection/doc15", + "key": "collection/doc15", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2208,7 +2212,7 @@ "version": 1000 }, { - "key": "collection/doc16", + "key": "collection/doc16", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2219,7 +2223,7 @@ "version": 1000 }, { - "key": "collection/doc17", + "key": "collection/doc17", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2230,7 +2234,7 @@ "version": 1000 }, { - "key": "collection/doc18", + "key": "collection/doc18", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2241,7 +2245,7 @@ "version": 1000 }, { - "key": "collection/doc19", + "key": "collection/doc19", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2252,7 +2256,7 @@ "version": 1000 }, { - "key": "collection/doc20", + "key": "collection/doc20", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2263,7 +2267,7 @@ "version": 1000 }, { - "key": "collection/doc21", + "key": "collection/doc21", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2274,7 +2278,7 @@ "version": 1000 }, { - "key": "collection/doc22", + "key": "collection/doc22", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2285,7 +2289,7 @@ "version": 1000 }, { - "key": "collection/doc23", + "key": "collection/doc23", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2296,7 +2300,7 @@ "version": 1000 }, { - "key": "collection/doc24", + "key": "collection/doc24", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2307,7 +2311,7 @@ "version": 1000 }, { - "key": "collection/doc25", + "key": "collection/doc25", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2318,7 +2322,7 @@ "version": 1000 }, { - "key": "collection/doc26", + "key": "collection/doc26", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2329,7 +2333,7 @@ "version": 1000 }, { - "key": "collection/doc27", + "key": "collection/doc27", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2340,7 +2344,7 @@ "version": 1000 }, { - "key": "collection/doc28", + "key": "collection/doc28", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2351,7 +2355,7 @@ "version": 1000 }, { - "key": "collection/doc29", + "key": "collection/doc29", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2362,7 +2366,7 @@ "version": 1000 }, { - "key": "collection/doc30", + "key": "collection/doc30", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2373,7 +2377,7 @@ "version": 1000 }, { - "key": "collection/doc31", + "key": "collection/doc31", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2384,7 +2388,7 @@ "version": 1000 }, { - "key": "collection/doc32", + "key": "collection/doc32", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2395,7 +2399,7 @@ "version": 1000 }, { - "key": "collection/doc33", + "key": "collection/doc33", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2406,7 +2410,7 @@ "version": 1000 }, { - "key": "collection/doc34", + "key": "collection/doc34", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2417,7 +2421,7 @@ "version": 1000 }, { - "key": "collection/doc35", + "key": "collection/doc35", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2428,7 +2432,7 @@ "version": 1000 }, { - "key": "collection/doc36", + "key": "collection/doc36", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2439,7 +2443,7 @@ "version": 1000 }, { - "key": "collection/doc37", + "key": "collection/doc37", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2450,7 +2454,7 @@ "version": 1000 }, { - "key": "collection/doc38", + "key": "collection/doc38", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2461,7 +2465,7 @@ "version": 1000 }, { - "key": "collection/doc39", + "key": "collection/doc39", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2472,7 +2476,7 @@ "version": 1000 }, { - "key": "collection/doc40", + "key": "collection/doc40", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2483,7 +2487,7 @@ "version": 1000 }, { - "key": "collection/doc41", + "key": "collection/doc41", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2494,7 +2498,7 @@ "version": 1000 }, { - "key": "collection/doc42", + "key": "collection/doc42", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2505,7 +2509,7 @@ "version": 1000 }, { - "key": "collection/doc43", + "key": "collection/doc43", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2516,7 +2520,7 @@ "version": 1000 }, { - "key": "collection/doc44", + "key": "collection/doc44", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2527,7 +2531,7 @@ "version": 1000 }, { - "key": "collection/doc45", + "key": "collection/doc45", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2538,7 +2542,7 @@ "version": 1000 }, { - "key": "collection/doc46", + "key": "collection/doc46", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2549,7 +2553,7 @@ "version": 1000 }, { - "key": "collection/doc47", + "key": "collection/doc47", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2560,7 +2564,7 @@ "version": 1000 }, { - "key": "collection/doc48", + "key": "collection/doc48", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2571,7 +2575,7 @@ "version": 1000 }, { - "key": "collection/doc49", + "key": "collection/doc49", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2582,7 +2586,7 @@ "version": 1000 }, { - "key": "collection/doc50", + "key": "collection/doc50", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2593,7 +2597,7 @@ "version": 1000 }, { - "key": "collection/doc51", + "key": "collection/doc51", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2604,7 +2608,7 @@ "version": 1000 }, { - "key": "collection/doc52", + "key": "collection/doc52", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2615,7 +2619,7 @@ "version": 1000 }, { - "key": "collection/doc53", + "key": "collection/doc53", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2626,7 +2630,7 @@ "version": 1000 }, { - "key": "collection/doc54", + "key": "collection/doc54", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2637,7 +2641,7 @@ "version": 1000 }, { - "key": "collection/doc55", + "key": "collection/doc55", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2648,7 +2652,7 @@ "version": 1000 }, { - "key": "collection/doc56", + "key": "collection/doc56", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2659,7 +2663,7 @@ "version": 1000 }, { - "key": "collection/doc57", + "key": "collection/doc57", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2670,7 +2674,7 @@ "version": 1000 }, { - "key": "collection/doc58", + "key": "collection/doc58", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2681,7 +2685,7 @@ "version": 1000 }, { - "key": "collection/doc59", + "key": "collection/doc59", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2692,7 +2696,7 @@ "version": 1000 }, { - "key": "collection/doc60", + "key": "collection/doc60", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2703,7 +2707,7 @@ "version": 1000 }, { - "key": "collection/doc61", + "key": "collection/doc61", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2714,7 +2718,7 @@ "version": 1000 }, { - "key": "collection/doc62", + "key": "collection/doc62", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2725,7 +2729,7 @@ "version": 1000 }, { - "key": "collection/doc63", + "key": "collection/doc63", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2736,7 +2740,7 @@ "version": 1000 }, { - "key": "collection/doc64", + "key": "collection/doc64", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2747,7 +2751,7 @@ "version": 1000 }, { - "key": "collection/doc65", + "key": "collection/doc65", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2758,7 +2762,7 @@ "version": 1000 }, { - "key": "collection/doc66", + "key": "collection/doc66", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2769,7 +2773,7 @@ "version": 1000 }, { - "key": "collection/doc67", + "key": "collection/doc67", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2780,7 +2784,7 @@ "version": 1000 }, { - "key": "collection/doc68", + "key": "collection/doc68", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2791,7 +2795,7 @@ "version": 1000 }, { - "key": "collection/doc69", + "key": "collection/doc69", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2802,7 +2806,7 @@ "version": 1000 }, { - "key": "collection/doc70", + "key": "collection/doc70", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2813,7 +2817,7 @@ "version": 1000 }, { - "key": "collection/doc71", + "key": "collection/doc71", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2824,7 +2828,7 @@ "version": 1000 }, { - "key": "collection/doc72", + "key": "collection/doc72", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2835,7 +2839,7 @@ "version": 1000 }, { - "key": "collection/doc73", + "key": "collection/doc73", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2846,7 +2850,7 @@ "version": 1000 }, { - "key": "collection/doc74", + "key": "collection/doc74", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2857,7 +2861,7 @@ "version": 1000 }, { - "key": "collection/doc75", + "key": "collection/doc75", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2868,7 +2872,7 @@ "version": 1000 }, { - "key": "collection/doc76", + "key": "collection/doc76", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2879,7 +2883,7 @@ "version": 1000 }, { - "key": "collection/doc77", + "key": "collection/doc77", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2890,7 +2894,7 @@ "version": 1000 }, { - "key": "collection/doc78", + "key": "collection/doc78", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2901,7 +2905,7 @@ "version": 1000 }, { - "key": "collection/doc79", + "key": "collection/doc79", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2912,7 +2916,7 @@ "version": 1000 }, { - "key": "collection/doc80", + "key": "collection/doc80", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2923,7 +2927,7 @@ "version": 1000 }, { - "key": "collection/doc81", + "key": "collection/doc81", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2934,7 +2938,7 @@ "version": 1000 }, { - "key": "collection/doc82", + "key": "collection/doc82", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2945,7 +2949,7 @@ "version": 1000 }, { - "key": "collection/doc83", + "key": "collection/doc83", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2956,7 +2960,7 @@ "version": 1000 }, { - "key": "collection/doc84", + "key": "collection/doc84", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2967,7 +2971,7 @@ "version": 1000 }, { - "key": "collection/doc85", + "key": "collection/doc85", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2978,7 +2982,7 @@ "version": 1000 }, { - "key": "collection/doc86", + "key": "collection/doc86", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2989,7 +2993,7 @@ "version": 1000 }, { - "key": "collection/doc87", + "key": "collection/doc87", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -3000,7 +3004,7 @@ "version": 1000 }, { - "key": "collection/doc88", + "key": "collection/doc88", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -3011,7 +3015,7 @@ "version": 1000 }, { - "key": "collection/doc89", + "key": "collection/doc89", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -3022,7 +3026,7 @@ "version": 1000 }, { - "key": "collection/doc90", + "key": "collection/doc90", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -3033,7 +3037,7 @@ "version": 1000 }, { - "key": "collection/doc91", + "key": "collection/doc91", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -3044,7 +3048,7 @@ "version": 1000 }, { - "key": "collection/doc92", + "key": "collection/doc92", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -3055,7 +3059,7 @@ "version": 1000 }, { - "key": "collection/doc93", + "key": "collection/doc93", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -3066,7 +3070,7 @@ "version": 1000 }, { - "key": "collection/doc94", + "key": "collection/doc94", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -3077,7 +3081,7 @@ "version": 1000 }, { - "key": "collection/doc95", + "key": "collection/doc95", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -3088,7 +3092,7 @@ "version": 1000 }, { - "key": "collection/doc96", + "key": "collection/doc96", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -3099,7 +3103,7 @@ "version": 1000 }, { - "key": "collection/doc97", + "key": "collection/doc97", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -3110,7 +3114,7 @@ "version": 1000 }, { - "key": "collection/doc98", + "key": "collection/doc98", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -3121,7 +3125,7 @@ "version": 1000 }, { - "key": "collection/doc99", + "key": "collection/doc99", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -3295,7 +3299,8 @@ "path": "collection/doc50" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "11": { "queries": [ @@ -3307,7 +3312,8 @@ "path": "collection/doc55" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "13": { "queries": [ @@ -3319,7 +3325,8 @@ "path": "collection/doc56" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "15": { "queries": [ @@ -3331,7 +3338,8 @@ "path": "collection/doc57" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "17": { "queries": [ @@ -3343,7 +3351,8 @@ "path": "collection/doc58" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "19": { "queries": [ @@ -3355,7 +3364,8 @@ "path": "collection/doc59" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "2": { "queries": [ @@ -3379,7 +3389,8 @@ "path": "collection/doc60" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "23": { "queries": [ @@ -3391,7 +3402,8 @@ "path": "collection/doc61" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "25": { "queries": [ @@ -3403,7 +3415,8 @@ "path": "collection/doc62" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "27": { "queries": [ @@ -3415,7 +3428,8 @@ "path": "collection/doc63" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "29": { "queries": [ @@ -3427,7 +3441,8 @@ "path": "collection/doc64" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "3": { "queries": [ @@ -3439,7 +3454,8 @@ "path": "collection/doc51" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "31": { "queries": [ @@ -3451,7 +3467,8 @@ "path": "collection/doc65" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "33": { "queries": [ @@ -3463,7 +3480,8 @@ "path": "collection/doc66" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "35": { "queries": [ @@ -3475,7 +3493,8 @@ "path": "collection/doc67" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "37": { "queries": [ @@ -3487,7 +3506,8 @@ "path": "collection/doc68" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "39": { "queries": [ @@ -3499,7 +3519,8 @@ "path": "collection/doc69" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "41": { "queries": [ @@ -3511,7 +3532,8 @@ "path": "collection/doc70" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "43": { "queries": [ @@ -3523,7 +3545,8 @@ "path": "collection/doc71" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "45": { "queries": [ @@ -3535,7 +3558,8 @@ "path": "collection/doc72" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "47": { "queries": [ @@ -3547,7 +3571,8 @@ "path": "collection/doc73" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "49": { "queries": [ @@ -3559,7 +3584,8 @@ "path": "collection/doc74" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "5": { "queries": [ @@ -3571,7 +3597,8 @@ "path": "collection/doc52" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "51": { "queries": [ @@ -3583,7 +3610,8 @@ "path": "collection/doc75" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "53": { "queries": [ @@ -3595,7 +3623,8 @@ "path": "collection/doc76" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "55": { "queries": [ @@ -3607,7 +3636,8 @@ "path": "collection/doc77" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "57": { "queries": [ @@ -3619,7 +3649,8 @@ "path": "collection/doc78" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "59": { "queries": [ @@ -3631,7 +3662,8 @@ "path": "collection/doc79" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "61": { "queries": [ @@ -3643,7 +3675,8 @@ "path": "collection/doc80" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "63": { "queries": [ @@ -3655,7 +3688,8 @@ "path": "collection/doc81" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "65": { "queries": [ @@ -3667,7 +3701,8 @@ "path": "collection/doc82" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "67": { "queries": [ @@ -3679,7 +3714,8 @@ "path": "collection/doc83" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "69": { "queries": [ @@ -3691,7 +3727,8 @@ "path": "collection/doc84" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "7": { "queries": [ @@ -3703,7 +3740,8 @@ "path": "collection/doc53" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "71": { "queries": [ @@ -3715,7 +3753,8 @@ "path": "collection/doc85" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "73": { "queries": [ @@ -3727,7 +3766,8 @@ "path": "collection/doc86" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "75": { "queries": [ @@ -3739,7 +3779,8 @@ "path": "collection/doc87" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "77": { "queries": [ @@ -3751,7 +3792,8 @@ "path": "collection/doc88" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "79": { "queries": [ @@ -3763,7 +3805,8 @@ "path": "collection/doc89" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "81": { "queries": [ @@ -3775,7 +3818,8 @@ "path": "collection/doc90" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "83": { "queries": [ @@ -3787,7 +3831,8 @@ "path": "collection/doc91" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "85": { "queries": [ @@ -3799,7 +3844,8 @@ "path": "collection/doc92" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "87": { "queries": [ @@ -3811,7 +3857,8 @@ "path": "collection/doc93" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "89": { "queries": [ @@ -3823,7 +3870,8 @@ "path": "collection/doc94" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "9": { "queries": [ @@ -3835,7 +3883,8 @@ "path": "collection/doc54" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "91": { "queries": [ @@ -3847,7 +3896,8 @@ "path": "collection/doc95" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "93": { "queries": [ @@ -3859,7 +3909,8 @@ "path": "collection/doc96" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "95": { "queries": [ @@ -3871,7 +3922,8 @@ "path": "collection/doc97" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "97": { "queries": [ @@ -3883,7 +3935,8 @@ "path": "collection/doc98" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "99": { "queries": [ @@ -3895,7 +3948,8 @@ "path": "collection/doc99" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 } } } @@ -3995,7 +4049,7 @@ { "added": [ { - "key": "collection/1", + "key": "collection/1", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -4006,7 +4060,7 @@ "version": 1000 }, { - "key": "collection/2", + "key": "collection/2", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -4104,7 +4158,7 @@ { "added": [ { - "key": "collection/1", + "key": "collection/1", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -4115,7 +4169,7 @@ "version": 1000 }, { - "key": "collection/2", + "key": "collection/2", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -4238,7 +4292,7 @@ { "added": [ { - "key": "collection/1", + "key": "collection/1", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -4303,7 +4357,7 @@ { "added": [ { - "key": "collection/3", + "key": "collection/3", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -4416,7 +4470,7 @@ { "added": [ { - "key": "collection/2", + "key": "collection/2", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -4523,7 +4577,7 @@ { "added": [ { - "key": "collection/1", + "key": "collection/1", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -4578,7 +4632,7 @@ { "added": [ { - "key": "collection/1", + "key": "collection/1", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -4762,7 +4816,7 @@ { "added": [ { - "key": "collection/1", + "key": "collection/1", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -4773,7 +4827,7 @@ "version": 1000 }, { - "key": "collection/2", + "key": "collection/2", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -4907,7 +4961,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -4948,7 +5002,7 @@ }, "removed": [ { - "key": "collection/2", + "key": "collection/2", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -5064,7 +5118,7 @@ { "added": [ { - "key": "collection/1", + "key": "collection/1", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -5219,7 +5273,7 @@ { "added": [ { - "key": "collection/1", + "key": "collection/1", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -5337,7 +5391,7 @@ { "added": [ { - "key": "collection/1", + "key": "collection/1", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -5348,7 +5402,7 @@ "version": 1000 }, { - "key": "collection/2", + "key": "collection/2", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -5482,7 +5536,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -5533,7 +5587,7 @@ }, "removed": [ { - "key": "collection/2", + "key": "collection/2", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -5660,7 +5714,7 @@ { "added": [ { - "key": "collection/1", + "key": "collection/1", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -5671,7 +5725,7 @@ "version": 1000 }, { - "key": "collection/2", + "key": "collection/2", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -5835,7 +5889,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -5886,7 +5940,7 @@ }, "removed": [ { - "key": "collection/2", + "key": "collection/2", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -6002,7 +6056,7 @@ { "added": [ { - "key": "collection/a", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -6055,7 +6109,7 @@ }, "removed": [ { - "key": "collection/a", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -6285,7 +6339,7 @@ { "added": [ { - "key": "collection/a", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -6296,7 +6350,7 @@ "version": 1000 }, { - "key": "collection/b", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -6372,7 +6426,8 @@ "path": "collection/b" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "2": { "queries": [ @@ -6422,7 +6477,7 @@ }, "removed": [ { - "key": "collection/b", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -6550,7 +6605,7 @@ { "added": [ { - "key": "collection/a", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -6561,7 +6616,7 @@ "version": 1000 }, { - "key": "collection/b", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -6634,7 +6689,8 @@ "path": "collection" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 1 } } } @@ -6744,7 +6800,7 @@ { "added": [ { - "key": "collection/a", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -6755,7 +6811,7 @@ "version": 1000 }, { - "key": "collection/b", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -6766,7 +6822,7 @@ "version": 1000 }, { - "key": "collection/c", + "key": "collection/c", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -6826,14 +6882,7 @@ "path": "collection" } } - ] - }, - { - "watchRemove": { - "targetIds": [ - 2 - ] - }, + ], "expectedState": { "activeTargets": { "2": { @@ -6846,7 +6895,8 @@ "path": "collection" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 2 } } } @@ -6945,7 +6995,7 @@ { "added": [ { - "key": "collection/a", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -6956,7 +7006,7 @@ "version": 1000 }, { - "key": "collection/b", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -7029,7 +7079,8 @@ "path": "collection" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 1 } } } @@ -7128,7 +7179,7 @@ { "added": [ { - "key": "collection/a", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -7139,7 +7190,7 @@ "version": 1000 }, { - "key": "collection/b", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -7212,7 +7263,8 @@ "path": "collection" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 1 } } } @@ -7321,7 +7373,7 @@ { "added": [ { - "key": "collection/a", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -7332,7 +7384,7 @@ "version": 1000 }, { - "key": "collection/b", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -7381,7 +7433,7 @@ { "added": [ { - "key": "collection/b", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -7502,7 +7554,7 @@ { "added": [ { - "key": "collection/c", + "key": "collection/c", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -7588,7 +7640,8 @@ "path": "collection/a" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "2": { "queries": [ @@ -7685,7 +7738,8 @@ "path": "collection/a" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "2": { "queries": [ @@ -7714,7 +7768,8 @@ "path": "collection/c" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "4": { "queries": [ diff --git a/firebase-firestore/src/test/resources/json/limbo_spec_test.json b/firebase-firestore/src/test/resources/json/limbo_spec_test.json index d966cb1f238..de82951040a 100644 --- a/firebase-firestore/src/test/resources/json/limbo_spec_test.json +++ b/firebase-firestore/src/test/resources/json/limbo_spec_test.json @@ -235,7 +235,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -281,7 +281,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -406,7 +406,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -489,7 +489,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -572,7 +572,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -675,7 +675,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "10": { "queries": [ @@ -775,7 +775,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "10": { "queries": [ @@ -866,7 +866,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -940,7 +940,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -1202,7 +1202,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -1248,7 +1248,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -1373,7 +1373,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -1456,7 +1456,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -1539,7 +1539,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -1642,7 +1642,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "10": { "queries": [ @@ -1742,7 +1742,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "10": { "queries": [ @@ -2038,7 +2038,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -2123,7 +2123,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -2206,7 +2206,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -2420,7 +2420,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -2834,7 +2834,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -3119,7 +3119,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -3386,7 +3386,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -3633,7 +3633,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -3921,7 +3921,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -4037,7 +4037,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -4298,7 +4298,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -4646,7 +4646,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -5025,7 +5025,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -5114,7 +5114,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -5486,7 +5486,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -5511,7 +5511,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } } } @@ -5623,7 +5623,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -5648,7 +5648,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } } } @@ -5703,7 +5703,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } } } @@ -5822,7 +5822,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } } } @@ -6255,7 +6255,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -6782,7 +6782,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -7109,7 +7109,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -7193,7 +7193,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -7512,7 +7512,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -7537,7 +7537,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -7646,7 +7646,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "7": { "queries": [ @@ -7659,7 +7659,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -7765,7 +7765,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -8187,7 +8187,8 @@ "path": "collection/a1" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "2": { "queries": [ @@ -8211,7 +8212,8 @@ "path": "collection/a2" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -8632,7 +8634,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -8658,7 +8660,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -8765,7 +8767,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -9095,7 +9097,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -9120,7 +9122,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -9210,7 +9212,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "5": { "queries": [ @@ -9223,7 +9225,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -9307,7 +9309,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "7": { "queries": [ @@ -9320,7 +9322,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -9403,7 +9405,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "9": { "queries": [ @@ -9416,7 +9418,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -9497,7 +9499,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -9869,7 +9871,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ diff --git a/firebase-firestore/src/test/resources/json/limit_spec_test.json b/firebase-firestore/src/test/resources/json/limit_spec_test.json index 3b226ee1061..ed2b461ce74 100644 --- a/firebase-firestore/src/test/resources/json/limit_spec_test.json +++ b/firebase-firestore/src/test/resources/json/limit_spec_test.json @@ -214,7 +214,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -4334,7 +4334,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -4361,7 +4361,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -4495,7 +4495,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -4520,7 +4520,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } } } @@ -4661,7 +4661,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "7": { "queries": [ @@ -4674,7 +4674,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } } } @@ -4814,7 +4814,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } } } @@ -5304,7 +5304,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -5565,7 +5565,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ diff --git a/firebase-firestore/src/test/resources/json/offline_spec_test.json b/firebase-firestore/src/test/resources/json/offline_spec_test.json index eb8a35f3074..91e4205e441 100644 --- a/firebase-firestore/src/test/resources/json/offline_spec_test.json +++ b/firebase-firestore/src/test/resources/json/offline_spec_test.json @@ -1149,7 +1149,8 @@ "path": "collection/a" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "2": { "queries": [ @@ -1186,7 +1187,8 @@ "path": "collection/a" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 3 }, "2": { "queries": [ diff --git a/firebase-firestore/src/test/resources/json/recovery_spec_test.json b/firebase-firestore/src/test/resources/json/recovery_spec_test.json index bb7306476a3..2e66d63b8d5 100644 --- a/firebase-firestore/src/test/resources/json/recovery_spec_test.json +++ b/firebase-firestore/src/test/resources/json/recovery_spec_test.json @@ -3095,7 +3095,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -3184,7 +3184,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -3569,7 +3569,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -3629,7 +3629,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ From 59f2859f933d0558c9763d873da8de26517f3f9a Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Thu, 16 Mar 2023 15:08:36 -0400 Subject: [PATCH 12/22] Update the integration test to verify that bloom filter averted full requery (#4768) --- .../google/firebase/firestore/QueryTest.java | 180 +++++++++++--- ...hChangeAggregatorTestingHooksAccessor.java | 228 ++++++++++++++++++ .../testutil/IntegrationTestUtil.java | 22 +- .../remote/WatchChangeAggregator.java | 6 + .../WatchChangeAggregatorTestingHooks.java | 166 +++++++++++++ 5 files changed, 566 insertions(+), 36 deletions(-) create mode 100644 firebase-firestore/src/androidTest/java/com/google/firebase/firestore/remote/WatchChangeAggregatorTestingHooksAccessor.java create mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregatorTestingHooks.java diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java index 67713bb696d..ef11f4006ad 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java @@ -14,6 +14,7 @@ package com.google.firebase.firestore; +import static com.google.common.truth.Truth.assertWithMessage; import static com.google.firebase.firestore.testutil.IntegrationTestUtil.isRunningAgainstEmulator; import static com.google.firebase.firestore.testutil.IntegrationTestUtil.nullList; import static com.google.firebase.firestore.testutil.IntegrationTestUtil.querySnapshotToIds; @@ -30,17 +31,18 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.gms.tasks.Task; import com.google.common.collect.Lists; import com.google.firebase.firestore.Query.Direction; +import com.google.firebase.firestore.remote.WatchChangeAggregatorTestingHooksAccessor; import com.google.firebase.firestore.testutil.EventAccumulator; import com.google.firebase.firestore.testutil.IntegrationTestUtil; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -1033,43 +1035,151 @@ public void testMultipleUpdatesWhileOffline() { } @Test - public void resumingQueryShouldRemoveDeletedDocumentsIndicatedByExistenceFilter() - throws InterruptedException { - assumeFalse( - "Skip this test when running against the Firestore emulator as there is a bug related to " - + "sending existence filter in response: b/270731363.", - isRunningAgainstEmulator()); - + public void resumingAQueryShouldUseBloomFilterToAvoidFullRequery() throws Exception { + // Prepare the names and contents of the 100 documents to create. Map> testData = new HashMap<>(); - for (int i = 1; i <= 100; i++) { - testData.put("doc" + i, map("key", i)); + for (int i = 0; i < 100; i++) { + testData.put("doc" + (1000 + i), map("key", 42)); } - CollectionReference collection = testCollectionWithDocs(testData); - - // Populate the cache and save the resume token. - QuerySnapshot snapshot1 = waitFor(collection.get()); - assertEquals(snapshot1.size(), 100); - List documents = snapshot1.getDocuments(); - // Delete 50 docs in transaction so that it doesn't affect local cache. - waitFor( - collection - .getFirestore() - .runTransaction( - transaction -> { - for (int i = 1; i <= 50; i++) { - DocumentReference docRef = documents.get(i).getReference(); - transaction.delete(docRef); - } - return null; - })); - - // Wait 10 seconds, during which Watch will stop tracking the query - // and will send an existence filter rather than "delete" events. - Thread.sleep(10000); - - QuerySnapshot snapshot2 = waitFor(collection.get()); - assertEquals(snapshot2.size(), 50); + // Each iteration of the "while" loop below runs a single iteration of the test. The test will + // be run multiple times only if a bloom filter false positive occurs. + int attemptNumber = 0; + while (true) { + attemptNumber++; + + // Create 100 documents in a new collection. + CollectionReference collection = testCollectionWithDocs(testData); + + // Run a query to populate the local cache with the 100 documents and a resume token. + List createdDocuments = new ArrayList<>(); + { + QuerySnapshot querySnapshot = waitFor(collection.get()); + assertWithMessage("querySnapshot1").that(querySnapshot.size()).isEqualTo(100); + for (DocumentSnapshot documentSnapshot : querySnapshot.getDocuments()) { + createdDocuments.add(documentSnapshot.getReference()); + } + } + + // Delete 50 of the 100 documents. Do this in a transaction, rather than + // DocumentReference.delete(), to avoid affecting the local cache. + HashSet deletedDocumentIds = new HashSet<>(); + waitFor( + collection + .getFirestore() + .runTransaction( + transaction -> { + for (int i = 0; i < createdDocuments.size(); i += 2) { + DocumentReference documentToDelete = createdDocuments.get(i); + transaction.delete(documentToDelete); + deletedDocumentIds.add(documentToDelete.getId()); + } + return null; + })); + + // Wait for 10 seconds, during which Watch will stop tracking the query and will send an + // existence filter rather than "delete" events when the query is resumed. + Thread.sleep(10000); + + // Resume the query and save the resulting snapshot for verification. Use some internal + // testing hooks to "capture" the existence filter mismatches to verify that Watch sent a + // bloom filter, and it was used to avert a full requery. + QuerySnapshot snapshot2; + WatchChangeAggregatorTestingHooksAccessor.ExistenceFilterMismatchInfo + existenceFilterMismatchInfo; + WatchChangeAggregatorTestingHooksAccessor.ExistenceFilterMismatchAccumulator + existenceFilterMismatchAccumulator = + new WatchChangeAggregatorTestingHooksAccessor.ExistenceFilterMismatchAccumulator(); + existenceFilterMismatchAccumulator.register(); + try { + snapshot2 = waitFor(collection.get()); + // TODO(b/270731363): Remove the "if" condition below once the Firestore Emulator is fixed + // to send an existence filter. + if (isRunningAgainstEmulator()) { + existenceFilterMismatchInfo = null; + } else { + existenceFilterMismatchInfo = + existenceFilterMismatchAccumulator.waitForExistenceFilterMismatch( + /*timeoutMillis=*/ 5000); + } + } finally { + existenceFilterMismatchAccumulator.unregister(); + } + + // Verify that the snapshot from the resumed query contains the expected documents; that is, + // that it contains the 50 documents that were _not_ deleted. + // TODO(b/270731363): Remove the "if" condition below once the Firestore Emulator is fixed to + // send an existence filter. At the time of writing, the Firestore emulator fails to send an + // existence filter, resulting in the client including the deleted documents in the snapshot + // of the resumed query. + if (!(isRunningAgainstEmulator() && snapshot2.size() == 100)) { + HashSet actualDocumentIds = new HashSet<>(); + for (DocumentSnapshot documentSnapshot : snapshot2.getDocuments()) { + actualDocumentIds.add(documentSnapshot.getId()); + } + HashSet expectedDocumentIds = new HashSet<>(); + for (DocumentReference documentRef : createdDocuments) { + if (!deletedDocumentIds.contains(documentRef.getId())) { + expectedDocumentIds.add(documentRef.getId()); + } + } + assertWithMessage("snapshot2.docs") + .that(actualDocumentIds) + .containsExactlyElementsIn(expectedDocumentIds); + } + + // Skip the verification of the existence filter mismatch when testing against the Firestore + // emulator because the Firestore emulator does not include the `unchanged_names` bloom filter + // when it sends ExistenceFilter messages. Some day the emulator _may_ implement this logic, + // at which time this short-circuit can be removed. + if (isRunningAgainstEmulator()) { + return; + } + + // Verify that Watch sent an existence filter with the correct counts when the query was + // resumed. + assertWithMessage("Watch should have sent an existence filter") + .that(existenceFilterMismatchInfo) + .isNotNull(); + assertWithMessage("localCacheCount") + .that(existenceFilterMismatchInfo.localCacheCount()) + .isEqualTo(100); + assertWithMessage("existenceFilterCount") + .that(existenceFilterMismatchInfo.existenceFilterCount()) + .isEqualTo(50); + + // Skip the verification of the bloom filter when testing against production because the bloom + // filter is only implemented in nightly. + // TODO(b/271949433) Remove this "if" block once the bloom filter logic is deployed to + // production. + if (IntegrationTestUtil.getTargetBackend() != IntegrationTestUtil.TargetBackend.NIGHTLY) { + return; + } + + // Verify that Watch sent a valid bloom filter. + WatchChangeAggregatorTestingHooksAccessor.ExistenceFilterBloomFilterInfo bloomFilter = + existenceFilterMismatchInfo.bloomFilter(); + assertWithMessage("The bloom filter specified in the existence filter") + .that(bloomFilter) + .isNotNull(); + assertWithMessage("hashCount").that(bloomFilter.hashCount()).isGreaterThan(0); + assertWithMessage("bitmapLength").that(bloomFilter.bitmapLength()).isGreaterThan(0); + assertWithMessage("padding").that(bloomFilter.padding()).isGreaterThan(0); + assertWithMessage("padding").that(bloomFilter.padding()).isLessThan(8); + + // Verify that the bloom filter was successfully used to avert a full requery. If a false + // positive occurred then retry the entire test. Although statistically rare, false positives + // are expected to happen occasionally. When a false positive _does_ happen, just retry the + // test with a different set of documents. If that retry _also_ experiences a false positive, + // then fail the test because that is so improbable that something must have gone wrong. + if (attemptNumber == 1 && !bloomFilter.applied()) { + continue; + } + + assertWithMessage("bloom filter successfully applied with attemptNumber=" + attemptNumber) + .that(bloomFilter.applied()) + .isTrue(); + } } @Test diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/remote/WatchChangeAggregatorTestingHooksAccessor.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/remote/WatchChangeAggregatorTestingHooksAccessor.java new file mode 100644 index 00000000000..836d32d9132 --- /dev/null +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/remote/WatchChangeAggregatorTestingHooksAccessor.java @@ -0,0 +1,228 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.firestore.remote; + +import static com.google.firebase.firestore.util.Preconditions.checkNotNull; + +import android.os.SystemClock; +import androidx.annotation.AnyThread; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.firebase.firestore.ListenerRegistration; +import java.util.ArrayList; + +/** + * Provides access to the {@link WatchChangeAggregatorTestingHooks} class and its methods. + * + *

The {@link WatchChangeAggregatorTestingHooks} class has default visibility, and, therefore, is + * only visible to other classes declared in the same package. This class effectively "re-exports" + * the functionality from {@link WatchChangeAggregatorTestingHooks} in a class with {@code public} + * visibility so that tests written in other packages can access its functionality. + */ +public final class WatchChangeAggregatorTestingHooksAccessor { + + private WatchChangeAggregatorTestingHooksAccessor() {} + + /** @see WatchChangeAggregatorTestingHooks#addExistenceFilterMismatchListener */ + public static ListenerRegistration addExistenceFilterMismatchListener( + @NonNull ExistenceFilterMismatchListener listener) { + checkNotNull(listener, "a null listener is not allowed"); + return WatchChangeAggregatorTestingHooks.addExistenceFilterMismatchListener( + new ExistenceFilterMismatchListenerWrapper(listener)); + } + + /** @see WatchChangeAggregatorTestingHooks.ExistenceFilterMismatchListener */ + public interface ExistenceFilterMismatchListener { + @AnyThread + void onExistenceFilterMismatch(ExistenceFilterMismatchInfo info); + } + + /** @see WatchChangeAggregatorTestingHooks.ExistenceFilterMismatchInfo */ + public interface ExistenceFilterMismatchInfo { + int localCacheCount(); + + int existenceFilterCount(); + + @Nullable + ExistenceFilterBloomFilterInfo bloomFilter(); + } + + /** @see WatchChangeAggregatorTestingHooks.ExistenceFilterBloomFilterInfo */ + public interface ExistenceFilterBloomFilterInfo { + boolean applied(); + + int hashCount(); + + int bitmapLength(); + + int padding(); + } + + private static final class ExistenceFilterMismatchInfoImpl + implements ExistenceFilterMismatchInfo { + + private final WatchChangeAggregatorTestingHooks.ExistenceFilterMismatchInfo info; + + ExistenceFilterMismatchInfoImpl( + @NonNull WatchChangeAggregatorTestingHooks.ExistenceFilterMismatchInfo info) { + this.info = info; + } + + @Override + public int localCacheCount() { + return info.localCacheCount(); + } + + @Override + public int existenceFilterCount() { + return info.existenceFilterCount(); + } + + @Nullable + @Override + public ExistenceFilterBloomFilterInfo bloomFilter() { + WatchChangeAggregatorTestingHooks.ExistenceFilterBloomFilterInfo bloomFilterInfo = + info.bloomFilter(); + return bloomFilterInfo == null + ? null + : new ExistenceFilterBloomFilterInfoImpl(bloomFilterInfo); + } + } + + private static final class ExistenceFilterBloomFilterInfoImpl + implements ExistenceFilterBloomFilterInfo { + + private final WatchChangeAggregatorTestingHooks.ExistenceFilterBloomFilterInfo info; + + ExistenceFilterBloomFilterInfoImpl( + @NonNull WatchChangeAggregatorTestingHooks.ExistenceFilterBloomFilterInfo info) { + this.info = info; + } + + @Override + public boolean applied() { + return info.applied(); + } + + @Override + public int hashCount() { + return info.hashCount(); + } + + @Override + public int bitmapLength() { + return info.bitmapLength(); + } + + @Override + public int padding() { + return info.padding(); + } + } + + private static final class ExistenceFilterMismatchListenerWrapper + implements WatchChangeAggregatorTestingHooks.ExistenceFilterMismatchListener { + + private final ExistenceFilterMismatchListener wrappedListener; + + ExistenceFilterMismatchListenerWrapper( + @NonNull ExistenceFilterMismatchListener listenerToWrap) { + this.wrappedListener = listenerToWrap; + } + + @Override + public void onExistenceFilterMismatch( + WatchChangeAggregatorTestingHooks.ExistenceFilterMismatchInfo info) { + this.wrappedListener.onExistenceFilterMismatch(new ExistenceFilterMismatchInfoImpl(info)); + } + } + + public static final class ExistenceFilterMismatchAccumulator { + + private ExistenceFilterMismatchListenerImpl listener; + private ListenerRegistration listenerRegistration = null; + + /** Registers the accumulator to begin listening for existence filter mismatches. */ + public synchronized void register() { + if (listener != null) { + throw new IllegalStateException("already registered"); + } + listener = new ExistenceFilterMismatchListenerImpl(); + listenerRegistration = + WatchChangeAggregatorTestingHooksAccessor.addExistenceFilterMismatchListener(listener); + } + + /** Unregisters the accumulator from listening for existence filter mismatches. */ + public synchronized void unregister() { + if (listener == null) { + return; + } + listenerRegistration.remove(); + listenerRegistration = null; + listener = null; + } + + @Nullable + public WatchChangeAggregatorTestingHooksAccessor.ExistenceFilterMismatchInfo + waitForExistenceFilterMismatch(long timeoutMillis) throws InterruptedException { + ExistenceFilterMismatchListenerImpl capturedListener; + synchronized (this) { + capturedListener = listener; + } + if (capturedListener == null) { + throw new IllegalStateException( + "must be registered before waiting for an existence filter mismatch"); + } + return capturedListener.waitForExistenceFilterMismatch(timeoutMillis); + } + + private static final class ExistenceFilterMismatchListenerImpl + implements WatchChangeAggregatorTestingHooksAccessor.ExistenceFilterMismatchListener { + + private final ArrayList existenceFilterMismatches = + new ArrayList<>(); + + @Override + public void onExistenceFilterMismatch( + WatchChangeAggregatorTestingHooksAccessor.ExistenceFilterMismatchInfo info) { + synchronized (existenceFilterMismatches) { + existenceFilterMismatches.add(info); + existenceFilterMismatches.notifyAll(); + } + } + + @Nullable + WatchChangeAggregatorTestingHooksAccessor.ExistenceFilterMismatchInfo + waitForExistenceFilterMismatch(long timeoutMillis) throws InterruptedException { + if (timeoutMillis <= 0) { + throw new IllegalArgumentException("invalid timeout: " + timeoutMillis); + } + synchronized (existenceFilterMismatches) { + long endTimeMillis = SystemClock.uptimeMillis() + timeoutMillis; + while (true) { + if (existenceFilterMismatches.size() > 0) { + return existenceFilterMismatches.remove(0); + } + long currentWaitMillis = endTimeMillis - SystemClock.uptimeMillis(); + if (currentWaitMillis <= 0) { + return null; + } + existenceFilterMismatches.wait(currentWaitMillis); + } + } + } + } + } +} diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java index e14f8bffb48..4efa914633a 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/testutil/IntegrationTestUtil.java @@ -36,6 +36,7 @@ import com.google.firebase.firestore.ListenerRegistration; import com.google.firebase.firestore.MetadataChanges; import com.google.firebase.firestore.QuerySnapshot; +import com.google.firebase.firestore.WriteBatch; import com.google.firebase.firestore.auth.User; import com.google.firebase.firestore.core.DatabaseInfo; import com.google.firebase.firestore.model.DatabaseId; @@ -347,8 +348,27 @@ public static CollectionReference testCollectionWithDocs(Map> docs) { + WriteBatch writeBatch = null; + int writeBatchSize = 0; + for (Map.Entry> doc : docs.entrySet()) { - waitFor(collection.document(doc.getKey()).set(doc.getValue())); + if (writeBatch == null) { + writeBatch = collection.getFirestore().batch(); + } + + writeBatch.set(collection.document(doc.getKey()), doc.getValue()); + writeBatchSize++; + + // Write batches are capped at 500 writes. Use 400 just to be safe. + if (writeBatchSize == 400) { + waitFor(writeBatch.commit()); + writeBatch = null; + writeBatchSize = 0; + } + } + + if (writeBatch != null) { + waitFor(writeBatch.commit()); } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java index dc29f2633f1..b9c3dba252a 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java @@ -229,6 +229,12 @@ public void handleExistenceFilter(ExistenceFilterWatchChange watchChange) { pendingTargetResets.put(targetId, purpose); } + + WatchChangeAggregatorTestingHooks.notifyOnExistenceFilterMismatch( + WatchChangeAggregatorTestingHooks.ExistenceFilterMismatchInfo.from( + status == BloomFilterApplicationStatus.SUCCESS, + currentSize, + watchChange.getExistenceFilter())); } } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregatorTestingHooks.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregatorTestingHooks.java new file mode 100644 index 00000000000..6a492cd77df --- /dev/null +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregatorTestingHooks.java @@ -0,0 +1,166 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.firestore.remote; + +import static com.google.firebase.firestore.util.Preconditions.checkNotNull; + +import androidx.annotation.AnyThread; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import com.google.auto.value.AutoValue; +import com.google.firebase.firestore.ListenerRegistration; +import com.google.firebase.firestore.util.Executors; +import com.google.firestore.v1.BloomFilter; +import java.util.HashMap; +import java.util.Map; + +final class WatchChangeAggregatorTestingHooks { + + private WatchChangeAggregatorTestingHooks() {} + + private static final Map + existenceFilterMismatchListeners = new HashMap<>(); + + /** + * Notifies all registered {@link ExistenceFilterMismatchListener}` listeners registered via + * {@link #addExistenceFilterMismatchListener}. + * + * @param info Information about the existence filter mismatch to deliver to the listeners. + */ + static void notifyOnExistenceFilterMismatch(ExistenceFilterMismatchInfo info) { + synchronized (existenceFilterMismatchListeners) { + for (ExistenceFilterMismatchListener listener : existenceFilterMismatchListeners.values()) { + Executors.BACKGROUND_EXECUTOR.execute(() -> listener.onExistenceFilterMismatch(info)); + } + } + } + + /** + * Registers a {@link ExistenceFilterMismatchListener} to be notified when an existence filter + * mismatch occurs in the Watch listen stream. + * + *

The relative order in which callbacks are notified is unspecified; do not rely on any + * particular ordering. If a given callback is registered multiple times then it will be notified + * multiple times, once per registration. + * + *

The thread on which the callback occurs is unspecified; listeners should perform their work + * as quickly as possible and return to avoid blocking any critical work. In particular, the + * listener callbacks should not block or perform long-running operations. Listener + * callbacks can occur concurrently with other callbacks on the same and other listeners. + * + * @param listener the listener to register. + * @return an object that unregisters the given listener via its {@link + * ListenerRegistration#remove} method; only the first unregistration request does anything; + * all subsequent requests do nothing. + */ + @VisibleForTesting + static ListenerRegistration addExistenceFilterMismatchListener( + @NonNull ExistenceFilterMismatchListener listener) { + checkNotNull(listener, "a null listener is not allowed"); + + Object listenerId = new Object(); + synchronized (existenceFilterMismatchListeners) { + existenceFilterMismatchListeners.put(listenerId, listener); + } + + return () -> { + synchronized (existenceFilterMismatchListeners) { + existenceFilterMismatchListeners.remove(listenerId); + } + }; + } + + interface ExistenceFilterMismatchListener { + @AnyThread + void onExistenceFilterMismatch(ExistenceFilterMismatchInfo info); + } + + @AutoValue + abstract static class ExistenceFilterMismatchInfo { + + static ExistenceFilterMismatchInfo create( + int localCacheCount, + int existenceFilterCount, + @Nullable ExistenceFilterBloomFilterInfo bloomFilter) { + return new AutoValue_WatchChangeAggregatorTestingHooks_ExistenceFilterMismatchInfo( + localCacheCount, existenceFilterCount, bloomFilter); + } + + /** Returns the number of documents that matched the query in the local cache. */ + abstract int localCacheCount(); + + /** + * Returns the number of documents that matched the query on the server, as specified in the + * ExistenceFilter message's `count` field. + */ + abstract int existenceFilterCount(); + + /** + * Returns information about the bloom filter provided by Watch in the ExistenceFilter message's + * `unchangedNames` field. A `null` return value means that Watch did _not_ provide a bloom + * filter. + */ + @Nullable + abstract ExistenceFilterBloomFilterInfo bloomFilter(); + + static ExistenceFilterMismatchInfo from( + boolean bloomFilterApplied, int localCacheCount, ExistenceFilter existenceFilter) { + return create( + localCacheCount, + existenceFilter.getCount(), + ExistenceFilterBloomFilterInfo.from(bloomFilterApplied, existenceFilter)); + } + } + + @AutoValue + abstract static class ExistenceFilterBloomFilterInfo { + + static ExistenceFilterBloomFilterInfo create( + boolean applied, int hashCount, int bitmapLength, int padding) { + return new AutoValue_WatchChangeAggregatorTestingHooks_ExistenceFilterBloomFilterInfo( + applied, hashCount, bitmapLength, padding); + } + + /** + * Returns whether a full requery was averted by using the bloom filter. If false, then + * something happened, such as a false positive, to prevent using the bloom filter to avoid a + * full requery. + */ + abstract boolean applied(); + + /** Returns the number of hash functions used in the bloom filter. */ + abstract int hashCount(); + + /** Returns the number of bytes in the bloom filter's bitmask. */ + abstract int bitmapLength(); + + /** Returns the number of bits of padding in the last byte of the bloom filter. */ + abstract int padding(); + + static ExistenceFilterBloomFilterInfo from( + boolean bloomFilterApplied, ExistenceFilter existenceFilter) { + BloomFilter unchangedNames = existenceFilter.getUnchangedNames(); + if (unchangedNames == null) { + return null; + } + return create( + bloomFilterApplied, + unchangedNames.getHashCount(), + unchangedNames.getBits().getBitmap().size(), + unchangedNames.getBits().getPadding()); + } + } +} From d63be2be829ccb8fdfd2e222f2d10ea2351773e2 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Wed, 29 Mar 2023 17:29:14 -0700 Subject: [PATCH 13/22] Improve bloom filter application test coverage (#4828) --- .../firestore/remote/RemoteSerializer.java | 1 - .../firestore/local/LocalSerializerTest.java | 45 +++++++ .../firestore/remote/RemoteEventTest.java | 116 ++++++++++++++++++ .../remote/RemoteSerializerTest.java | 95 ++++++++++++++ .../testutil/TestTargetMetadataProvider.java | 8 +- 5 files changed, 263 insertions(+), 2 deletions(-) diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java index 9a352000f6b..1df86b26278 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java @@ -501,7 +501,6 @@ public Target encodeTarget(TargetData targetData) { builder.setResumeToken(targetData.getResumeToken()); } - // TODO(Mila) Incorporate this into the if statement above. if (targetData.getExpectedCount() != null && (!targetData.getResumeToken().isEmpty() || targetData.getSnapshotVersion().compareTo(SnapshotVersion.NONE) > 0)) { diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java index 20223e78dec..df345f1e6c0 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java @@ -404,6 +404,51 @@ public void testEncodesTargetData() { assertEquals(targetData, decoded); } + @Test + public void localSerializerShouldDropExpectedCountInTargetData() { + Query query = TestUtil.query("room"); + int targetId = 42; + long sequenceNumber = 10; + SnapshotVersion snapshotVersion = TestUtil.version(1039); + SnapshotVersion limboFreeVersion = TestUtil.version(1000); + ByteString resumeToken = TestUtil.resumeToken(1039); + + TargetData targetData = + new TargetData( + query.toTarget(), + targetId, + sequenceNumber, + QueryPurpose.LISTEN, + snapshotVersion, + limboFreeVersion, + resumeToken, + /* expectedCount= */ 1234); + + com.google.firestore.v1.Target.QueryTarget queryTarget = + remoteSerializer.encodeQueryTarget(query.toTarget()); + + com.google.firebase.firestore.proto.Target expected = + com.google.firebase.firestore.proto.Target.newBuilder() + .setTargetId(targetId) + .setLastListenSequenceNumber(sequenceNumber) + .setSnapshotVersion(com.google.protobuf.Timestamp.newBuilder().setNanos(1039000)) + .setResumeToken(ByteString.copyFrom(resumeToken.toByteArray())) + .setQuery( + com.google.firestore.v1.Target.QueryTarget.newBuilder() + .setParent(queryTarget.getParent()) + .setStructuredQuery(queryTarget.getStructuredQuery())) + .setLastLimboFreeSnapshotVersion( + com.google.protobuf.Timestamp.newBuilder().setNanos(1000000)) + .build(); + + assertEquals(expected, serializer.encodeTargetData(targetData)); + TargetData decoded = serializer.decodeTargetData(expected); + // Set the expected_count in TargetData to null, as serializing a TargetData into local Target + // proto will drop the expected_count and the deserialized TargetData will not include the + // expected_count. + assertEquals(targetData.withExpectedCount(null), decoded); + } + @Test public void testEncodesQuery() { Target target = diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/RemoteEventTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/RemoteEventTest.java index c8761ec7050..57d1d6c0d83 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/RemoteEventTest.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/RemoteEventTest.java @@ -39,6 +39,8 @@ import com.google.firebase.firestore.remote.WatchChange.WatchTargetChange; import com.google.firebase.firestore.remote.WatchChange.WatchTargetChangeType; import com.google.firebase.firestore.testutil.TestTargetMetadataProvider; +import com.google.firestore.v1.BitSequence; +import com.google.firestore.v1.BloomFilter; import com.google.protobuf.ByteString; import java.util.ArrayList; import java.util.Collections; @@ -456,6 +458,120 @@ public void testExistenceFilterMismatchClearsTarget() { assertEquals(0, event.getDocumentUpdates().size()); } + @Test + public void existenceFilterMismatchWithSuccessfulBloomFilterApplication() { + Map targetMap = activeQueries(1, 2); + + MutableDocument doc1 = doc("docs/1", 1, map("value", 1)); + MutableDocument doc2 = doc("docs/2", 2, map("value", 2)); + + WatchChange change1 = new DocumentChange(asList(1), emptyList(), doc1.getKey(), doc1); + WatchChange change2 = new DocumentChange(asList(1), emptyList(), doc2.getKey(), doc2); + WatchChange change3 = new WatchTargetChange(WatchTargetChangeType.Current, asList(1)); + + // The BloomFilter proto value below is created based on the document paths that are constructed + // using the pattern: "projects/test-project/databases/test-database/documents/"+document_key. + // Override the default database ID to ensure that the document path matches the pattern above. + targetMetadataProvider.setDatabaseId("test-project", "test-database"); + WatchChangeAggregator aggregator = + createAggregator( + targetMap, + noOutstandingResponses, + keySet(doc1.getKey(), doc2.getKey()), + change1, + change2, + change3); + + RemoteEvent event = aggregator.createRemoteEvent(version(3)); + + assertEquals(version(3), event.getSnapshotVersion()); + assertEquals(2, event.getDocumentUpdates().size()); + assertEquals(doc1, event.getDocumentUpdates().get(doc1.getKey())); + assertEquals(doc2, event.getDocumentUpdates().get(doc2.getKey())); + + assertEquals(2, event.getTargetChanges().size()); + + TargetChange mapping1 = targetChange(resumeToken, true, null, asList(doc1, doc2), null); + assertEquals(mapping1, event.getTargetChanges().get(1)); + + TargetChange mapping2 = targetChange(resumeToken, false, null, null, null); + assertEquals(mapping2, event.getTargetChanges().get(2)); + + // This BloomFilter will return false on MightContain(doc1) and true on MightContain(doc2). + BitSequence.Builder bitSequence = BitSequence.newBuilder(); + bitSequence.setPadding(1); + bitSequence.setBitmap(ByteString.copyFrom(new byte[] {0x0E, 0x0F})); + com.google.firestore.v1.BloomFilter.Builder bloomFilter = BloomFilter.newBuilder(); + bloomFilter.setBits(bitSequence); + bloomFilter.setHashCount(7); + + WatchChange.ExistenceFilterWatchChange watchChange = + new WatchChange.ExistenceFilterWatchChange(1, new ExistenceFilter(1, bloomFilter.build())); + aggregator.handleExistenceFilter(watchChange); + + event = aggregator.createRemoteEvent(version(3)); + + assertEquals(1, event.getTargetChanges().size()); + assertEquals(0, event.getTargetMismatches().size()); + assertEquals(0, event.getDocumentUpdates().size()); + } + + @Test + public void existenceFilterMismatchWithBloomFilterFalsePositiveResult() { + Map targetMap = activeQueries(1, 2); + + MutableDocument doc1 = doc("docs/1", 1, map("value", 1)); + MutableDocument doc2 = doc("docs/2", 2, map("value", 2)); + + WatchChange change1 = new DocumentChange(asList(1), emptyList(), doc1.getKey(), doc1); + WatchChange change2 = new DocumentChange(asList(1), emptyList(), doc2.getKey(), doc2); + WatchChange change3 = new WatchTargetChange(WatchTargetChangeType.Current, asList(1)); + + WatchChangeAggregator aggregator = + createAggregator( + targetMap, + noOutstandingResponses, + keySet(doc1.getKey(), doc2.getKey()), + change1, + change2, + change3); + + RemoteEvent event = aggregator.createRemoteEvent(version(3)); + + assertEquals(version(3), event.getSnapshotVersion()); + assertEquals(2, event.getDocumentUpdates().size()); + assertEquals(doc1, event.getDocumentUpdates().get(doc1.getKey())); + assertEquals(doc2, event.getDocumentUpdates().get(doc2.getKey())); + + assertEquals(2, event.getTargetChanges().size()); + + TargetChange mapping1 = targetChange(resumeToken, true, null, asList(doc1, doc2), null); + assertEquals(mapping1, event.getTargetChanges().get(1)); + + TargetChange mapping2 = targetChange(resumeToken, false, null, null, null); + assertEquals(mapping2, event.getTargetChanges().get(2)); + + // With this BloomFilter, mightContain() will return true for all documents. + BitSequence.Builder bitSequence = BitSequence.newBuilder(); + bitSequence.setPadding(7); + bitSequence.setBitmap(ByteString.copyFrom(new byte[] {(byte) 0xFF, (byte) 0xFF})); + com.google.firestore.v1.BloomFilter.Builder bloomFilter = BloomFilter.newBuilder(); + bloomFilter.setBits(bitSequence); + bloomFilter.setHashCount(33); + + WatchChange.ExistenceFilterWatchChange watchChange = + new WatchChange.ExistenceFilterWatchChange(1, new ExistenceFilter(1, bloomFilter.build())); + aggregator.handleExistenceFilter(watchChange); + + event = aggregator.createRemoteEvent(version(3)); + + TargetChange mapping3 = targetChange(ByteString.EMPTY, false, null, null, asList(doc1, doc2)); + assertEquals(1, event.getTargetChanges().size()); + assertEquals(mapping3, event.getTargetChanges().get(1)); + assertEquals(1, event.getTargetMismatches().size()); + assertEquals(0, event.getDocumentUpdates().size()); + } + @Test public void testExistenceFilterMismatchRemovesCurrentChanges() { Map targetMap = activeQueries(1); diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/RemoteSerializerTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/RemoteSerializerTest.java index e3d605c9fbe..30e5715613b 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/RemoteSerializerTest.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/RemoteSerializerTest.java @@ -509,6 +509,11 @@ public void testEncodesListenRequestLabels() { targetData = new TargetData(query.toTarget(), 2, 3, QueryPurpose.EXISTENCE_FILTER_MISMATCH); result = serializer.encodeListenRequestLabels(targetData); assertEquals(map("goog-listen-tags", "existence-filter-mismatch"), result); + + targetData = + new TargetData(query.toTarget(), 2, 3, QueryPurpose.EXISTENCE_FILTER_MISMATCH_BLOOM); + result = serializer.encodeListenRequestLabels(targetData); + assertEquals(map("goog-listen-tags", "existence-filter-mismatch-bloom"), result); } @Test @@ -1153,6 +1158,96 @@ public void testEncodesReadTime() { serializer.decodeQueryTarget(serializer.encodeQueryTarget(q.toTarget())), q.toTarget()); } + @Test + public void encodesExpectedCountWhenResumeTokenIsPresent() { + Query q = Query.atPath(ResourcePath.fromString("docs")); + TargetData targetData = + new TargetData(q.toTarget(), 1, 2, QueryPurpose.LISTEN) + .withResumeToken(TestUtil.resumeToken(1000), SnapshotVersion.NONE) + .withExpectedCount(42); + Target actual = serializer.encodeTarget(targetData); + + StructuredQuery.Builder structuredQueryBuilder = + StructuredQuery.newBuilder() + .addFrom(CollectionSelector.newBuilder().setCollectionId("docs")) + .addOrderBy(defaultKeyOrder()); + + QueryTarget.Builder queryBuilder = + QueryTarget.newBuilder() + .setParent("projects/p/databases/d/documents") + .setStructuredQuery(structuredQueryBuilder); + Target expected = + Target.newBuilder() + .setQuery(queryBuilder) + .setTargetId(1) + .setResumeToken(TestUtil.resumeToken(1000)) + .setExpectedCount(Int32Value.newBuilder().setValue(42)) + .build(); + + assertEquals(expected, actual); + assertEquals( + serializer.decodeQueryTarget(serializer.encodeQueryTarget(q.toTarget())), q.toTarget()); + } + + @Test + public void encodesExpectedCountWhenReadTimeIsPresent() { + Query q = Query.atPath(ResourcePath.fromString("docs")); + TargetData targetData = + new TargetData(q.toTarget(), 1, 2, QueryPurpose.LISTEN) + .withResumeToken(ByteString.EMPTY, version(4000000)) + .withExpectedCount(42); + Target actual = serializer.encodeTarget(targetData); + + StructuredQuery.Builder structuredQueryBuilder = + StructuredQuery.newBuilder() + .addFrom(CollectionSelector.newBuilder().setCollectionId("docs")) + .addOrderBy(defaultKeyOrder()); + + QueryTarget.Builder queryBuilder = + QueryTarget.newBuilder() + .setParent("projects/p/databases/d/documents") + .setStructuredQuery(structuredQueryBuilder); + Target expected = + Target.newBuilder() + .setQuery(queryBuilder) + .setTargetId(1) + .setReadTime(Timestamp.newBuilder().setSeconds(4)) + .setExpectedCount(Int32Value.newBuilder().setValue(42)) + .build(); + + assertEquals(expected, actual); + assertEquals( + serializer.decodeQueryTarget(serializer.encodeQueryTarget(q.toTarget())), q.toTarget()); + } + + @Test + public void shouldIgnoreExpectedCountWithoutResumeTokenOrReadTime() { + Query q = Query.atPath(ResourcePath.fromString("docs")); + TargetData targetData = + new TargetData(q.toTarget(), 1, 2, QueryPurpose.LISTEN).withExpectedCount(42); + Target actual = serializer.encodeTarget(targetData); + + StructuredQuery.Builder structuredQueryBuilder = + StructuredQuery.newBuilder() + .addFrom(CollectionSelector.newBuilder().setCollectionId("docs")) + .addOrderBy(defaultKeyOrder()); + + QueryTarget.Builder queryBuilder = + QueryTarget.newBuilder() + .setParent("projects/p/databases/d/documents") + .setStructuredQuery(structuredQueryBuilder); + Target expected = + Target.newBuilder() + .setQuery(queryBuilder) + .setTargetId(1) + .setResumeToken(ByteString.EMPTY) + .build(); + + assertEquals(expected, actual); + assertEquals( + serializer.decodeQueryTarget(serializer.encodeQueryTarget(q.toTarget())), q.toTarget()); + } + /** * Wraps the given query in TargetData. This is useful because the APIs we're testing accept * TargetData, but for the most part we're just testing variations on Query. diff --git a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java index 21394a90269..698628b3300 100644 --- a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java +++ b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java @@ -30,6 +30,7 @@ public class TestTargetMetadataProvider implements WatchChangeAggregator.TargetMetadataProvider { final Map> syncedKeys = new HashMap<>(); final Map queryData = new HashMap<>(); + DatabaseId databaseId = DatabaseId.forProject("test-project"); @Override public ImmutableSortedSet getRemoteKeysForTarget(int targetId) { @@ -44,7 +45,12 @@ public TargetData getTargetDataForTarget(int targetId) { @Override public DatabaseId getDatabaseId() { - return DatabaseId.forProject("test-project"); + return databaseId; + } + + /** Replaces the default project ID and database ID. */ + public void setDatabaseId(String projectId, String databaseId) { + this.databaseId = DatabaseId.forDatabase(projectId, databaseId); } /** Sets or replaces the local state for the provided query data. */ From 158c0842bf63a890a5ee02eccf33a3b37ba4ea73 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Tue, 11 Apr 2023 12:06:36 -0400 Subject: [PATCH 14/22] QueryTest.java: Remove check for `getTargetBackend() != NIGHTLY` since bloom filter support has now been deployed to production. (#4871) --- .../java/com/google/firebase/firestore/QueryTest.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java index 6aa5a8e91a4..9881348dcb8 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java @@ -1148,14 +1148,6 @@ public void resumingAQueryShouldUseBloomFilterToAvoidFullRequery() throws Except .that(existenceFilterMismatchInfo.existenceFilterCount()) .isEqualTo(50); - // Skip the verification of the bloom filter when testing against production because the bloom - // filter is only implemented in nightly. - // TODO(b/271949433) Remove this "if" block once the bloom filter logic is deployed to - // production. - if (IntegrationTestUtil.getTargetBackend() != IntegrationTestUtil.TargetBackend.NIGHTLY) { - return; - } - // Verify that Watch sent a valid bloom filter. ExistenceFilterMismatchListener.ExistenceFilterBloomFilterInfo bloomFilter = existenceFilterMismatchInfo.bloomFilter(); From c76b67c555e5a66df2d7f1d0c46be20a47e23e7a Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Mon, 24 Apr 2023 15:33:22 -0400 Subject: [PATCH 15/22] Port spec test changes from https://github.com/firebase/firebase-js-sdk/pull/7021 (Bundle the readTime and resumeToken into a data structure) --- .../firebase/firestore/spec/SpecTestCase.java | 23 +++- .../json/existence_filter_spec_test.json | 114 ++++++++++-------- .../test/resources/json/limbo_spec_test.json | 25 ++-- .../test/resources/json/limit_spec_test.json | 12 +- 4 files changed, 105 insertions(+), 69 deletions(-) diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java index 8fa7375ebeb..1b2dcc4c66e 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java @@ -478,6 +478,18 @@ private List parseIntList(@Nullable JSONArray arr) throws JSONException return result; } + /** Deeply parses a JSONArray into a List. */ + private List parseStringList(@Nullable JSONArray arr) throws JSONException { + List result = new ArrayList<>(); + if (arr == null) { + return result; + } + for (int i = 0; i < arr.length(); ++i) { + result.add(arr.getString(i)); + } + return result; + } + // // Methods for doing the steps of the spec test. // @@ -665,15 +677,14 @@ private void doWatchEntity(JSONObject watchEntity) throws Exception { } } - private void doWatchFilter(JSONArray watchFilter) throws Exception { - List targets = parseIntList(watchFilter.getJSONArray(0)); + private void doWatchFilter(JSONObject watchFilter) throws Exception { + List keys = parseStringList(watchFilter.getJSONArray("keys")); + List targets = parseIntList(watchFilter.getJSONArray("targetIds")); Assert.hardAssert( targets.size() == 1, "ExistenceFilters currently support exactly one target only."); - int keyCount = watchFilter.length() == 0 ? 0 : watchFilter.length() - 1; - // TODO: extend this with different existence filters over time. - ExistenceFilter filter = new ExistenceFilter(keyCount); + ExistenceFilter filter = new ExistenceFilter(keys.size()); ExistenceFilterWatchChange change = new ExistenceFilterWatchChange(targets.get(0), filter); writeWatchChange(change, SnapshotVersion.NONE); } @@ -850,7 +861,7 @@ private void doStep(JSONObject step) throws Exception { } else if (step.has("watchEntity")) { doWatchEntity(step.getJSONObject("watchEntity")); } else if (step.has("watchFilter")) { - doWatchFilter(step.getJSONArray("watchFilter")); + doWatchFilter(step.getJSONObject("watchFilter")); } else if (step.has("watchReset")) { doWatchReset(step.getJSONArray("watchReset")); } else if (step.has("watchSnapshot")) { diff --git a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json index c0be6b22cfb..0a4ecb48201 100644 --- a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json +++ b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json @@ -132,12 +132,14 @@ ] }, { - "watchFilter": [ - [ - 2 + "watchFilter": { + "keys": [ + "collection/1" ], - "collection/1" - ] + "targetIds": [ + 2 + ] + } }, { "watchSnapshot": { @@ -366,13 +368,15 @@ ] }, { - "watchFilter": [ - [ - 2 + "watchFilter": { + "keys": [ + "collection/1", + "collection/2" ], - "collection/1", - "collection/2" - ] + "targetIds": [ + 2 + ] + } }, { "watchEntity": { @@ -729,11 +733,13 @@ } }, { - "watchFilter": [ - [ + "watchFilter": { + "keys": [ + ], + "targetIds": [ 2 ] - ] + } }, { "watchRemove": { @@ -910,12 +916,14 @@ ] }, { - "watchFilter": [ - [ - 2 + "watchFilter": { + "keys": [ + "collection/1" ], - "collection/1" - ] + "targetIds": [ + 2 + ] + } }, { "watchSnapshot": { @@ -1203,12 +1211,14 @@ ] }, { - "watchFilter": [ - [ - 2 + "watchFilter": { + "keys": [ + "collection/1" ], - "collection/1" - ] + "targetIds": [ + 2 + ] + } }, { "watchSnapshot": { @@ -1313,12 +1323,14 @@ } }, { - "watchFilter": [ - [ - 2 + "watchFilter": { + "keys": [ + "collection/1" ], - "collection/1" - ] + "targetIds": [ + 2 + ] + } }, { "watchSnapshot": { @@ -1489,12 +1501,14 @@ ] }, { - "watchFilter": [ - [ - 2 + "watchFilter": { + "keys": [ + "collection/1" ], - "collection/1" - ] + "targetIds": [ + 2 + ] + } }, { "watchSnapshot": { @@ -1846,12 +1860,14 @@ ] }, { - "watchFilter": [ - [ - 2 + "watchFilter": { + "keys": [ + "collection/1" ], - "collection/1" - ] + "targetIds": [ + 2 + ] + } }, { "watchSnapshot": { @@ -2149,11 +2165,13 @@ ] }, { - "watchFilter": [ - [ + "watchFilter": { + "keys": [ + ], + "targetIds": [ 2 ] - ] + } }, { "watchSnapshot": { @@ -2265,12 +2283,14 @@ ] }, { - "watchFilter": [ - [ - 2 + "watchFilter": { + "keys": [ + "collection/1" ], - "collection/1" - ] + "targetIds": [ + 2 + ] + } }, { "watchSnapshot": { diff --git a/firebase-firestore/src/test/resources/json/limbo_spec_test.json b/firebase-firestore/src/test/resources/json/limbo_spec_test.json index c4c179fd8ba..8172a189689 100644 --- a/firebase-firestore/src/test/resources/json/limbo_spec_test.json +++ b/firebase-firestore/src/test/resources/json/limbo_spec_test.json @@ -3445,11 +3445,13 @@ ] }, { - "watchFilter": [ - [ + "watchFilter": { + "keys": [ + ], + "targetIds": [ 1 ] - ] + } }, { "watchCurrent": [ @@ -8201,15 +8203,16 @@ } }, { - "watchFilter": [ - [ - 2 + "watchFilter": { + "keys": [ + "collection/b1", + "collection/b2", + "collection/b3" ], - "collection/b1", - "collection/b2", - "collection/b3" - ] - + "targetIds": [ + 2 + ] + } }, { "watchSnapshot": { diff --git a/firebase-firestore/src/test/resources/json/limit_spec_test.json b/firebase-firestore/src/test/resources/json/limit_spec_test.json index 37ec88b11c0..257c53eeb4c 100644 --- a/firebase-firestore/src/test/resources/json/limit_spec_test.json +++ b/firebase-firestore/src/test/resources/json/limit_spec_test.json @@ -5611,12 +5611,14 @@ } }, { - "watchFilter": [ - [ - 2 + "watchFilter": { + "keys": [ + "collection/b" ], - "collection/b" - ] + "targetIds": [ + 2 + ] + } }, { "watchSnapshot": { From 0f870e937a26c7068cb8bb84b8a458ef402c70c4 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Mon, 24 Apr 2023 16:26:41 -0400 Subject: [PATCH 16/22] Port spec test changes from https://github.com/firebase/firebase-js-sdk/pull/7229 (Optimize local cache sync when resuming a query that had docs deleted) --- .../firebase/firestore/spec/SpecTestCase.java | 18 +- .../test/resources/json/bundle_spec_test.json | 2 +- .../json/existence_filter_spec_test.json | 7167 +++++++++++++++-- .../test/resources/json/limbo_spec_test.json | 512 +- .../test/resources/json/limit_spec_test.json | 20 +- .../test/resources/json/listen_spec_test.json | 685 ++ .../resources/json/offline_spec_test.json | 4 +- .../resources/json/recovery_spec_test.json | 8 +- 8 files changed, 7643 insertions(+), 773 deletions(-) diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java index 1b2dcc4c66e..622261258ea 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java @@ -420,6 +420,22 @@ private Query parseQuery(Object querySpec) throws JSONException { } } + private static QueryPurpose parseQueryPurpose(Object value) { + if (!(value instanceof Integer)) { + throw new IllegalArgumentException("invalid query purpose: " + value); + } + switch ((Integer) value) { + case 0: + return QueryPurpose.LISTEN; + case 1: + return QueryPurpose.EXISTENCE_FILTER_MISMATCH; + case 3: + return QueryPurpose.LIMBO_RESOLUTION; + default: + throw new IllegalArgumentException("unknown query purpose value: " + value); + } + } + private DocumentViewChange parseChange(JSONObject jsonDoc, DocumentViewChange.Type type) throws JSONException { long version = jsonDoc.getLong("version"); @@ -1027,7 +1043,7 @@ private void validateExpectedState(@Nullable JSONObject expectedState) throws JS QueryPurpose purpose = QueryPurpose.LISTEN; if (queryDataJson.has("targetPurpose")) { - purpose = QueryPurpose.values()[queryDataJson.getInt("targetPurpose")]; + purpose = parseQueryPurpose(queryDataJson.get("targetPurpose")); } TargetData targetData = diff --git a/firebase-firestore/src/test/resources/json/bundle_spec_test.json b/firebase-firestore/src/test/resources/json/bundle_spec_test.json index 0ef88d3f1a0..d3ccf3e7b2d 100644 --- a/firebase-firestore/src/test/resources/json/bundle_spec_test.json +++ b/firebase-firestore/src/test/resources/json/bundle_spec_test.json @@ -1179,7 +1179,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ diff --git a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json index 0a4ecb48201..24da8086f70 100644 --- a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json +++ b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json @@ -1,9 +1,10 @@ { - "Existence filter clears resume token": { + "Bloom filter can process special characters in document name": { "describeName": "Existence Filters:", - "itName": "Existence filter clears resume token", + "itName": "Bloom filter can process special characters in document name", "tags": [ - "durable-persistence" + "no-ios", + "no-android" ], "config": { "numClients": 1, @@ -48,7 +49,7 @@ "docs": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/ÀÒ∑", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -60,13 +61,13 @@ }, { "createTime": 0, - "key": "collection/2", + "key": "collection/À∑Ò", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, "version": 1000 } @@ -95,7 +96,7 @@ "added": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/ÀÒ∑", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -107,13 +108,13 @@ }, { "createTime": 0, - "key": "collection/2", + "key": "collection/À∑Ò", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, "version": 1000 } @@ -133,8 +134,15 @@ }, { "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "IIAAIIAIIAAIIAIIAA==", + "padding": 4 + }, + "hashCount": 10 + }, "keys": [ - "collection/1" + "collection/ÀÒ∑" ], "targetIds": [ 2 @@ -162,7 +170,23 @@ } ], "expectedState": { + "activeLimboDocs": [ + "collection/À∑Ò" + ], "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/À∑Ò" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, "2": { "queries": [ { @@ -173,23 +197,25 @@ "path": "collection" } ], - "resumeToken": "", - "targetPurpose": 1 + "resumeToken": "" } } } - }, - { - "restart": true, - "expectedState": { - "activeLimboDocs": [ - ], - "activeTargets": { - }, - "enqueuedLimboDocs": [ - ] - } - }, + } + ] + }, + "Bloom filter fills in default values for undefined padding and hashCount": { + "describeName": "Existence Filters:", + "itName": "Bloom filter fills in default values for undefined padding and hashCount", + "tags": [ + "no-ios", + "no-android" + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ { "userListen": { "query": { @@ -201,12 +227,81 @@ }, "targetId": 2 }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, "expectedSnapshotEvents": [ { "added": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -218,7 +313,7 @@ }, { "createTime": 0, - "key": "collection/2", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -229,6 +324,42 @@ "version": 1000 } ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "AhAAApAAAIAEBIAABA==" + } + }, + "keys": [ + "collection/a" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { "errorCode": 0, "fromCache": true, "hasPendingWrites": false, @@ -253,17 +384,20 @@ "path": "collection" } ], - "resumeToken": "" + "resumeToken": "", + "targetPurpose": 1 } } } } ] }, - "Existence filter handled at global snapshot": { + "Bloom filter is handled at global snapshot": { "describeName": "Existence Filters:", - "itName": "Existence filter handled at global snapshot", + "itName": "Bloom filter is handled at global snapshot", "tags": [ + "no-ios", + "no-android" ], "config": { "numClients": 1, @@ -308,7 +442,7 @@ "docs": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -317,6 +451,18 @@ "v": 1 }, "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 } ], "targets": [ @@ -343,7 +489,7 @@ "added": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -352,6 +498,18 @@ "v": 1 }, "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 } ], "errorCode": 0, @@ -369,9 +527,15 @@ }, { "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "AhAAApAAAIAEBIAABA==", + "padding": 4 + }, + "hashCount": 10 + }, "keys": [ - "collection/1", - "collection/2" + "collection/a" ], "targetIds": [ 2 @@ -383,7 +547,7 @@ "docs": [ { "createTime": 0, - "key": "collection/3", + "key": "collection/c", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -410,7 +574,7 @@ "added": [ { "createTime": 0, - "key": "collection/3", + "key": "collection/c", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -434,7 +598,23 @@ } ], "expectedState": { + "activeLimboDocs": [ + "collection/b" + ], "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/b" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, "2": { "queries": [ { @@ -445,17 +625,51 @@ "path": "collection" } ], - "resumeToken": "", - "targetPurpose": 1 + "resumeToken": "" } } } - }, + } + ] + }, + "Bloom filter limbo resolution is denied": { + "describeName": "Existence Filters:", + "itName": "Bloom filter limbo resolution is denied", + "tags": [ + "no-ios", + "no-android" + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ { - "watchRemove": { - "targetIds": [ - 2 - ] + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } } }, { @@ -468,7 +682,7 @@ "docs": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -480,27 +694,5431 @@ }, { "createTime": 0, - "key": "collection/2", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, - "version": 2000 + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "AhAAApAAAIAEBIAABA==", + "padding": 4 + }, + "hashCount": 10 + }, + "keys": [ + "collection/a" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeLimboDocs": [ + "collection/b" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/b" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchRemove": { + "cause": { + "code": 7 + }, + "targetIds": [ + 1 + ] + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "removed": [ + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ] + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + } + ] + }, + "Bloom filter with large size works as expected": { + "describeName": "Existence Filters:", + "itName": "Bloom filter with large size works as expected", + "tags": [ + "no-ios", + "no-android" + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/doc0", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc4", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc5", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc6", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc7", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc8", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc9", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc10", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc11", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc12", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc13", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc14", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc15", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc16", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc17", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc18", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc19", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc20", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc21", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc22", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc23", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc24", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc25", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc26", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc27", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc28", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc29", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc30", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc31", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc32", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc33", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc34", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc35", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc36", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc37", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc38", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc39", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc40", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc41", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc42", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc43", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc44", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc45", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc46", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc47", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc48", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc49", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc50", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc51", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc52", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc53", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc54", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc55", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc56", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc57", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc58", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc59", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc60", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc61", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc62", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc63", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc64", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc65", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc66", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc67", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc68", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc69", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc70", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc71", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc72", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc73", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc74", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc75", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc76", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc77", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc78", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc79", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc80", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc81", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc82", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc83", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc84", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc85", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc86", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc87", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc88", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc89", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc90", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc91", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc92", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc93", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc94", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc95", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc96", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc97", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc98", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc99", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/doc0", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc4", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc5", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc6", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc7", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc8", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc9", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc10", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc11", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc12", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc13", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc14", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc15", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc16", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc17", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc18", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc19", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc20", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc21", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc22", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc23", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc24", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc25", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc26", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc27", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc28", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc29", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc30", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc31", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc32", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc33", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc34", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc35", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc36", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc37", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc38", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc39", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc40", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc41", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc42", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc43", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc44", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc45", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc46", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc47", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc48", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc49", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc50", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc51", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc52", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc53", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc54", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc55", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc56", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc57", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc58", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc59", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc60", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc61", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc62", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc63", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc64", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc65", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc66", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc67", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc68", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc69", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc70", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc71", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc72", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc73", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc74", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc75", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc76", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc77", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc78", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc79", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc80", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc81", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc82", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc83", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc84", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc85", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc86", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc87", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc88", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc89", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc90", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc91", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc92", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc93", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc94", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc95", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc96", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc97", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc98", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/doc99", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "+9oMQXUptl274DOaET8sfebQ4aCu0Roiddbja3z8TfadKuyPV/9XWV5Ksv+vywRXTfZSNIn8z+xk/oq1+cbOPepeNvbXVOF6H92fCOAz/KiS3Mcw338R9tXE3Y7QB1L2kbvbvVHW3Kn/k3Vx8k9Oa19eWX6RYE97Q+oCcVU=", + "padding": 0 + }, + "hashCount": 16 + }, + "keys": [ + "collection/doc0", + "collection/doc1", + "collection/doc2", + "collection/doc3", + "collection/doc4", + "collection/doc5", + "collection/doc6", + "collection/doc7", + "collection/doc8", + "collection/doc9", + "collection/doc10", + "collection/doc11", + "collection/doc12", + "collection/doc13", + "collection/doc14", + "collection/doc15", + "collection/doc16", + "collection/doc17", + "collection/doc18", + "collection/doc19", + "collection/doc20", + "collection/doc21", + "collection/doc22", + "collection/doc23", + "collection/doc24", + "collection/doc25", + "collection/doc26", + "collection/doc27", + "collection/doc28", + "collection/doc29", + "collection/doc30", + "collection/doc31", + "collection/doc32", + "collection/doc33", + "collection/doc34", + "collection/doc35", + "collection/doc36", + "collection/doc37", + "collection/doc38", + "collection/doc39", + "collection/doc40", + "collection/doc41", + "collection/doc42", + "collection/doc43", + "collection/doc44", + "collection/doc45", + "collection/doc46", + "collection/doc47", + "collection/doc48", + "collection/doc49" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeLimboDocs": [ + "collection/doc50", + "collection/doc51", + "collection/doc52", + "collection/doc53", + "collection/doc54", + "collection/doc55", + "collection/doc56", + "collection/doc57", + "collection/doc58", + "collection/doc59", + "collection/doc60", + "collection/doc61", + "collection/doc62", + "collection/doc63", + "collection/doc64", + "collection/doc65", + "collection/doc66", + "collection/doc67", + "collection/doc68", + "collection/doc69", + "collection/doc70", + "collection/doc71", + "collection/doc72", + "collection/doc73", + "collection/doc74", + "collection/doc75", + "collection/doc76", + "collection/doc77", + "collection/doc78", + "collection/doc79", + "collection/doc80", + "collection/doc81", + "collection/doc82", + "collection/doc83", + "collection/doc84", + "collection/doc85", + "collection/doc86", + "collection/doc87", + "collection/doc88", + "collection/doc89", + "collection/doc90", + "collection/doc91", + "collection/doc92", + "collection/doc93", + "collection/doc94", + "collection/doc95", + "collection/doc96", + "collection/doc97", + "collection/doc98", + "collection/doc99" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc50" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "11": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc55" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "13": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc56" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "15": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc57" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "17": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc58" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "19": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc59" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + }, + "21": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc60" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "23": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc61" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "25": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc62" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "27": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc63" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "29": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc64" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "3": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc51" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "31": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc65" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "33": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc66" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "35": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc67" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "37": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc68" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "39": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc69" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "41": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc70" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "43": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc71" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "45": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc72" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "47": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc73" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "49": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc74" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "5": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc52" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "51": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc75" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "53": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc76" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "55": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc77" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "57": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc78" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "59": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc79" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "61": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc80" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "63": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc81" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "65": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc82" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "67": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc83" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "69": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc84" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "7": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc53" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "71": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc85" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "73": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc86" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "75": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc87" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "77": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc88" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "79": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc89" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "81": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc90" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "83": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc91" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "85": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc92" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "87": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc93" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "89": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc94" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "9": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc54" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "91": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc95" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "93": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc96" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "95": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc97" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "97": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc98" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "99": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/doc99" + } + ], + "resumeToken": "", + "targetPurpose": 3 + } + } + } + } + ] + }, + "Existence filter clears resume token": { + "describeName": "Existence Filters:", + "itName": "Existence filter clears resume token", + "tags": [ + "durable-persistence" + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "keys": [ + "collection/1" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "", + "targetPurpose": 1 + } + } + } + }, + { + "restart": true, + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + }, + "enqueuedLimboDocs": [ + ] + } + }, + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + } + ] + }, + "Existence filter handled at global snapshot": { + "describeName": "Existence Filters:", + "itName": "Existence filter handled at global snapshot", + "tags": [ + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "keys": [ + "collection/1", + "collection/2" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 3 + }, + "version": 3000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 3 + }, + "version": 3000 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "", + "targetPurpose": 1 + } + } + } + }, + { + "watchRemove": { + "targetIds": [ + 2 + ] + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 + }, + { + "createTime": 0, + "key": "collection/3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 3 + }, + "version": 3000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-3000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 3000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + } + ] + }, + "Existence filter ignored with pending target": { + "describeName": "Existence Filters:", + "itName": "Existence filter ignored with pending target", + "tags": [ + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": false + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "userUnlisten": [ + 2, + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "expectedState": { + "activeTargets": { + } + } + }, + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "resume-token-1000" + } + } + } + }, + { + "watchFilter": { + "keys": [ + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchRemove": { + "targetIds": [ + 2 + ] + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-2000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + } + ] + }, + "Existence filter limbo resolution is denied": { + "describeName": "Existence Filters:", + "itName": "Existence filter limbo resolution is denied", + "tags": [ + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "keys": [ + "collection/1" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "", + "targetPurpose": 1 + } + } + } + }, + { + "watchRemove": { + "targetIds": [ + 2 + ] + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-2000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedState": { + "activeLimboDocs": [ + "collection/2" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/2" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "", + "targetPurpose": 1 + } + } + } + }, + { + "watchRemove": { + "cause": { + "code": 7 + }, + "targetIds": [ + 1 + ] + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "removed": [ + { + "createTime": 0, + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ] + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "", + "targetPurpose": 1 + } + } + } + } + ] + }, + "Existence filter match": { + "describeName": "Existence Filters:", + "itName": "Existence filter match", + "tags": [ + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "keys": [ + "collection/1" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + } + } + ] + }, + "Existence filter match after pending update": { + "describeName": "Existence Filters:", + "itName": "Existence filter match after pending update", + "tags": [ + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchFilter": { + "keys": [ + "collection/1" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 2000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + } + ] + }, + "Existence filter mismatch triggers re-run of query": { + "describeName": "Existence Filters:", + "itName": "Existence filter mismatch triggers re-run of query", + "tags": [ + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "keys": [ + "collection/1" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "", + "targetPurpose": 1 + } + } + } + }, + { + "watchRemove": { + "targetIds": [ + 2 + ] + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-2000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedState": { + "activeLimboDocs": [ + "collection/2" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/2" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "", + "targetPurpose": 1 + } + } + } + }, + { + "watchAck": [ + 1 + ] + }, + { + "watchCurrent": [ + [ + 1 + ], + "resume-token-2000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "removed": [ + { + "createTime": 0, + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ] + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "", + "targetPurpose": 1 + } + } + } + } + ] + }, + "Existence filter mismatch will drop resume token": { + "describeName": "Existence Filters:", + "itName": "Existence filter mismatch will drop resume token", + "tags": [ + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 }, { "createTime": 0, - "key": "collection/3", + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "existence-filter-resume-token" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchStreamClose": { + "error": { + "code": 14, + "message": "Simulated Backend Error" + }, + "runBackoffTimer": true + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "existence-filter-resume-token" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchFilter": { + "keys": [ + "collection/1" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "", + "targetPurpose": 1 + } + } + } + }, + { + "watchRemove": { + "targetIds": [ + 2 + ] + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/1", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 3 + "v": 1 }, - "version": 3000 + "version": 1000 } ], "targets": [ @@ -513,18 +6131,81 @@ [ 2 ], - "resume-token-3000" + "resume-token-2000" ] }, { "watchSnapshot": { "targetIds": [ ], - "version": 3000 + "version": 2000 + }, + "expectedState": { + "activeLimboDocs": [ + "collection/2" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/2" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "", + "targetPurpose": 1 + } + } + } + }, + { + "watchAck": [ + 1 + ] + }, + { + "watchCurrent": [ + [ + 1 + ], + "resume-token-2000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 }, "expectedSnapshotEvents": [ { - "added": [ + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "removed": [ { "createTime": 0, "key": "collection/2", @@ -535,32 +6216,41 @@ "value": { "v": 2 }, - "version": 2000 + "version": 1000 } - ], - "errorCode": 0, - "fromCache": false, - "hasPendingWrites": false, - "query": { - "filters": [ - ], - "orderBys": [ + ] + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } ], - "path": "collection" + "resumeToken": "", + "targetPurpose": 1 } } - ] + } } ] }, - "Existence filter ignored with pending target": { + "Existence filter synthesizes deletes": { "describeName": "Existence Filters:", - "itName": "Existence filter ignored with pending target", + "itName": "Existence filter synthesizes deletes", "tags": [ ], "config": { "numClients": 1, - "useEagerGCForMemory": false + "useEagerGCForMemory": true }, "steps": [ { @@ -570,7 +6260,7 @@ ], "orderBys": [ ], - "path": "collection" + "path": "collection/a" }, "targetId": 2 }, @@ -583,7 +6273,7 @@ ], "orderBys": [ ], - "path": "collection" + "path": "collection/a" } ], "resumeToken": "" @@ -601,15 +6291,15 @@ "docs": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, - "version": 2000 + "version": 1000 } ], "targets": [ @@ -636,15 +6326,15 @@ "added": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, - "version": 2000 + "version": 1000 } ], "errorCode": 0, @@ -655,66 +6345,78 @@ ], "orderBys": [ ], - "path": "collection" + "path": "collection/a" } } ] }, { - "userUnlisten": [ - 2, - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } - ], - "expectedState": { - "activeTargets": { - } + "watchFilter": { + "keys": [ + ], + "targetIds": [ + 2 + ] } }, { - "userListen": { - "query": { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - }, - "targetId": 2 + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 }, "expectedSnapshotEvents": [ { - "added": [ + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/a" + }, + "removed": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, - "version": 2000 + "version": 1000 } - ], - "errorCode": 0, - "fromCache": true, - "hasPendingWrites": false, - "query": { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } + ] } - ], + ] + } + ] + }, + "Existence filter with empty target": { + "describeName": "Existence Filters:", + "itName": "Existence filter with empty target", + "tags": [ + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, "expectedState": { "activeTargets": { "2": { @@ -727,39 +6429,54 @@ "path": "collection" } ], - "resumeToken": "resume-token-1000" + "resumeToken": "" } } } }, { - "watchFilter": { - "keys": [ - ], - "targetIds": [ - 2 - ] - } + "watchAck": [ + 2 + ] }, { - "watchRemove": { - "targetIds": [ + "watchCurrent": [ + [ 2 - ] - } + ], + "resume-token-1000" + ] }, { - "watchAck": [ - 2 + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } ] }, { - "watchCurrent": [ - [ - 2 + "watchFilter": { + "keys": [ + "collection/1" ], - "resume-token-2000" - ] + "targetIds": [ + 2 + ] + } }, { "watchSnapshot": { @@ -770,7 +6487,7 @@ "expectedSnapshotEvents": [ { "errorCode": 0, - "fromCache": false, + "fromCache": true, "hasPendingWrites": false, "query": { "filters": [ @@ -780,14 +6497,33 @@ "path": "collection" } } - ] + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "", + "targetPurpose": 1 + } + } + } } ] }, - "Existence filter limbo resolution is denied": { + "Full re-query is skipped when bloom filter can identify documents deleted": { "describeName": "Existence Filters:", - "itName": "Existence filter limbo resolution is denied", + "itName": "Full re-query is skipped when bloom filter can identify documents deleted", "tags": [ + "no-ios", + "no-android" ], "config": { "numClients": 1, @@ -832,7 +6568,7 @@ "docs": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -844,7 +6580,7 @@ }, { "createTime": 0, - "key": "collection/2", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -879,7 +6615,7 @@ "added": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -891,7 +6627,7 @@ }, { "createTime": 0, - "key": "collection/2", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -917,8 +6653,15 @@ }, { "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "AhAAApAAAIAEBIAABA==", + "padding": 4 + }, + "hashCount": 10 + }, "keys": [ - "collection/1" + "collection/a" ], "targetIds": [ 2 @@ -946,7 +6689,23 @@ } ], "expectedState": { + "activeLimboDocs": [ + "collection/b" + ], "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/b" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, "2": { "queries": [ { @@ -957,49 +6716,20 @@ "path": "collection" } ], - "resumeToken": "", - "targetPurpose": 1 + "resumeToken": "" } } } }, - { - "watchRemove": { - "targetIds": [ - 2 - ] - } - }, { "watchAck": [ - 2 + 1 ] }, - { - "watchEntity": { - "docs": [ - { - "createTime": 0, - "key": "collection/1", - "options": { - "hasCommittedMutations": false, - "hasLocalMutations": false - }, - "value": { - "v": 1 - }, - "version": 1000 - } - ], - "targets": [ - 2 - ] - } - }, { "watchCurrent": [ [ - 2 + 1 ], "resume-token-2000" ] @@ -1010,49 +6740,6 @@ ], "version": 2000 }, - "expectedState": { - "activeLimboDocs": [ - "collection/2" - ], - "activeTargets": { - "1": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection/2" - } - ], - "resumeToken": "", - "targetPurpose": 2 - }, - "2": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } - ], - "resumeToken": "", - "targetPurpose": 1 - } - } - } - }, - { - "watchRemove": { - "cause": { - "code": 7 - }, - "targetIds": [ - 1 - ] - }, "expectedSnapshotEvents": [ { "errorCode": 0, @@ -1068,7 +6755,7 @@ "removed": [ { "createTime": 0, - "key": "collection/2", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1095,18 +6782,19 @@ "path": "collection" } ], - "resumeToken": "", - "targetPurpose": 1 + "resumeToken": "" } } } } ] }, - "Existence filter match": { + "Full re-query is triggered when bloom filter bitmap is invalid": { "describeName": "Existence Filters:", - "itName": "Existence filter match", + "itName": "Full re-query is triggered when bloom filter bitmap is invalid", "tags": [ + "no-ios", + "no-android" ], "config": { "numClients": 1, @@ -1150,128 +6838,35 @@ "watchEntity": { "docs": [ { - "createTime": 0, - "key": "collection/1", - "options": { - "hasCommittedMutations": false, - "hasLocalMutations": false - }, - "value": { - "v": 1 - }, - "version": 1000 - } - ], - "targets": [ - 2 - ] - } - }, - { - "watchCurrent": [ - [ - 2 - ], - "resume-token-1000" - ] - }, - { - "watchSnapshot": { - "targetIds": [ - ], - "version": 1000 - }, - "expectedSnapshotEvents": [ - { - "added": [ - { - "createTime": 0, - "key": "collection/1", - "options": { - "hasCommittedMutations": false, - "hasLocalMutations": false - }, - "value": { - "v": 1 - }, - "version": 1000 - } - ], - "errorCode": 0, - "fromCache": false, - "hasPendingWrites": false, - "query": { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } - } - ] - }, - { - "watchFilter": { - "keys": [ - "collection/1" - ], - "targetIds": [ - 2 - ] - } - }, - { - "watchSnapshot": { - "targetIds": [ - ], - "version": 2000 - } - } - ] - }, - "Existence filter match after pending update": { - "describeName": "Existence Filters:", - "itName": "Existence filter match after pending update", - "tags": [ - ], - "config": { - "numClients": 1, - "useEagerGCForMemory": true - }, - "steps": [ - { - "userListen": { - "query": { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - }, - "targetId": 2 - }, - "expectedState": { - "activeTargets": { - "2": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } - ], - "resumeToken": "" + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 } - } + ], + "targets": [ + 2 + ] } }, - { - "watchAck": [ - 2 - ] - }, { "watchCurrent": [ [ @@ -1284,10 +6879,36 @@ "watchSnapshot": { "targetIds": [ ], - "version": 2000 + "version": 1000 }, "expectedSnapshotEvents": [ { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + } + ], "errorCode": 0, "fromCache": false, "hasPendingWrites": false, @@ -1301,31 +6922,17 @@ } ] }, - { - "watchEntity": { - "docs": [ - { - "createTime": 0, - "key": "collection/1", - "options": { - "hasCommittedMutations": false, - "hasLocalMutations": false - }, - "value": { - "v": 2 - }, - "version": 2000 - } - ], - "targets": [ - 2 - ] - } - }, { "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "INVALID_BASE_64", + "padding": 4 + }, + "hashCount": 10 + }, "keys": [ - "collection/1" + "collection/a" ], "targetIds": [ 2 @@ -1340,22 +6947,8 @@ }, "expectedSnapshotEvents": [ { - "added": [ - { - "createTime": 0, - "key": "collection/1", - "options": { - "hasCommittedMutations": false, - "hasLocalMutations": false - }, - "value": { - "v": 2 - }, - "version": 2000 - } - ], "errorCode": 0, - "fromCache": false, + "fromCache": true, "hasPendingWrites": false, "query": { "filters": [ @@ -1365,14 +6958,33 @@ "path": "collection" } } - ] + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "", + "targetPurpose": 1 + } + } + } } ] }, - "Existence filter mismatch triggers re-run of query": { + "Full re-query is triggered when bloom filter can not identify documents deleted": { "describeName": "Existence Filters:", - "itName": "Existence filter mismatch triggers re-run of query", + "itName": "Full re-query is triggered when bloom filter can not identify documents deleted", "tags": [ + "no-ios", + "no-android" ], "config": { "numClients": 1, @@ -1417,7 +7029,7 @@ "docs": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1429,7 +7041,19 @@ }, { "createTime": 0, - "key": "collection/2", + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/c", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1464,7 +7088,7 @@ "added": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1476,7 +7100,19 @@ }, { "createTime": 0, - "key": "collection/2", + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/c", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1502,8 +7138,15 @@ }, { "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "AxBIApBIAIAWBoCQBA==", + "padding": 4 + }, + "hashCount": 10 + }, "keys": [ - "collection/1" + "collection/a" ], "targetIds": [ 2 @@ -1543,16 +7186,51 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": 2 } } } - }, + } + ] + }, + "Full re-query is triggered when bloom filter hashCount is invalid": { + "describeName": "Existence Filters:", + "itName": "Full re-query is triggered when bloom filter hashCount is invalid", + "tags": [ + "no-ios", + "no-android" + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ { - "watchRemove": { - "targetIds": [ - 2 - ] + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } } }, { @@ -1565,7 +7243,19 @@ "docs": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1577,108 +7267,103 @@ } ], "targets": [ - 2 - ] - } - }, - { - "watchCurrent": [ - [ - 2 - ], - "resume-token-2000" - ] - }, - { - "watchSnapshot": { - "targetIds": [ - ], - "version": 2000 - }, - "expectedState": { - "activeLimboDocs": [ - "collection/2" - ], - "activeTargets": { - "1": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection/2" - } - ], - "resumeToken": "", - "targetPurpose": 2 - }, - "2": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } - ], - "resumeToken": "", - "targetPurpose": 1 - } - } + 2 + ] } }, - { - "watchAck": [ - 1 - ] - }, { "watchCurrent": [ [ - 1 + 2 ], - "resume-token-2000" + "resume-token-1000" ] }, { "watchSnapshot": { "targetIds": [ ], - "version": 2000 + "version": 1000 }, "expectedSnapshotEvents": [ { - "errorCode": 0, - "fromCache": false, - "hasPendingWrites": false, - "query": { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - }, - "removed": [ + "added": [ { "createTime": 0, - "key": "collection/2", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 }, "version": 1000 } - ] + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "AhAAApAAAIAEBIAABA==", + "padding": 4 + }, + "hashCount": -1 + }, + "keys": [ + "collection/a" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } } ], "expectedState": { - "activeLimboDocs": [ - ], "activeTargets": { "2": { "queries": [ @@ -1698,10 +7383,12 @@ } ] }, - "Existence filter mismatch will drop resume token": { + "Full re-query is triggered when bloom filter is empty": { "describeName": "Existence Filters:", - "itName": "Existence filter mismatch will drop resume token", + "itName": "Full re-query is triggered when bloom filter is empty", "tags": [ + "no-ios", + "no-android" ], "config": { "numClients": 1, @@ -1746,7 +7433,7 @@ "docs": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1758,13 +7445,13 @@ }, { "createTime": 0, - "key": "collection/2", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, "version": 1000 } @@ -1779,7 +7466,7 @@ [ 2 ], - "existence-filter-resume-token" + "resume-token-1000" ] }, { @@ -1793,7 +7480,7 @@ "added": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1805,13 +7492,13 @@ }, { "createTime": 0, - "key": "collection/2", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 2 + "v": 1 }, "version": 1000 } @@ -1829,40 +7516,17 @@ } ] }, - { - "watchStreamClose": { - "error": { - "code": 14, - "message": "Simulated Backend Error" - }, - "runBackoffTimer": true - }, - "expectedState": { - "activeTargets": { - "2": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } - ], - "resumeToken": "existence-filter-resume-token" - } - } - } - }, - { - "watchAck": [ - 2 - ] - }, { "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "", + "padding": 0 + }, + "hashCount": 0 + }, "keys": [ - "collection/1" + "collection/a" ], "targetIds": [ 2 @@ -1906,12 +7570,57 @@ } } } - }, + } + ] + }, + "Same documents can have different bloom filters": { + "describeName": "Existence Filters:", + "itName": "Same documents can have different bloom filters", + "tags": [ + "no-ios", + "no-android" + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ { - "watchRemove": { - "targetIds": [ - 2 - ] + "userListen": { + "query": { + "filters": [ + [ + "v", + "<=", + 2 + ] + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + [ + "v", + "<=", + 2 + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } } }, { @@ -1924,7 +7633,7 @@ "docs": [ { "createTime": 0, - "key": "collection/1", + "key": "collection/a", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -1933,6 +7642,18 @@ "v": 1 }, "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 } ], "targets": [ @@ -1945,84 +7666,83 @@ [ 2 ], - "resume-token-2000" - ] - }, - { - "watchSnapshot": { - "targetIds": [ - ], - "version": 2000 - }, - "expectedState": { - "activeLimboDocs": [ - "collection/2" - ], - "activeTargets": { - "1": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection/2" - } - ], - "resumeToken": "", - "targetPurpose": 2 - }, - "2": { - "queries": [ - { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - } - ], - "resumeToken": "", - "targetPurpose": 1 - } - } - } - }, - { - "watchAck": [ - 1 - ] - }, - { - "watchCurrent": [ - [ - 1 - ], - "resume-token-2000" + "resume-token-1000" ] }, { "watchSnapshot": { "targetIds": [ ], - "version": 2000 + "version": 1000 }, "expectedSnapshotEvents": [ { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 1 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 2 + }, + "version": 1000 + } + ], "errorCode": 0, "fromCache": false, "hasPendingWrites": false, "query": { "filters": [ + [ + "v", + "<=", + 2 + ] ], "orderBys": [ ], "path": "collection" - }, - "removed": [ + } + } + ] + }, + { + "userListen": { + "query": { + "filters": [ + [ + "v", + ">=", + 2 + ] + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 4 + }, + "expectedSnapshotEvents": [ + { + "added": [ { "createTime": 0, - "key": "collection/2", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false @@ -2032,62 +7752,56 @@ }, "version": 1000 } - ] + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + [ + "v", + ">=", + 2 + ] + ], + "orderBys": [ + ], + "path": "collection" + } } ], "expectedState": { - "activeLimboDocs": [ - ], "activeTargets": { "2": { "queries": [ { "filters": [ + [ + "v", + "<=", + 2 + ] ], "orderBys": [ ], "path": "collection" } ], - "resumeToken": "", - "targetPurpose": 1 - } - } - } - } - ] - }, - "Existence filter synthesizes deletes": { - "describeName": "Existence Filters:", - "itName": "Existence filter synthesizes deletes", - "tags": [ - ], - "config": { - "numClients": 1, - "useEagerGCForMemory": true - }, - "steps": [ - { - "userListen": { - "query": { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection/a" - }, - "targetId": 2 - }, - "expectedState": { - "activeTargets": { - "2": { + "resumeToken": "" + }, + "4": { "queries": [ { "filters": [ + [ + "v", + ">=", + 2 + ] ], "orderBys": [ ], - "path": "collection/a" + "path": "collection" } ], "resumeToken": "" @@ -2097,7 +7811,7 @@ }, { "watchAck": [ - 2 + 4 ] }, { @@ -2105,48 +7819,60 @@ "docs": [ { "createTime": 0, - "key": "collection/a", + "key": "collection/b", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 1 + "v": 2 + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/c", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "v": 3 }, "version": 1000 } ], "targets": [ - 2 + 4 ] } }, { "watchCurrent": [ [ - 2 + 4 ], - "resume-token-1000" + "resume-token-1001" ] }, { "watchSnapshot": { "targetIds": [ ], - "version": 1000 + "version": 1001 }, "expectedSnapshotEvents": [ { "added": [ { "createTime": 0, - "key": "collection/a", + "key": "collection/c", "options": { "hasCommittedMutations": false, "hasLocalMutations": false }, "value": { - "v": 1 + "v": 3 }, "version": 1000 } @@ -2156,17 +7882,30 @@ "hasPendingWrites": false, "query": { "filters": [ + [ + "v", + ">=", + 2 + ] ], "orderBys": [ ], - "path": "collection/a" + "path": "collection" } } ] }, { "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "CQ==", + "padding": 3 + }, + "hashCount": 2 + }, "keys": [ + "collection/b" ], "targetIds": [ 2 @@ -2182,61 +7921,49 @@ "expectedSnapshotEvents": [ { "errorCode": 0, - "fromCache": false, + "fromCache": true, "hasPendingWrites": false, "query": { "filters": [ + [ + "v", + "<=", + 2 + ] ], "orderBys": [ ], - "path": "collection/a" - }, - "removed": [ - { - "createTime": 0, - "key": "collection/a", - "options": { - "hasCommittedMutations": false, - "hasLocalMutations": false - }, - "value": { - "v": 1 - }, - "version": 1000 - } - ] + "path": "collection" + } } - ] - } - ] - }, - "Existence filter with empty target": { - "describeName": "Existence Filters:", - "itName": "Existence filter with empty target", - "tags": [ - ], - "config": { - "numClients": 1, - "useEagerGCForMemory": true - }, - "steps": [ - { - "userListen": { - "query": { - "filters": [ - ], - "orderBys": [ - ], - "path": "collection" - }, - "targetId": 2 - }, + ], "expectedState": { + "activeLimboDocs": [ + "collection/a" + ], "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/a" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, "2": { "queries": [ { "filters": [ + [ + "v", + "<=", + 2 + ] ], "orderBys": [ ], @@ -2244,51 +7971,41 @@ } ], "resumeToken": "" - } - } - } - }, - { - "watchAck": [ - 2 - ] - }, - { - "watchCurrent": [ - [ - 2 - ], - "resume-token-1000" - ] - }, - { - "watchSnapshot": { - "targetIds": [ - ], - "version": 2000 - }, - "expectedSnapshotEvents": [ - { - "errorCode": 0, - "fromCache": false, - "hasPendingWrites": false, - "query": { - "filters": [ - ], - "orderBys": [ + }, + "4": { + "queries": [ + { + "filters": [ + [ + "v", + ">=", + 2 + ] + ], + "orderBys": [ + ], + "path": "collection" + } ], - "path": "collection" + "resumeToken": "" } } - ] + } }, { "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "CA==", + "padding": 4 + }, + "hashCount": 1 + }, "keys": [ - "collection/1" + "collection/b" ], "targetIds": [ - 2 + 4 ] } }, @@ -2296,7 +8013,7 @@ "watchSnapshot": { "targetIds": [ ], - "version": 2000 + "version": 3000 }, "expectedSnapshotEvents": [ { @@ -2305,6 +8022,11 @@ "hasPendingWrites": false, "query": { "filters": [ + [ + "v", + ">=", + 2 + ] ], "orderBys": [ ], @@ -2313,19 +8035,70 @@ } ], "expectedState": { + "activeLimboDocs": [ + "collection/a", + "collection/c" + ], "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/a" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, "2": { "queries": [ { "filters": [ + [ + "v", + "<=", + 2 + ] ], "orderBys": [ ], "path": "collection" } ], + "resumeToken": "" + }, + "3": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/c" + } + ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": 3 + }, + "4": { + "queries": [ + { + "filters": [ + [ + "v", + ">=", + 2 + ] + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" } } } diff --git a/firebase-firestore/src/test/resources/json/limbo_spec_test.json b/firebase-firestore/src/test/resources/json/limbo_spec_test.json index 8172a189689..f28e5809478 100644 --- a/firebase-firestore/src/test/resources/json/limbo_spec_test.json +++ b/firebase-firestore/src/test/resources/json/limbo_spec_test.json @@ -238,7 +238,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -284,7 +284,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -411,7 +411,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -495,7 +495,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -578,7 +578,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -682,7 +682,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "10": { "queries": [ @@ -782,7 +782,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "10": { "queries": [ @@ -873,7 +873,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -947,7 +947,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -1212,7 +1212,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -1258,7 +1258,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -1385,7 +1385,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -1469,7 +1469,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -1552,7 +1552,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -1656,7 +1656,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "10": { "queries": [ @@ -1756,7 +1756,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "10": { "queries": [ @@ -2055,7 +2055,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -2141,7 +2141,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -2224,7 +2224,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -2442,7 +2442,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -2862,7 +2862,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -3152,7 +3152,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -3422,7 +3422,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -3672,7 +3672,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -3965,7 +3965,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -4081,7 +4081,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -4345,7 +4345,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -4697,7 +4697,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -5082,7 +5082,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -5173,7 +5173,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -5553,7 +5553,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -5578,7 +5578,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } } } @@ -5690,7 +5690,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -5715,7 +5715,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } } } @@ -5770,7 +5770,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } } } @@ -5890,7 +5890,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } } } @@ -6332,7 +6332,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -6870,7 +6870,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -7203,7 +7203,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -7288,7 +7288,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -7618,7 +7618,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -7643,7 +7643,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -7754,7 +7754,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "7": { "queries": [ @@ -7767,7 +7767,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -7875,7 +7875,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -7952,6 +7952,402 @@ } ] }, + "Limbo resolution throttling with bloom filter application": { + "describeName": "Limbo Documents:", + "itName": "Limbo resolution throttling with bloom filter application", + "tags": [ + "no-ios", + "no-android" + ], + "config": { + "maxConcurrentLimboResolutions": 2, + "numClients": 1, + "useEagerGCForMemory": true + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/a1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a1" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/a2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a2" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/a3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a3" + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/a1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a1" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/a2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a2" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/a3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a3" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "enableNetwork": false, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + }, + "enqueuedLimboDocs": [ + ] + } + }, + { + "enableNetwork": true, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "resume-token-1000" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/b1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b1" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b2" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b3" + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchFilter": { + "bloomFilter": { + "bits": { + "bitmap": "yABCEAeZURNRGAkgAQ==", + "padding": 4 + }, + "hashCount": 10 + }, + "keys": [ + "collection/b1", + "collection/b2", + "collection/b3" + ], + "targetIds": [ + 2 + ] + } + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1001 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/b1", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b1" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b2", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b2" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b3", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b3" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1002" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1002 + }, + "expectedState": { + "activeLimboDocs": [ + "collection/a1", + "collection/a2" + ], + "activeTargets": { + "1": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/a1" + } + ], + "resumeToken": "", + "targetPurpose": 3 + }, + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "resume-token-1000" + }, + "3": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection/a2" + } + ], + "resumeToken": "", + "targetPurpose": 3 + } + }, + "enqueuedLimboDocs": [ + "collection/a3" + ] + } + } + ] + }, "Limbo resolution throttling with existence filter mismatch": { "describeName": "Limbo Documents:", "itName": "Limbo resolution throttling with existence filter mismatch", @@ -8378,7 +8774,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -8404,7 +8800,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -8513,7 +8909,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -8854,7 +9250,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -8879,7 +9275,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -8970,7 +9366,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "5": { "queries": [ @@ -8983,7 +9379,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -9068,7 +9464,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "7": { "queries": [ @@ -9081,7 +9477,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -9165,7 +9561,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "9": { "queries": [ @@ -9178,7 +9574,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -9260,7 +9656,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } }, "enqueuedLimboDocs": [ @@ -9642,7 +10038,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ diff --git a/firebase-firestore/src/test/resources/json/limit_spec_test.json b/firebase-firestore/src/test/resources/json/limit_spec_test.json index 257c53eeb4c..c6172e241fa 100644 --- a/firebase-firestore/src/test/resources/json/limit_spec_test.json +++ b/firebase-firestore/src/test/resources/json/limit_spec_test.json @@ -220,7 +220,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -4461,7 +4461,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -4488,7 +4488,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -4625,7 +4625,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -4650,7 +4650,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } } } @@ -4794,7 +4794,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "7": { "queries": [ @@ -4807,7 +4807,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } } } @@ -4950,7 +4950,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 } } } @@ -5449,7 +5449,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -5713,7 +5713,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ diff --git a/firebase-firestore/src/test/resources/json/listen_spec_test.json b/firebase-firestore/src/test/resources/json/listen_spec_test.json index 1537f3ccaad..adf88a62dca 100644 --- a/firebase-firestore/src/test/resources/json/listen_spec_test.json +++ b/firebase-firestore/src/test/resources/json/listen_spec_test.json @@ -3381,6 +3381,161 @@ } ] }, + "ExpectedCount in listen request should work after coming back online": { + "describeName": "Listens:", + "itName": "ExpectedCount in listen request should work after coming back online", + "tags": [ + "no-ios", + "no-android" + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": false + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "enableNetwork": false, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeLimboDocs": [ + ], + "activeTargets": { + }, + "enqueuedLimboDocs": [ + ] + } + }, + { + "enableNetwork": true, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "resume-token-1000" + } + } + } + } + ] + }, "Ignores update from inactive target": { "describeName": "Listens:", "itName": "Ignores update from inactive target", @@ -12587,6 +12742,536 @@ } ] }, + "Resuming a query should specify expectedCount that does not include pending mutations": { + "describeName": "Listens:", + "itName": "Resuming a query should specify expectedCount that does not include pending mutations", + "tags": [ + "no-ios", + "no-android" + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": false + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "userUnlisten": [ + 2, + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "expectedState": { + "activeTargets": { + } + } + }, + { + "userSet": [ + "collection/b", + { + "key": "b" + } + ] + }, + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": true + }, + "value": { + "key": "b" + }, + "version": 0 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": true, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "resume-token-1000" + } + } + } + } + ] + }, + "Resuming a query should specify expectedCount when adding the target": { + "describeName": "Listens:", + "itName": "Resuming a query should specify expectedCount when adding the target", + "tags": [ + "no-ios", + "no-android" + ], + "config": { + "numClients": 1, + "useEagerGCForMemory": false + }, + "steps": [ + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-1000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 1000 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "userUnlisten": [ + 2, + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "expectedState": { + "activeTargets": { + } + } + }, + { + "watchRemove": { + "targetIds": [ + 2 + ] + } + }, + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedSnapshotEvents": [ + { + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "resume-token-1000" + } + } + } + }, + { + "watchAck": [ + 2 + ] + }, + { + "watchEntity": { + "docs": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b" + }, + "version": 1000 + } + ], + "targets": [ + 2 + ] + } + }, + { + "watchCurrent": [ + [ + 2 + ], + "resume-token-2000" + ] + }, + { + "watchSnapshot": { + "targetIds": [ + ], + "version": 2000 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": false, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ] + }, + { + "userUnlisten": [ + 2, + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "expectedState": { + "activeTargets": { + } + } + }, + { + "userListen": { + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + }, + "targetId": 2 + }, + "expectedSnapshotEvents": [ + { + "added": [ + { + "createTime": 0, + "key": "collection/a", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "a" + }, + "version": 1000 + }, + { + "createTime": 0, + "key": "collection/b", + "options": { + "hasCommittedMutations": false, + "hasLocalMutations": false + }, + "value": { + "key": "b" + }, + "version": 1000 + } + ], + "errorCode": 0, + "fromCache": true, + "hasPendingWrites": false, + "query": { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + } + ], + "expectedState": { + "activeTargets": { + "2": { + "queries": [ + { + "filters": [ + ], + "orderBys": [ + ], + "path": "collection" + } + ], + "resumeToken": "resume-token-2000" + } + } + } + } + ] + }, "Secondary client advances query state with global snapshot from primary": { "describeName": "Listens:", "itName": "Secondary client advances query state with global snapshot from primary", diff --git a/firebase-firestore/src/test/resources/json/offline_spec_test.json b/firebase-firestore/src/test/resources/json/offline_spec_test.json index 5685ae1588e..e180f5f3198 100644 --- a/firebase-firestore/src/test/resources/json/offline_spec_test.json +++ b/firebase-firestore/src/test/resources/json/offline_spec_test.json @@ -1156,7 +1156,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ @@ -1194,7 +1194,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "2": { "queries": [ diff --git a/firebase-firestore/src/test/resources/json/recovery_spec_test.json b/firebase-firestore/src/test/resources/json/recovery_spec_test.json index 4b1f9401e1f..672bd161146 100644 --- a/firebase-firestore/src/test/resources/json/recovery_spec_test.json +++ b/firebase-firestore/src/test/resources/json/recovery_spec_test.json @@ -3133,7 +3133,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -3223,7 +3223,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -3613,7 +3613,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ @@ -3673,7 +3673,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": 3 }, "4": { "queries": [ From e1ac631e91f756cc49bc224bbfe20dc6539e8124 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Mon, 24 Apr 2023 20:02:55 -0400 Subject: [PATCH 17/22] regenerate spec tests json from js sdk --- .../test/resources/json/bundle_spec_test.json | 2 +- .../json/existence_filter_spec_test.json | 154 +++++++++--------- .../test/resources/json/limbo_spec_test.json | 128 +++++++-------- .../test/resources/json/limit_spec_test.json | 26 +-- .../resources/json/offline_spec_test.json | 4 +- .../resources/json/recovery_spec_test.json | 8 +- 6 files changed, 161 insertions(+), 161 deletions(-) diff --git a/firebase-firestore/src/test/resources/json/bundle_spec_test.json b/firebase-firestore/src/test/resources/json/bundle_spec_test.json index d3ccf3e7b2d..028895c50ac 100644 --- a/firebase-firestore/src/test/resources/json/bundle_spec_test.json +++ b/firebase-firestore/src/test/resources/json/bundle_spec_test.json @@ -1179,7 +1179,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ diff --git a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json index 24da8086f70..65da7e22375 100644 --- a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json +++ b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json @@ -185,7 +185,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -385,7 +385,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -613,7 +613,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -818,7 +818,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -3529,7 +3529,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "11": { "queries": [ @@ -3542,7 +3542,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "13": { "queries": [ @@ -3555,7 +3555,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "15": { "queries": [ @@ -3568,7 +3568,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "17": { "queries": [ @@ -3581,7 +3581,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "19": { "queries": [ @@ -3594,7 +3594,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -3619,7 +3619,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "23": { "queries": [ @@ -3632,7 +3632,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "25": { "queries": [ @@ -3645,7 +3645,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "27": { "queries": [ @@ -3658,7 +3658,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "29": { "queries": [ @@ -3671,7 +3671,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "3": { "queries": [ @@ -3684,7 +3684,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "31": { "queries": [ @@ -3697,7 +3697,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "33": { "queries": [ @@ -3710,7 +3710,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "35": { "queries": [ @@ -3723,7 +3723,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "37": { "queries": [ @@ -3736,7 +3736,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "39": { "queries": [ @@ -3749,7 +3749,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "41": { "queries": [ @@ -3762,7 +3762,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "43": { "queries": [ @@ -3775,7 +3775,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "45": { "queries": [ @@ -3788,7 +3788,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "47": { "queries": [ @@ -3801,7 +3801,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "49": { "queries": [ @@ -3814,7 +3814,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "5": { "queries": [ @@ -3827,7 +3827,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "51": { "queries": [ @@ -3840,7 +3840,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "53": { "queries": [ @@ -3853,7 +3853,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "55": { "queries": [ @@ -3866,7 +3866,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "57": { "queries": [ @@ -3879,7 +3879,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "59": { "queries": [ @@ -3892,7 +3892,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "61": { "queries": [ @@ -3905,7 +3905,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "63": { "queries": [ @@ -3918,7 +3918,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "65": { "queries": [ @@ -3931,7 +3931,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "67": { "queries": [ @@ -3944,7 +3944,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "69": { "queries": [ @@ -3957,7 +3957,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "7": { "queries": [ @@ -3970,7 +3970,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "71": { "queries": [ @@ -3983,7 +3983,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "73": { "queries": [ @@ -3996,7 +3996,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "75": { "queries": [ @@ -4009,7 +4009,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "77": { "queries": [ @@ -4022,7 +4022,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "79": { "queries": [ @@ -4035,7 +4035,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "81": { "queries": [ @@ -4048,7 +4048,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "83": { "queries": [ @@ -4061,7 +4061,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "85": { "queries": [ @@ -4074,7 +4074,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "87": { "queries": [ @@ -4087,7 +4087,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "89": { "queries": [ @@ -4100,7 +4100,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "9": { "queries": [ @@ -4113,7 +4113,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "91": { "queries": [ @@ -4126,7 +4126,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "93": { "queries": [ @@ -4139,7 +4139,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "95": { "queries": [ @@ -4152,7 +4152,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "97": { "queries": [ @@ -4165,7 +4165,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "99": { "queries": [ @@ -4178,7 +4178,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } } } @@ -4360,7 +4360,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -4632,7 +4632,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -5144,7 +5144,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -5212,7 +5212,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -5225,7 +5225,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -5282,7 +5282,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -5729,7 +5729,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -5797,7 +5797,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -5810,7 +5810,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -5877,7 +5877,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -6088,7 +6088,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -6156,7 +6156,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -6169,7 +6169,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -6236,7 +6236,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -6511,7 +6511,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -6704,7 +6704,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -6972,7 +6972,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -7186,7 +7186,7 @@ } ], "resumeToken": "", - "targetPurpose": 2 + "targetPurpose": "TargetPurposeExistenceFilterMismatchBloom" } } } @@ -7376,7 +7376,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -7566,7 +7566,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -7953,7 +7953,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -8051,7 +8051,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -8081,7 +8081,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ diff --git a/firebase-firestore/src/test/resources/json/limbo_spec_test.json b/firebase-firestore/src/test/resources/json/limbo_spec_test.json index f28e5809478..f8777f4dacd 100644 --- a/firebase-firestore/src/test/resources/json/limbo_spec_test.json +++ b/firebase-firestore/src/test/resources/json/limbo_spec_test.json @@ -238,7 +238,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -284,7 +284,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -411,7 +411,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -495,7 +495,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -578,7 +578,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -682,7 +682,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "10": { "queries": [ @@ -782,7 +782,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "10": { "queries": [ @@ -873,7 +873,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -947,7 +947,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -1212,7 +1212,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -1258,7 +1258,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -1385,7 +1385,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -1469,7 +1469,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -1552,7 +1552,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -1656,7 +1656,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "10": { "queries": [ @@ -1756,7 +1756,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "10": { "queries": [ @@ -2055,7 +2055,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -2141,7 +2141,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -2224,7 +2224,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -2442,7 +2442,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -2862,7 +2862,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -3152,7 +3152,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -3422,7 +3422,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -3672,7 +3672,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -3965,7 +3965,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -4081,7 +4081,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -4345,7 +4345,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -4697,7 +4697,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -5082,7 +5082,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -5173,7 +5173,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -5553,7 +5553,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -5578,7 +5578,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } } } @@ -5690,7 +5690,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -5715,7 +5715,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } } } @@ -5770,7 +5770,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } } } @@ -5890,7 +5890,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } } } @@ -6332,7 +6332,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -6870,7 +6870,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -7203,7 +7203,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -7288,7 +7288,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } }, "enqueuedLimboDocs": [ @@ -7618,7 +7618,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -7643,7 +7643,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } }, "enqueuedLimboDocs": [ @@ -7754,7 +7754,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "7": { "queries": [ @@ -7767,7 +7767,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } }, "enqueuedLimboDocs": [ @@ -7875,7 +7875,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } }, "enqueuedLimboDocs": [ @@ -8313,7 +8313,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -8338,7 +8338,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } }, "enqueuedLimboDocs": [ @@ -8681,7 +8681,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -8774,7 +8774,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -8787,7 +8787,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" }, "3": { "queries": [ @@ -8800,7 +8800,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } }, "enqueuedLimboDocs": [ @@ -8896,7 +8896,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" }, "5": { "queries": [ @@ -8909,7 +8909,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } }, "enqueuedLimboDocs": [ @@ -8978,7 +8978,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } }, "enqueuedLimboDocs": [ @@ -9250,7 +9250,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -9275,7 +9275,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } }, "enqueuedLimboDocs": [ @@ -9366,7 +9366,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "5": { "queries": [ @@ -9379,7 +9379,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } }, "enqueuedLimboDocs": [ @@ -9464,7 +9464,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "7": { "queries": [ @@ -9477,7 +9477,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } }, "enqueuedLimboDocs": [ @@ -9561,7 +9561,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "9": { "queries": [ @@ -9574,7 +9574,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } }, "enqueuedLimboDocs": [ @@ -9656,7 +9656,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } }, "enqueuedLimboDocs": [ @@ -10038,7 +10038,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ diff --git a/firebase-firestore/src/test/resources/json/limit_spec_test.json b/firebase-firestore/src/test/resources/json/limit_spec_test.json index c6172e241fa..fe1ed3c7c73 100644 --- a/firebase-firestore/src/test/resources/json/limit_spec_test.json +++ b/firebase-firestore/src/test/resources/json/limit_spec_test.json @@ -220,7 +220,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -4461,7 +4461,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -4488,7 +4488,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -4625,7 +4625,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -4650,7 +4650,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } } } @@ -4794,7 +4794,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "7": { "queries": [ @@ -4807,7 +4807,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } } } @@ -4950,7 +4950,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" } } } @@ -5449,7 +5449,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -5645,7 +5645,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -5713,7 +5713,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -5732,7 +5732,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } @@ -5825,7 +5825,7 @@ } ], "resumeToken": "", - "targetPurpose": 1 + "targetPurpose": "TargetPurposeExistenceFilterMismatch" } } } diff --git a/firebase-firestore/src/test/resources/json/offline_spec_test.json b/firebase-firestore/src/test/resources/json/offline_spec_test.json index e180f5f3198..c93ef8349d2 100644 --- a/firebase-firestore/src/test/resources/json/offline_spec_test.json +++ b/firebase-firestore/src/test/resources/json/offline_spec_test.json @@ -1156,7 +1156,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ @@ -1194,7 +1194,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "2": { "queries": [ diff --git a/firebase-firestore/src/test/resources/json/recovery_spec_test.json b/firebase-firestore/src/test/resources/json/recovery_spec_test.json index 672bd161146..0af9569b7a2 100644 --- a/firebase-firestore/src/test/resources/json/recovery_spec_test.json +++ b/firebase-firestore/src/test/resources/json/recovery_spec_test.json @@ -3133,7 +3133,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -3223,7 +3223,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -3613,7 +3613,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ @@ -3673,7 +3673,7 @@ } ], "resumeToken": "", - "targetPurpose": 3 + "targetPurpose": "TargetPurposeLimboResolution" }, "4": { "queries": [ From 766f99a7dd199fd41360165560077f1839201429 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Mon, 24 Apr 2023 20:13:28 -0400 Subject: [PATCH 18/22] SpecTestCase.java: update to handle `targetPurpose` as a string, not an integer --- .../google/firebase/firestore/spec/SpecTestCase.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java index 622261258ea..f30c5b30fff 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java @@ -421,15 +421,15 @@ private Query parseQuery(Object querySpec) throws JSONException { } private static QueryPurpose parseQueryPurpose(Object value) { - if (!(value instanceof Integer)) { + if (!(value instanceof String)) { throw new IllegalArgumentException("invalid query purpose: " + value); } - switch ((Integer) value) { - case 0: + switch ((String) value) { + case "TargetPurposeListen": return QueryPurpose.LISTEN; - case 1: + case "TargetPurposeExistenceFilterMismatch": return QueryPurpose.EXISTENCE_FILTER_MISMATCH; - case 3: + case "TargetPurposeLimboResolution": return QueryPurpose.LIMBO_RESOLUTION; default: throw new IllegalArgumentException("unknown query purpose value: " + value); From 2573baa55128bec2b714425801dd71e3fbfbe3f4 Mon Sep 17 00:00:00 2001 From: milaGGL <107142260+milaGGL@users.noreply.github.com> Date: Fri, 5 May 2023 10:14:54 -0400 Subject: [PATCH 19/22] Update CHANGELOG.md --- firebase-firestore/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firebase-firestore/CHANGELOG.md b/firebase-firestore/CHANGELOG.md index 4024baaca32..a1f9c4100ee 100644 --- a/firebase-firestore/CHANGELOG.md +++ b/firebase-firestore/CHANGELOG.md @@ -1,5 +1,5 @@ # Unreleased - +* [feature] Implemented an optimization in the local cache synchronization logic that reduces the number of billed document reads when documents were deleted on the server while the client was not actively listening to the query (e.g. while the client was offline). # 24.6.0 * [fixed] Fixed stack overflow caused by deeply nested server timestamps. From cc0428a6213869cde8fdc12a23cd85ac97023452 Mon Sep 17 00:00:00 2001 From: milaGGL <107142260+milaGGL@users.noreply.github.com> Date: Mon, 8 May 2023 10:33:29 -0400 Subject: [PATCH 20/22] update CHANGELOG + format --- firebase-firestore/CHANGELOG.md | 2 +- .../com/google/firebase/firestore/QueryTest.java | 15 +++++++-------- .../firestore/remote/TestingHooksUtil.java | 1 - 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/firebase-firestore/CHANGELOG.md b/firebase-firestore/CHANGELOG.md index a1f9c4100ee..5167c64ca2b 100644 --- a/firebase-firestore/CHANGELOG.md +++ b/firebase-firestore/CHANGELOG.md @@ -1,5 +1,5 @@ # Unreleased -* [feature] Implemented an optimization in the local cache synchronization logic that reduces the number of billed document reads when documents were deleted on the server while the client was not actively listening to the query (e.g. while the client was offline). +- [feature] Implemented an optimization in the local cache synchronization logic that reduces the number of billed document reads when documents were deleted on the server while the client was not actively listening to the query (e.g. while the client was offline). (GitHub [#4702](//github.com/firebase/firebase-android-sdk/pull/4982){: .external}) # 24.6.0 * [fixed] Fixed stack overflow caused by deeply nested server timestamps. diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java index feb29d93e18..745ac0be2e0 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/QueryTest.java @@ -50,7 +50,6 @@ import java.util.Map; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicReference; - import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; @@ -1092,11 +1091,11 @@ public void resumingAQueryShouldUseBloomFilterToAvoidFullRequery() throws Except // bloom filter, and it was used to avert a full requery. AtomicReference snapshot2Ref = new AtomicReference<>(); ArrayList existenceFilterMismatches = - captureExistenceFilterMismatches( - () -> { - QuerySnapshot querySnapshot = waitFor(collection.get()); - snapshot2Ref.set(querySnapshot); - }); + captureExistenceFilterMismatches( + () -> { + QuerySnapshot querySnapshot = waitFor(collection.get()); + snapshot2Ref.set(querySnapshot); + }); QuerySnapshot snapshot2 = snapshot2Ref.get(); // Verify that the snapshot from the resumed query contains the expected documents; that is, @@ -1132,8 +1131,8 @@ public void resumingAQueryShouldUseBloomFilterToAvoidFullRequery() throws Except // Verify that Watch sent an existence filter with the correct counts when the query was // resumed. assertWithMessage("Watch should have sent exactly 1 existence filter") - .that(existenceFilterMismatches) - .hasSize(1); + .that(existenceFilterMismatches) + .hasSize(1); ExistenceFilterMismatchInfo existenceFilterMismatchInfo = existenceFilterMismatches.get(0); assertWithMessage("localCacheCount") .that(existenceFilterMismatchInfo.localCacheCount()) diff --git a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/remote/TestingHooksUtil.java b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/remote/TestingHooksUtil.java index e2c408f44c3..2e8faa4dc4c 100644 --- a/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/remote/TestingHooksUtil.java +++ b/firebase-firestore/src/androidTest/java/com/google/firebase/firestore/remote/TestingHooksUtil.java @@ -16,7 +16,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; - import com.google.firebase.firestore.ListenerRegistration; import java.util.ArrayList; From d0849f42833d0602e524c4b176861a986d377393 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Mon, 8 May 2023 10:52:25 -0400 Subject: [PATCH 21/22] Random improvements. (#4986) --- .../firestore/remote/BloomFilter.java | 70 ++++++-- .../remote/BloomFilterException.java | 23 --- .../remote/WatchChangeAggregator.java | 7 +- .../firestore/remote/BloomFilterTest.java | 151 +++++++++++------- 4 files changed, 153 insertions(+), 98 deletions(-) delete mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java index e51a89906c7..4ba5a84cc5c 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java @@ -17,42 +17,82 @@ import android.util.Base64; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; +import com.google.protobuf.ByteString; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -public class BloomFilter { +public final class BloomFilter { private final int bitCount; - private final byte[] bitmap; + private final ByteString bitmap; private final int hashCount; private final MessageDigest md5HashMessageDigest; - public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount) { - if (bitmap == null) { - throw new NullPointerException("Bitmap cannot be null."); - } + /** + * Creates a new {@link BloomFilter} with the given parameters. + * + * @param bitmap the bitmap of the bloom filter; must not be null. + * @param padding the padding, in bits, of the last byte of the bloom filter; must be between 0 + * (zero) and 7, inclusive; must be 0 (zero) if {@code bitmap.length==0}. + * @param hashCount The number of hash functions to use; must be strictly greater than zero; may + * be 0 (zero) if and only if {@code bitmap.length==0}. + */ + public BloomFilter(@NonNull ByteString bitmap, int padding, int hashCount) { if (padding < 0 || padding >= 8) { - throw new BloomFilterException("Invalid padding: " + padding); + throw new IllegalArgumentException("Invalid padding: " + padding); } if (hashCount < 0) { - throw new BloomFilterException("Invalid hash count: " + hashCount); + throw new IllegalArgumentException("Invalid hash count: " + hashCount); } - if (bitmap.length > 0 && hashCount == 0) { + if (bitmap.size() > 0 && hashCount == 0) { // Only empty bloom filter can have 0 hash count. - throw new BloomFilterException("Invalid hash count: " + hashCount); + throw new IllegalArgumentException("Invalid hash count: " + hashCount); } - if (bitmap.length == 0 && padding != 0) { + if (bitmap.size() == 0 && padding != 0) { // Empty bloom filter should have 0 padding. - throw new BloomFilterException( + throw new IllegalArgumentException( "Expected padding of 0 when bitmap length is 0, but got " + padding); } this.bitmap = bitmap; this.hashCount = hashCount; - this.bitCount = bitmap.length * 8 - padding; + this.bitCount = bitmap.size() * 8 - padding; this.md5HashMessageDigest = createMd5HashMessageDigest(); } + /** + * Creates an instance of {@link BloomFilter} with the given arguments, throwing a well-defined + * exception if the given arguments do not satisfy the requirements documented in the {@link + * BloomFilter} constructor. + */ + public static BloomFilter create(@NonNull ByteString bitmap, int padding, int hashCount) + throws BloomFilterCreateException { + if (padding < 0 || padding >= 8) { + throw new BloomFilterCreateException("Invalid padding: " + padding); + } + if (hashCount < 0) { + throw new BloomFilterCreateException("Invalid hash count: " + hashCount); + } + if (bitmap.size() > 0 && hashCount == 0) { + // Only empty bloom filter can have 0 hash count. + throw new BloomFilterCreateException("Invalid hash count: " + hashCount); + } + if (bitmap.size() == 0 && padding != 0) { + // Empty bloom filter should have 0 padding. + throw new BloomFilterCreateException( + "Expected padding of 0 when bitmap length is 0, but got " + padding); + } + + return new BloomFilter(bitmap, padding, hashCount); + } + + /** Exception thrown by {@link #create} if the given arguments are not valid. */ + public static final class BloomFilterCreateException extends Exception { + public BloomFilterCreateException(String message) { + super(message); + } + } + @VisibleForTesting int getBitCount() { return this.bitCount; @@ -146,7 +186,7 @@ private static long unsignedRemainder(long dividend, long divisor) { /** Return whether the bit at the given index in the bitmap is set to 1. */ private boolean isBitSet(int index) { // To retrieve bit n, calculate: (bitmap[n / 8] & (0x01 << (n % 8))). - byte byteAtIndex = this.bitmap[index / 8]; + byte byteAtIndex = this.bitmap.byteAt(index / 8); int offset = index % 8; return (byteAtIndex & (0x01 << offset)) != 0; } @@ -159,7 +199,7 @@ public String toString() { + ", size=" + bitCount + ", bitmap=\"" - + Base64.encodeToString(bitmap, Base64.NO_WRAP) + + Base64.encodeToString(bitmap.toByteArray(), Base64.NO_WRAP) + "\"}"; } } diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java deleted file mode 100644 index 429b501ed47..00000000000 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.google.firebase.firestore.remote; - -import androidx.annotation.NonNull; - -public class BloomFilterException extends RuntimeException { - public BloomFilterException(@NonNull String detailMessage) { - super(detailMessage); - } -} diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java index b8056377e44..922f8bc2f55 100644 --- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java +++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java @@ -31,6 +31,7 @@ import com.google.firebase.firestore.remote.WatchChange.ExistenceFilterWatchChange; import com.google.firebase.firestore.remote.WatchChange.WatchTargetChange; import com.google.firebase.firestore.util.Logger; +import com.google.protobuf.ByteString; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -252,14 +253,14 @@ private BloomFilterApplicationStatus applyBloomFilter( return BloomFilterApplicationStatus.SKIPPED; } - byte[] bitmap = unchangedNames.getBits().getBitmap().toByteArray(); + ByteString bitmap = unchangedNames.getBits().getBitmap(); BloomFilter bloomFilter; try { bloomFilter = - new BloomFilter( + BloomFilter.create( bitmap, unchangedNames.getBits().getPadding(), unchangedNames.getHashCount()); - } catch (BloomFilterException e) { + } catch (BloomFilter.BloomFilterCreateException e) { Logger.warn( LOG_TAG, "Applying bloom filter failed: (" diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java index c2ba39c4d7f..0c82dcf5c46 100644 --- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java +++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; +import com.google.protobuf.ByteString; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStreamReader; @@ -42,98 +43,123 @@ public class BloomFilterTest { @Test public void instantiateEmptyBloomFilter() { - BloomFilter bloomFilter = new BloomFilter(new byte[0], 0, 0); + BloomFilter bloomFilter = new BloomFilter(ByteString.empty(), 0, 0); assertEquals(bloomFilter.getBitCount(), 0); } @Test public void instantiateNonEmptyBloomFilter() { { - BloomFilter bloomFilter1 = new BloomFilter(new byte[] {1}, 0, 1); - assertEquals(bloomFilter1.getBitCount(), 8); + BloomFilter bloomFilter = new BloomFilter(ByteString.copyFrom(new byte[] {1}), 0, 1); + assertEquals(bloomFilter.getBitCount(), 8); } { - BloomFilter bloomFilter2 = new BloomFilter(new byte[] {1}, 7, 1); - assertEquals(bloomFilter2.getBitCount(), 1); + BloomFilter bloomFilter = new BloomFilter(ByteString.copyFrom(new byte[] {1}), 7, 1); + assertEquals(bloomFilter.getBitCount(), 1); } } @Test public void constructorShouldThrowNPEOnNullBitmap() { + assertThrows(NullPointerException.class, () -> new BloomFilter(null, 0, 0)); + assertThrows(NullPointerException.class, () -> new BloomFilter(null, 1, 1)); + } + + @Test + public void createShouldCreateAnEmptyBloomFilter() throws Exception { + BloomFilter bloomFilter = BloomFilter.create(ByteString.empty(), 0, 0); + assertEquals(bloomFilter.getBitCount(), 0); + } + + @Test + public void createShouldCreatenNonEmptyBloomFilter() throws Exception { { - NullPointerException emptyBloomFilterException = - assertThrows(NullPointerException.class, () -> new BloomFilter(null, 0, 0)); - assertThat(emptyBloomFilterException).hasMessageThat().contains("Bitmap cannot be null."); + BloomFilter bloomFilter = BloomFilter.create(ByteString.copyFrom(new byte[] {1}), 0, 1); + assertEquals(bloomFilter.getBitCount(), 8); } { - NullPointerException nonEmptyBloomFilterException = - assertThrows(NullPointerException.class, () -> new BloomFilter(null, 1, 1)); - assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Bitmap cannot be null."); + BloomFilter bloomFilter = BloomFilter.create(ByteString.copyFrom(new byte[] {1}), 7, 1); + assertEquals(bloomFilter.getBitCount(), 1); } } @Test - public void constructorShouldThrowBFEOnEmptyBloomFilterWithNonZeroPadding() { - BloomFilterException exception = - assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[0], 1, 0)); - assertThat(exception) - .hasMessageThat() - .contains("Expected padding of 0 when bitmap length is 0, but got 1"); + public void createShouldThrowBFEOnEmptyBloomFilterWithNonZeroPadding() { + BloomFilter.BloomFilterCreateException exception = + assertThrows( + BloomFilter.BloomFilterCreateException.class, + () -> BloomFilter.create(ByteString.empty(), 1, 0)); + assertThat(exception).hasMessageThat().ignoringCase().contains("padding of 0"); + assertThat(exception).hasMessageThat().ignoringCase().contains("bitmap length is 0"); + assertThat(exception).hasMessageThat().ignoringCase().contains("got 1"); } @Test - public void constructorShouldThrowBFEOnNonEmptyBloomFilterWithZeroHashCount() { - BloomFilterException zeroHashCountException = - assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, 1, 0)); - assertThat(zeroHashCountException).hasMessageThat().contains("Invalid hash count: 0"); + public void createShouldThrowOnNonEmptyBloomFilterWithZeroHashCount() { + BloomFilter.BloomFilterCreateException exception = + assertThrows( + BloomFilter.BloomFilterCreateException.class, + () -> BloomFilter.create(ByteString.copyFrom(new byte[] {1}), 1, 0)); + assertThat(exception).hasMessageThat().ignoringCase().contains("hash count: 0"); } @Test - public void constructorShouldThrowBFEOnNegativePadding() { + public void createShouldThrowOnNegativePadding() { { - BloomFilterException emptyBloomFilterException = - assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[0], -1, 0)); - assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1"); + BloomFilter.BloomFilterCreateException exception = + assertThrows( + BloomFilter.BloomFilterCreateException.class, + () -> BloomFilter.create(ByteString.empty(), -1, 0)); + assertThat(exception).hasMessageThat().ignoringCase().contains("padding: -1"); } { - BloomFilterException nonEmptyBloomFilterException = - assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, -1, 1)); - assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1"); + BloomFilter.BloomFilterCreateException exception = + assertThrows( + BloomFilter.BloomFilterCreateException.class, + () -> BloomFilter.create(ByteString.copyFrom(new byte[] {1}), -1, 1)); + assertThat(exception).hasMessageThat().ignoringCase().contains("padding: -1"); } } @Test - public void constructorShouldThrowBFEOnNegativeHashCount() { + public void createShouldThrowOnNegativeHashCount() { { - BloomFilterException emptyBloomFilterException = - assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[0], 0, -1)); - assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1"); + BloomFilter.BloomFilterCreateException exception = + assertThrows( + BloomFilter.BloomFilterCreateException.class, + () -> BloomFilter.create(ByteString.empty(), 0, -1)); + assertThat(exception).hasMessageThat().ignoringCase().contains("hash count: -1"); } { - BloomFilterException nonEmptyBloomFilterException = - assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, 1, -1)); - assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1"); + BloomFilter.BloomFilterCreateException exception = + assertThrows( + BloomFilter.BloomFilterCreateException.class, + () -> BloomFilter.create(ByteString.copyFrom(new byte[] {1}), 1, -1)); + assertThat(exception).hasMessageThat().ignoringCase().contains("hash count: -1"); } } @Test - public void constructorShouldThrowBFEIfPaddingIsTooLarge() { - BloomFilterException exception = - assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, 8, 1)); - assertThat(exception).hasMessageThat().contains("Invalid padding: 8"); + public void createShouldThrowIfPaddingIsTooLarge() { + BloomFilter.BloomFilterCreateException exception = + assertThrows( + BloomFilter.BloomFilterCreateException.class, + () -> BloomFilter.create(ByteString.copyFrom(new byte[] {1}), 8, 1)); + assertThat(exception).hasMessageThat().ignoringCase().contains("padding: 8"); } @Test public void mightContainCanProcessNonStandardCharacters() { // A non-empty BloomFilter object with 1 insertion : "ÀÒ∑" - BloomFilter bloomFilter = new BloomFilter(new byte[] {(byte) 237, 5}, 5, 8); + BloomFilter bloomFilter = + new BloomFilter(ByteString.copyFrom(new byte[] {(byte) 237, 5}), 5, 8); assertTrue(bloomFilter.mightContain("ÀÒ∑")); assertFalse(bloomFilter.mightContain("Ò∑À")); } @Test public void mightContainOnEmptyBloomFilterShouldReturnFalse() { - BloomFilter bloomFilter = new BloomFilter(new byte[0], 0, 0); + BloomFilter bloomFilter = new BloomFilter(ByteString.empty(), 0, 0); assertFalse(bloomFilter.mightContain("")); assertFalse(bloomFilter.mightContain("a")); } @@ -141,26 +167,36 @@ public void mightContainOnEmptyBloomFilterShouldReturnFalse() { @Test public void mightContainWithEmptyStringMightReturnFalsePositiveResult() { { - BloomFilter bloomFilter1 = new BloomFilter(new byte[] {1}, 1, 1); - assertFalse(bloomFilter1.mightContain("")); + BloomFilter bloomFilter = new BloomFilter(ByteString.copyFrom(new byte[] {1}), 1, 1); + assertFalse(bloomFilter.mightContain("")); } { - BloomFilter bloomFilter2 = new BloomFilter(new byte[] {(byte) 255}, 0, 16); - assertTrue(bloomFilter2.mightContain("")); + BloomFilter bloomFilter = + new BloomFilter(ByteString.copyFrom(new byte[] {(byte) 255}), 0, 16); + assertTrue(bloomFilter.mightContain("")); } } @Test - public void bloomFilterToString() { - { - BloomFilter emptyBloomFilter = new BloomFilter(new byte[0], 0, 0); - assertEquals(emptyBloomFilter.toString(), "BloomFilter{hashCount=0, size=0, bitmap=\"\"}"); - } - { - BloomFilter nonEmptyBloomFilter = new BloomFilter(new byte[] {1}, 1, 1); - assertEquals( - nonEmptyBloomFilter.toString(), "BloomFilter{hashCount=1, size=7, bitmap=\"AQ==\"}"); - } + public void toStringOnEmptyBitmap() { + String toStringResult = new BloomFilter(ByteString.empty(), 0, 0).toString(); + assertThat(toStringResult).startsWith("BloomFilter{"); + assertThat(toStringResult).endsWith("}"); + assertThat(toStringResult).contains("hashCount=0"); + assertThat(toStringResult).contains("size=0"); + assertThat(toStringResult).contains("bitmap=\"\""); + } + + @Test + public void toStringOnNonEmptyBitmap() { + String toStringResult = + new BloomFilter(ByteString.copyFrom(new byte[] {0x01, (byte) 0xAE, (byte) 0xFF}), 3, 7) + .toString(); + assertThat(toStringResult).startsWith("BloomFilter{"); + assertThat(toStringResult).endsWith("}"); + assertThat(toStringResult).contains("hashCount=7"); + assertThat(toStringResult).contains("size=21"); + assertThat(toStringResult).contains("bitmap=\"Aa7/\""); } /** @@ -177,7 +213,7 @@ public void bloomFilterToString() { private static void runGoldenTest(String testFile) throws Exception { String resultFile = testFile.replace("bloom_filter_proto", "membership_test_result"); if (resultFile.equals(testFile)) { - throw new BloomFilterException("Cannot find corresponding result file for " + testFile); + throw new IllegalArgumentException("Cannot find corresponding result file for " + testFile); } JSONObject testJson = readJsonFile(testFile); @@ -188,7 +224,8 @@ private static void runGoldenTest(String testFile) throws Exception { int padding = bits.getInt("padding"); int hashCount = testJson.getInt("hashCount"); BloomFilter bloomFilter = - new BloomFilter(Base64.getDecoder().decode(bitmap), padding, hashCount); + BloomFilter.create( + ByteString.copyFrom(Base64.getDecoder().decode(bitmap)), padding, hashCount); String membershipTestResults = resultJSON.getString("membershipTestResults"); From d9a59e22b577c7ca8a426943a770a9bdeb8a91cb Mon Sep 17 00:00:00 2001 From: milaGGL <107142260+milaGGL@users.noreply.github.com> Date: Mon, 8 May 2023 13:19:19 -0400 Subject: [PATCH 22/22] Update CHANGELOG.md --- firebase-firestore/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firebase-firestore/CHANGELOG.md b/firebase-firestore/CHANGELOG.md index 5167c64ca2b..04ccfd9489c 100644 --- a/firebase-firestore/CHANGELOG.md +++ b/firebase-firestore/CHANGELOG.md @@ -1,5 +1,5 @@ # Unreleased -- [feature] Implemented an optimization in the local cache synchronization logic that reduces the number of billed document reads when documents were deleted on the server while the client was not actively listening to the query (e.g. while the client was offline). (GitHub [#4702](//github.com/firebase/firebase-android-sdk/pull/4982){: .external}) +- [feature] Implemented an optimization in the local cache synchronization logic that reduces the number of billed document reads when documents were deleted on the server while the client was not actively listening to the query (e.g. while the client was offline). (GitHub [#4982](//github.com/firebase/firebase-android-sdk/pull/4982){: .external}) # 24.6.0 * [fixed] Fixed stack overflow caused by deeply nested server timestamps.