HDDS-1511. Space tracking for Open Containers in HDDS Volumes. Contributed by Supratim Deka (#812)

This commit is contained in:
supratimdeka 2019-05-15 22:56:01 +05:30 committed by Arpit Agarwal
parent 570fa2da20
commit 9569015802
4 changed files with 107 additions and 0 deletions

View File

@ -71,6 +71,8 @@ public abstract class ContainerData {
private final long maxSize; private final long maxSize;
private boolean committedSpace;
//ID of the pipeline where this container is created //ID of the pipeline where this container is created
private String originPipelineId; private String originPipelineId;
//ID of the datanode where this container is created //ID of the datanode where this container is created
@ -184,7 +186,23 @@ public synchronized ContainerDataProto.State getState() {
* @param state * @param state
*/ */
public synchronized void setState(ContainerDataProto.State state) { public synchronized void setState(ContainerDataProto.State state) {
ContainerDataProto.State oldState = this.state;
this.state = state; this.state = state;
if ((oldState == ContainerDataProto.State.OPEN) &&
(state != oldState)) {
releaseCommitSpace();
}
/**
* commit space when container transitions (back) to Open.
* when? perhaps closing a container threw an exception
*/
if ((state == ContainerDataProto.State.OPEN) &&
(state != oldState)) {
Preconditions.checkState(getMaxSize() > 0);
commitSpace();
}
} }
/** /**
@ -280,6 +298,41 @@ public synchronized void closeContainer() {
setState(ContainerDataProto.State.CLOSED); setState(ContainerDataProto.State.CLOSED);
} }
private void releaseCommitSpace() {
long unused = getMaxSize() - getBytesUsed();
// only if container size < max size
if (unused > 0 && committedSpace) {
getVolume().incCommittedBytes(0 - unused);
}
committedSpace = false;
}
/**
* add available space in the container to the committed space in the volume.
* available space is the number of bytes remaining till max capacity.
*/
public void commitSpace() {
long unused = getMaxSize() - getBytesUsed();
ContainerDataProto.State myState = getState();
HddsVolume cVol;
//we don't expect duplicate calls
Preconditions.checkState(!committedSpace);
// Only Open Containers have Committed Space
if (myState != ContainerDataProto.State.OPEN) {
return;
}
// junit tests do not always set up volume
cVol = getVolume();
if (unused > 0 && (cVol != null)) {
cVol.incCommittedBytes(unused);
committedSpace = true;
}
}
/** /**
* Get the number of bytes read from the container. * Get the number of bytes read from the container.
* @return the number of bytes read from the container. * @return the number of bytes read from the container.
@ -321,10 +374,20 @@ public long getWriteBytes() {
/** /**
* Increase the number of bytes write into the container. * Increase the number of bytes write into the container.
* Also decrement committed bytes against the bytes written.
* @param bytes the number of bytes write into the container. * @param bytes the number of bytes write into the container.
*/ */
public void incrWriteBytes(long bytes) { public void incrWriteBytes(long bytes) {
long unused = getMaxSize() - getBytesUsed();
this.writeBytes.addAndGet(bytes); this.writeBytes.addAndGet(bytes);
// only if container size < max size
if (committedSpace && unused > 0) {
//with this write, container size might breach max size
long decrement = Math.min(bytes, unused);
this.getVolume().incCommittedBytes(0 - decrement);
}
} }
/** /**

View File

@ -68,6 +68,8 @@ public boolean addContainer(Container container) throws
if(containerMap.putIfAbsent(containerId, container) == null) { if(containerMap.putIfAbsent(containerId, container) == null) {
LOG.debug("Container with container Id {} is added to containerMap", LOG.debug("Container with container Id {} is added to containerMap",
containerId); containerId);
// wish we could have done this from ContainerData.setState
container.getContainerData().commitSpace();
return true; return true;
} else { } else {
LOG.warn("Container already exists with container Id {}", containerId); LOG.warn("Container already exists with container Id {}", containerId);

View File

@ -44,6 +44,7 @@
import java.io.IOException; import java.io.IOException;
import java.util.Properties; import java.util.Properties;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
/** /**
* HddsVolume represents volume in a datanode. {@link VolumeSet} maintains a * HddsVolume represents volume in a datanode. {@link VolumeSet} maintains a
@ -85,6 +86,7 @@ public class HddsVolume
private String datanodeUuid; // id of the DataNode private String datanodeUuid; // id of the DataNode
private long cTime; // creation time of the file system state private long cTime; // creation time of the file system state
private int layoutVersion; // layout version of the storage data private int layoutVersion; // layout version of the storage data
private final AtomicLong committedBytes; // till Open containers become full
/** /**
* Run a check on the current volume to determine if it is healthy. * Run a check on the current volume to determine if it is healthy.
@ -168,6 +170,7 @@ private HddsVolume(Builder b) throws IOException {
.storageType(b.storageType) .storageType(b.storageType)
.configuredCapacity(b.configuredCapacity); .configuredCapacity(b.configuredCapacity);
this.volumeInfo = volumeBuilder.build(); this.volumeInfo = volumeBuilder.build();
this.committedBytes = new AtomicLong(0);
LOG.info("Creating Volume: " + this.hddsRootDir + " of storage type : " + LOG.info("Creating Volume: " + this.hddsRootDir + " of storage type : " +
b.storageType + " and capacity : " + volumeInfo.getCapacity()); b.storageType + " and capacity : " + volumeInfo.getCapacity());
@ -181,6 +184,7 @@ private HddsVolume(Builder b) throws IOException {
volumeInfo = null; volumeInfo = null;
storageID = UUID.randomUUID().toString(); storageID = UUID.randomUUID().toString();
state = VolumeState.FAILED; state = VolumeState.FAILED;
committedBytes = null;
} }
} }
@ -421,6 +425,23 @@ public enum VolumeState {
NOT_INITIALIZED NOT_INITIALIZED
} }
/**
* add "delta" bytes to committed space in the volume.
* @param delta bytes to add to committed space counter
* @return bytes of committed space
*/
public long incCommittedBytes(long delta) {
return committedBytes.addAndGet(delta);
}
/**
* return the committed space in the volume.
* @return bytes of committed space
*/
public long getCommittedBytes() {
return committedBytes.get();
}
/** /**
* Only for testing. Do not use otherwise. * Only for testing. Do not use otherwise.
*/ */

View File

@ -162,6 +162,9 @@ private DispatcherContext getDispatcherContext() {
private Container addContainer(ContainerSet cSet, long cID) private Container addContainer(ContainerSet cSet, long cID)
throws IOException { throws IOException {
long commitBytesBefore = 0;
long commitBytesAfter = 0;
long commitIncrement = 0;
KeyValueContainerData data = new KeyValueContainerData(cID, KeyValueContainerData data = new KeyValueContainerData(cID,
ContainerTestHelper.CONTAINER_MAX_SIZE, UUID.randomUUID().toString(), ContainerTestHelper.CONTAINER_MAX_SIZE, UUID.randomUUID().toString(),
UUID.randomUUID().toString()); UUID.randomUUID().toString());
@ -169,7 +172,15 @@ private Container addContainer(ContainerSet cSet, long cID)
data.addMetadata("owner)", "bilbo"); data.addMetadata("owner)", "bilbo");
KeyValueContainer container = new KeyValueContainer(data, conf); KeyValueContainer container = new KeyValueContainer(data, conf);
container.create(volumeSet, volumeChoosingPolicy, SCM_ID); container.create(volumeSet, volumeChoosingPolicy, SCM_ID);
commitBytesBefore = container.getContainerData()
.getVolume().getCommittedBytes();
cSet.addContainer(container); cSet.addContainer(container);
commitBytesAfter = container.getContainerData()
.getVolume().getCommittedBytes();
commitIncrement = commitBytesAfter - commitBytesBefore;
// did we commit space for the new container?
Assert.assertTrue(commitIncrement ==
ContainerTestHelper.CONTAINER_MAX_SIZE);
return container; return container;
} }
@ -328,6 +339,9 @@ public void testListContainer() throws IOException {
private ChunkInfo writeChunkHelper(BlockID blockID) throws IOException { private ChunkInfo writeChunkHelper(BlockID blockID) throws IOException {
final int datalen = 1024; final int datalen = 1024;
long commitBytesBefore = 0;
long commitBytesAfter = 0;
long commitDecrement = 0;
long testContainerID = blockID.getContainerID(); long testContainerID = blockID.getContainerID();
Container container = containerSet.getContainer(testContainerID); Container container = containerSet.getContainer(testContainerID);
if (container == null) { if (container == null) {
@ -337,8 +351,15 @@ private ChunkInfo writeChunkHelper(BlockID blockID) throws IOException {
blockID.getLocalID(), 0, 0, datalen); blockID.getLocalID(), 0, 0, datalen);
byte[] data = getData(datalen); byte[] data = getData(datalen);
setDataChecksum(info, data); setDataChecksum(info, data);
commitBytesBefore = container.getContainerData()
.getVolume().getCommittedBytes();
chunkManager.writeChunk(container, blockID, info, ByteBuffer.wrap(data), chunkManager.writeChunk(container, blockID, info, ByteBuffer.wrap(data),
getDispatcherContext()); getDispatcherContext());
commitBytesAfter = container.getContainerData()
.getVolume().getCommittedBytes();
commitDecrement = commitBytesBefore - commitBytesAfter;
// did we decrement commit bytes by the amount of data we wrote?
Assert.assertTrue(commitDecrement == info.getLen());
return info; return info;
} }