55
55
import com .google .firebase .firestore .util .Util ;
56
56
import io .grpc .Status ;
57
57
import java .io .IOException ;
58
- import java .util .ArrayDeque ;
59
58
import java .util .ArrayList ;
60
59
import java .util .Collections ;
61
60
import java .util .HashMap ;
61
+ import java .util .Iterator ;
62
+ import java .util .LinkedHashSet ;
62
63
import java .util .List ;
63
64
import java .util .Map ;
64
- import java .util .Queue ;
65
65
import java .util .Set ;
66
66
67
67
/**
@@ -130,7 +130,7 @@ interface SyncEngineCallback {
130
130
* The keys of documents that are in limbo for which we haven't yet started a limbo resolution
131
131
* query.
132
132
*/
133
- private final Queue <DocumentKey > enqueuedLimboResolutions ;
133
+ private final LinkedHashSet <DocumentKey > enqueuedLimboResolutions ;
134
134
135
135
/** Keeps track of the target ID for each document that is in limbo with an active target. */
136
136
private final Map <DocumentKey , Integer > activeLimboTargetsByKey ;
@@ -169,7 +169,7 @@ public SyncEngine(
169
169
queryViewsByQuery = new HashMap <>();
170
170
queriesByTarget = new HashMap <>();
171
171
172
- enqueuedLimboResolutions = new ArrayDeque <>();
172
+ enqueuedLimboResolutions = new LinkedHashSet <>();
173
173
activeLimboTargetsByKey = new HashMap <>();
174
174
activeLimboResolutionsByTarget = new HashMap <>();
175
175
limboDocumentRefs = new ReferenceSet ();
@@ -603,6 +603,7 @@ private void removeAndCleanupTarget(int targetId, Status status) {
603
603
}
604
604
605
605
private void removeLimboTarget (DocumentKey key ) {
606
+ enqueuedLimboResolutions .remove (key );
606
607
// It's possible that the target already got removed because the query failed. In that case,
607
608
// the key won't exist in `limboTargetsByKey`. Only do the cleanup if we still have the target.
608
609
Integer targetId = activeLimboTargetsByKey .get (key );
@@ -676,7 +677,7 @@ private void updateTrackedLimboDocuments(List<LimboDocumentChange> limboChanges,
676
677
677
678
private void trackLimboChange (LimboDocumentChange change ) {
678
679
DocumentKey key = change .getKey ();
679
- if (!activeLimboTargetsByKey .containsKey (key )) {
680
+ if (!activeLimboTargetsByKey .containsKey (key ) && ! enqueuedLimboResolutions . contains ( key ) ) {
680
681
Logger .debug (TAG , "New document in limbo: %s" , key );
681
682
enqueuedLimboResolutions .add (key );
682
683
pumpEnqueuedLimboResolutions ();
@@ -694,7 +695,9 @@ private void trackLimboChange(LimboDocumentChange change) {
694
695
private void pumpEnqueuedLimboResolutions () {
695
696
while (!enqueuedLimboResolutions .isEmpty ()
696
697
&& activeLimboTargetsByKey .size () < maxConcurrentLimboResolutions ) {
697
- DocumentKey key = enqueuedLimboResolutions .remove ();
698
+ Iterator <DocumentKey > it = enqueuedLimboResolutions .iterator ();
699
+ DocumentKey key = it .next ();
700
+ it .remove ();
698
701
int limboTargetId = targetIdGenerator .nextId ();
699
702
activeLimboResolutionsByTarget .put (limboTargetId , new LimboResolution (key ));
700
703
activeLimboTargetsByKey .put (key , limboTargetId );
@@ -714,9 +717,9 @@ public Map<DocumentKey, Integer> getActiveLimboDocumentResolutions() {
714
717
}
715
718
716
719
@ VisibleForTesting
717
- public Queue <DocumentKey > getEnqueuedLimboDocumentResolutions () {
718
- // Make a defensive copy as the Queue continues to be modified.
719
- return new ArrayDeque <>(enqueuedLimboResolutions );
720
+ public List <DocumentKey > getEnqueuedLimboDocumentResolutions () {
721
+ // Make a defensive copy as the LinkedHashSet continues to be modified.
722
+ return new ArrayList <>(enqueuedLimboResolutions );
720
723
}
721
724
722
725
public void handleCredentialChange (User user ) {
0 commit comments