in src/main/java/com/google/firebase/database/core/view/ViewProcessor.java [469:539]
private ViewCache applyServerMerge(
final ViewCache viewCache,
final Path path,
CompoundWrite changedChildren,
final WriteTreeRef writesCache,
final Node serverCache,
final boolean filterServerNode,
final ChildChangeAccumulator accumulator) {
// If we don't have a cache yet, this merge was intended for a previously listen in the same
// location. Ignore it and wait for the complete data update coming soon.
if (viewCache.getServerCache().getNode().isEmpty()
&& !viewCache.getServerCache().isFullyInitialized()) {
return viewCache;
}
// HACK: In the case of a limit query, there may be some changes that bump things out of the
// window leaving room for new items. It's important we process these changes first, so we
// iterate the changes twice, first processing any that affect items currently in view.
// TODO: I consider an item "in view" if cacheHasChild is true, which checks both the server
// and event snap. I'm not sure if this will result in edge cases when a child is in one
// but
// not the other.
ViewCache curViewCache = viewCache;
assert changedChildren.rootWrite() == null : "Can't have a merge that is an overwrite";
CompoundWrite actualMerge;
if (path.isEmpty()) {
actualMerge = changedChildren;
} else {
actualMerge = CompoundWrite.emptyWrite().addWrites(path, changedChildren);
}
Node serverNode = viewCache.getServerCache().getNode();
Map<ChildKey, CompoundWrite> childCompoundWrites = actualMerge.childCompoundWrites();
for (Map.Entry<ChildKey, CompoundWrite> childMerge : childCompoundWrites.entrySet()) {
ChildKey childKey = childMerge.getKey();
if (serverNode.hasChild(childKey)) {
Node serverChild = serverNode.getImmediateChild(childKey);
Node newChild = childMerge.getValue().apply(serverChild);
curViewCache =
applyServerOverwrite(
curViewCache,
new Path(childKey),
newChild,
writesCache,
serverCache,
filterServerNode,
accumulator);
}
}
for (Map.Entry<ChildKey, CompoundWrite> childMerge : childCompoundWrites.entrySet()) {
ChildKey childKey = childMerge.getKey();
CompoundWrite childCompoundWrite = childMerge.getValue();
boolean isUnknownDeepMerge =
!viewCache.getServerCache().isCompleteForChild(childKey)
&& childCompoundWrite.rootWrite() == null;
if (!serverNode.hasChild(childKey) && !isUnknownDeepMerge) {
Node serverChild = serverNode.getImmediateChild(childKey);
Node newChild = childMerge.getValue().apply(serverChild);
curViewCache =
applyServerOverwrite(
curViewCache,
new Path(childKey),
newChild,
writesCache,
serverCache,
filterServerNode,
accumulator);
}
}
return curViewCache;
}