File tree Expand file tree Collapse file tree 5 files changed +220
-4
lines changed Expand file tree Collapse file tree 5 files changed +220
-4
lines changed Original file line number Diff line number Diff line change 3
3
neither succeeds nor fails within 10 seconds, the SDK will consider itself
4
4
"offline", causing getDocument() calls to resolve with cached results, rather
5
5
than continuing to wait.
6
+ - [ fixed] Fixed a potential race condition after calling ` enableNetwork() ` that
7
+ could result in a "Mutation batchIDs must be acknowledged in order" assertion
8
+ crash.
6
9
7
10
# v0.10.3
8
11
- [ fixed] Fixed a regression in the 4.10.0 Firebase iOS SDK release that
Original file line number Diff line number Diff line change @@ -217,6 +217,22 @@ - (void)testNextMutationBatchAfterBatchID {
217
217
XCTAssertNil (notFound);
218
218
}
219
219
220
+ - (void )testNextMutationBatchAfterBatchIDSkipsAcknowledgedBatches {
221
+ if ([self isTestBaseClass ]) return ;
222
+
223
+ NSMutableArray <FSTMutationBatch *> *batches = [self createBatches: 3 ];
224
+ XCTAssertEqualObjects ([self .mutationQueue nextMutationBatchAfterBatchID: kFSTBatchIDUnknown ],
225
+ batches[0 ]);
226
+
227
+ [self acknowledgeBatch: batches[0 ]];
228
+ XCTAssertEqualObjects ([self .mutationQueue nextMutationBatchAfterBatchID: kFSTBatchIDUnknown ],
229
+ batches[1 ]);
230
+ XCTAssertEqualObjects ([self .mutationQueue nextMutationBatchAfterBatchID: batches[0 ].batchID],
231
+ batches[1 ]);
232
+ XCTAssertEqualObjects ([self .mutationQueue nextMutationBatchAfterBatchID: batches[1 ].batchID],
233
+ batches[2 ]);
234
+ }
235
+
220
236
- (void )testAllMutationBatchesThroughBatchID {
221
237
if ([self isTestBaseClass ]) return ;
222
238
Original file line number Diff line number Diff line change 3407
3407
}
3408
3408
]
3409
3409
},
3410
+ "Held writes are not re-sent after disable/enable network." : {
3411
+ "describeName" : " Writes:" ,
3412
+ "itName" : " Held writes are not re-sent after disable/enable network." ,
3413
+ "tags" : [],
3414
+ "config" : {
3415
+ "useGarbageCollection" : true
3416
+ },
3417
+ "steps" : [
3418
+ {
3419
+ "userListen" : [
3420
+ 2 ,
3421
+ {
3422
+ "path" : " collection" ,
3423
+ "filters" : [],
3424
+ "orderBys" : []
3425
+ }
3426
+ ],
3427
+ "stateExpect" : {
3428
+ "activeTargets" : {
3429
+ "2" : {
3430
+ "query" : {
3431
+ "path" : " collection" ,
3432
+ "filters" : [],
3433
+ "orderBys" : []
3434
+ },
3435
+ "resumeToken" : " "
3436
+ }
3437
+ }
3438
+ }
3439
+ },
3440
+ {
3441
+ "watchAck" : [
3442
+ 2
3443
+ ]
3444
+ },
3445
+ {
3446
+ "watchEntity" : {
3447
+ "docs" : [],
3448
+ "targets" : [
3449
+ 2
3450
+ ]
3451
+ }
3452
+ },
3453
+ {
3454
+ "watchCurrent" : [
3455
+ [
3456
+ 2
3457
+ ],
3458
+ " resume-token-500"
3459
+ ],
3460
+ "watchSnapshot" : 500 ,
3461
+ "expect" : [
3462
+ {
3463
+ "query" : {
3464
+ "path" : " collection" ,
3465
+ "filters" : [],
3466
+ "orderBys" : []
3467
+ },
3468
+ "errorCode" : 0 ,
3469
+ "fromCache" : false ,
3470
+ "hasPendingWrites" : false
3471
+ }
3472
+ ]
3473
+ },
3474
+ {
3475
+ "userSet" : [
3476
+ " collection/a" ,
3477
+ {
3478
+ "v" : 1
3479
+ }
3480
+ ],
3481
+ "expect" : [
3482
+ {
3483
+ "query" : {
3484
+ "path" : " collection" ,
3485
+ "filters" : [],
3486
+ "orderBys" : []
3487
+ },
3488
+ "added" : [
3489
+ [
3490
+ " collection/a" ,
3491
+ 0 ,
3492
+ {
3493
+ "v" : 1
3494
+ },
3495
+ " local"
3496
+ ]
3497
+ ],
3498
+ "errorCode" : 0 ,
3499
+ "fromCache" : false ,
3500
+ "hasPendingWrites" : true
3501
+ }
3502
+ ]
3503
+ },
3504
+ {
3505
+ "writeAck" : {
3506
+ "version" : 1000 ,
3507
+ "expectUserCallback" : true
3508
+ },
3509
+ "stateExpect" : {
3510
+ "writeStreamRequestCount" : 2
3511
+ }
3512
+ },
3513
+ {
3514
+ "enableNetwork" : false ,
3515
+ "stateExpect" : {
3516
+ "activeTargets" : {},
3517
+ "limboDocs" : [],
3518
+ "writeStreamRequestCount" : 3
3519
+ },
3520
+ "expect" : [
3521
+ {
3522
+ "query" : {
3523
+ "path" : " collection" ,
3524
+ "filters" : [],
3525
+ "orderBys" : []
3526
+ },
3527
+ "errorCode" : 0 ,
3528
+ "fromCache" : true ,
3529
+ "hasPendingWrites" : true
3530
+ }
3531
+ ]
3532
+ },
3533
+ {
3534
+ "enableNetwork" : true ,
3535
+ "stateExpect" : {
3536
+ "activeTargets" : {
3537
+ "2" : {
3538
+ "query" : {
3539
+ "path" : " collection" ,
3540
+ "filters" : [],
3541
+ "orderBys" : []
3542
+ },
3543
+ "resumeToken" : " resume-token-500"
3544
+ }
3545
+ },
3546
+ "writeStreamRequestCount" : 3
3547
+ }
3548
+ },
3549
+ {
3550
+ "watchAck" : [
3551
+ 2
3552
+ ]
3553
+ },
3554
+ {
3555
+ "watchEntity" : {
3556
+ "docs" : [
3557
+ [
3558
+ " collection/a" ,
3559
+ 1000 ,
3560
+ {
3561
+ "v" : 1
3562
+ }
3563
+ ]
3564
+ ],
3565
+ "targets" : [
3566
+ 2
3567
+ ]
3568
+ }
3569
+ },
3570
+ {
3571
+ "watchCurrent" : [
3572
+ [
3573
+ 2
3574
+ ],
3575
+ " resume-token-2000"
3576
+ ],
3577
+ "watchSnapshot" : 2000 ,
3578
+ "expect" : [
3579
+ {
3580
+ "query" : {
3581
+ "path" : " collection" ,
3582
+ "filters" : [],
3583
+ "orderBys" : []
3584
+ },
3585
+ "metadata" : [
3586
+ [
3587
+ " collection/a" ,
3588
+ 1000 ,
3589
+ {
3590
+ "v" : 1
3591
+ }
3592
+ ]
3593
+ ],
3594
+ "errorCode" : 0 ,
3595
+ "fromCache" : false ,
3596
+ "hasPendingWrites" : false
3597
+ }
3598
+ ]
3599
+ }
3600
+ ]
3601
+ },
3410
3602
"Held writes are released when there are no queries left." : {
3411
3603
"describeName" : " Writes:" ,
3412
3604
"itName" : " Held writes are released when there are no queries left." ,
Original file line number Diff line number Diff line change @@ -315,7 +315,12 @@ - (nullable FSTMutationBatch *)lookupMutationBatch:(FSTBatchID)batchID {
315
315
}
316
316
317
317
- (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID : (FSTBatchID)batchID {
318
- std::string key = [self mutationKeyForBatchID: batchID + 1 ];
318
+ // All batches with batchID <= self.metadata.lastAcknowledgedBatchId have been acknowledged so
319
+ // the first unacknowledged batch after batchID will have a batchID larger than both of these
320
+ // values.
321
+ FSTBatchID nextBatchID = MAX (batchID, self.metadata .lastAcknowledgedBatchId ) + 1 ;
322
+
323
+ std::string key = [self mutationKeyForBatchID: nextBatchID];
319
324
std::unique_ptr<Iterator> it (_db->NewIterator (StandardReadOptions ()));
320
325
it->Seek (key);
321
326
@@ -336,7 +341,7 @@ - (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID:(FSTBatchID)batchID
336
341
return nil ;
337
342
}
338
343
339
- FSTAssert (rowKey.batchID > batchID , @" Should have found mutation after %d " , batchID );
344
+ FSTAssert (rowKey.batchID >= nextBatchID , @" Should have found mutation after %d " , nextBatchID );
340
345
return [self decodedMutationBatch: it->value ()];
341
346
}
342
347
Original file line number Diff line number Diff line change @@ -192,10 +192,10 @@ - (nullable FSTMutationBatch *)nextMutationBatchAfterBatchID:(FSTBatchID)batchID
192
192
193
193
// All batches with batchID <= self.highestAcknowledgedBatchID have been acknowledged so the
194
194
// first unacknowledged batch after batchID will have a batchID larger than both of these values.
195
- batchID = MAX (batchID + 1 , self.highestAcknowledgedBatchID );
195
+ FSTBatchID nextBatchID = MAX (batchID, self.highestAcknowledgedBatchID ) + 1 ;
196
196
197
197
// The requested batchID may still be out of range so normalize it to the start of the queue.
198
- NSInteger rawIndex = [self indexOfBatchID: batchID ];
198
+ NSInteger rawIndex = [self indexOfBatchID: nextBatchID ];
199
199
NSUInteger index = rawIndex < 0 ? 0 : (NSUInteger )rawIndex;
200
200
201
201
// Finally return the first non-tombstone batch.
You can’t perform that action at this time.
0 commit comments