Skip to content

Implement BundleCache for IDB and memory. #3170

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 21 commits into from
Jun 14, 2020

Conversation

wu-hui
Copy link
Contributor

@wu-hui wu-hui commented Jun 5, 2020

No description provided.

@wu-hui wu-hui changed the base branch from wuandy/Bundles to wuandy/BundleReaderNode June 5, 2020 15:17
@wu-hui wu-hui requested a review from schmidt-sebastian June 5, 2020 15:17
Copy link
Contributor

@schmidt-sebastian schmidt-sebastian left a comment

Choose a reason for hiding this comment

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

This looks great! Some nits and one general question: Do we have a story for how to validate the actual JSON contents? We may want to validate the bundle data that we read from the user before writing it to persistence.

export interface Bundle {
readonly id: string;
readonly version: number;
// When the saved bundle is built from the server SDKs.
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you point out in the documentation that this is to SnapshotVersion.MIN if the above is not true? In its current form, the comment raises the question why the type is not nullable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am not sure what do you mean here, sorry!

Copy link
Contributor

Choose a reason for hiding this comment

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

Something like:

Set to the snapshot version of the bundle if created by the Server SDKs. Otherwise set to SnapshotVersion.MIN.

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.

): PersistencePromise<Bundle | undefined>;

/**
* Saves a `BundleMetadata` from a bundle into local storage, using its id as the persistent key.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Wrap at 80 characters.

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.

.get(bundleId)
.next(bundle => {
if (bundle) {
return this.serializer.fromDbBundle(bundle!);
Copy link
Contributor

Choose a reason for hiding this comment

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

You should be able to drop the bang.

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.

.get(queryName)
.next(query => {
if (query) {
return this.serializer.fromDbNamedQuery(query!);
Copy link
Contributor

Choose a reason for hiding this comment

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

You should be able to drop the bang.

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.

version: metadata.version!,
createTime: this.remoteSerializer.fromVersion(metadata.createTime!)
};
}
Copy link
Contributor

@schmidt-sebastian schmidt-sebastian Jun 8, 2020

Choose a reason for hiding this comment

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

Ideally, we should not add any more code to the main SDK for "optional" features. Do you mind exploring what it would entail to make these functions free-standing? They would then look like:

function fromBundleMetadata(serializer: RemoteSerializer, metadata: bundleProto.BundleMetadata): Bundle {
    return {
      id: metadata.id!,
      version: metadata.version!,
      createTime: serializer.fromVersion(metadata.createTime!)
    };
  }

If you have to make a ton of state public, you can look at what we did here:

class DatastoreImpl extends Datastore {

DatastoreImp has public state, but in itself is private.

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.

@wu-hui wu-hui changed the base branch from wuandy/BundleReaderNode to wuandy/Bundles June 10, 2020 18:34
Copy link
Contributor Author

@wu-hui wu-hui left a comment

Choose a reason for hiding this comment

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

As discussed offline, validation will be added in future PRs, when I implement bundle loading.

): PersistencePromise<Bundle | undefined>;

/**
* Saves a `BundleMetadata` from a bundle into local storage, using its id as the persistent key.
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.

.get(bundleId)
.next(bundle => {
if (bundle) {
return this.serializer.fromDbBundle(bundle!);
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.

.get(queryName)
.next(query => {
if (query) {
return this.serializer.fromDbNamedQuery(query!);
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.

version: metadata.version!,
createTime: this.remoteSerializer.fromVersion(metadata.createTime!)
};
}
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.

export interface Bundle {
readonly id: string;
readonly version: number;
// When the saved bundle is built from the server SDKs.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am not sure what do you mean here, sorry!

@wu-hui wu-hui changed the base branch from wuandy/Bundles to wuandy/BundleReaderNode June 11, 2020 00:56
@wu-hui wu-hui changed the base branch from wuandy/BundleReaderNode to wuandy/Bundles June 11, 2020 00:57
Copy link
Contributor

@schmidt-sebastian schmidt-sebastian left a comment

Choose a reason for hiding this comment

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

Some final nits, but looks great. Thanks for the updates!

export interface Bundle {
readonly id: string;
readonly version: number;
// When the saved bundle is built from the server SDKs.
Copy link
Contributor

Choose a reason for hiding this comment

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

Something like:

Set to the snapshot version of the bundle if created by the Server SDKs. Otherwise set to SnapshotVersion.MIN.

* @param source The data source to use.
* @param bytesPerRead How many bytes each `read()` from the returned reader
* will read. It is ignored if the passed in source does not provide
* such control(example: ReadableStream).
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing space before (.

Your indent also seems slightly off. We usually indent by four spaces (not 6), but I do see some counterexamples in our sources (both 6 and 0 exists, but 6 is an outlier).

}
throw new Error(
'Source of `toByteStreamReader` has to be Uint8Array, ArrayBuffer or ReadableStream'
'Source of `toByteStreamReader` has to be a ArrayBuffer or ReadableStream'
Copy link
Contributor

Choose a reason for hiding this comment

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

s/a/an/

}

/**
* Encodes a `BundledQuery` from bundle proto to a Query object.
Copy link
Contributor

Choose a reason for hiding this comment

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

s/from bundle/from a bundle/

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.

export interface NamedQuery {
readonly name: string;
readonly query: Query;
// When the results for this query are read to the saved bundle.
Copy link
Contributor

Choose a reason for hiding this comment

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

/** The time at which the results for this query were read. */

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.

bundledQuery: bundleProto.BundledQuery
): Query {
const query = serializer.remoteSerializer.convertQueryTargetToQuery({
parent: bundledQuery.parent!,
Copy link
Contributor

Choose a reason for hiding this comment

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

Did you file a bug to validate the bundle contents? As part of this we need to validate that the parent matches the Firestore project that we are loading the SDK into.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

b/158846981

return {
id: dbBundle.bundleId,
createTime: serializer.fromDbTimestamp(dbBundle.createTime),
version: dbBundle.version
Copy link
Contributor

Choose a reason for hiding this comment

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

What is our versioning strategy? I wonder if we should reject any bundle with a version greater than 1. If so, please file a bug.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

b/158845787

}

/** Encodes a BundleMetadata to a DbBundle. */
export function toDbBundle(
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't have an actual opinion, but I am a bit surprised that you moved this function out of the serializer file. I think it makes sense that even the free-standing functions are next to the main serializer, but I can also see why you moved them to. Just wanted to know whether you considered this?

No need to move 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.

Moved them back. I think putting them here also makes sense, but I don't feel strongly anyways.

import { expect } from 'chai';
import { IndexedDbPersistence } from '../../../src/local/indexeddb_persistence';
import { filter, orderBy, path } from '../../util/helpers';
import * as persistenceHelpers from './persistence_test_helpers';
Copy link
Contributor

Choose a reason for hiding this comment

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

In general, I would suggest to avoid namespace imports (import * as ).

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.

let persistence: IndexedDbPersistence;
beforeEach(async () => {
persistence = await persistenceHelpers.testIndexedDbPersistence({
synchronizeTabs: true
Copy link
Contributor

Choose a reason for hiding this comment

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

I would omit this setting. It poses questions as to why you added it here, but doesn't (yet) at much benefit - other than remind me that I forgot to reply to your question about multi-tab sync...

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.

@wu-hui wu-hui merged commit d3f0ab4 into wuandy/Bundles Jun 14, 2020
@firebase firebase locked and limited conversation to collaborators Jul 15, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants