This is an automated email from the ASF dual-hosted git repository.
SteNicholas pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/celeborn.git
The following commit(s) were added to refs/heads/main by this push:
new 71a7d0afa [CELEBORN-2257] Add reporting of remote disks during
registration
71a7d0afa is described below
commit 71a7d0afa21b807f360a9c5e3d21e45258a6c441
Author: Filip Darmanovic <[email protected]>
AuthorDate: Thu May 14 09:56:37 2026 +0800
[CELEBORN-2257] Add reporting of remote disks during registration
### What changes were proposed in this pull request?
1. Disks reported to the master on registration now include remote disks
(HDFS, S3, OSS)
2. Refactored method names to clarify difference between local and remote
disks.
3. Embedded disk type information into the enum.
4. Refactored unnecessarily complicated code in the slot assignment and
worker registration path.
### Why are the changes needed?
1. Before the first heartbeat, the master won't be able to assign slots
from the remote disks on the worker.
2. All other changes are in preparation for better support of remote disks.
### Does this PR resolve a correctness bug?
Not a correctness bug
### Does this PR introduce _any_ user-facing change?
No
### How was this patch tested?
**Important**: I want help from the community on how to write tests for
this.
Closes #3597 from Dzeri96/CELEBORN-2257.
Authored-by: Filip Darmanovic <[email protected]>
Signed-off-by: SteNicholas <[email protected]>
---
.../celeborn/common/protocol/StorageInfo.java | 31 +++++++++---
.../apache/celeborn/common/meta/WorkerInfo.scala | 16 +++---
.../service/deploy/master/SlotsAllocator.java | 59 +++++++---------------
.../tests/spark/CelebornHashCheckDiskSuite.scala | 4 +-
.../service/deploy/worker/Controller.scala | 2 +-
.../celeborn/service/deploy/worker/Worker.scala | 17 +++----
.../deploy/worker/storage/StorageManager.scala | 32 +++++++-----
.../service/deploy/MiniClusterFeature.scala | 2 +-
.../service/deploy/worker/WorkerSuite.scala | 56 ++++++++++++++++++--
.../worker/storage/StorageManagerSuite.scala | 2 +-
10 files changed, 131 insertions(+), 90 deletions(-)
diff --git
a/common/src/main/java/org/apache/celeborn/common/protocol/StorageInfo.java
b/common/src/main/java/org/apache/celeborn/common/protocol/StorageInfo.java
index 1ab97309e..c204907c2 100644
--- a/common/src/main/java/org/apache/celeborn/common/protocol/StorageInfo.java
+++ b/common/src/main/java/org/apache/celeborn/common/protocol/StorageInfo.java
@@ -22,22 +22,34 @@ import java.util.*;
public class StorageInfo implements Serializable {
public enum Type {
- MEMORY(0),
- HDD(1),
- SSD(2),
- HDFS(3),
- OSS(4),
- S3(5);
+ MEMORY(0, false, MEMORY_MASK),
+ HDD(1, false, LOCAL_DISK_MASK),
+ SSD(2, false, LOCAL_DISK_MASK),
+ HDFS(3, true, HDFS_MASK),
+ OSS(4, true, OSS_MASK),
+ S3(5, true, S3_MASK);
private final int value;
+ private final boolean isDFS;
+ private final int mask;
- Type(int value) {
+ Type(int value, boolean isDFS, int mask) {
this.value = value;
+ this.isDFS = isDFS;
+ this.mask = mask;
}
public int getValue() {
return value;
}
+
+ public boolean isDFS() {
+ return isDFS;
+ }
+
+ public int getMask() {
+ return mask;
+ }
}
public static final Map<Integer, Type> typesMap = new HashMap<>();
@@ -232,6 +244,11 @@ public class StorageInfo implements Serializable {
return S3Available(availableStorageTypes);
}
+ public static boolean isAvailable(Type type, int availableStorageTypes) {
+ return availableStorageTypes == ALL_TYPES_AVAILABLE_MASK
+ || (availableStorageTypes & type.getMask()) > 0;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git
a/common/src/main/scala/org/apache/celeborn/common/meta/WorkerInfo.scala
b/common/src/main/scala/org/apache/celeborn/common/meta/WorkerInfo.scala
index 10a37cf07..0304bd423 100644
--- a/common/src/main/scala/org/apache/celeborn/common/meta/WorkerInfo.scala
+++ b/common/src/main/scala/org/apache/celeborn/common/meta/WorkerInfo.scala
@@ -214,6 +214,10 @@ class WorkerInfo(
for (newDisk <- newDiskInfos.values().asScala) {
val mountPoint: String = newDisk.mountPoint
val curDisk = diskInfos.get(mountPoint)
+ if (estimatedPartitionSize.nonEmpty && !newDisk.storageType.isDFS) {
+ newDisk.maxSlots = newDisk.totalSpace / estimatedPartitionSize.get
+ newDisk.availableSlots = newDisk.actualUsableSpace /
estimatedPartitionSize.get
+ }
if (curDisk != null) {
curDisk.actualUsableSpace = newDisk.actualUsableSpace
curDisk.totalSpace = newDisk.totalSpace
@@ -221,18 +225,10 @@ class WorkerInfo(
curDisk.activeSlots = newDisk.activeSlots
curDisk.avgFlushTime = newDisk.avgFlushTime
curDisk.avgFetchTime = newDisk.avgFetchTime
- if (estimatedPartitionSize.nonEmpty && curDisk.storageType !=
StorageInfo.Type.HDFS
- && curDisk.storageType != StorageInfo.Type.S3 &&
curDisk.storageType != StorageInfo.Type.OSS) {
- curDisk.maxSlots = curDisk.totalSpace / estimatedPartitionSize.get
- curDisk.availableSlots = curDisk.actualUsableSpace /
estimatedPartitionSize.get
- }
+ curDisk.maxSlots = newDisk.maxSlots
+ curDisk.availableSlots = newDisk.availableSlots
curDisk.setStatus(newDisk.status)
} else {
- if (estimatedPartitionSize.nonEmpty && newDisk.storageType !=
StorageInfo.Type.HDFS
- && newDisk.storageType != StorageInfo.Type.S3 &&
newDisk.storageType != StorageInfo.Type.OSS) {
- newDisk.maxSlots = newDisk.totalSpace / estimatedPartitionSize.get
- newDisk.availableSlots = newDisk.actualUsableSpace /
estimatedPartitionSize.get
- }
diskInfos.put(mountPoint, newDisk)
}
}
diff --git
a/master/src/main/java/org/apache/celeborn/service/deploy/master/SlotsAllocator.java
b/master/src/main/java/org/apache/celeborn/service/deploy/master/SlotsAllocator.java
index 5580cd341..07b817427 100644
---
a/master/src/main/java/org/apache/celeborn/service/deploy/master/SlotsAllocator.java
+++
b/master/src/main/java/org/apache/celeborn/service/deploy/master/SlotsAllocator.java
@@ -17,6 +17,8 @@
package org.apache.celeborn.service.deploy.master;
+import static org.apache.celeborn.common.protocol.StorageInfo.Type.*;
+
import java.util.*;
import java.util.function.IntUnaryOperator;
import java.util.stream.Collectors;
@@ -40,6 +42,12 @@ public class SlotsAllocator {
DiskInfo diskInfo;
long usableSlots;
+ /** @param diskInfo will be used as source for usableSlots. */
+ UsableDiskInfo(DiskInfo diskInfo) {
+ this.diskInfo = diskInfo;
+ this.usableSlots = diskInfo.getAvailableSlots();
+ }
+
UsableDiskInfo(DiskInfo diskInfo, long usableSlots) {
this.diskInfo = diskInfo;
this.usableSlots = usableSlots;
@@ -70,31 +78,10 @@ public class SlotsAllocator {
for (WorkerInfo worker : workers) {
List<UsableDiskInfo> usableDisks =
slotsRestrictions.computeIfAbsent(worker, v -> new ArrayList<>());
- for (Map.Entry<String, DiskInfo> diskInfoEntry :
worker.diskInfos().entrySet()) {
- if (diskInfoEntry.getValue().status().equals(DiskStatus.HEALTHY)) {
- if (StorageInfo.localDiskAvailable(availableStorageTypes)
- && diskInfoEntry.getValue().storageType() !=
StorageInfo.Type.HDFS
- && diskInfoEntry.getValue().storageType() != StorageInfo.Type.S3
- && diskInfoEntry.getValue().storageType() !=
StorageInfo.Type.OSS) {
- usableDisks.add(
- new UsableDiskInfo(
- diskInfoEntry.getValue(),
diskInfoEntry.getValue().getAvailableSlots()));
- } else if (StorageInfo.HDFSAvailable(availableStorageTypes)
- && diskInfoEntry.getValue().storageType() ==
StorageInfo.Type.HDFS) {
- usableDisks.add(
- new UsableDiskInfo(
- diskInfoEntry.getValue(),
diskInfoEntry.getValue().getAvailableSlots()));
- } else if (StorageInfo.S3Available(availableStorageTypes)
- && diskInfoEntry.getValue().storageType() ==
StorageInfo.Type.S3) {
- usableDisks.add(
- new UsableDiskInfo(
- diskInfoEntry.getValue(),
diskInfoEntry.getValue().getAvailableSlots()));
- } else if (StorageInfo.OSSAvailable(availableStorageTypes)
- && diskInfoEntry.getValue().storageType() ==
StorageInfo.Type.OSS) {
- usableDisks.add(
- new UsableDiskInfo(
- diskInfoEntry.getValue(),
diskInfoEntry.getValue().availableSlots()));
- }
+ for (DiskInfo diskInfo : worker.diskInfos().values()) {
+ if (DiskStatus.HEALTHY.equals(diskInfo.status())
+ && StorageInfo.isAvailable(diskInfo.storageType(),
availableStorageTypes)) {
+ usableDisks.add(new UsableDiskInfo(diskInfo));
}
}
}
@@ -157,9 +144,7 @@ public class SlotsAllocator {
diskToWorkerMap.put(diskInfo, i);
if (diskInfo.actualUsableSpace() > 0
&& diskInfo.status().equals(DiskStatus.HEALTHY)
- && diskInfo.storageType() != StorageInfo.Type.HDFS
- && diskInfo.storageType() != StorageInfo.Type.S3
- && diskInfo.storageType() != StorageInfo.Type.OSS) {
+ && !diskInfo.storageType().isDFS()) {
usableDisks.add(diskInfo);
}
}));
@@ -225,12 +210,8 @@ public class SlotsAllocator {
}
usableDiskInfos.get(diskIndex).usableSlots--;
DiskInfo selectedDiskInfo = usableDiskInfos.get(diskIndex).diskInfo;
- if (selectedDiskInfo.storageType() == StorageInfo.Type.HDFS) {
- storageInfo = new StorageInfo("", StorageInfo.Type.HDFS,
availableStorageTypes);
- } else if (selectedDiskInfo.storageType() == StorageInfo.Type.S3) {
- storageInfo = new StorageInfo("", StorageInfo.Type.S3,
availableStorageTypes);
- } else if (selectedDiskInfo.storageType() == StorageInfo.Type.OSS) {
- storageInfo = new StorageInfo("", StorageInfo.Type.OSS,
availableStorageTypes);
+ if (selectedDiskInfo.storageType().isDFS()) {
+ storageInfo = new StorageInfo("", selectedDiskInfo.storageType(),
availableStorageTypes);
} else {
storageInfo =
new StorageInfo(
@@ -243,9 +224,7 @@ public class SlotsAllocator {
if (StorageInfo.localDiskAvailable(availableStorageTypes)) {
DiskInfo[] diskInfos =
selectedWorker.diskInfos().values().stream()
- .filter(p -> p.storageType() != StorageInfo.Type.HDFS)
- .filter(p -> p.storageType() != StorageInfo.Type.S3)
- .filter(p -> p.storageType() != StorageInfo.Type.OSS)
+ .filter(p -> !p.storageType().isDFS())
.collect(Collectors.toList())
.toArray(new DiskInfo[0]);
int diskIndex =
@@ -257,11 +236,11 @@ public class SlotsAllocator {
availableStorageTypes);
workerDiskIndex.put(selectedWorker, (diskIndex + 1) %
diskInfos.length);
} else if (StorageInfo.S3Available(availableStorageTypes)) {
- storageInfo = new StorageInfo("", StorageInfo.Type.S3,
availableStorageTypes);
+ storageInfo = new StorageInfo("", S3, availableStorageTypes);
} else if (StorageInfo.OSSAvailable(availableStorageTypes)) {
- storageInfo = new StorageInfo("", StorageInfo.Type.OSS,
availableStorageTypes);
+ storageInfo = new StorageInfo("", OSS, availableStorageTypes);
} else if (StorageInfo.HDFSAvailable(availableStorageTypes)) {
- storageInfo = new StorageInfo("", StorageInfo.Type.HDFS,
availableStorageTypes);
+ storageInfo = new StorageInfo("", HDFS, availableStorageTypes);
} else if (StorageInfo.memoryAvailable(availableStorageTypes)) {
storageInfo = new StorageInfo("", StorageInfo.Type.MEMORY,
availableStorageTypes);
} else {
diff --git
a/tests/spark-it/src/test/scala/org/apache/celeborn/tests/spark/CelebornHashCheckDiskSuite.scala
b/tests/spark-it/src/test/scala/org/apache/celeborn/tests/spark/CelebornHashCheckDiskSuite.scala
index 7ac2ac48c..4f22982bb 100644
---
a/tests/spark-it/src/test/scala/org/apache/celeborn/tests/spark/CelebornHashCheckDiskSuite.scala
+++
b/tests/spark-it/src/test/scala/org/apache/celeborn/tests/spark/CelebornHashCheckDiskSuite.scala
@@ -75,7 +75,7 @@ class CelebornHashCheckDiskSuite extends SparkTestBase {
// shuffle key not expired, diskInfo.actualUsableSpace <= 0, no space
workers.foreach { worker =>
worker.storageManager.updateDiskInfos()
- worker.storageManager.disksSnapshot().foreach { diskInfo =>
+ worker.storageManager.localDisksSnapshot().foreach { diskInfo =>
assert(diskInfo.actualUsableSpace <= 0)
}
}
@@ -89,7 +89,7 @@ class CelebornHashCheckDiskSuite extends SparkTestBase {
assert(t.size() === 0)
}
// after shuffle key expired, diskInfo.actualUsableSpace will equal
capacity=1000
- worker.storageManager.disksSnapshot().foreach { diskInfo =>
+ worker.storageManager.localDisksSnapshot().foreach { diskInfo =>
assert(diskInfo.actualUsableSpace === 1000)
}
}
diff --git
a/worker/src/main/scala/org/apache/celeborn/service/deploy/worker/Controller.scala
b/worker/src/main/scala/org/apache/celeborn/service/deploy/worker/Controller.scala
index ee959e4d6..565acb441 100644
---
a/worker/src/main/scala/org/apache/celeborn/service/deploy/worker/Controller.scala
+++
b/worker/src/main/scala/org/apache/celeborn/service/deploy/worker/Controller.scala
@@ -190,7 +190,7 @@ private[deploy] class Controller(
return
}
- if (storageManager.healthyWorkingDirs().size <= 0 &&
remoteStorageDirs.isEmpty) {
+ if (storageManager.healthyLocalWorkingDirs().size <= 0 &&
remoteStorageDirs.isEmpty) {
val msg = "Local storage has no available dirs!"
logError(s"[handleReserveSlots] $msg")
context.reply(ReserveSlotsResponse(StatusCode.NO_AVAILABLE_WORKING_DIR,
msg))
diff --git
a/worker/src/main/scala/org/apache/celeborn/service/deploy/worker/Worker.scala
b/worker/src/main/scala/org/apache/celeborn/service/deploy/worker/Worker.scala
index da2cab1c3..1c5bc2018 100644
---
a/worker/src/main/scala/org/apache/celeborn/service/deploy/worker/Worker.scala
+++
b/worker/src/main/scala/org/apache/celeborn/service/deploy/worker/Worker.scala
@@ -284,11 +284,10 @@ private[celeborn] class Worker(
storageManager.updateDiskInfos()
storageManager.startDeviceMonitor()
- // WorkerInfo's diskInfos is a reference to storageManager.diskInfos
- val diskInfos = JavaUtils.newConcurrentHashMap[String, DiskInfo]()
- storageManager.disksSnapshot().foreach { diskInfo =>
- diskInfos.put(diskInfo.mountPoint, diskInfo)
- }
+ private val diskInfos = storageManager
+ .allDisksSnapshot()
+ .map { diskInfo => diskInfo.mountPoint -> diskInfo }
+ .toMap.asJava
val workerInfo =
new WorkerInfo(
@@ -515,10 +514,10 @@ private[celeborn] class Worker(
activeShuffleKeys.addAll(partitionLocationInfo.shuffleKeySet)
activeShuffleKeys.addAll(storageManager.shuffleKeySet())
storageManager.updateDiskInfos()
- val diskInfos =
- workerInfo.updateThenGetDiskInfos(storageManager.disksSnapshot().map {
disk =>
- disk.mountPoint -> disk
- }.toMap.asJava).values().asScala.toSeq ++
storageManager.remoteDiskInfos.getOrElse(Set.empty)
+ val currentDiskMap = storageManager.allDisksSnapshot().map { disk =>
+ disk.mountPoint -> disk
+ }.toMap.asJava
+ val diskInfos =
workerInfo.updateThenGetDiskInfos(currentDiskMap).asScala.values.toSeq
workerStatusManager.checkIfNeedTransitionStatus()
val response = masterClient.askSync[HeartbeatFromWorkerResponse](
HeartbeatFromWorker(
diff --git
a/worker/src/main/scala/org/apache/celeborn/service/deploy/worker/storage/StorageManager.scala
b/worker/src/main/scala/org/apache/celeborn/service/deploy/worker/storage/StorageManager.scala
index 25014470a..cde13f29a 100644
---
a/worker/src/main/scala/org/apache/celeborn/service/deploy/worker/storage/StorageManager.scala
+++
b/worker/src/main/scala/org/apache/celeborn/service/deploy/worker/storage/StorageManager.scala
@@ -103,19 +103,23 @@ final private[worker] class StorageManager(conf:
CelebornConf, workerSource: Abs
if (diskInfoSet.nonEmpty) Some(diskInfoSet) else None
}
- def disksSnapshot(): List[DiskInfo] = {
+ def localDisksSnapshot(): List[DiskInfo] = {
diskInfos.synchronized {
val disks = new util.ArrayList[DiskInfo](diskInfos.values())
disks.asScala.toList
}
}
- def healthyWorkingDirs(): List[File] =
- disksSnapshot().filter(_.status == DiskStatus.HEALTHY).flatMap(_.dirs)
+ def allDisksSnapshot(): List[DiskInfo] = {
+ localDisksSnapshot() ++ remoteDiskInfos.getOrElse(Nil)
+ }
+
+ def healthyLocalWorkingDirs(): List[File] =
+ localDisksSnapshot().filter(_.status == DiskStatus.HEALTHY).flatMap(_.dirs)
private val diskOperators: ConcurrentHashMap[String, ThreadPoolExecutor] = {
val cleaners = JavaUtils.newConcurrentHashMap[String, ThreadPoolExecutor]()
- disksSnapshot().foreach {
+ localDisksSnapshot().foreach {
diskInfo =>
cleaners.put(
diskInfo.mountPoint,
@@ -127,7 +131,7 @@ final private[worker] class StorageManager(conf:
CelebornConf, workerSource: Abs
}
val tmpDiskInfos = JavaUtils.newConcurrentHashMap[String, DiskInfo]()
- disksSnapshot().foreach { diskInfo =>
+ localDisksSnapshot().foreach { diskInfo =>
tmpDiskInfos.put(diskInfo.mountPoint, diskInfo)
}
private val deviceMonitor =
@@ -142,7 +146,7 @@ final private[worker] class StorageManager(conf:
CelebornConf, workerSource: Abs
_totalLocalFlusherThread: Int) = {
val flushers = JavaUtils.newConcurrentHashMap[String, LocalFlusher]()
var totalThread = 0
- disksSnapshot().foreach { diskInfo =>
+ localDisksSnapshot().foreach { diskInfo =>
if (!flushers.containsKey(diskInfo.mountPoint)) {
val flusher = new LocalFlusher(
workerSource,
@@ -269,7 +273,7 @@ final private[worker] class StorageManager(conf:
CelebornConf, workerSource: Abs
private val counter = new AtomicInteger()
private val counterOperator = new IntUnaryOperator() {
override def applyAsInt(operand: Int): Int = {
- val dirs = healthyWorkingDirs()
+ val dirs = healthyLocalWorkingDirs()
if (dirs.nonEmpty) {
(operand + 1) % dirs.length
} else 0
@@ -489,7 +493,7 @@ final private[worker] class StorageManager(conf:
CelebornConf, workerSource: Abs
userIdentifier: UserIdentifier,
partitionSplitEnabled: Boolean,
isSegmentGranularityVisible: Boolean): PartitionDataWriter = {
- if (healthyWorkingDirs().isEmpty && remoteStorageDirs.isEmpty) {
+ if (healthyLocalWorkingDirs().isEmpty && remoteStorageDirs.isEmpty) {
throw new IOException("No available working dirs!")
}
val partitionDataWriterContext = new PartitionDataWriterContext(
@@ -687,7 +691,7 @@ final private[worker] class StorageManager(conf:
CelebornConf, workerSource: Abs
}
}
val (appId, shuffleId) = Utils.splitShuffleKey(shuffleKey)
- disksSnapshot().filter(diskInfo =>
+ localDisksSnapshot().filter(diskInfo =>
diskInfo.status == DiskStatus.HEALTHY
|| diskInfo.status == DiskStatus.HIGH_DISK_USAGE).foreach {
diskInfo =>
diskInfo.dirs.foreach { dir =>
@@ -751,7 +755,7 @@ final private[worker] class StorageManager(conf:
CelebornConf, workerSource: Abs
TimeUnit.MINUTES)
private def cleanupExpiredAppDirs(expireDuration: Long): Unit = {
- val diskInfoAndAppDirs = disksSnapshot()
+ val diskInfoAndAppDirs = localDisksSnapshot()
.filter(diskInfo =>
diskInfo.status == DiskStatus.HEALTHY
|| diskInfo.status == DiskStatus.HIGH_DISK_USAGE)
@@ -801,7 +805,7 @@ final private[worker] class StorageManager(conf:
CelebornConf, workerSource: Abs
val appIds = shuffleKeySet().asScala.map(key =>
Utils.splitShuffleKey(key)._1)
while (retryTimes < conf.workerCheckFileCleanMaxRetries) {
val localCleaned =
- !disksSnapshot().filter(_.status != DiskStatus.IO_HANG).exists {
diskInfo =>
+ !localDisksSnapshot().filter(_.status != DiskStatus.IO_HANG).exists {
diskInfo =>
diskInfo.dirs.exists {
case workingDir if workingDir.exists() =>
// Don't check appDirs that store information in the fileInfos
@@ -946,7 +950,7 @@ final private[worker] class StorageManager(conf:
CelebornConf, workerSource: Abs
}
def updateDiskInfos(): Unit = this.synchronized {
- disksSnapshot()
+ localDisksSnapshot()
.filter(diskInfo =>
diskInfo.status != DiskStatus.IO_HANG && diskInfo.status !=
DiskStatus.READ_OR_WRITE_FAILURE)
.foreach {
@@ -985,7 +989,7 @@ final private[worker] class StorageManager(conf:
CelebornConf, workerSource: Abs
diskInfo.updateFlushTime()
diskInfo.updateFetchTime()
}
- logInfo(s"Updated diskInfos:\n${disksSnapshot().mkString("\n")}")
+ logInfo(s"Updated diskInfos:\n${localDisksSnapshot().mkString("\n")}")
}
def getFileSystemReportedSpace(mountPoint: String): (Long, Long) = {
@@ -1148,7 +1152,7 @@ final private[worker] class StorageManager(conf:
CelebornConf, workerSource: Abs
logInfo(s"Disk(${diskInfo.mountPoint}) unavailable for
$suggestedMountPoint, return all healthy" +
s" working dirs.")
}
- healthyWorkingDirs()
+ healthyLocalWorkingDirs()
}
if (dirs.isEmpty && hdfsFlusher.isEmpty && s3Flusher.isEmpty &&
ossFlusher.isEmpty) {
throw new IOException(s"No available disks! suggested mountPoint
$suggestedMountPoint")
diff --git
a/worker/src/test/scala/org/apache/celeborn/service/deploy/MiniClusterFeature.scala
b/worker/src/test/scala/org/apache/celeborn/service/deploy/MiniClusterFeature.scala
index 95d69fc12..2fab21e71 100644
---
a/worker/src/test/scala/org/apache/celeborn/service/deploy/MiniClusterFeature.scala
+++
b/worker/src/test/scala/org/apache/celeborn/service/deploy/MiniClusterFeature.scala
@@ -213,12 +213,12 @@ trait MiniClusterFeature extends Logging {
val workers = new Array[Worker](workerNum)
val flagUpdateLock = new ReentrantLock()
val threads = (1 to workerNum).map { i =>
+ val worker = createWorker(workerConf)
val workerThread = new RunnerWrap({
var workerStartRetry = 0
var workerStarted = false
while (!workerStarted) {
try {
- val worker = createWorker(workerConf)
flagUpdateLock.lock()
workers(i - 1) = worker
flagUpdateLock.unlock()
diff --git
a/worker/src/test/scala/org/apache/celeborn/service/deploy/worker/WorkerSuite.scala
b/worker/src/test/scala/org/apache/celeborn/service/deploy/worker/WorkerSuite.scala
index 2e13ef1d6..26a1cb1b6 100644
---
a/worker/src/test/scala/org/apache/celeborn/service/deploy/worker/WorkerSuite.scala
+++
b/worker/src/test/scala/org/apache/celeborn/service/deploy/worker/WorkerSuite.scala
@@ -21,27 +21,30 @@ import java.io.File
import java.nio.file.{Files, Paths}
import java.util
import java.util.{HashSet => JHashSet}
-import java.util.concurrent.ConcurrentHashMap
import scala.collection.JavaConverters._
-import scala.collection.mutable.ArrayBuffer
import org.junit.Assert
+import org.mockito.{ArgumentCaptor, ArgumentMatchers, MockedConstruction,
Mockito}
+import org.mockito.MockedConstruction.MockInitializer
+import org.mockito.Mockito.mockConstruction
import org.mockito.MockitoSugar._
-import org.scalatest.{shortstacks, BeforeAndAfterEach}
+import org.scalatest.BeforeAndAfterEach
import org.scalatest.funsuite.AnyFunSuite
import org.apache.celeborn.common.CelebornConf
+import org.apache.celeborn.common.client.MasterClient
import org.apache.celeborn.common.identity.UserIdentifier
-import org.apache.celeborn.common.protocol.{PartitionLocation,
PartitionSplitMode, PartitionType}
+import org.apache.celeborn.common.protocol._
import
org.apache.celeborn.common.protocol.message.ControlMessages.CommitFilesResponse
import org.apache.celeborn.common.protocol.message.StatusCode
import org.apache.celeborn.common.quota.ResourceConsumption
import org.apache.celeborn.common.rpc.RpcCallContext
import org.apache.celeborn.common.util.{CelebornExitKind, JavaUtils,
ThreadUtils}
+import org.apache.celeborn.service.deploy.MiniClusterFeature
import org.apache.celeborn.service.deploy.worker.storage.PartitionDataWriter
-class WorkerSuite extends AnyFunSuite with BeforeAndAfterEach {
+class WorkerSuite extends AnyFunSuite with BeforeAndAfterEach with
MiniClusterFeature {
private var worker: Worker = _
private val conf = new CelebornConf()
private val workerArgs = new WorkerArguments(Array(), conf)
@@ -303,4 +306,47 @@ class WorkerSuite extends AnyFunSuite with
BeforeAndAfterEach {
assert(shuffleCommitTime.get(shuffleKey).get(epoch2) == null)
assert(epochCommitMap.get(epoch2).response.status == StatusCode.SUCCESS)
}
+
+ test("CELEBORN-2257: Properly reports remote disks on worker registration") {
+ val mockInitializer = {
+ // Old syntax needed for scala 2.11
+ new MockInitializer[MasterClient] {
+ override def prepare(instance: MasterClient, context:
MockedConstruction.Context): Unit = {
+ doReturn(PbRegisterWorkerResponse
+ .newBuilder()
+ .setSuccess(true)
+ .build())
+ .when(instance)
+ .askSync(
+ ArgumentMatchers.any(classOf[PbRegisterWorker]),
+ ArgumentMatchers.eq(classOf[PbRegisterWorkerResponse]))
+ }
+ }
+ }
+ val mockedMasterClient = mockConstruction(classOf[MasterClient],
mockInitializer)
+ val argCaptor = ArgumentCaptor.forClass(classOf[PbRegisterWorker])
+ val workerConf: Map[String, String] = Map(
+ CelebornConf.ACTIVE_STORAGE_TYPES.key -> "HDFS",
+ CelebornConf.HDFS_DIR.key -> "file:///")
+ setupMiniClusterWithRandomPorts(workerNum = 1, workerConf = workerConf);
+
+ try {
+ val createdMocks = mockedMasterClient.constructed();
+ assert(createdMocks.size() == 1)
+ verify(createdMocks.get(0), timeout(5000).atLeast(1))
+ .askSync(argCaptor.capture(),
ArgumentMatchers.eq(classOf[PbRegisterWorkerResponse]))
+ val registrationMessage = argCaptor.getValue;
+
+ Assert.assertEquals(2, registrationMessage.getDisksCount)
+ val maybeS3DiskInfo = registrationMessage
+ .getDisksList.asScala
+ .find(diskInfo => diskInfo.getStorageType ==
StorageInfo.Type.HDFS.getValue)
+ assert(maybeS3DiskInfo.nonEmpty)
+ } catch {
+ case e: Throwable => throw e;
+ } finally {
+ shutdownMiniCluster()
+ mockedMasterClient.close()
+ }
+ }
}
diff --git
a/worker/src/test/scala/org/apache/celeborn/service/deploy/worker/storage/StorageManagerSuite.scala
b/worker/src/test/scala/org/apache/celeborn/service/deploy/worker/storage/StorageManagerSuite.scala
index d393df083..fb1d3e2d2 100644
---
a/worker/src/test/scala/org/apache/celeborn/service/deploy/worker/storage/StorageManagerSuite.scala
+++
b/worker/src/test/scala/org/apache/celeborn/service/deploy/worker/storage/StorageManagerSuite.scala
@@ -54,7 +54,7 @@ class StorageManagerSuite extends CelebornFunSuite with
MockitoHelper {
diskInfo.setUsableSpace(-1L)
var diskSetSpace = (0L, 0L)
- doReturn(List(diskInfo)).when(spyStorageManager).disksSnapshot()
+ doReturn(List(diskInfo)).when(spyStorageManager).localDisksSnapshot()
doAnswer(diskSetSpace).when(spyStorageManager).getFileSystemReportedSpace(any)
// disk usable 80g, total 80g, worker config 8EB