Skip to content

Use ObjectMap instead of Map with proper comparator. #6018

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

Merged
merged 5 commits into from
Feb 28, 2022

Conversation

ehsannas
Copy link
Contributor

I used Map and Set in PR #5969, but these data structures use reference comparison for the keys instead of using the object's comparator function. This PR fixes this by using ObjectMap and SortedSet.

@changeset-bot
Copy link

changeset-bot bot commented Feb 18, 2022

⚠️ No Changeset found

Latest commit: 428c432

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Feb 18, 2022

Size Report 1

Affected Products

  • @firebase/app

    TypeBase (c8907fa)Merge (4c53ff5)Diff
    browser7.74 kB13.9 kB+6.16 kB (+79.6%)
    esm59.37 kB18.8 kB+9.40 kB (+100.3%)
    main10.2 kB19.7 kB+9.54 kB (+93.4%)
    module7.74 kB13.9 kB+6.16 kB (+79.6%)
  • @firebase/firestore

    TypeBase (c8907fa)Merge (4c53ff5)Diff
    browser244 kB251 kB+6.88 kB (+2.8%)
    esm5304 kB312 kB+7.82 kB (+2.6%)
    main487 kB501 kB+14.0 kB (+2.9%)
    module244 kB251 kB+6.88 kB (+2.8%)
    react-native244 kB251 kB+6.88 kB (+2.8%)
  • @firebase/firestore-lite

    TypeBase (c8907fa)Merge (4c53ff5)Diff
    browser73.0 kB73.1 kB+137 B (+0.2%)
    esm586.4 kB86.5 kB+137 B (+0.2%)
    main125 kB126 kB+116 B (+0.1%)
    module73.0 kB73.1 kB+137 B (+0.2%)
    react-native73.2 kB73.3 kB+137 B (+0.2%)
  • @firebase/messaging-sw

    TypeBase (c8907fa)Merge (4c53ff5)Diff
    main29.5 kB29.6 kB+84 B (+0.3%)
    module22.8 kB22.8 kB+6 B (+0.0%)
  • bundle

    43 size changes

    TypeBase (c8907fa)Merge (4c53ff5)Diff
    analytics (logEvent)34.7 kB41.8 kB+7.10 kB (+20.5%)
    app-check (CustomProvider)27.4 kB35.7 kB+8.26 kB (+30.2%)
    app-check (ReCaptchaEnterpriseProvider)29.6 kB37.9 kB+8.26 kB (+27.9%)
    app-check (ReCaptchaV3Provider)29.6 kB37.8 kB+8.26 kB (+27.9%)
    auth (Anonymous)56.9 kB65.3 kB+8.32 kB (+14.6%)
    auth (EmailAndPassword)61.0 kB69.3 kB+8.32 kB (+13.6%)
    auth (GoogleFBTwitterGitHubPopup)80.8 kB89.1 kB+8.32 kB (+10.3%)
    auth (GooglePopup)80.5 kB88.9 kB+8.32 kB (+10.3%)
    auth (GoogleRedirect)80.7 kB89.1 kB+8.32 kB (+10.3%)
    auth (Phone)67.0 kB75.3 kB+8.32 kB (+12.4%)
    database (Append to a list of data)137 kB146 kB+8.29 kB (+6.0%)
    database (Filtering data)136 kB144 kB+8.29 kB (+6.1%)
    database (Listen for child events)152 kB160 kB+8.29 kB (+5.4%)
    database (Listen for value events + Detach listeners)152 kB160 kB+8.29 kB (+5.4%)
    database (Listen for value events)152 kB160 kB+8.29 kB (+5.5%)
    database (Read data once)144 kB152 kB+8.29 kB (+5.8%)
    database (Save data as transactions)154 kB162 kB+8.29 kB (+5.4%)
    database (Sort data)138 kB146 kB+8.29 kB (+6.0%)
    database (Write data)136 kB145 kB+8.29 kB (+6.1%)
    firestore (Persistence)245 kB263 kB+18.3 kB (+7.5%)
    firestore (Query Cursors)192 kB203 kB+11.7 kB (+6.1%)
    firestore (Query)193 kB204 kB+11.7 kB (+6.1%)
    firestore (Read data once)181 kB193 kB+11.7 kB (+6.4%)
    firestore (Realtime updates)183 kB195 kB+11.7 kB (+6.4%)
    firestore (Transaction)166 kB178 kB+11.7 kB (+7.0%)
    firestore (Write data)165 kB177 kB+11.7 kB (+7.1%)
    firestore-lite (Query Cursors)56.8 kB68.3 kB+11.4 kB (+20.1%)
    firestore-lite (Query)59.9 kB71.3 kB+11.5 kB (+19.1%)
    firestore-lite (Read data once)44.4 kB55.8 kB+11.4 kB (+25.8%)
    firestore-lite (Transaction)61.7 kB73.1 kB+11.4 kB (+18.5%)
    firestore-lite (Write data)47.2 kB58.6 kB+11.4 kB (+24.2%)
    functions (call)18.3 kB29.6 kB+11.3 kB (+62.0%)
    messaging (send + receive)37.8 kB44.9 kB+7.10 kB (+18.8%)
    performance (trace)42.3 kB49.4 kB+7.10 kB (+16.8%)
    remote-config (getAndFetch)36.7 kB44.1 kB+7.47 kB (+20.4%)
    storage (getBytes)26.6 kB37.9 kB+11.3 kB (+42.5%)
    storage (getDownloadURL)28.7 kB40.0 kB+11.3 kB (+39.5%)
    storage (getMetadata)28.1 kB39.4 kB+11.3 kB (+40.2%)
    storage (list + listAll)27.5 kB38.9 kB+11.3 kB (+41.1%)
    storage (updateMetadata)28.4 kB39.7 kB+11.3 kB (+39.9%)
    storage (uploadBytes)32.9 kB44.3 kB+11.3 kB (+34.4%)
    storage (uploadBytesResumable)42.4 kB53.7 kB+11.3 kB (+26.7%)
    storage (uploadString)33.1 kB44.5 kB+11.3 kB (+34.1%)

  • firebase

    TypeBase (c8907fa)Merge (4c53ff5)Diff
    firebase-app-compat.js17.9 kB28.2 kB+10.3 kB (+57.6%)
    firebase-app.js51.4 kB84.2 kB+32.7 kB (+63.6%)
    firebase-compat.js769 kB779 kB+10.6 kB (+1.4%)
    firebase-firestore-compat.js296 kB303 kB+6.85 kB (+2.3%)
    firebase-firestore-lite.js250 kB250 kB+457 B (+0.2%)
    firebase-firestore.js812 kB836 kB+23.7 kB (+2.9%)
    firebase-messaging-compat.js37.9 kB38.0 kB+6 B (+0.0%)
    firebase-messaging-sw.js102 kB102 kB+6 B (+0.0%)
    firebase-performance-standalone-compat.es2017.js78.9 kB87.5 kB+8.60 kB (+10.9%)
    firebase-performance-standalone-compat.js57.0 kB65.7 kB+8.66 kB (+15.2%)

Test Logs

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

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Feb 18, 2022

Size Analysis Report 1

This report is too large (836,786 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/9wp4fIg8MX.html

import { DocumentKeySet } from '../model/collections';
import {
DocumentKeySet,
DocumentKeyToMutationMap,
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not a huge fan of the names... could these just be MutationMap and OverlayMap? Less precise but a little more compact. Feel free to push back.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that sounds fine. The one thing that I'm thinking about is that there are these existing type definitions:

export type DocumentMap = SortedMap<DocumentKey, Document>;
export type MutableDocumentMap = SortedMap<DocumentKey, MutableDocument>;

and the new ones I've added are:

export type OverlayMap = ObjectMap<DocumentKey, Overlay>;
export type MutationMap = ObjectMap<DocumentKey, Mutation>;

I wonder if I should use SortedMap to be consistent with those two existing types.
e.g.
for a DocumentMap, one should do documentMap = documentMap.insert(...)
for a MutationMap, one should do mutationMap.set(...) (it's a void function).

Having said that, the key->overlay map and key->mutation map don't need to be sorted, so using a SortedMap for them would waste some cpu cycles to keep them sorted for no reason. I'd guess that SortedMap's performance is non-negligibly slower than ObjectMap as it also has to return a new copy of the map every time there's an addition/deletion.

Was there a specific reason that we chose to use SortedMap for DocumentMap and MutableDocumentMap ? Do they really need to stay sorted?

(also Ideally they should have been called SortedDocumentMap and SortedMutableDocumentMap).

Copy link
Contributor

Choose a reason for hiding this comment

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

The sorted maps are actually pretty expensive - they are not only immutable and create new copies, but they are backed by a red/black tree so most operations are O(log n). I would steer away from them unless needed. I do think that this advice also applies to most existing usages of DocumentMap and MutableDocumentMap - and they probably do not need to be sorted in most places (but they do in some - e.g. code similar to the one here https://github.com/firebase/firebase-js-sdk/blob/master/packages/firestore/src/local/indexeddb_remote_document_cache.ts#L232).

So what this means is that I think we should go with the more concise names OverlayMap and MutationMap and then separately audit the use of DocumentMap and MutableDocumentMap/

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good. I'll file an issue to audit uses of DocumentMap and MutableDocumentMap.

@@ -110,4 +110,8 @@ export class ObjectMap<KeyType, ValueType> {
isEmpty(): boolean {
return isEmpty(this.inner);
}

size(): number {
return objectSize(this.inner);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is pretty expensive and will turn into an O(n) scan for every Overlay that we return. Can we track the size manually?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@github-actions
Copy link
Contributor

github-actions bot commented Feb 23, 2022

Changeset File Check ✅

  • No modified packages are missing from the changeset file.
  • No changeset formatting errors detected.

@ehsannas ehsannas removed their assignment Feb 23, 2022
@ehsannas
Copy link
Contributor Author

@schmidt-sebastian PTAL

@@ -47,6 +50,22 @@ export function documentMap(): DocumentMap {
return EMPTY_DOCUMENT_MAP;
}

export type OverlayMap = ObjectMap<DocumentKey, Overlay>;
export function newDocumentKeyToOverlayMap(): OverlayMap {
Copy link
Contributor

Choose a reason for hiding this comment

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

newOverlayMap

}

export type MutationMap = ObjectMap<DocumentKey, Mutation>;
export function newDocumentKeyToMutationMap(): MutationMap {
Copy link
Contributor

Choose a reason for hiding this comment

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

newMutationMap

@ehsannas ehsannas merged commit 09e6243 into master Feb 28, 2022
@ehsannas ehsannas deleted the ehsann/use-objmap-for-overlays branch February 28, 2022 17:26
@firebase firebase locked and limited conversation to collaborators Mar 31, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants