And waits for them. That's pointless.
unexpected_parts.size(), unexpected_parts_rows, unexpected_parts_nonnew, unexpected_parts_nonnew_rows,
                    parts_to_fetch.size(), parts_to_fetch_blocks);
    }
    
    std::vector<std::future<Coordination::ExistsResponse>> exists_futures;
    exists_futures.reserve(parts_to_fetch.size());
    for (const String & part_name : parts_to_fetch)
    {
        String part_path = fs::path(replica_path) / "parts" / part_name;
        exists_futures.emplace_back(zookeeper->asyncExists(part_path));
    }
    std::vector<std::future<Coordination::MultiResponse>> enqueue_futures;
    enqueue_futures.reserve(parts_to_fetch.size());
    for (size_t i = 0; i < parts_to_fetch.size(); ++i)
    {
        const String & part_name = parts_to_fetch[i];
        LOG_ERROR(log, "Removing locally missing part from ZooKeeper and queueing a fetch: {}", part_name);
        Coordination::Requests ops;
        time_t part_create_time = 0;
        Coordination::ExistsResponse exists_resp = exists_futures[i].get();
        if (exists_resp.error == Coordination::Error::ZOK)
        {
            part_create_time = exists_resp.stat.ctime / 1000;
            removePartFromZooKeeper(part_name, ops, exists_resp.stat.numChildren > 0);
        }
        LogEntry log_entry;
        log_entry.type = LogEntry::GET_PART;
        log_entry.source_replica = "";
        log_entry.new_part_name = part_name;
        log_entry.create_time = part_create_time;