class_docstr: Container for cluster load metrics.
  
  Metrics here are updated from raylet heartbeats. The autoscaler
  queries these metrics to determine when to scale up, and which nodes
  can be removed.
code: def update(
      self,
      ip: str,
      raylet_id: bytes,
      static_resources: Dict[str, Dict],
      dynamic_resources: Dict[str, Dict],
      waiting_bundles: List[Dict[str, float]] = None,
      infeasible_bundles: List[Dict[str, float]] = None,
      pending_placement_groups: List[PlacementGroupTableData] = None,
      cluster_full_of_actors_detected: bool = False,
  ):
      self.static_resources_by_ip[ip] = static_resources
      self.raylet_id_by_ip[ip] = raylet_id
      self.cluster_full_of_actors_detected = (
          cluster_full_of_actors_detected
      )
  
      if not waiting_bundles:
          waiting_bundles = []
      if not infeasible_bundles:
          infeasible_bundles = []
      if not pending_placement_groups:
          pending_placement_groups = []
  
      # We are not guaranteed to have a corresponding dynamic resource
      # for every static resource because dynamic resources are based on
      # the available resources in the heartbeat, which does not exist
      # if it is zero. Thus, we have to update dynamic resources here.
      dynamic_resources_update = dynamic_resources.copy()
      for resource_name, capacity in self.static_resources_by_ip[
          ip
      ].items():
          if resource_name not in dynamic_resources_update:
              dynamic_resources_update[resource_name] = 0.0
      self.dynamic_resources_by_ip[ip] = dynamic_resources_update
  
      now = time.time()
      if (
          ip not in self.last_used_time_by_ip
          or self.static_resources_by_ip[ip]
          != self.dynamic_resources_by_ip[ip]
      ):
          self.last_used_time_by_ip[ip] = now
      self.last_heartbeat_time_by_ip[ip] = now
      self.waiting_bundles = waiting_bundles
      self.infeasible_bundles = infeasible_bundles
      self.pending_placement_groups = pending_placement_groups
  
imports: import logging
  import time
  from collections import Counter
  from functools import reduce
  from typing import Dict, List
  from ray._private.gcs_utils import PlacementGroupTableData
  from ray.autoscaler._private.constants import AUTOSCALER_MAX_RESOURCE_DEMAND_VECTOR_SIZE, AUTOSCALER_REPORT_PER_NODE_STATUS
  from ray.autoscaler._private.util import DictCount, LoadMetricsSummary, NodeIP, ResourceDict
  from ray.core.generated.common_pb2 import PlacementStrategy
label_desc: Use image node_id 3 for calling the LoadMetrics obj's underlying member method code with example usage: obj.update(ip, raylet_id, static_resources, dynamic_resources, waiting_bundles, infeasible_bundles, pending_placement_groups, cluster_full_of_actors_detected) without return types