in database/src/desktop/core/sync_tree.cc [99:213]
std::vector<Event> SyncTree::AddEventRegistration(
UniquePtr<EventRegistration> event_registration) {
std::vector<Event> events;
persistence_manager_->RunInTransaction([&, this]() -> bool {
const QuerySpec& query_spec = event_registration->query_spec();
const Path& path = query_spec.path;
const QueryParams& params = query_spec.params;
Optional<Variant> server_cache_variant;
bool found_ancestor_default_view = false;
// Any covering writes will necessarily be at the root, so really all we
// need to find is the server cache.
{
std::vector<std::string> directories = path.GetDirectories();
Tree<SyncPoint>* tree = &sync_point_tree_;
for (auto iter = directories.begin(); tree != nullptr; ++iter) {
Optional<SyncPoint>& current_sync_point = tree->value();
if (current_sync_point.has_value()) {
if (!server_cache_variant.has_value()) {
server_cache_variant =
OptionalFromPointer(current_sync_point->GetCompleteServerCache(
Path(iter, directories.end())));
}
found_ancestor_default_view |= current_sync_point->HasCompleteView();
}
if (iter == directories.end()) break;
tree = tree->GetChild(*iter);
}
}
// Get the SyncPoint.
SyncPoint* sync_point = sync_point_tree_.GetValueAt(path);
if (sync_point) {
// Found a SyncPoint.
found_ancestor_default_view |= sync_point->HasCompleteView();
if (!server_cache_variant.has_value()) {
server_cache_variant =
OptionalFromPointer(sync_point->GetCompleteServerCache(Path()));
}
} else {
Optional<SyncPoint>& result =
sync_point_tree_.SetValueAt(path, SyncPoint{});
sync_point = &result.value();
}
persistence_manager_->SetQueryActive(query_spec);
// Generate a server CacheNode. If we had a complete server cache, just use
// that to populate it. If we didn't have a complete server cache, we're
// going to need to build it up from what data we do have.
CacheNode server_cache;
if (server_cache_variant.has_value()) {
server_cache =
CacheNode(IndexedVariant(*server_cache_variant, params), true, false);
} else {
// Hit persistence
CacheNode persistent_server_cache =
persistence_manager_->ServerCache(query_spec);
if (persistent_server_cache.fully_initialized()) {
server_cache = persistent_server_cache;
} else {
server_cache_variant = Variant::Null();
Tree<SyncPoint>* subtree = sync_point_tree_.GetChild(path);
for (auto& path_subtree_pair : subtree->children()) {
Path key(path_subtree_pair.first);
Tree<SyncPoint>& child_subtree = path_subtree_pair.second;
Optional<SyncPoint>& child_sync_point = child_subtree.value();
if (child_sync_point.has_value()) {
const Variant* complete_cache =
child_sync_point->GetCompleteServerCache(Path());
if (complete_cache) {
SetVariantAtPath(&*server_cache_variant, key, *complete_cache);
}
}
}
// Fill the node with any available children we have.
auto& variant = persistent_server_cache.indexed_variant().variant();
if (variant.is_map()) {
for (auto& key_value_pair : variant.map()) {
const char* key = key_value_pair.first.AsString().string_value();
const Variant& value = key_value_pair.second;
if (GetInternalVariant(&*server_cache_variant, key) == nullptr) {
VariantUpdateChild(&server_cache_variant.value(), key, value);
}
}
}
server_cache = CacheNode(IndexedVariant(*server_cache_variant, params),
false, false);
}
}
// Now that we have the sync point, see if there is an existing view of the
// database, and if there isn't, then set one up.
bool view_already_exists = sync_point->ViewExistsForQuery(query_spec);
if (!view_already_exists && !QuerySpecLoadsAllData(query_spec)) {
// We need to track a tag for this query
FIREBASE_DEV_ASSERT_MESSAGE(!query_spec_to_tag_map_.count(query_spec),
"View does not exist but we have a tag");
Tag tag = GetNextQueryTag();
query_spec_to_tag_map_[query_spec] = tag;
tag_to_query_spec_map_[*tag] = query_spec;
}
WriteTreeRef writes_cache = pending_write_tree_->ChildWrites(path);
events = sync_point->AddEventRegistration(Move(event_registration),
writes_cache, server_cache,
persistence_manager_.get());
if (!view_already_exists && !found_ancestor_default_view) {
const View* view = sync_point->ViewForQuery(query_spec);
SetupListener(query_spec, view);
}
return true;
});
return events;
}