FViewProcessor.m 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "FViewProcessor.h"
  17. #import "FAckUserWrite.h"
  18. #import "FCacheNode.h"
  19. #import "FChange.h"
  20. #import "FChildChangeAccumulator.h"
  21. #import "FChildrenNode.h"
  22. #import "FCompleteChildSource.h"
  23. #import "FCompoundWrite.h"
  24. #import "FEmptyNode.h"
  25. #import "FIRDataEventType.h"
  26. #import "FImmutableTree.h"
  27. #import "FKeyIndex.h"
  28. #import "FMerge.h"
  29. #import "FNode.h"
  30. #import "FNodeFilter.h"
  31. #import "FOperation.h"
  32. #import "FOperationSource.h"
  33. #import "FOverwrite.h"
  34. #import "FPath.h"
  35. #import "FViewCache.h"
  36. #import "FViewProcessorResult.h"
  37. #import "FWriteTreeRef.h"
  38. /**
  39. * An implementation of FCompleteChildSource that never returns any additional
  40. * children
  41. */
  42. @interface FNoCompleteChildSource : NSObject <FCompleteChildSource>
  43. @end
  44. @implementation FNoCompleteChildSource
  45. + (FNoCompleteChildSource *)instance {
  46. static FNoCompleteChildSource *source = nil;
  47. static dispatch_once_t once;
  48. dispatch_once(&once, ^{
  49. source = [[FNoCompleteChildSource alloc] init];
  50. });
  51. return source;
  52. }
  53. - (id<FNode>)completeChild:(NSString *)childKey {
  54. return nil;
  55. }
  56. - (FNamedNode *)childByIndex:(id<FIndex>)index
  57. afterChild:(FNamedNode *)child
  58. isReverse:(BOOL)reverse {
  59. return nil;
  60. }
  61. @end
  62. /**
  63. * An implementation of FCompleteChildSource that uses a FWriteTree in addition
  64. * to any other server data or old event caches available to calculate complete
  65. * children.
  66. */
  67. @interface FWriteTreeCompleteChildSource : NSObject <FCompleteChildSource>
  68. @property(nonatomic, strong) FWriteTreeRef *writes;
  69. @property(nonatomic, strong) FViewCache *viewCache;
  70. @property(nonatomic, strong) id<FNode> optCompleteServerCache;
  71. @end
  72. @implementation FWriteTreeCompleteChildSource
  73. - (id)initWithWrites:(FWriteTreeRef *)writes
  74. viewCache:(FViewCache *)viewCache
  75. serverCache:(id<FNode>)optCompleteServerCache {
  76. self = [super init];
  77. if (self) {
  78. self.writes = writes;
  79. self.viewCache = viewCache;
  80. self.optCompleteServerCache = optCompleteServerCache;
  81. }
  82. return self;
  83. }
  84. - (id<FNode>)completeChild:(NSString *)childKey {
  85. FCacheNode *node = self.viewCache.cachedEventSnap;
  86. if ([node isCompleteForChild:childKey]) {
  87. return [node.node getImmediateChild:childKey];
  88. } else {
  89. FCacheNode *serverNode;
  90. if (self.optCompleteServerCache) {
  91. // Since we're only ever getting child nodes, we can use the key
  92. // index here
  93. FIndexedNode *indexed =
  94. [FIndexedNode indexedNodeWithNode:self.optCompleteServerCache
  95. index:[FKeyIndex keyIndex]];
  96. serverNode = [[FCacheNode alloc] initWithIndexedNode:indexed
  97. isFullyInitialized:YES
  98. isFiltered:NO];
  99. } else {
  100. serverNode = self.viewCache.cachedServerSnap;
  101. }
  102. return [self.writes calculateCompleteChild:childKey cache:serverNode];
  103. }
  104. }
  105. - (FNamedNode *)childByIndex:(id<FIndex>)index
  106. afterChild:(FNamedNode *)child
  107. isReverse:(BOOL)reverse {
  108. id<FNode> completeServerData = self.optCompleteServerCache != nil
  109. ? self.optCompleteServerCache
  110. : self.viewCache.completeServerSnap;
  111. return [self.writes calculateNextNodeAfterPost:child
  112. completeServerData:completeServerData
  113. reverse:reverse
  114. index:index];
  115. }
  116. @end
  117. @interface FViewProcessor ()
  118. @property(nonatomic, strong) id<FNodeFilter> filter;
  119. @end
  120. @implementation FViewProcessor
  121. - (id)initWithFilter:(id<FNodeFilter>)nodeFilter {
  122. self = [super init];
  123. if (self) {
  124. self.filter = nodeFilter;
  125. }
  126. return self;
  127. }
  128. - (FViewProcessorResult *)applyOperationOn:(FViewCache *)oldViewCache
  129. operation:(id<FOperation>)operation
  130. writesCache:(FWriteTreeRef *)writesCache
  131. completeCache:(id<FNode>)optCompleteCache {
  132. FChildChangeAccumulator *accumulator =
  133. [[FChildChangeAccumulator alloc] init];
  134. FViewCache *newViewCache;
  135. if (operation.type == FOperationTypeOverwrite) {
  136. FOverwrite *overwrite = (FOverwrite *)operation;
  137. if (operation.source.fromUser) {
  138. newViewCache = [self applyUserOverwriteTo:oldViewCache
  139. changePath:overwrite.path
  140. changedSnap:overwrite.snap
  141. writesCache:writesCache
  142. completeCache:optCompleteCache
  143. accumulator:accumulator];
  144. } else {
  145. NSAssert(operation.source.fromServer,
  146. @"Unknown source for overwrite.");
  147. // We filter the node if it's a tagged update or the node has been
  148. // previously filtered and the update is not at the root in which
  149. // case it is ok (and necessary) to mark the node unfiltered again
  150. BOOL filterServerNode = overwrite.source.isTagged ||
  151. (oldViewCache.cachedServerSnap.isFiltered &&
  152. !overwrite.path.isEmpty);
  153. newViewCache = [self applyServerOverwriteTo:oldViewCache
  154. changePath:overwrite.path
  155. snap:overwrite.snap
  156. writesCache:writesCache
  157. completeCache:optCompleteCache
  158. filterServerNode:filterServerNode
  159. accumulator:accumulator];
  160. }
  161. } else if (operation.type == FOperationTypeMerge) {
  162. FMerge *merge = (FMerge *)operation;
  163. if (operation.source.fromUser) {
  164. newViewCache = [self applyUserMergeTo:oldViewCache
  165. path:merge.path
  166. changedChildren:merge.children
  167. writesCache:writesCache
  168. completeCache:optCompleteCache
  169. accumulator:accumulator];
  170. } else {
  171. NSAssert(operation.source.fromServer, @"Unknown source for merge.");
  172. // We filter the node if it's a tagged update or the node has been
  173. // previously filtered
  174. BOOL filterServerNode = merge.source.isTagged ||
  175. oldViewCache.cachedServerSnap.isFiltered;
  176. newViewCache = [self applyServerMergeTo:oldViewCache
  177. path:merge.path
  178. changedChildren:merge.children
  179. writesCache:writesCache
  180. completeCache:optCompleteCache
  181. filterServerNode:filterServerNode
  182. accumulator:accumulator];
  183. }
  184. } else if (operation.type == FOperationTypeAckUserWrite) {
  185. FAckUserWrite *ackWrite = (FAckUserWrite *)operation;
  186. if (!ackWrite.revert) {
  187. newViewCache = [self ackUserWriteOn:oldViewCache
  188. ackPath:ackWrite.path
  189. affectedTree:ackWrite.affectedTree
  190. writesCache:writesCache
  191. completeCache:optCompleteCache
  192. accumulator:accumulator];
  193. } else {
  194. newViewCache = [self revertUserWriteOn:oldViewCache
  195. path:ackWrite.path
  196. writesCache:writesCache
  197. completeCache:optCompleteCache
  198. accumulator:accumulator];
  199. }
  200. } else if (operation.type == FOperationTypeListenComplete) {
  201. newViewCache = [self listenCompleteOldCache:oldViewCache
  202. path:operation.path
  203. writesCache:writesCache
  204. serverCache:optCompleteCache
  205. accumulator:accumulator];
  206. } else {
  207. [NSException
  208. raise:NSInternalInconsistencyException
  209. format:@"Unknown operation encountered %ld.", (long)operation.type];
  210. return nil;
  211. }
  212. NSArray *changes = [self maybeAddValueFromOldViewCache:oldViewCache
  213. newViewCache:newViewCache
  214. changes:accumulator.changes];
  215. FViewProcessorResult *results =
  216. [[FViewProcessorResult alloc] initWithViewCache:newViewCache
  217. changes:changes];
  218. return results;
  219. }
  220. - (NSArray *)maybeAddValueFromOldViewCache:(FViewCache *)oldViewCache
  221. newViewCache:(FViewCache *)newViewCache
  222. changes:(NSArray *)changes {
  223. NSArray *newChanges = changes;
  224. FCacheNode *eventSnap = newViewCache.cachedEventSnap;
  225. if (eventSnap.isFullyInitialized) {
  226. BOOL isLeafOrEmpty =
  227. eventSnap.node.isLeafNode || eventSnap.node.isEmpty;
  228. if ([changes count] > 0 ||
  229. !oldViewCache.cachedEventSnap.isFullyInitialized ||
  230. (isLeafOrEmpty &&
  231. ![eventSnap.node isEqual:oldViewCache.completeEventSnap]) ||
  232. ![eventSnap.node.getPriority
  233. isEqual:oldViewCache.completeEventSnap.getPriority]) {
  234. FChange *valueChange =
  235. [[FChange alloc] initWithType:FIRDataEventTypeValue
  236. indexedNode:eventSnap.indexedNode];
  237. NSMutableArray *mutableChanges = [changes mutableCopy];
  238. [mutableChanges addObject:valueChange];
  239. newChanges = mutableChanges;
  240. }
  241. }
  242. return newChanges;
  243. }
  244. - (FViewCache *)
  245. generateEventCacheAfterServerEvent:(FViewCache *)viewCache
  246. path:(FPath *)changePath
  247. writesCache:(FWriteTreeRef *)writesCache
  248. source:(id<FCompleteChildSource>)source
  249. accumulator:(FChildChangeAccumulator *)accumulator {
  250. FCacheNode *oldEventSnap = viewCache.cachedEventSnap;
  251. if ([writesCache shadowingWriteAtPath:changePath] != nil) {
  252. // we have a shadowing write, ignore changes.
  253. return viewCache;
  254. } else {
  255. FIndexedNode *newEventCache;
  256. if (changePath.isEmpty) {
  257. // TODO: figure out how this plays with "sliding ack windows"
  258. NSAssert(
  259. viewCache.cachedServerSnap.isFullyInitialized,
  260. @"If change path is empty, we must have complete server data");
  261. id<FNode> nodeWithLocalWrites;
  262. if (viewCache.cachedServerSnap.isFiltered) {
  263. // We need to special case this, because we need to only apply
  264. // writes to complete children, or we might end up raising
  265. // events for incomplete children. If the server data is
  266. // filtered deep writes cannot be guaranteed to be complete
  267. id<FNode> serverCache = viewCache.completeServerSnap;
  268. FChildrenNode *completeChildren =
  269. ([serverCache isKindOfClass:[FChildrenNode class]])
  270. ? serverCache
  271. : [FEmptyNode emptyNode];
  272. nodeWithLocalWrites = [writesCache
  273. calculateCompleteEventChildrenWithCompleteServerChildren:
  274. completeChildren];
  275. } else {
  276. nodeWithLocalWrites = [writesCache
  277. calculateCompleteEventCacheWithCompleteServerCache:
  278. viewCache.completeServerSnap];
  279. }
  280. FIndexedNode *indexedNode =
  281. [FIndexedNode indexedNodeWithNode:nodeWithLocalWrites
  282. index:self.filter.index];
  283. newEventCache = [self.filter
  284. updateFullNode:viewCache.cachedEventSnap.indexedNode
  285. withNewNode:indexedNode
  286. accumulator:accumulator];
  287. } else {
  288. NSString *childKey = [changePath getFront];
  289. if ([childKey isEqualToString:@".priority"]) {
  290. NSAssert(
  291. changePath.length == 1,
  292. @"Can't have a priority with additional path components");
  293. id<FNode> oldEventNode = oldEventSnap.node;
  294. id<FNode> serverNode = viewCache.cachedServerSnap.node;
  295. // we might have overwrites for this priority
  296. id<FNode> updatedPriority = [writesCache
  297. calculateEventCacheAfterServerOverwriteWithChildPath:
  298. changePath
  299. existingEventSnap:
  300. oldEventNode
  301. existingServerSnap:
  302. serverNode];
  303. if (updatedPriority != nil) {
  304. newEventCache =
  305. [self.filter updatePriority:updatedPriority
  306. forNode:oldEventSnap.indexedNode];
  307. } else {
  308. // priority didn't change, keep old node
  309. newEventCache = oldEventSnap.indexedNode;
  310. }
  311. } else {
  312. FPath *childChangePath = [changePath popFront];
  313. id<FNode> newEventChild;
  314. if ([oldEventSnap isCompleteForChild:childKey]) {
  315. id<FNode> serverNode = viewCache.cachedServerSnap.node;
  316. id<FNode> eventChildUpdate = [writesCache
  317. calculateEventCacheAfterServerOverwriteWithChildPath:
  318. changePath
  319. existingEventSnap:
  320. oldEventSnap.node
  321. existingServerSnap:
  322. serverNode];
  323. if (eventChildUpdate != nil) {
  324. newEventChild =
  325. [[oldEventSnap.node getImmediateChild:childKey]
  326. updateChild:childChangePath
  327. withNewChild:eventChildUpdate];
  328. } else {
  329. // Nothing changed, just keep the old child
  330. newEventChild =
  331. [oldEventSnap.node getImmediateChild:childKey];
  332. }
  333. } else {
  334. newEventChild = [writesCache
  335. calculateCompleteChild:childKey
  336. cache:viewCache.cachedServerSnap];
  337. }
  338. if (newEventChild != nil) {
  339. newEventCache =
  340. [self.filter updateChildIn:oldEventSnap.indexedNode
  341. forChildKey:childKey
  342. newChild:newEventChild
  343. affectedPath:childChangePath
  344. fromSource:source
  345. accumulator:accumulator];
  346. } else {
  347. // No complete children available or no change
  348. newEventCache = oldEventSnap.indexedNode;
  349. }
  350. }
  351. }
  352. return [viewCache updateEventSnap:newEventCache
  353. isComplete:(oldEventSnap.isFullyInitialized ||
  354. changePath.isEmpty)
  355. isFiltered:self.filter.filtersNodes];
  356. }
  357. }
  358. - (FViewCache *)applyServerOverwriteTo:(FViewCache *)oldViewCache
  359. changePath:(FPath *)changePath
  360. snap:(id<FNode>)changedSnap
  361. writesCache:(FWriteTreeRef *)writesCache
  362. completeCache:(id<FNode>)optCompleteCache
  363. filterServerNode:(BOOL)filterServerNode
  364. accumulator:(FChildChangeAccumulator *)accumulator {
  365. FCacheNode *oldServerSnap = oldViewCache.cachedServerSnap;
  366. FIndexedNode *newServerCache;
  367. id<FNodeFilter> serverFilter =
  368. filterServerNode ? self.filter : self.filter.indexedFilter;
  369. if (changePath.isEmpty) {
  370. FIndexedNode *indexed =
  371. [FIndexedNode indexedNodeWithNode:changedSnap
  372. index:serverFilter.index];
  373. newServerCache = [serverFilter updateFullNode:oldServerSnap.indexedNode
  374. withNewNode:indexed
  375. accumulator:nil];
  376. } else if (serverFilter.filtersNodes && !oldServerSnap.isFiltered) {
  377. // We want to filter the server node, but we didn't filter the server
  378. // node yet, so simulate a full update
  379. NSAssert(![changePath isEmpty],
  380. @"An empty path should been caught in the other branch");
  381. NSString *childKey = [changePath getFront];
  382. FPath *updatePath = [changePath popFront];
  383. id<FNode> newChild = [[oldServerSnap.node getImmediateChild:childKey]
  384. updateChild:updatePath
  385. withNewChild:changedSnap];
  386. FIndexedNode *indexed =
  387. [oldServerSnap.indexedNode updateChild:childKey
  388. withNewChild:newChild];
  389. newServerCache = [serverFilter updateFullNode:oldServerSnap.indexedNode
  390. withNewNode:indexed
  391. accumulator:nil];
  392. } else {
  393. NSString *childKey = [changePath getFront];
  394. if (![oldServerSnap isCompleteForPath:changePath] &&
  395. changePath.length > 1) {
  396. // We don't update incomplete nodes with updates intended for other
  397. // listeners.
  398. return oldViewCache;
  399. }
  400. FPath *childChangePath = [changePath popFront];
  401. id<FNode> childNode = [oldServerSnap.node getImmediateChild:childKey];
  402. id<FNode> newChildNode = [childNode updateChild:childChangePath
  403. withNewChild:changedSnap];
  404. if ([childKey isEqualToString:@".priority"]) {
  405. newServerCache =
  406. [serverFilter updatePriority:newChildNode
  407. forNode:oldServerSnap.indexedNode];
  408. } else {
  409. newServerCache =
  410. [serverFilter updateChildIn:oldServerSnap.indexedNode
  411. forChildKey:childKey
  412. newChild:newChildNode
  413. affectedPath:childChangePath
  414. fromSource:[FNoCompleteChildSource instance]
  415. accumulator:nil];
  416. }
  417. }
  418. FViewCache *newViewCache =
  419. [oldViewCache updateServerSnap:newServerCache
  420. isComplete:(oldServerSnap.isFullyInitialized ||
  421. changePath.isEmpty)
  422. isFiltered:serverFilter.filtersNodes];
  423. id<FCompleteChildSource> source =
  424. [[FWriteTreeCompleteChildSource alloc] initWithWrites:writesCache
  425. viewCache:newViewCache
  426. serverCache:optCompleteCache];
  427. return [self generateEventCacheAfterServerEvent:newViewCache
  428. path:changePath
  429. writesCache:writesCache
  430. source:source
  431. accumulator:accumulator];
  432. }
  433. - (FViewCache *)applyUserOverwriteTo:(FViewCache *)oldViewCache
  434. changePath:(FPath *)changePath
  435. changedSnap:(id<FNode>)changedSnap
  436. writesCache:(FWriteTreeRef *)writesCache
  437. completeCache:(id<FNode>)optCompleteCache
  438. accumulator:(FChildChangeAccumulator *)accumulator {
  439. FCacheNode *oldEventSnap = oldViewCache.cachedEventSnap;
  440. FViewCache *newViewCache;
  441. id<FCompleteChildSource> source =
  442. [[FWriteTreeCompleteChildSource alloc] initWithWrites:writesCache
  443. viewCache:oldViewCache
  444. serverCache:optCompleteCache];
  445. if (changePath.isEmpty) {
  446. FIndexedNode *newIndexed =
  447. [FIndexedNode indexedNodeWithNode:changedSnap
  448. index:self.filter.index];
  449. FIndexedNode *newEventCache =
  450. [self.filter updateFullNode:oldEventSnap.indexedNode
  451. withNewNode:newIndexed
  452. accumulator:accumulator];
  453. newViewCache = [oldViewCache updateEventSnap:newEventCache
  454. isComplete:YES
  455. isFiltered:self.filter.filtersNodes];
  456. } else {
  457. NSString *childKey = [changePath getFront];
  458. if ([childKey isEqualToString:@".priority"]) {
  459. FIndexedNode *newEventCache = [self.filter
  460. updatePriority:changedSnap
  461. forNode:oldViewCache.cachedEventSnap.indexedNode];
  462. newViewCache =
  463. [oldViewCache updateEventSnap:newEventCache
  464. isComplete:oldEventSnap.isFullyInitialized
  465. isFiltered:oldEventSnap.isFiltered];
  466. } else {
  467. FPath *childChangePath = [changePath popFront];
  468. id<FNode> oldChild = [oldEventSnap.node getImmediateChild:childKey];
  469. id<FNode> newChild;
  470. if (childChangePath.isEmpty) {
  471. // Child overwrite, we can replace the child
  472. newChild = changedSnap;
  473. } else {
  474. id<FNode> childNode = [source completeChild:childKey];
  475. if (childNode != nil) {
  476. if ([[childChangePath getBack]
  477. isEqualToString:@".priority"] &&
  478. [childNode getChild:[childChangePath parent]].isEmpty) {
  479. // This is a priority update on an empty node. If this
  480. // node exists on the server, the server will send down
  481. // the priority in the update, so ignore for now
  482. newChild = childNode;
  483. } else {
  484. newChild = [childNode updateChild:childChangePath
  485. withNewChild:changedSnap];
  486. }
  487. } else {
  488. newChild = [FEmptyNode emptyNode];
  489. }
  490. }
  491. if (![oldChild isEqual:newChild]) {
  492. FIndexedNode *newEventSnap =
  493. [self.filter updateChildIn:oldEventSnap.indexedNode
  494. forChildKey:childKey
  495. newChild:newChild
  496. affectedPath:childChangePath
  497. fromSource:source
  498. accumulator:accumulator];
  499. newViewCache = [oldViewCache
  500. updateEventSnap:newEventSnap
  501. isComplete:oldEventSnap.isFullyInitialized
  502. isFiltered:self.filter.filtersNodes];
  503. } else {
  504. newViewCache = oldViewCache;
  505. }
  506. }
  507. }
  508. return newViewCache;
  509. }
  510. + (BOOL)cache:(FViewCache *)viewCache hasChild:(NSString *)childKey {
  511. return [viewCache.cachedEventSnap isCompleteForChild:childKey];
  512. }
  513. /**
  514. * @param changedChildren NSDictionary of child name (NSString*) to child value
  515. * (id<FNode>)
  516. */
  517. - (FViewCache *)applyUserMergeTo:(FViewCache *)viewCache
  518. path:(FPath *)path
  519. changedChildren:(FCompoundWrite *)changedChildren
  520. writesCache:(FWriteTreeRef *)writesCache
  521. completeCache:(id<FNode>)serverCache
  522. accumulator:(FChildChangeAccumulator *)accumulator {
  523. // HACK: In the case of a limit query, there may be some changes that bump
  524. // things out of the window leaving room for new items. It's important we
  525. // process these changes first, so we iterate the changes twice, first
  526. // processing any that affect items currently in view.
  527. // TODO: I consider an item "in view" if cacheHasChild is true, which checks
  528. // both the server and event snap. I'm not sure if this will result in edge
  529. // cases when a child is in one but not the other.
  530. __block FViewCache *curViewCache = viewCache;
  531. [changedChildren enumerateWrites:^(FPath *relativePath, id<FNode> childNode,
  532. BOOL *stop) {
  533. FPath *writePath = [path child:relativePath];
  534. if ([FViewProcessor cache:viewCache hasChild:[writePath getFront]]) {
  535. curViewCache = [self applyUserOverwriteTo:curViewCache
  536. changePath:writePath
  537. changedSnap:childNode
  538. writesCache:writesCache
  539. completeCache:serverCache
  540. accumulator:accumulator];
  541. }
  542. }];
  543. [changedChildren enumerateWrites:^(FPath *relativePath, id<FNode> childNode,
  544. BOOL *stop) {
  545. FPath *writePath = [path child:relativePath];
  546. if (![FViewProcessor cache:viewCache hasChild:[writePath getFront]]) {
  547. curViewCache = [self applyUserOverwriteTo:curViewCache
  548. changePath:writePath
  549. changedSnap:childNode
  550. writesCache:writesCache
  551. completeCache:serverCache
  552. accumulator:accumulator];
  553. }
  554. }];
  555. return curViewCache;
  556. }
  557. - (FViewCache *)applyServerMergeTo:(FViewCache *)viewCache
  558. path:(FPath *)path
  559. changedChildren:(FCompoundWrite *)changedChildren
  560. writesCache:(FWriteTreeRef *)writesCache
  561. completeCache:(id<FNode>)serverCache
  562. filterServerNode:(BOOL)filterServerNode
  563. accumulator:(FChildChangeAccumulator *)accumulator {
  564. // If we don't have a cache yet, this merge was intended for a previously
  565. // listen in the same location. Ignore it and wait for the complete data
  566. // update coming soon.
  567. if (viewCache.cachedServerSnap.node.isEmpty &&
  568. !viewCache.cachedServerSnap.isFullyInitialized) {
  569. return viewCache;
  570. }
  571. // HACK: In the case of a limit query, there may be some changes that bump
  572. // things out of the window leaving room for new items. It's important we
  573. // process these changes first, so we iterate the changes twice, first
  574. // processing any that affect items currently in view.
  575. // TODO: I consider an item "in view" if cacheHasChild is true, which checks
  576. // both the server and event snap. I'm not sure if this will result in edge
  577. // cases when a child is in one but not the other.
  578. __block FViewCache *curViewCache = viewCache;
  579. FCompoundWrite *actualMerge;
  580. if (path.isEmpty) {
  581. actualMerge = changedChildren;
  582. } else {
  583. actualMerge =
  584. [[FCompoundWrite emptyWrite] addCompoundWrite:changedChildren
  585. atPath:path];
  586. }
  587. id<FNode> serverNode = viewCache.cachedServerSnap.node;
  588. NSDictionary *childCompoundWrites = actualMerge.childCompoundWrites;
  589. [childCompoundWrites
  590. enumerateKeysAndObjectsUsingBlock:^(
  591. NSString *childKey, FCompoundWrite *childMerge, BOOL *stop) {
  592. if ([serverNode hasChild:childKey]) {
  593. id<FNode> serverChild =
  594. [viewCache.cachedServerSnap.node getImmediateChild:childKey];
  595. id<FNode> newChild = [childMerge applyToNode:serverChild];
  596. curViewCache =
  597. [self applyServerOverwriteTo:curViewCache
  598. changePath:[[FPath alloc] initWith:childKey]
  599. snap:newChild
  600. writesCache:writesCache
  601. completeCache:serverCache
  602. filterServerNode:filterServerNode
  603. accumulator:accumulator];
  604. }
  605. }];
  606. [childCompoundWrites
  607. enumerateKeysAndObjectsUsingBlock:^(
  608. NSString *childKey, FCompoundWrite *childMerge, BOOL *stop) {
  609. bool isUnknownDeepMerge =
  610. ![viewCache.cachedServerSnap isCompleteForChild:childKey] &&
  611. childMerge.rootWrite == nil;
  612. if (![serverNode hasChild:childKey] && !isUnknownDeepMerge) {
  613. id<FNode> serverChild =
  614. [viewCache.cachedServerSnap.node getImmediateChild:childKey];
  615. id<FNode> newChild = [childMerge applyToNode:serverChild];
  616. curViewCache =
  617. [self applyServerOverwriteTo:curViewCache
  618. changePath:[[FPath alloc] initWith:childKey]
  619. snap:newChild
  620. writesCache:writesCache
  621. completeCache:serverCache
  622. filterServerNode:filterServerNode
  623. accumulator:accumulator];
  624. }
  625. }];
  626. return curViewCache;
  627. }
  628. - (FViewCache *)ackUserWriteOn:(FViewCache *)viewCache
  629. ackPath:(FPath *)ackPath
  630. affectedTree:(FImmutableTree *)affectedTree
  631. writesCache:(FWriteTreeRef *)writesCache
  632. completeCache:(id<FNode>)optCompleteCache
  633. accumulator:(FChildChangeAccumulator *)accumulator {
  634. if ([writesCache shadowingWriteAtPath:ackPath] != nil) {
  635. return viewCache;
  636. }
  637. // Only filter server node if it is currently filtered
  638. BOOL filterServerNode = viewCache.cachedServerSnap.isFiltered;
  639. // Essentially we'll just get our existing server cache for the affected
  640. // paths and re-apply it as a server update now that it won't be shadowed.
  641. FCacheNode *serverCache = viewCache.cachedServerSnap;
  642. if (affectedTree.value != nil) {
  643. // This is an overwrite.
  644. if ((ackPath.isEmpty && serverCache.isFullyInitialized) ||
  645. [serverCache isCompleteForPath:ackPath]) {
  646. return
  647. [self applyServerOverwriteTo:viewCache
  648. changePath:ackPath
  649. snap:[serverCache.node getChild:ackPath]
  650. writesCache:writesCache
  651. completeCache:optCompleteCache
  652. filterServerNode:filterServerNode
  653. accumulator:accumulator];
  654. } else if (ackPath.isEmpty) {
  655. // This is a goofy edge case where we are acking data at this
  656. // location but don't have full data. We should just re-apply
  657. // whatever we have in our cache as a merge.
  658. FCompoundWrite *changedChildren = [FCompoundWrite emptyWrite];
  659. for (FNamedNode *child in serverCache.node.childEnumerator) {
  660. changedChildren = [changedChildren addWrite:child.node
  661. atKey:child.name];
  662. }
  663. return [self applyServerMergeTo:viewCache
  664. path:ackPath
  665. changedChildren:changedChildren
  666. writesCache:writesCache
  667. completeCache:optCompleteCache
  668. filterServerNode:filterServerNode
  669. accumulator:accumulator];
  670. } else {
  671. return viewCache;
  672. }
  673. } else {
  674. // This is a merge.
  675. __block FCompoundWrite *changedChildren = [FCompoundWrite emptyWrite];
  676. [affectedTree forEach:^(FPath *mergePath, id value) {
  677. FPath *serverCachePath = [ackPath child:mergePath];
  678. if ([serverCache isCompleteForPath:serverCachePath]) {
  679. changedChildren = [changedChildren
  680. addWrite:[serverCache.node getChild:serverCachePath]
  681. atPath:mergePath];
  682. }
  683. }];
  684. return [self applyServerMergeTo:viewCache
  685. path:ackPath
  686. changedChildren:changedChildren
  687. writesCache:writesCache
  688. completeCache:optCompleteCache
  689. filterServerNode:filterServerNode
  690. accumulator:accumulator];
  691. }
  692. }
  693. - (FViewCache *)revertUserWriteOn:(FViewCache *)viewCache
  694. path:(FPath *)path
  695. writesCache:(FWriteTreeRef *)writesCache
  696. completeCache:(id<FNode>)optCompleteCache
  697. accumulator:(FChildChangeAccumulator *)accumulator {
  698. if ([writesCache shadowingWriteAtPath:path] != nil) {
  699. return viewCache;
  700. } else {
  701. id<FCompleteChildSource> source = [[FWriteTreeCompleteChildSource alloc]
  702. initWithWrites:writesCache
  703. viewCache:viewCache
  704. serverCache:optCompleteCache];
  705. FIndexedNode *oldEventCache = viewCache.cachedEventSnap.indexedNode;
  706. FIndexedNode *newEventCache;
  707. if (path.isEmpty || [[path getFront] isEqualToString:@".priority"]) {
  708. id<FNode> newNode;
  709. if (viewCache.cachedServerSnap.isFullyInitialized) {
  710. newNode = [writesCache
  711. calculateCompleteEventCacheWithCompleteServerCache:
  712. viewCache.completeServerSnap];
  713. } else {
  714. newNode = [writesCache
  715. calculateCompleteEventChildrenWithCompleteServerChildren:
  716. viewCache.cachedServerSnap.node];
  717. }
  718. FIndexedNode *indexedNode =
  719. [FIndexedNode indexedNodeWithNode:newNode
  720. index:self.filter.index];
  721. newEventCache = [self.filter updateFullNode:oldEventCache
  722. withNewNode:indexedNode
  723. accumulator:accumulator];
  724. } else {
  725. NSString *childKey = [path getFront];
  726. id<FNode> newChild =
  727. [writesCache calculateCompleteChild:childKey
  728. cache:viewCache.cachedServerSnap];
  729. if (newChild == nil &&
  730. [viewCache.cachedServerSnap isCompleteForChild:childKey]) {
  731. newChild = [oldEventCache.node getImmediateChild:childKey];
  732. }
  733. if (newChild != nil) {
  734. newEventCache = [self.filter updateChildIn:oldEventCache
  735. forChildKey:childKey
  736. newChild:newChild
  737. affectedPath:[path popFront]
  738. fromSource:source
  739. accumulator:accumulator];
  740. } else if (newChild == nil &&
  741. [viewCache.cachedEventSnap.node hasChild:childKey]) {
  742. // No complete child available, delete the existing one, if any
  743. newEventCache =
  744. [self.filter updateChildIn:oldEventCache
  745. forChildKey:childKey
  746. newChild:[FEmptyNode emptyNode]
  747. affectedPath:[path popFront]
  748. fromSource:source
  749. accumulator:accumulator];
  750. } else {
  751. newEventCache = oldEventCache;
  752. }
  753. if (newEventCache.node.isEmpty &&
  754. viewCache.cachedServerSnap.isFullyInitialized) {
  755. // We might have reverted all child writes. Maybe the old event
  756. // was a leaf node.
  757. id<FNode> complete = [writesCache
  758. calculateCompleteEventCacheWithCompleteServerCache:
  759. viewCache.completeServerSnap];
  760. if (complete.isLeafNode) {
  761. FIndexedNode *indexed =
  762. [FIndexedNode indexedNodeWithNode:complete];
  763. newEventCache = [self.filter updateFullNode:newEventCache
  764. withNewNode:indexed
  765. accumulator:accumulator];
  766. }
  767. }
  768. }
  769. BOOL complete = viewCache.cachedServerSnap.isFullyInitialized ||
  770. [writesCache shadowingWriteAtPath:[FPath empty]] != nil;
  771. return [viewCache updateEventSnap:newEventCache
  772. isComplete:complete
  773. isFiltered:self.filter.filtersNodes];
  774. }
  775. }
  776. - (FViewCache *)listenCompleteOldCache:(FViewCache *)viewCache
  777. path:(FPath *)path
  778. writesCache:(FWriteTreeRef *)writesCache
  779. serverCache:(id<FNode>)servercache
  780. accumulator:(FChildChangeAccumulator *)accumulator {
  781. FCacheNode *oldServerNode = viewCache.cachedServerSnap;
  782. FViewCache *newViewCache = [viewCache
  783. updateServerSnap:oldServerNode.indexedNode
  784. isComplete:(oldServerNode.isFullyInitialized || path.isEmpty)
  785. isFiltered:oldServerNode.isFiltered];
  786. return [self
  787. generateEventCacheAfterServerEvent:newViewCache
  788. path:path
  789. writesCache:writesCache
  790. source:[FNoCompleteChildSource instance]
  791. accumulator:accumulator];
  792. }
  793. @end