This is an automated email from the ASF dual-hosted git repository.
szetszwo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 03c80f8d9b HDDS-12591. Include ContainerInfo in ContainerAttribute.
(#8083)
03c80f8d9b is described below
commit 03c80f8d9bb4eab545852b1a182ab9eca77c39c1
Author: Tsz-Wo Nicholas Sze <[email protected]>
AuthorDate: Fri Mar 14 16:05:08 2025 -0700
HDDS-12591. Include ContainerInfo in ContainerAttribute. (#8083)
---
.../scm/container/states/ContainerAttribute.java | 86 ++++++++++------------
.../scm/container/states/ContainerStateMap.java | 40 ++++++----
.../container/states/TestContainerAttribute.java | 35 ++++-----
3 files changed, 81 insertions(+), 80 deletions(-)
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/states/ContainerAttribute.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/states/ContainerAttribute.java
index 1888471ea2..8a7fdc472b 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/states/ContainerAttribute.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/states/ContainerAttribute.java
@@ -20,17 +20,18 @@
import static
org.apache.hadoop.hdds.scm.exceptions.SCMException.ResultCodes.FAILED_TO_CHANGE_CONTAINER_STATE;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Maps;
+import java.util.ArrayList;
import java.util.EnumMap;
-import java.util.NavigableSet;
+import java.util.List;
+import java.util.NavigableMap;
import java.util.Objects;
-import java.util.SortedSet;
-import java.util.TreeSet;
+import java.util.SortedMap;
+import java.util.TreeMap;
import org.apache.hadoop.hdds.scm.container.ContainerID;
+import org.apache.hadoop.hdds.scm.container.ContainerInfo;
import org.apache.hadoop.hdds.scm.exceptions.SCMException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.ratis.util.Preconditions;
/**
* Each Attribute that we manage for a container is maintained as a map.
@@ -60,11 +61,8 @@
* @param <T> Attribute type
*/
public class ContainerAttribute<T extends Enum<T>> {
- private static final Logger LOG =
- LoggerFactory.getLogger(ContainerAttribute.class);
-
private final Class<T> attributeClass;
- private final ImmutableMap<T, NavigableSet<ContainerID>> attributeMap;
+ private final ImmutableMap<T, NavigableMap<ContainerID, ContainerInfo>>
attributeMap;
/**
* Create an empty Container Attribute map.
@@ -72,25 +70,21 @@ public class ContainerAttribute<T extends Enum<T>> {
public ContainerAttribute(Class<T> attributeClass) {
this.attributeClass = attributeClass;
- final EnumMap<T, NavigableSet<ContainerID>> map = new
EnumMap<>(attributeClass);
+ final EnumMap<T, NavigableMap<ContainerID, ContainerInfo>> map = new
EnumMap<>(attributeClass);
for (T t : attributeClass.getEnumConstants()) {
- map.put(t, new TreeSet<>());
+ map.put(t, new TreeMap<>());
}
this.attributeMap = Maps.immutableEnumMap(map);
}
/**
- * Insert the value in the Attribute map, keep the original value if it
exists
- * already.
- *
- * @param key - The key to the set where the ContainerID should exist.
- * @param value - Actual Container ID.
- * @return true if the value is added;
- * otherwise, the value already exists, return false.
+ * Add the given non-existing {@link ContainerInfo} to this attribute.
+ * @throws IllegalStateException if it already exists.
*/
- public boolean insert(T key, ContainerID value) {
- Objects.requireNonNull(value, "value == null");
- return get(key).add(value);
+ public void addNonExisting(T key, ContainerInfo info) {
+ Objects.requireNonNull(info, "value == null");
+ final ContainerInfo previous = get(key).put(info.containerID(), info);
+ Preconditions.assertNull(previous, "previous");
}
/**
@@ -103,30 +97,30 @@ public void clearSet(T key) {
}
/**
- * Removes a container ID from the set pointed by the key.
- *
- * @param key - key to identify the set.
- * @param value - Container ID
+ * Remove a container for the given id.
+ * @return the info if there was a mapping for the id; otherwise, return null
*/
- public boolean remove(T key, ContainerID value) {
- Objects.requireNonNull(value, "value == null");
+ public ContainerInfo remove(T key, ContainerID id) {
+ Objects.requireNonNull(id, "id == null");
+ return get(key).remove(id);
+ }
- if (!get(key).remove(value)) {
- LOG.debug("Container {} not found in {} attribute", value, key);
- return false;
- }
- return true;
+ /** Remove an existing {@link ContainerInfo}. */
+ public void removeExisting(T key, ContainerInfo existing) {
+ Objects.requireNonNull(existing, "existing == null");
+ final ContainerInfo removed = remove(key, existing.containerID());
+ Preconditions.assertSame(existing, removed, "removed");
}
- NavigableSet<ContainerID> get(T attribute) {
+ NavigableMap<ContainerID, ContainerInfo> get(T attribute) {
Objects.requireNonNull(attribute, "attribute == null");
- final NavigableSet<ContainerID> set = attributeMap.get(attribute);
- if (set == null) {
+ final NavigableMap<ContainerID, ContainerInfo> map =
attributeMap.get(attribute);
+ if (map == null) {
throw new IllegalStateException("Attribute not found: " + attribute
+ " (" + attributeClass.getSimpleName() + ")");
}
- return set;
+ return map;
}
/**
@@ -135,13 +129,13 @@ NavigableSet<ContainerID> get(T attribute) {
* @param key - Key to the bucket.
* @return Underlying Set in immutable form.
*/
- public NavigableSet<ContainerID> getCollection(T key) {
- return ImmutableSortedSet.copyOf(get(key));
+ public List<ContainerInfo> getCollection(T key) {
+ return new ArrayList<>(get(key).values());
}
- public SortedSet<ContainerID> tailSet(T key, ContainerID start) {
+ public SortedMap<ContainerID, ContainerInfo> tailMap(T key, ContainerID
start) {
Objects.requireNonNull(start, "start == null");
- return get(key).tailSet(start);
+ return get(key).tailMap(start);
}
public int count(T key) {
@@ -163,17 +157,13 @@ public void update(T currentKey, T newKey, ContainerID
value)
}
Objects.requireNonNull(newKey, "newKey == null");
- final boolean removed = remove(currentKey, value);
- if (!removed) {
+ final ContainerInfo removed = remove(currentKey, value);
+ if (removed == null) {
throw new SCMException("Failed to update Container " + value + " from "
+ currentKey + " to " + newKey
+ ": Container " + value + " not found in attribute " + currentKey,
FAILED_TO_CHANGE_CONTAINER_STATE);
}
- final boolean inserted = insert(newKey, value);
- if (!inserted) {
- LOG.warn("Update Container {} from {} to {}: Container {} already exists
in {}",
- value, currentKey, newKey, value, newKey);
- }
+ addNonExisting(newKey, removed);
}
}
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/states/ContainerStateMap.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/states/ContainerStateMap.java
index a424183a61..a01ce7c52f 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/states/ContainerStateMap.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/states/ContainerStateMap.java
@@ -68,8 +68,10 @@
* select a container that belongs to user1, with Ratis replication which can
* make 3 copies of data. The fact that we will look for open containers by
* default and if we cannot find them we will add new containers.
- *
+ * <p>
* All the calls are idempotent.
+ * <p>
+ * This class is NOT thread-safe.
*/
public class ContainerStateMap {
private static final Logger LOG =
@@ -167,9 +169,23 @@ ContainerReplica removeReplica(ContainerID containerID,
DatanodeID datanodeID) {
return entry == null ? null : entry.removeReplica(datanodeID);
}
}
-
+ /**
+ * Map {@link LifeCycleState} to {@link ContainerInfo}.
+ * Note that a {@link ContainerInfo} can only exists in at most one of the
{@link LifeCycleState}s.
+ */
private final ContainerAttribute<LifeCycleState> lifeCycleStateMap = new
ContainerAttribute<>(LifeCycleState.class);
+ /**
+ * Map {@link ReplicationType} to {@link ContainerInfo}.
+ * Note that a {@link ContainerInfo} can only exists in at most one of the
{@link ReplicationType}s.
+ */
private final ContainerAttribute<ReplicationType> typeMap = new
ContainerAttribute<>(ReplicationType.class);
+ /**
+ * Map {@link ContainerID} to ({@link ContainerInfo} and {@link
ContainerReplica}).
+ * Note that the following sets are exactly the same
+ * 1. The {@link ContainerInfo} in this map.
+ * 2. The {@link ContainerInfo} in the union of all the states in {@link
#lifeCycleStateMap}.
+ * 2. The {@link ContainerInfo} in the union of all the types in {@link
#typeMap}.
+ */
private final ContainerMap containerMap = new ContainerMap();
/**
@@ -191,9 +207,8 @@ public static Logger getLogger() {
public void addContainer(final ContainerInfo info) {
Objects.requireNonNull(info, "info == null");
if (containerMap.addIfAbsent(info)) {
- final ContainerID id = info.containerID();
- lifeCycleStateMap.insert(info.getState(), id);
- typeMap.insert(info.getReplicationType(), id);
+ lifeCycleStateMap.addNonExisting(info.getState(), info);
+ typeMap.addNonExisting(info.getReplicationType(), info);
LOG.trace("Added {}", info);
}
}
@@ -211,8 +226,8 @@ public void removeContainer(final ContainerID id) {
Objects.requireNonNull(id, "id == null");
final ContainerInfo info = containerMap.remove(id);
if (info != null) {
- lifeCycleStateMap.remove(info.getState(), id);
- typeMap.remove(info.getReplicationType(), id);
+ lifeCycleStateMap.removeExisting(info.getState(), info);
+ typeMap.removeExisting(info.getReplicationType(), info);
LOG.trace("Removed {}", info);
}
}
@@ -291,22 +306,17 @@ public List<ContainerInfo> getContainerInfos(ContainerID
start, int count) {
*/
public List<ContainerInfo> getContainerInfos(LifeCycleState state,
ContainerID start, int count) {
Preconditions.assertTrue(count >= 0, "count < 0");
- return lifeCycleStateMap.tailSet(state, start).stream()
- .map(this::getContainerInfo)
+ return lifeCycleStateMap.tailMap(state, start).values().stream()
.limit(count)
.collect(Collectors.toList());
}
public List<ContainerInfo> getContainerInfos(LifeCycleState state) {
- return lifeCycleStateMap.getCollection(state).stream()
- .map(this::getContainerInfo)
- .collect(Collectors.toList());
+ return lifeCycleStateMap.getCollection(state);
}
public List<ContainerInfo> getContainerInfos(ReplicationType type) {
- return typeMap.getCollection(type).stream()
- .map(this::getContainerInfo)
- .collect(Collectors.toList());
+ return typeMap.getCollection(type);
}
/** @return the number of containers for the given state. */
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/states/TestContainerAttribute.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/states/TestContainerAttribute.java
index acf58ded0b..8f321c8574 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/states/TestContainerAttribute.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/states/TestContainerAttribute.java
@@ -23,8 +23,9 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import java.util.NavigableSet;
+import java.util.NavigableMap;
import org.apache.hadoop.hdds.scm.container.ContainerID;
+import org.apache.hadoop.hdds.scm.container.ContainerInfo;
import org.apache.hadoop.hdds.scm.exceptions.SCMException;
import org.junit.jupiter.api.Test;
@@ -43,24 +44,21 @@ static <T extends Enum<T>> boolean
hasContainerID(ContainerAttribute<T> attribut
}
static <T extends Enum<T>> boolean hasContainerID(ContainerAttribute<T>
attribute, T key, ContainerID id) {
- final NavigableSet<ContainerID> set = attribute.get(key);
- return set != null && set.contains(id);
+ final NavigableMap<ContainerID, ContainerInfo> map = attribute.get(key);
+ return map != null && map.containsKey(id);
}
@Test
- public void testInsert() {
+ public void testAddNonExisting() {
ContainerAttribute<Key> containerAttribute = new
ContainerAttribute<>(Key.class);
- ContainerID id = ContainerID.valueOf(42);
- containerAttribute.insert(key1, id);
+ ContainerInfo info = new
ContainerInfo.Builder().setContainerID(42).build();
+ ContainerID id = info.containerID();
+ containerAttribute.addNonExisting(key1, info);
assertEquals(1, containerAttribute.getCollection(key1).size());
- assertThat(containerAttribute.getCollection(key1)).contains(id);
+ assertThat(containerAttribute.get(key1)).containsKey(id);
- // Insert again and verify that the new ContainerId is inserted.
- ContainerID newId =
- ContainerID.valueOf(42);
- containerAttribute.insert(key1, newId);
- assertEquals(1, containerAttribute.getCollection(key1).size());
- assertThat(containerAttribute.getCollection(key1)).contains(newId);
+ // Adding it again should fail.
+ assertThrows(IllegalStateException.class, () ->
containerAttribute.addNonExisting(key1, info));
}
@Test
@@ -68,7 +66,8 @@ public void testClearSet() {
ContainerAttribute<Key> containerAttribute = new
ContainerAttribute<>(Key.class);
for (Key k : Key.values()) {
for (int x = 1; x < 101; x++) {
- containerAttribute.insert(k, ContainerID.valueOf(x));
+ ContainerInfo info = new
ContainerInfo.Builder().setContainerID(x).build();
+ containerAttribute.addNonExisting(k, info);
}
}
for (Key k : Key.values()) {
@@ -85,7 +84,8 @@ public void testRemove() {
for (Key k : Key.values()) {
for (int x = 1; x < 101; x++) {
- containerAttribute.insert(k, ContainerID.valueOf(x));
+ ContainerInfo info = new
ContainerInfo.Builder().setContainerID(x).build();
+ containerAttribute.addNonExisting(k, info);
}
}
for (int x = 1; x < 101; x += 2) {
@@ -106,9 +106,10 @@ public void testRemove() {
@Test
public void tesUpdate() throws SCMException {
ContainerAttribute<Key> containerAttribute = new
ContainerAttribute<>(Key.class);
- ContainerID id = ContainerID.valueOf(42);
+ ContainerInfo info = new
ContainerInfo.Builder().setContainerID(42).build();
+ ContainerID id = info.containerID();
- containerAttribute.insert(key1, id);
+ containerAttribute.addNonExisting(key1, info);
assertTrue(hasContainerID(containerAttribute, key1, id));
assertFalse(hasContainerID(containerAttribute, key2, id));
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]