Skip to content

Commit 4085051

Browse files
committed
Merge pull request #605 from ParsePlatform/nlutsenko.lds.query.batch
Batch pointer fetch by 25 objects on querying from LDS.
2 parents 692415d + 370060b commit 4085051

File tree

1 file changed

+87
-36
lines changed

1 file changed

+87
-36
lines changed

Parse/Internal/LocalDataStore/OfflineStore/PFOfflineStore.m

Lines changed: 87 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -520,30 +520,34 @@ - (BFTask *)findAsyncForQueryState:(PFQueryState *)queryState
520520
@strongify(self);
521521
PFConstraintMatcherBlock matcherBlock = [self.offlineQueryLogic createMatcherForQueryState:queryState user:user];
522522

523-
BFTask *checkAllObjectsTask = [BFTask taskWithResult:nil];
524-
for (NSString *uuid in task.result) {
525-
__block PFObject *object = nil;
526-
527-
checkAllObjectsTask = [[[[checkAllObjectsTask continueWithSuccessBlock:^id(BFTask *task) {
528-
return [self _getPointerAsyncWithUUID:uuid database:database];
529-
}] continueWithSuccessBlock:^id(BFTask *task) {
530-
object = task.result;
531-
return [self fetchObjectLocallyAsync:object database:database];
532-
}] continueWithSuccessBlock:^id(BFTask *task) {
533-
if (!object.dataAvailable) {
534-
return @NO;
523+
BFTask *checkAllTask = [BFTask taskWithResult:nil];
524+
NSArray *uuidBatches = [PFInternalUtils arrayBySplittingArray:task.result withMaximumComponentsPerSegment:64];
525+
for (NSArray *uuids in uuidBatches) {
526+
checkAllTask = [[checkAllTask continueWithSuccessBlock:^id(BFTask *_) {
527+
return [self _getObjectPointersAsyncWithUUIDs:uuids fromDatabase:database];
528+
}] continueWithSuccessBlock:^id(BFTask PF_GENERIC(NSArray<PFObject *> *)*task) {
529+
BFTask *checkBatchTask = [BFTask taskWithResult:nil];
530+
for (PFObject *object in task.result) {
531+
checkBatchTask = [[[checkBatchTask continueWithSuccessBlock:^id(BFTask *_) {
532+
return [self fetchObjectLocallyAsync:object database:database];
533+
}] continueWithSuccessBlock:^id(BFTask *_) {
534+
if (!object.dataAvailable) {
535+
return nil;
536+
}
537+
return matcherBlock(object, database);
538+
}] continueWithSuccessBlock:^id(BFTask *task) {
539+
if ([task.result boolValue]) {
540+
[mutableResults addObject:object];
541+
}
542+
return nil;
543+
}];
535544
}
536-
return matcherBlock(object, database);
537-
}] continueWithSuccessBlock:^id(BFTask *task) {
538-
if ([task.result boolValue]) {
539-
[mutableResults addObject:object];
540-
}
541-
return nil;
545+
return checkBatchTask;
542546
}];
543547
}
544-
return checkAllObjectsTask;
548+
return checkAllTask;
545549
}];
546-
}] continueWithSuccessBlock:^id(BFTask *task) {
550+
}] continueWithSuccessBlock:^id(BFTask *_) {
547551
@strongify(self);
548552

549553
// Sort, Apply Skip and Limit
@@ -561,7 +565,7 @@ - (BFTask *)findAsyncForQueryState:(PFQueryState *)queryState
561565
ofQueryState:queryState
562566
inDatabase:database];
563567

564-
return [fetchIncludesTask continueWithSuccessBlock:^id(BFTask *task) {
568+
return [fetchIncludesTask continueWithSuccessBlock:^id(BFTask *_) {
565569
return results;
566570
}];
567571
}];
@@ -867,6 +871,8 @@ - (BFTask *)getOrCreateUUIDAsyncForObject:(PFObject *)object
867871
return tcs.task;
868872
}
869873

874+
#pragma mark Pointers
875+
870876
/*!
871877
Gets an unfetched pointer to an object in the database, based on its uuid. The object may or may
872878
not be in memory, but it must be in database. If it is already in memory, the instance will be
@@ -877,8 +883,7 @@ - (BFTask *)getOrCreateUUIDAsyncForObject:(PFObject *)object
877883
@param database The database instance to retrieve from.
878884
@returns The object with that UUID.
879885
*/
880-
- (BFTask *)_getPointerAsyncWithUUID:(NSString *)uuid
881-
database:(PFSQLiteDatabase *)database {
886+
- (BFTask *)_getPointerAsyncWithUUID:(NSString *)uuid database:(PFSQLiteDatabase *)database {
882887
@synchronized (self.lock) {
883888
PFObject *existing = [self.UUIDToObjectMap objectForKey:uuid];
884889
if (existing) {
@@ -905,24 +910,70 @@ - (BFTask *)_getPointerAsyncWithUUID:(NSString *)uuid
905910

906911
return nil;
907912
}] continueWithSuccessBlock:^id(BFTask *_) {
908-
PFObject *pointer = nil;
909-
@synchronized (self.lock) {
910-
pointer = [self.UUIDToObjectMap objectForKey:uuid];
911-
if (!pointer) {
912-
pointer = [PFObject objectWithoutDataWithClassName:className objectId:objectId];
913-
914-
// If it doesn't have objectId, we don't really need the UUID, and this simplifies some
915-
// other logic elsewhere if we only update the map for new objects.
916-
if (!objectId) {
917-
[self.UUIDToObjectMap setObject:pointer forKey:uuid];
918-
[self.objectToUUIDMap setObject:[BFTask taskWithResult:uuid] forKey:pointer];
919-
}
913+
return [self _getOrCreateInMemoryPointerForObjectWithUUID:uuid parseClassName:className objectId:objectId];
914+
}];
915+
}
916+
917+
- (BFTask PF_GENERIC(NSArray<PFObject *> *)*)_getObjectPointersAsyncWithUUIDs:(NSArray PF_GENERIC(NSString *)*)uuids
918+
fromDatabase:(PFSQLiteDatabase *)database {
919+
NSMutableArray PF_GENERIC(PFObject *)*objects = [NSMutableArray array];
920+
NSMutableArray PF_GENERIC(NSString *)*missingUUIDs = [NSMutableArray array];
921+
@synchronized(self.lock) {
922+
for (NSString *uuid in uuids) {
923+
PFObject *object = [self.UUIDToObjectMap objectForKey:uuid];
924+
if (object) {
925+
[objects addObject:object];
926+
} else {
927+
[missingUUIDs addObject:uuid];
920928
}
921929
}
922-
return pointer;
930+
}
931+
NSString *queryString = [NSString stringWithFormat:@"SELECT %@, %@, %@ FROM %@ WHERE %@ IN ('%@');",
932+
PFOfflineStoreKeyOfUUID, PFOfflineStoreKeyOfObjectId, PFOfflineStoreKeyOfClassName,
933+
PFOfflineStoreTableOfObjects, PFOfflineStoreKeyOfUUID,
934+
[missingUUIDs componentsJoinedByString:@"','"]];
935+
NSMutableArray PF_GENERIC(BFTask <PFObject *>*)*fetchPointersTasks = [NSMutableArray arrayWithCapacity:missingUUIDs.count];
936+
return [[database executeQueryAsync:queryString withArgumentsInArray:nil block:^id(PFSQLiteDatabaseResult *result) {
937+
while ([result next]) {
938+
NSString *uuid = [result stringForColumnIndex:0];
939+
NSString *objectId = [result stringForColumnIndex:1];
940+
NSString *parseClassName = [result stringForColumnIndex:2];
941+
BFTask *task = [BFTask taskFromExecutor:[BFExecutor defaultPriorityBackgroundExecutor] withBlock:^id{
942+
return [self _getOrCreateInMemoryPointerForObjectWithUUID:uuid parseClassName:parseClassName objectId:objectId];
943+
}];
944+
[fetchPointersTasks addObject:task];
945+
}
946+
return [BFTask taskForCompletionOfAllTasks:fetchPointersTasks];
947+
}] continueWithSuccessBlock:^id(BFTask *_) {
948+
for (BFTask PF_GENERIC(PFObject *)*task in fetchPointersTasks) {
949+
[objects addObject:task.result];
950+
}
951+
return objects;
923952
}];
924953
}
925954

955+
- (BFTask PF_GENERIC(PFObject *)*)_getOrCreateInMemoryPointerForObjectWithUUID:(NSString *)uuid
956+
parseClassName:(NSString *)parseClassName
957+
objectId:(NSString *)objectId {
958+
PFObject *pointer = nil;
959+
@synchronized (self.lock) {
960+
pointer = [self.UUIDToObjectMap objectForKey:uuid];
961+
if (!pointer) {
962+
pointer = [PFObject objectWithoutDataWithClassName:parseClassName objectId:objectId];
963+
964+
// If it doesn't have objectId, we don't really need the UUID, and this simplifies some
965+
// other logic elsewhere if we only update the map for new objects.
966+
if (!objectId) {
967+
[self.UUIDToObjectMap setObject:pointer forKey:uuid];
968+
[self.objectToUUIDMap setObject:[BFTask taskWithResult:uuid] forKey:pointer];
969+
}
970+
}
971+
}
972+
return [BFTask taskWithResult:pointer];
973+
}
974+
975+
#pragma mark Else
976+
926977
- (PFObject *)getOrCreateObjectWithoutDataWithClassName:(NSString *)className
927978
objectId:(NSString *)objectId {
928979
PFParameterAssert(objectId, @"objectId cannot be nil.");

0 commit comments

Comments
 (0)