Skip to content
Prev Previous commit
Next Next commit
Concurrent transaction queue, serialize access to _transactions Mutab…
…leDictionary.
  • Loading branch information
FrankSalad committed Jan 6, 2017
commit db3f0159f0787b25780490902720e902e6cd506b
1 change: 1 addition & 0 deletions ios/Firestack/FirestackDatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

@property NSMutableDictionary *dbReferences;
@property NSMutableDictionary *transactions;
@property dispatch_queue_t transactionQueue;

@end

Expand Down
39 changes: 25 additions & 14 deletions ios/Firestack/FirestackDatabase.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ @interface FirestackDBReference : NSObject
@property FIRDatabaseHandle childMovedHandler;
@property FIRDatabaseHandle childValueHandler;
+ (NSDictionary *) snapshotToDict:(FIRDataSnapshot *) snapshot;

@end

@implementation FirestackDBReference
Expand Down Expand Up @@ -366,6 +367,7 @@ - (id) init
if (self != nil) {
_dbReferences = [[NSMutableDictionary alloc] init];
_transactions = [[NSMutableDictionary alloc] init];
_transactionQueue = dispatch_queue_create("com.fullstackreact.react-native-firestack", DISPATCH_QUEUE_CONCURRENT);
}
return self;
}
Expand Down Expand Up @@ -462,24 +464,29 @@ - (id) init
applyLocally:(BOOL) applyLocally
onComplete:(RCTResponseSenderBlock) onComplete)
{
NSMutableDictionary *transactionState = [NSMutableDictionary new];
[_transactions setValue:transactionState forKey:identifier];
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
[transactionState setObject:sema forKey:@"semaphore"];

FIRDatabaseReference *ref = [self getPathRef:path];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(_transactionQueue, ^{
NSMutableDictionary *transactionState = [NSMutableDictionary new];
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
[transactionState setObject:sema forKey:@"semaphore"];
FIRDatabaseReference *ref = [self getPathRef:path];
[ref runTransactionBlock:^FIRTransactionResult * _Nonnull(FIRMutableData * _Nonnull currentData) {
[self sendEventWithName:DATABASE_TRANSACTION_EVENT
body:@{
@"id": identifier,
@"originalValue": currentData.value
}];
dispatch_barrier_async(_transactionQueue, ^{
[_transactions setValue:transactionState forKey:identifier];
[self sendEventWithName:DATABASE_TRANSACTION_EVENT
body:@{
@"id": identifier,
@"originalValue": currentData.value
}];
});
// Wait for the event handler to call tryCommitTransaction
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
BOOL abort = [transactionState valueForKey:@"abort"];
id value = [transactionState valueForKey:@"value"];
[_transactions removeObjectForKey:identifier];
dispatch_barrier_async(_transactionQueue, ^{
[_transactions removeObjectForKey:identifier];
});
if (abort) {
return [FIRTransactionResult abort];
} else {
Expand Down Expand Up @@ -510,9 +517,13 @@ - (id) init
withData:(NSDictionary *) data
orAbort:(BOOL) abort)
{
NSMutableDictionary *transactionState = [_transactions valueForKey:identifier];
__block NSMutableDictionary *transactionState;
dispatch_sync(_transactionQueue, ^{
transactionState = [_transactions objectForKey: identifier];
});
if (!transactionState) {
NSLog(@"tryCommitTransaction for unknown ID %@", identifier);
return;
}
dispatch_semaphore_t sema = [transactionState valueForKey:@"semaphore"];
if (abort) {
Expand Down