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

Implement IndexedDB LRU Reference Delegate, add LRU tests #1224

Merged
merged 24 commits into from
Sep 19, 2018

Conversation

gsoltis
Copy link

@gsoltis gsoltis commented Sep 12, 2018

Adds:

  • LruGarbageCollector which implements the steps for LRU garbage collection
    • Includes a selective port of java.util.PriorityQueue
  • LruDelegate interface, which specifies what is needed for a persistence layer for LRU GC
  • ReferenceDelegate interface, which handles lifecycle hooks for document references and unreferences
    • Note that this is not yet wired up in most production code, as there is currently only a single implementation
  • IndexedDbLruDelegate, implements ReferenceDelegate and LruDelegate for IndexedDbPersistence
  • The LRU test suite
    • This currently only runs against IndexedDbPersistence, and as such contains a few casts that will be removed once the generic interfaces support the needed methods.

Android Port: https://github.com/FirebasePrivate/firebase-android-sdk/pull/190
iOS Port: firebase/firebase-ios-sdk#1600

@gsoltis
Copy link
Author

gsoltis commented Sep 12, 2018

Oops, lint errors. Will assign back shortly.

@gsoltis gsoltis assigned gsoltis and unassigned mikelehen Sep 12, 2018
@gsoltis gsoltis assigned mikelehen and unassigned gsoltis Sep 12, 2018
@gsoltis
Copy link
Author

gsoltis commented Sep 12, 2018

Ok, lint stuff fixed

Copy link
Contributor

@mikelehen mikelehen left a comment

Choose a reason for hiding this comment

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

I flagged a bunch of nits that you can push back on, and may have found one issue. Despite the amount of feedback (sorry), I think this generally looks good. :-)

packages/firestore/src/local/indexeddb_persistence.ts Outdated Show resolved Hide resolved
packages/firestore/src/local/indexeddb_persistence.ts Outdated Show resolved Hide resolved
packages/firestore/src/local/indexeddb_persistence.ts Outdated Show resolved Hide resolved
packages/firestore/src/local/indexeddb_persistence.ts Outdated Show resolved Hide resolved
packages/firestore/src/local/indexeddb_persistence.ts Outdated Show resolved Hide resolved
@mikelehen mikelehen assigned gsoltis and unassigned mikelehen Sep 14, 2018
@gsoltis gsoltis assigned mikelehen and unassigned gsoltis Sep 17, 2018
@gsoltis
Copy link
Author

gsoltis commented Sep 18, 2018

@mikelehen fyi, I'm also going to create an lru-master branch to merge this into, so the final merge to master will be one commit, like the other clients.

@gsoltis gsoltis changed the base branch from master to lru-master September 18, 2018 16:16
Copy link
Contributor

@mikelehen mikelehen left a comment

Choose a reason for hiding this comment

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

Thanks! A couple potential nits and I'm still concerned about SentinelRow / sentinelKeyStore() being defined as distinct from the TargetDocuments schema in indexeddb_schema.ts, but otherwise looking good.

packages/firestore/src/local/lru_garbage_collector.ts Outdated Show resolved Hide resolved
packages/firestore/src/local/indexeddb_persistence.ts Outdated Show resolved Hide resolved
packages/firestore/src/local/indexeddb_persistence.ts Outdated Show resolved Hide resolved
packages/firestore/src/local/lru_garbage_collector.ts Outdated Show resolved Hide resolved
});
return this.db.getQueryCache().updateQueryData(txn, updated);
getTargetCount(txn: PersistenceTransaction): PersistencePromise<number> {
return this.db.getQueryCache().getQueryCount(txn);
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you want to change this to getTargetCount() too, or is this a preexisting issue?

packages/firestore/src/local/persistence.ts Show resolved Hide resolved
index: DbTargetDocument.documentTargetsIndex
},
([targetId, docKey], { path, sequenceNumber }) => {
if (targetId === 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh! I assumed that only documents not belonging to a target would have a sentinel row. But I guess every document will have a sentinel row? Is the sequence number for a non-0 targetId row still meaningful? I assumed only the sequence number on the DbTarget row would matter if a document belongs to a target. Yes?

Anyway, I think these questions should be answered in comments in the code. And I think indexeddb_schema.ts is the right place to do that. And to do that, we'll need to include the sentinel row schema in indexeddb_schema.ts as I've requested elsewhere. :-)

/**
* The sentinel key store is the same as the DbTargetDocument store, but allows for
* reading and writing sequence numbers as part of the value stored.
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel pretty strongly that indexeddb_schema.ts should continue to be a complete and authoritative description of our schema. So sequenceNumber should be included there.

Having sentinelKey() and sentinelRow() helpers here seems useful and good (and consistent with Android), but sentinelKeyStore() strongly communicates to me that there's a separate object store for these sentinel rows, which is not what we've actually implemented. I'd be fine with moving them to a separate store, but if they're in the "targetDocuments" object store, calling it something else is confusing to me.

So can we drop SentinelRow and sentinelKeyStore() from here, and just define "sequenceNumber" as part of the DbTargetDocument schema?

docKey: DocumentKey
): PersistencePromise<void> {
return PersistencePromise.waitFor([
sentinelKeyStore(txn).delete(sentinelKey(docKey)),
Copy link
Contributor

Choose a reason for hiding this comment

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

I still have mixed feelings about this. I liked having individual object stores owned by a specific component. That way it's easy for me to consider all of the interactions within that store together. I'm curious why we didn't just have a separate store for the sentinel rows, but I assume there was a good reason and that ship has probably sailed anyway.

So I'm fine with this as-is, except per my other comments I think we should avoid sentinelKeyStore() since it suggests there is a separate store, which is not the case.

@mikelehen mikelehen assigned gsoltis and unassigned mikelehen Sep 18, 2018
Copy link
Author

@gsoltis gsoltis left a comment

Choose a reason for hiding this comment

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

Ok, I think I've addressed everything? Unless github is still hiding things from me...

docKey: DocumentKey
): PersistencePromise<void> {
return PersistencePromise.waitFor([
sentinelKeyStore(txn).delete(sentinelKey(docKey)),
Copy link
Author

Choose a reason for hiding this comment

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

The reason sentinel rows are interleaved with target-document rows is efficiency. The current algorithm for identifying orphaned documents is a scan. Using a separate store would require scanning that store, and then for each row, doing a lookup in the target-document store. FWIW, we tried this in sqlite on Android by adding a sequence number column to each remote document. It was faster to add a nullable column to the target-document many-to-many table that only had values where targetId == 0.

/**
* The sentinel key store is the same as the DbTargetDocument store, but allows for
* reading and writing sequence numbers as part of the value stored.
*/
Copy link
Author

Choose a reason for hiding this comment

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

My main concern is that I don't want the query cache to have access to the sequence number. It's not present for any rows that the query cache would be dealing with. I've removed SentinelRow and sentinelKeyStore() though. I've added an assert to the constructor for DbTargetDocument.

packages/firestore/src/local/lru_garbage_collector.ts Outdated Show resolved Hide resolved
packages/firestore/src/local/persistence.ts Show resolved Hide resolved
packages/firestore/src/local/lru_garbage_collector.ts Outdated Show resolved Hide resolved
@gsoltis gsoltis assigned mikelehen and unassigned gsoltis Sep 19, 2018
Copy link
Contributor

@mikelehen mikelehen left a comment

Choose a reason for hiding this comment

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

LGTM with a couple nits.

packages/firestore/src/local/indexeddb_schema.ts Outdated Show resolved Hide resolved
packages/firestore/src/local/indexeddb_schema.ts Outdated Show resolved Hide resolved
@mikelehen mikelehen assigned gsoltis and unassigned mikelehen Sep 19, 2018
@gsoltis gsoltis merged commit eaeeb2a into lru-master Sep 19, 2018
@gsoltis gsoltis deleted the gsoltis/indexeddb_lru branch September 19, 2018 18:46
@gsoltis gsoltis mentioned this pull request Oct 4, 2018
gsoltis pushed a commit that referenced this pull request Oct 4, 2018
* Implement IndexedDB LRU Reference Delegate, add LRU tests (#1224)
* Implement LRU Reference Delegate for Memory Persistence (#1237)
* Implement Eager Reference Delegate for Memory Persistence, drop old GC (#1256)
* Remove sequential forEach, replace with parallel forEach
long1eu added a commit to long1eu/firebase_dart_sdk that referenced this pull request Oct 15, 2018
Requested rename from firebase/firebase-js-sdk#1224, targets is a better
name than queries for internal portions of the SDK.
@firebase firebase locked and limited conversation to collaborators Oct 16, 2019
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.

3 participants