Copilot commented on code in PR #3719:
URL: https://github.com/apache/celeborn/pull/3719#discussion_r3759850467


##########
master/src/main/scala/org/apache/celeborn/service/deploy/master/tags/TagsManager.scala:
##########
@@ -19,112 +19,64 @@ package org.apache.celeborn.service.deploy.master.tags
 
 import java.util
 import java.util.{Collections, Set => JSet}
-import java.util.concurrent.ConcurrentHashMap
 import java.util.function.Predicate
 import java.util.stream.Collectors
 
-import scala.collection.JavaConverters.{asScalaIteratorConverter, 
mapAsScalaConcurrentMapConverter}
+import scala.collection.JavaConverters._
 
 import org.apache.celeborn.common.identity.UserIdentifier
 import org.apache.celeborn.common.internal.Logging
 import org.apache.celeborn.common.meta.WorkerInfo
-import org.apache.celeborn.common.util.JavaUtils
 import org.apache.celeborn.server.common.service.config.ConfigService
 
 class TagsManager(configService: Option[ConfigService]) extends Logging {
-  private val defaultTagStore = JavaUtils.newConcurrentHashMap[String, 
JSet[String]]()
 
-  private val addNewTagFunc =
-    new util.function.Function[String, ConcurrentHashMap.KeySetView[String, 
java.lang.Boolean]]() {
-      override def apply(t: String): ConcurrentHashMap.KeySetView[String, 
java.lang.Boolean] =
-        ConcurrentHashMap.newKeySet[String]()
-    }
-
-  private def getTagStore: ConcurrentHashMap[String, JSet[String]] = {
+  private def tagStore: Option[util.Map[String, JSet[String]]] = {
     configService match {
-      case Some(cs) =>
-        // TODO: Make configStore.getTags return ConcurrentMap
-        JavaUtils.newConcurrentHashMap(cs.getSystemConfigFromCache.getTags)
-      case _ =>
-        defaultTagStore
+      case Some(cs) => Option(cs.getSystemConfigFromCache.getTags)
+      case _ => None
     }
   }

Review Comment:
   Previously this code defensively copied the config-store tags into a 
concurrent map; now it directly uses the underlying `getTags` map. If that 
underlying map (or its value sets) can be updated concurrently by the config 
service, `getTaggedWorkers`/`getTagsForWorker` can observe races or throw 
(e.g., `ConcurrentModificationException`). Suggestion (mandatory for thread 
safety): take a snapshot copy per call (e.g., into a new 
`HashMap`/`ConcurrentHashMap` with copied sets) or reintroduce the prior 
`JavaUtils.newConcurrentHashMap(...)` approach so reads are stable.



##########
master/src/test/scala/org/apache/celeborn/service/deploy/master/tags/TagsManagerSuite.scala:
##########
@@ -199,4 +130,37 @@ class TagsManagerSuite extends CelebornFunSuite {
       assert(taggedWorkers.contains(WORKER3))
     }
   }
+
+  test("getTaggedWorkers matches workers tagged via either config store or 
self-registration") {
+    tagsManager = new TagsManager(Option(configService))
+    val selfTaggedWorker = workerWithTags("host4", TAG1)
+    val all = List(WORKER1, WORKER2, WORKER3, selfTaggedWorker).asJava
+
+    val tagged = tagsManager.getTaggedWorkers(user, TAG1, all)
+    assert(tagged.size == 3) // WORKER1, WORKER2 (config store) + selfTagged 
(self)
+    assert(tagged.contains(WORKER1))
+    assert(tagged.contains(WORKER2))
+    assert(!tagged.contains(WORKER3))
+    assert(tagged.contains(selfTaggedWorker))
+  }
+
+  test("getTaggedWorkers matches a worker whose tags span config store and 
self-registration") {
+    tagsManager = new TagsManager(Option(configService))
+    // host1 already tagged via config service
+    val selfTaggedWorker = workerWithTags("host1", TAG2)
+    val all = List(WORKER1, WORKER2, WORKER3, selfTaggedWorker).asJava

Review Comment:
   This test case specifically relies on the worker being the same identity as 
the config-store entry ('host1 already tagged via config service'), but 
`workerWithTags(\"host1\", ...)` likely produces a different `toUniqueId` (due 
to different ports) than `WORKER1`. Adjust the test to ensure 
`selfTaggedWorker.toUniqueId == WORKER1.toUniqueId` (e.g., create `WorkerInfo` 
with `WORKER1`’s ports, then set `tags`).



##########
master/src/test/scala/org/apache/celeborn/service/deploy/master/tags/TagsManagerSuite.scala:
##########
@@ -38,127 +38,58 @@ class TagsManagerSuite extends CelebornFunSuite {
   private val workers = List(WORKER1, WORKER2, WORKER3).asJava
 
   private val user = UserIdentifier("tenant_01", "Jerry")
+  private var configService: ConfigService = _
 
   override def beforeEach(): Unit = {
     super.beforeEach()
     DynamicConfigServiceFactory.reset()
-  }
-
-  test("test tags manager") {
-    tagsManager = new TagsManager(Option(null))
-
-    tagsManager.addTagToWorker(TAG1, WORKER1.toUniqueId)
-    tagsManager.addTagToWorker(TAG1, WORKER2.toUniqueId)
-
-    tagsManager.addTagToWorker(TAG2, WORKER2.toUniqueId)
-    tagsManager.addTagToWorker(TAG2, WORKER3.toUniqueId)
 
-    {
-      val taggedWorkers = tagsManager.getTaggedWorkers(user, TAG1, workers)
-      assert(taggedWorkers.size == 2)
-      assert(taggedWorkers.contains(WORKER1))
-      assert(taggedWorkers.contains(WORKER2))
-      assert(!taggedWorkers.contains(WORKER3))
-    }
+    val conf = new CelebornConf()
+    conf.set(CelebornConf.DYNAMIC_CONFIG_STORE_BACKEND, "FS")
+    conf.set(
+      CelebornConf.DYNAMIC_CONFIG_STORE_FS_PATH.key,
+      getTestResourceFile("dynamicConfig-tags.yaml").getPath)
+    configService = DynamicConfigServiceFactory.getConfigService(conf)
+  }
 
-    {
-      val taggedWorkers = tagsManager.getTaggedWorkers(user, TAG2, workers)
-      assert(taggedWorkers.size == 2)
-      assert(!taggedWorkers.contains(WORKER1))
-      assert(taggedWorkers.contains(WORKER2))
-      assert(taggedWorkers.contains(WORKER3))
-    }
+  private def workerWithTags(host: String, tags: String*): WorkerInfo = {
+    val w = new WorkerInfo(host, 111, 112, 113, 114, 115)
+    w.tags = new java.util.HashSet[String](tags.asJava)
+    w
+  }

Review Comment:
   `workerWithTags` hard-codes ports, but tag lookup against the config-store 
is done via `worker.toUniqueId`. In tests that intend to merge config-store 
tags with self-registration for an existing worker, creating a `WorkerInfo` 
with the same host but different ports will likely produce a different 
`toUniqueId`, so the config-store tags won’t apply. Fix by constructing the 
tagged worker using the exact same host/port tuple as the target worker (e.g., 
derive ports from `WORKER1`/`WORKER2`), or mutate `tags` on an existing 
`WorkerInfo` instance used in the test.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to