Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: sort strings in UTF-8 encoded byte order with lazy encoding #8787

Open
wants to merge 16 commits into
base: main
Choose a base branch
from

Conversation

milaGGL
Copy link
Contributor

@milaGGL milaGGL commented Feb 11, 2025

Strings should be sorted in UTF-8 encoded byte order. Public document: https://cloud.google.com/firestore/docs/concepts/data-types#data_types

SDK sorts strings using built in comparator method, which sorts lexicographically, and leads to mismatch between server and sdk when special characters are present. This PR fixes the string order mismatches on document field, map key, and document key.

The previous fix added created a performance issue due to expensive UTF-8 encoding and reverted, #8774, #8778. compareUtf8Strings is updated to use lazy encoding instead.

b/329441702

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Feb 11, 2025

Size Report 1

Affected Products

  • @firebase/analytics

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?21.8 kB? (?)
    main?23.1 kB? (?)
    module?21.8 kB? (?)
  • @firebase/analytics-compat

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?2.57 kB? (?)
    main?3.01 kB? (?)
    module?2.57 kB? (?)
  • @firebase/api-documenter

    TypeBase (a24a76a)Merge (0c24573)Diff
    main?3.95 kB? (?)
  • @firebase/app

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?19.5 kB? (?)
    main?20.4 kB? (?)
    module?19.5 kB? (?)
  • @firebase/app-check

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?26.4 kB? (?)
    main?27.4 kB? (?)
    module?26.4 kB? (?)
  • @firebase/app-check-compat

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?2.27 kB? (?)
    main?2.74 kB? (?)
    module?2.27 kB? (?)
  • @firebase/app-compat

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?5.33 kB? (?)
    lite?4.06 kB? (?)
    main?5.90 kB? (?)
    module?5.33 kB? (?)
  • @firebase/auth

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?189 kB? (?)
    cordova?164 kB? (?)
    main?146 kB? (?)
    module?189 kB? (?)
    react-native?164 kB? (?)
  • @firebase/auth-compat

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?20.2 kB? (?)
    main?22.4 kB? (?)
    module?20.2 kB? (?)
  • @firebase/auth-cordova

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?164 kB? (?)
    module?164 kB? (?)
  • @firebase/auth-web-extension

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?141 kB? (?)
    main?158 kB? (?)
    module?141 kB? (?)
  • @firebase/auth/internal

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?200 kB? (?)
    main?172 kB? (?)
    module?200 kB? (?)
  • @firebase/component

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?6.54 kB? (?)
    main?6.87 kB? (?)
    module?6.54 kB? (?)
  • @firebase/data-connect

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?21.1 kB? (?)
    main?23.1 kB? (?)
    module?21.1 kB? (?)
  • @firebase/database

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?249 kB? (?)
    main?254 kB? (?)
    module?249 kB? (?)
  • @firebase/database-compat

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?18.3 kB? (?)
    main?18.9 kB? (?)
    module?18.3 kB? (?)
  • @firebase/database-compat/standalone

    TypeBase (a24a76a)Merge (0c24573)Diff
    main?366 kB? (?)
  • @firebase/firestore

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?381 kB? (?)
    main?590 kB? (?)
    module?381 kB? (?)
    react-native?381 kB? (?)
  • @firebase/firestore-compat

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?20.6 kB? (?)
    main?21.0 kB? (?)
    module?20.6 kB? (?)
    react-native?20.6 kB? (?)
  • @firebase/firestore-lite

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?113 kB? (?)
    main?155 kB? (?)
    module?113 kB? (?)
    react-native?113 kB? (?)
  • @firebase/functions

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?14.0 kB? (?)
    main?14.6 kB? (?)
    module?14.0 kB? (?)
  • @firebase/functions-compat

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?1.79 kB? (?)
    main?2.12 kB? (?)
    module?1.79 kB? (?)
  • @firebase/installations

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?17.8 kB? (?)
    main?18.3 kB? (?)
    module?17.8 kB? (?)
  • @firebase/installations-compat

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?945 B? (?)
    main?1.27 kB? (?)
    module?945 B? (?)
  • @firebase/logger

    TypeBase (a24a76a)Merge (0c24573)Diff
    main?3.83 kB? (?)
    module?3.25 kB? (?)
  • @firebase/messaging

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?22.0 kB? (?)
    main?22.4 kB? (?)
    module?22.0 kB? (?)
  • @firebase/messaging-compat

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?2.08 kB? (?)
    main?2.43 kB? (?)
    module?2.08 kB? (?)
  • @firebase/messaging-sw

    TypeBase (a24a76a)Merge (0c24573)Diff
    main?24.1 kB? (?)
    module?23.5 kB? (?)
  • @firebase/performance

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?30.6 kB? (?)
    main?31.1 kB? (?)
    module?30.6 kB? (?)
  • @firebase/performance-compat

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?1.10 kB? (?)
    main?1.42 kB? (?)
    module?1.10 kB? (?)
  • @firebase/remote-config

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?23.2 kB? (?)
    main?24.4 kB? (?)
    module?23.2 kB? (?)
  • @firebase/remote-config-compat

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?1.85 kB? (?)
    main?2.18 kB? (?)
    module?1.85 kB? (?)
  • @firebase/rules-unit-testing

    TypeBase (a24a76a)Merge (0c24573)Diff
    main?12.3 kB? (?)
  • @firebase/storage

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?58.0 kB? (?)
    main?59.4 kB? (?)
    module?58.0 kB? (?)
  • @firebase/storage-compat

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?5.67 kB? (?)
    main?6.05 kB? (?)
    module?5.67 kB? (?)
  • @firebase/util

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?23.3 kB? (?)
    main?29.3 kB? (?)
    module?23.3 kB? (?)
  • @firebase/vertexai

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?34.2 kB? (?)
    main?35.2 kB? (?)
    module?34.2 kB? (?)
  • @firebase/webchannel-wrapper

    TypeBase (a24a76a)Merge (0c24573)Diff
    main?38 B? (?)
  • @firebase/webchannel-wrapper/bloom-blob

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?11.1 kB? (?)
    main?11.1 kB? (?)
    module?11.1 kB? (?)
  • @firebase/webchannel-wrapper/webchannel-blob

    TypeBase (a24a76a)Merge (0c24573)Diff
    browser?42.2 kB? (?)
    main?42.2 kB? (?)
    module?42.2 kB? (?)
  • bundle

    46 size changes

    TypeBase (a24a76a)Merge (0c24573)Diff
    analytics (logEvent)?44.7 kB? (?)
    app-check (CustomProvider)?37.6 kB? (?)
    app-check (ReCaptchaEnterpriseProvider)?40.1 kB? (?)
    app-check (ReCaptchaV3Provider)?40.0 kB? (?)
    auth (Anonymous)?76.7 kB? (?)
    auth (EmailAndPassword)?86.8 kB? (?)
    auth (GoogleFBTwitterGitHubPopup)?104 kB? (?)
    auth (GooglePopup)?101 kB? (?)
    auth (GoogleRedirect)?101 kB? (?)
    auth (Phone)?94.2 kB? (?)
    database (Append to a list of data)?150 kB? (?)
    database (Filtering data)?149 kB? (?)
    database (Listen for child events)?165 kB? (?)
    database (Listen for value events + Detach listeners)?165 kB? (?)
    database (Listen for value events)?165 kB? (?)
    database (Read data once)?164 kB? (?)
    database (Save data as transactions)?167 kB? (?)
    database (Sort data)?150 kB? (?)
    database (Write data)?149 kB? (?)
    firestore (CSI Auto Indexing Disable and Delete)?272 kB? (?)
    firestore (CSI Auto Indexing Enable)?272 kB? (?)
    firestore (Persistence)?303 kB? (?)
    firestore (Query Cursors)?250 kB? (?)
    firestore (Query)?248 kB? (?)
    firestore (Read data once)?236 kB? (?)
    firestore (Read Write w Persistence)?328 kB? (?)
    firestore (Realtime updates)?238 kB? (?)
    firestore (Transaction)?215 kB? (?)
    firestore (Write data)?214 kB? (?)
    firestore-lite (Query Cursors)?104 kB? (?)
    firestore-lite (Query)?99.9 kB? (?)
    firestore-lite (Read data once)?75.4 kB? (?)
    firestore-lite (Transaction)?101 kB? (?)
    firestore-lite (Write data)?85.0 kB? (?)
    functions (call)?34.8 kB? (?)
    messaging (send + receive)?47.5 kB? (?)
    performance (trace)?62.4 kB? (?)
    remote-config (getAndFetch)?48.8 kB? (?)
    storage (getBytes)?42.4 kB? (?)
    storage (getDownloadURL)?44.5 kB? (?)
    storage (getMetadata)?44.0 kB? (?)
    storage (list + listAll)?43.4 kB? (?)
    storage (updateMetadata)?44.2 kB? (?)
    storage (uploadBytes)?49.1 kB? (?)
    storage (uploadBytesResumable)?59.0 kB? (?)
    storage (uploadString)?49.3 kB? (?)

  • firebase

    32 size changes

    TypeBase (a24a76a)Merge (0c24573)Diff
    firebase-analytics-compat.js?25.7 kB? (?)
    firebase-analytics.js?29.7 kB? (?)
    firebase-app-check-compat.js?22.7 kB? (?)
    firebase-app-check.js?25.0 kB? (?)
    firebase-app-compat.js?31.8 kB? (?)
    firebase-app.js?103 kB? (?)
    firebase-auth-compat.js?140 kB? (?)
    firebase-auth-cordova.js?137 kB? (?)
    firebase-auth-web-extension.js?119 kB? (?)
    firebase-auth.js?155 kB? (?)
    firebase-compat.js?793 kB? (?)
    firebase-data-connect.js?17.3 kB? (?)
    firebase-database-compat.js?164 kB? (?)
    firebase-database.js?187 kB? (?)
    firebase-firestore-compat.js?339 kB? (?)
    firebase-firestore-lite.js?131 kB? (?)
    firebase-firestore.js?440 kB? (?)
    firebase-functions-compat.js?10.4 kB? (?)
    firebase-functions.js?14.8 kB? (?)
    firebase-installations-compat.js?12.9 kB? (?)
    firebase-installations.js?15.2 kB? (?)
    firebase-messaging-compat.js?37.0 kB? (?)
    firebase-messaging-sw.js?30.1 kB? (?)
    firebase-messaging.js?29.1 kB? (?)
    firebase-performance-compat.js?40.0 kB? (?)
    firebase-performance-standalone-compat.js?105 kB? (?)
    firebase-performance.js?45.5 kB? (?)
    firebase-remote-config-compat.js?28.3 kB? (?)
    firebase-remote-config.js?32.7 kB? (?)
    firebase-storage-compat.js?39.7 kB? (?)
    firebase-storage.js?46.3 kB? (?)
    firebase-vertexai.js?27.8 kB? (?)

  • functions

    TypeBase (a24a76a)Merge (0c24573)Diff
    main?46 B? (?)

Test Logs

  1. https://storage.googleapis.com/firebase-sdk-metric-reports/4Ay38uO1Ze.html

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Feb 11, 2025

Size Analysis Report 1

This report is too large (575,697 characters) to be displayed here in a GitHub comment. Please use the below link to see the full report on Google Cloud Storage.

Test Logs

  1. https://storage.googleapis.com/firebase-sdk-metric-reports/S2nrkEDB0O.html

@milaGGL milaGGL changed the title Fix: change the compareUtf8Strings to lazy encoding Fix: sort strings in UTF-8 encoded byte order with lazy encoding Feb 11, 2025
Copy link

changeset-bot bot commented Feb 11, 2025

🦋 Changeset detected

Latest commit: 9174b34

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@firebase/firestore Patch
firebase Patch
@firebase/firestore-compat Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@milaGGL milaGGL requested a review from a team as a code owner February 19, 2025 15:17
@milaGGL milaGGL requested a review from dconeybe February 20, 2025 21:27
Comment on lines 96 to 105
for (
let j = 0;
j < Math.min(leftBytes.length, rightBytes.length);
j++
) {
const comp = primitiveComparator(leftBytes[j], rightBytes[j]);
if (comp !== 0) {
return comp;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

IIUC we're having this loop because we can't use Buffer.from(...) in the browser (outside of Node). If leftBytes.length is not equal to rightBytes.length and the first Math.min(...) bytes do match, then this loop won't return a comparison. So the code falls through to the primitiveComparator (line 112) way more often than it should.

  • can we use the compareBlobs function?
  • if not, can you take this loop out of here and make a helper function that compares 2 Uint8Arrays byte by byte and also considers the length of them?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we cannot import compareBlobs as it would create circular dependency due to the ByteString.

@milaGGL milaGGL requested a review from ehsannas February 27, 2025 17:09
@ehsannas ehsannas removed their assignment Feb 27, 2025
@milaGGL milaGGL requested a review from ehsannas March 3, 2025 16:16
@milaGGL milaGGL assigned ehsannas and unassigned milaGGL Mar 3, 2025
Copy link
Contributor

@ehsannas ehsannas left a comment

Choose a reason for hiding this comment

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

LGTM. Please check the GitHub Actions failures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants