Skip to content

Commit c3beeb7

Browse files
lokeshj1703nandakumar131
authored andcommitted
HDDS-2048: State check during container state transition in datanode should be lock protected (#1375)
1 parent bc2d3a7 commit c3beeb7

File tree

3 files changed

+94
-64
lines changed

3 files changed

+94
-64
lines changed

hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueContainer.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@
8282
import org.slf4j.LoggerFactory;
8383

8484
/**
85-
* Class to perform KeyValue Container operations.
85+
* Class to perform KeyValue Container operations. Any modifications to
86+
* KeyValueContainer object should ideally be done via api exposed in
87+
* KeyValueHandler class.
8688
*/
8789
public class KeyValueContainer implements Container<KeyValueContainerData> {
8890

@@ -554,6 +556,8 @@ public boolean hasReadLock() {
554556
* Acquire write lock.
555557
*/
556558
public void writeLock() {
559+
// TODO: The lock for KeyValueContainer object should not be exposed
560+
// publicly.
557561
this.lock.writeLock().lock();
558562
}
559563

hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueHandler.java

Lines changed: 71 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -881,75 +881,97 @@ public void exportContainer(final Container container,
881881
@Override
882882
public void markContainerForClose(Container container)
883883
throws IOException {
884-
// Move the container to CLOSING state only if it's OPEN
885-
if (container.getContainerState() == State.OPEN) {
886-
container.markContainerForClose();
887-
sendICR(container);
884+
container.writeLock();
885+
try {
886+
// Move the container to CLOSING state only if it's OPEN
887+
if (container.getContainerState() == State.OPEN) {
888+
container.markContainerForClose();
889+
sendICR(container);
890+
}
891+
} finally {
892+
container.writeUnlock();
888893
}
889894
}
890895

891896
@Override
892897
public void markContainerUnhealthy(Container container)
893898
throws IOException {
894-
if (container.getContainerState() != State.UNHEALTHY) {
895-
try {
896-
container.markContainerUnhealthy();
897-
} catch (IOException ex) {
898-
// explicitly catch IOException here since the this operation
899-
// will fail if the Rocksdb metadata is corrupted.
900-
long id = container.getContainerData().getContainerID();
901-
LOG.warn("Unexpected error while marking container "
902-
+id+ " as unhealthy", ex);
903-
} finally {
904-
sendICR(container);
899+
container.writeLock();
900+
try {
901+
if (container.getContainerState() != State.UNHEALTHY) {
902+
try {
903+
container.markContainerUnhealthy();
904+
} catch (IOException ex) {
905+
// explicitly catch IOException here since the this operation
906+
// will fail if the Rocksdb metadata is corrupted.
907+
long id = container.getContainerData().getContainerID();
908+
LOG.warn("Unexpected error while marking container " + id
909+
+ " as unhealthy", ex);
910+
} finally {
911+
sendICR(container);
912+
}
905913
}
914+
} finally {
915+
container.writeUnlock();
906916
}
907917
}
908918

909919
@Override
910920
public void quasiCloseContainer(Container container)
911921
throws IOException {
912-
final State state = container.getContainerState();
913-
// Quasi close call is idempotent.
914-
if (state == State.QUASI_CLOSED) {
915-
return;
916-
}
917-
// The container has to be in CLOSING state.
918-
if (state != State.CLOSING) {
919-
ContainerProtos.Result error = state == State.INVALID ?
920-
INVALID_CONTAINER_STATE : CONTAINER_INTERNAL_ERROR;
921-
throw new StorageContainerException("Cannot quasi close container #" +
922-
container.getContainerData().getContainerID() + " while in " +
923-
state + " state.", error);
922+
container.writeLock();
923+
try {
924+
final State state = container.getContainerState();
925+
// Quasi close call is idempotent.
926+
if (state == State.QUASI_CLOSED) {
927+
return;
928+
}
929+
// The container has to be in CLOSING state.
930+
if (state != State.CLOSING) {
931+
ContainerProtos.Result error =
932+
state == State.INVALID ? INVALID_CONTAINER_STATE :
933+
CONTAINER_INTERNAL_ERROR;
934+
throw new StorageContainerException(
935+
"Cannot quasi close container #" + container.getContainerData()
936+
.getContainerID() + " while in " + state + " state.", error);
937+
}
938+
container.quasiClose();
939+
sendICR(container);
940+
} finally {
941+
container.writeUnlock();
924942
}
925-
container.quasiClose();
926-
sendICR(container);
927943
}
928944

929945
@Override
930946
public void closeContainer(Container container)
931947
throws IOException {
932-
final State state = container.getContainerState();
933-
// Close call is idempotent.
934-
if (state == State.CLOSED) {
935-
return;
948+
container.writeLock();
949+
try {
950+
final State state = container.getContainerState();
951+
// Close call is idempotent.
952+
if (state == State.CLOSED) {
953+
return;
954+
}
955+
if (state == State.UNHEALTHY) {
956+
throw new StorageContainerException(
957+
"Cannot close container #" + container.getContainerData()
958+
.getContainerID() + " while in " + state + " state.",
959+
ContainerProtos.Result.CONTAINER_UNHEALTHY);
960+
}
961+
// The container has to be either in CLOSING or in QUASI_CLOSED state.
962+
if (state != State.CLOSING && state != State.QUASI_CLOSED) {
963+
ContainerProtos.Result error =
964+
state == State.INVALID ? INVALID_CONTAINER_STATE :
965+
CONTAINER_INTERNAL_ERROR;
966+
throw new StorageContainerException(
967+
"Cannot close container #" + container.getContainerData()
968+
.getContainerID() + " while in " + state + " state.", error);
969+
}
970+
container.close();
971+
sendICR(container);
972+
} finally {
973+
container.writeUnlock();
936974
}
937-
if (state == State.UNHEALTHY) {
938-
throw new StorageContainerException(
939-
"Cannot close container #" + container.getContainerData()
940-
.getContainerID() + " while in " + state + " state.",
941-
ContainerProtos.Result.CONTAINER_UNHEALTHY);
942-
}
943-
// The container has to be either in CLOSING or in QUASI_CLOSED state.
944-
if (state != State.CLOSING && state != State.QUASI_CLOSED) {
945-
ContainerProtos.Result error = state == State.INVALID ?
946-
INVALID_CONTAINER_STATE : CONTAINER_INTERNAL_ERROR;
947-
throw new StorageContainerException("Cannot close container #" +
948-
container.getContainerData().getContainerID() + " while in " +
949-
state + " state.", error);
950-
}
951-
container.close();
952-
sendICR(container);
953975
}
954976

955977
@Override

hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/impl/BlockManagerImpl.java

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -258,21 +258,25 @@ public List<BlockData> listBlock(Container container, long startLocalID, int
258258
Preconditions.checkArgument(count > 0,
259259
"Count must be a positive number.");
260260
container.readLock();
261-
List<BlockData> result = null;
262-
KeyValueContainerData cData = (KeyValueContainerData) container
263-
.getContainerData();
264-
try(ReferenceCountedDB db = BlockUtils.getDB(cData, config)) {
265-
result = new ArrayList<>();
266-
byte[] startKeyInBytes = Longs.toByteArray(startLocalID);
267-
List<Map.Entry<byte[], byte[]>> range =
268-
db.getStore().getSequentialRangeKVs(startKeyInBytes, count,
269-
MetadataKeyFilters.getNormalKeyFilter());
270-
for (Map.Entry<byte[], byte[]> entry : range) {
271-
BlockData value = BlockUtils.getBlockData(entry.getValue());
272-
BlockData data = new BlockData(value.getBlockID());
273-
result.add(data);
261+
try {
262+
List<BlockData> result = null;
263+
KeyValueContainerData cData =
264+
(KeyValueContainerData) container.getContainerData();
265+
try (ReferenceCountedDB db = BlockUtils.getDB(cData, config)) {
266+
result = new ArrayList<>();
267+
byte[] startKeyInBytes = Longs.toByteArray(startLocalID);
268+
List<Map.Entry<byte[], byte[]>> range = db.getStore()
269+
.getSequentialRangeKVs(startKeyInBytes, count,
270+
MetadataKeyFilters.getNormalKeyFilter());
271+
for (Map.Entry<byte[], byte[]> entry : range) {
272+
BlockData value = BlockUtils.getBlockData(entry.getValue());
273+
BlockData data = new BlockData(value.getBlockID());
274+
result.add(data);
275+
}
276+
return result;
274277
}
275-
return result;
278+
} finally {
279+
container.readUnlock();
276280
}
277281
}
278282

0 commit comments

Comments
 (0)