@@ -880,34 +880,49 @@ export class LocalStore {
880
880
*/
881
881
// PORTING NOTE: `keepPersistedQueryData` is multi-tab only.
882
882
releaseQuery ( query : Query , keepPersistedQueryData : boolean ) : Promise < void > {
883
- const mode = keepPersistedQueryData ? 'readwrite' : 'readwrite-primary' ;
884
- return this . persistence . runTransaction ( 'Release query' , mode , txn => {
885
- const targetId = this . targetIdByQuery . get ( query ) ;
886
- assert (
887
- targetId !== undefined ,
888
- 'Tried to release nonexistent query: ' + query
889
- ) ;
890
- const queryData = this . queryDataByTarget . get ( targetId ! ) ! ;
891
-
892
- // References for documents sent via Watch are automatically removed
893
- // when we delete a query's target data from the reference delegate.
894
- // Since this does not remove references for locally mutated documents,
895
- // we have to remove the target associations for these documents
896
- // manually.
897
- const removed = this . localViewReferences . removeReferencesForId ( targetId ! ) ;
898
- this . queryDataByTarget = this . queryDataByTarget . remove ( targetId ! ) ;
899
- this . targetIdByQuery . delete ( query ) ;
900
-
901
- if ( ! keepPersistedQueryData ) {
902
- return PersistencePromise . forEach ( removed , ( key : DocumentKey ) =>
903
- this . persistence . referenceDelegate . removeReference ( txn , key )
904
- ) . next ( ( ) => {
905
- this . persistence . referenceDelegate . removeTarget ( txn , queryData ) ;
906
- } ) ;
907
- } else {
908
- return PersistencePromise . resolve ( ) ;
909
- }
910
- } ) ;
883
+ let targetId : number ;
884
+
885
+ const mode = keepPersistedQueryData
886
+ ? 'readwrite-idempotent'
887
+ : 'readwrite-primary-idempotent' ;
888
+ return this . persistence
889
+ . runTransaction ( 'Release query' , mode , txn => {
890
+ const cachedTargetId = this . targetIdByQuery . get ( query ) ;
891
+ assert (
892
+ cachedTargetId !== undefined ,
893
+ 'Tried to release nonexistent query: ' + query
894
+ ) ;
895
+ targetId = cachedTargetId ! ;
896
+ const queryData = this . queryDataByTarget . get ( targetId ) ! ;
897
+
898
+ // References for documents sent via Watch are automatically removed
899
+ // when we delete a query's target data from the reference delegate.
900
+ // Since this does not remove references for locally mutated documents,
901
+ // we have to remove the target associations for these documents
902
+ // manually.
903
+ // This operation needs to be run inside the transaction since EagerGC
904
+ // uses the local view references during the transaction commit.
905
+ // Fortunately, the operation is safe to be re-run in case the
906
+ // transaction fails since there are no side effects if the target has
907
+ // already been removed.
908
+ const removed = this . localViewReferences . removeReferencesForId (
909
+ targetId
910
+ ) ;
911
+
912
+ if ( ! keepPersistedQueryData ) {
913
+ return PersistencePromise . forEach ( removed , ( key : DocumentKey ) =>
914
+ this . persistence . referenceDelegate . removeReference ( txn , key )
915
+ ) . next ( ( ) => {
916
+ this . persistence . referenceDelegate . removeTarget ( txn , queryData ) ;
917
+ } ) ;
918
+ } else {
919
+ return PersistencePromise . resolve ( ) ;
920
+ }
921
+ } )
922
+ . then ( ( ) => {
923
+ this . queryDataByTarget = this . queryDataByTarget . remove ( targetId ) ;
924
+ this . targetIdByQuery . delete ( query ) ;
925
+ } ) ;
911
926
}
912
927
913
928
/**
0 commit comments