code: def put_client_data(self, client_id, data, phase):
      self.condition.acquire()
      self.client_data[phase][client_id] = data
      logging.debug(
          f"server receive data [{client_id}], \
  got {len(self.client_data[phase])}/{self.client_num}"
      )
  
      if len(self.client_data[phase]) == self.client_num:
          logging.debug(
              "server received all client data, start aggregate"
          )
          self.aggregate(phase)
          logging.debug("clearing client data")
          self.client_data[phase] = {}
          self.condition.notify_all()
      else:
          logging.debug(f"[{client_id}] waiting")
          self.condition.wait()
      self.condition.release()
  
file_path: BigDL/python/ppml/src/bigdl/ppml/fl/nn/tensorflow/aggregator.py
imports: import os
  from bigdl.ppml.utils.safepickle import SafePickle
  import logging
  import threading
  from bigdl.dllib.utils.log4Error import invalidInputError, invalidOperationError
  from bigdl.ppml.fl.nn.utils import ndarray_map_to_tensor_map
  from threading import Condition
  import numpy
  import tensorflow
label_desc: Use image node_id 5 for calling the Aggregator obj's underlying member method code with example usage: obj.put_client_data(client_id, data, phase) without return types