std::vector SyncTree::AddEventRegistration()

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;
}