HDFS-11567. Ozone: SCM: Support update container. Contributed by Weiwei Yang.

This commit is contained in:
Xiaoyu Yao 2017-03-29 12:19:31 -07:00 committed by Owen O'Malley
parent 17a6e62629
commit bc9c313907
5 changed files with 167 additions and 2 deletions

View File

@ -163,8 +163,7 @@ public class Dispatcher implements ContainerDispatcher {
return ContainerUtils.unsupportedRequest(msg);
case UpdateContainer:
// TODO : Support Update Container.
return ContainerUtils.unsupportedRequest(msg);
return handleUpdateContainer(msg);
case ReadContainer:
return handleReadContainer(msg);
@ -297,6 +296,33 @@ public class Dispatcher implements ContainerDispatcher {
}
}
/**
* Update an existing container with the new container data.
*
* @param msg Request
* @return ContainerCommandResponseProto
* @throws IOException
*/
private ContainerCommandResponseProto handleUpdateContainer(
ContainerCommandRequestProto msg)
throws IOException {
if (!msg.hasUpdateContainer()) {
LOG.debug("Malformed read container request. trace ID: {}",
msg.getTraceID());
return ContainerUtils.malformedRequest(msg);
}
Pipeline pipeline = Pipeline.getFromProtoBuf(
msg.getUpdateContainer().getPipeline());
String containerName = msg.getUpdateContainer()
.getContainerData().getName();
ContainerData data = ContainerData.getFromProtBuf(
msg.getUpdateContainer().getContainerData());
this.containerManager.updateContainer(pipeline, containerName, data);
return ContainerUtils.getContainerResponse(msg);
}
/**
* Calls into container logic and returns appropriate response.
*

View File

@ -69,6 +69,17 @@ public interface ContainerManager extends RwLock {
void deleteContainer(Pipeline pipeline, String containerName)
throws StorageContainerException;
/**
* Update an existing container.
*
* @param pipeline container nodes
* @param containerName name of the container
* @param data container data
* @throws StorageContainerException
*/
void updateContainer(Pipeline pipeline, String containerName,
ContainerData data) throws StorageContainerException;
/**
* As simple interface for container Iterations.
*

View File

@ -41,6 +41,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.Map;
/**
* Helpers for container tests.
@ -292,6 +293,43 @@ public final class ContainerTestHelper {
return request.build();
}
/**
* Return an update container command for test purposes.
* Creates a container data based on the given meta data,
* and request to update an existing container with it.
*
* @param containerName
* @param metaData
* @return
* @throws IOException
*/
public static ContainerCommandRequestProto getUpdateContainerRequest(
String containerName, Map<String, String> metaData) throws IOException {
ContainerProtos.UpdateContainerRequestProto.Builder updateRequestBuilder =
ContainerProtos.UpdateContainerRequestProto.newBuilder();
ContainerProtos.ContainerData.Builder containerData = ContainerProtos
.ContainerData.newBuilder();
containerData.setName(containerName);
String[] keys = metaData.keySet().toArray(new String[]{});
for(int i=0; i<keys.length; i++) {
ContainerProtos.KeyValue.Builder kvBuilder =
ContainerProtos.KeyValue.newBuilder();
kvBuilder.setKey(keys[i]);
kvBuilder.setValue(metaData.get(keys[i]));
containerData.addMetadata(i, kvBuilder.build());
}
updateRequestBuilder.setPipeline(
ContainerTestHelper.createSingleNodePipeline(containerName)
.getProtobufMessage());
updateRequestBuilder.setContainerData(containerData.build());
ContainerCommandRequestProto.Builder request =
ContainerCommandRequestProto.newBuilder();
request.setCmdType(ContainerProtos.Type.UpdateContainer);
request.setUpdateContainer(updateRequestBuilder.build());
return request.build();
}
/**
* Returns a create container response for test purposes. There are a bunch of
* tests where we need to just send a request and get a reply.

View File

@ -44,6 +44,7 @@ import org.junit.rules.ExpectedException;
import org.junit.rules.Timeout;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.file.DirectoryStream;
@ -613,5 +614,71 @@ public class TestContainerPersistence {
keyManager.deleteKey(pipeline, keyName);
}
/**
* Tries to update an existing and non-existing container.
* Verifies container map and persistent data both updated.
*
* @throws IOException
*/
@Test
public void testUpdateContainer() throws IOException {
String containerName = OzoneUtils.getRequestID();
ContainerData data = new ContainerData(containerName);
data.addMetadata("VOLUME", "shire");
data.addMetadata("owner)", "bilbo");
containerManager.createContainer(
createSingleNodePipeline(containerName),
data);
File orgContainerFile = containerManager.getContainerFile(data);
Assert.assertTrue(orgContainerFile.exists());
ContainerData newData = new ContainerData(containerName);
newData.addMetadata("VOLUME", "shire_new");
newData.addMetadata("owner)", "bilbo_new");
containerManager.updateContainer(
createSingleNodePipeline(containerName),
containerName,
newData);
Assert.assertEquals(1, containerManager.getContainerMap().size());
Assert.assertTrue(containerManager.getContainerMap()
.containsKey(containerName));
// Verify in-memory map
ContainerData actualNewData = containerManager.getContainerMap()
.get(containerName).getContainer();
Assert.assertEquals(actualNewData.getAllMetadata().get("VOLUME"),
"shire_new");
Assert.assertEquals(actualNewData.getAllMetadata().get("owner)"),
"bilbo_new");
// Verify container data on disk
File newContainerFile = containerManager.getContainerFile(actualNewData);
Assert.assertTrue("Container file should exist.",
newContainerFile.exists());
Assert.assertEquals("Container file should be in same location.",
orgContainerFile.getAbsolutePath(),
newContainerFile.getAbsolutePath());
try (FileInputStream newIn = new FileInputStream(newContainerFile)) {
ContainerProtos.ContainerData actualContainerDataProto =
ContainerProtos.ContainerData.parseDelimitedFrom(newIn);
ContainerData actualContainerData = ContainerData
.getFromProtBuf(actualContainerDataProto);
Assert.assertEquals(actualContainerData.getAllMetadata().get("VOLUME"),
"shire_new");
Assert.assertEquals(actualContainerData.getAllMetadata().get("owner)"),
"bilbo_new");
}
// Update a non-existing container
exception.expect(StorageContainerException.class);
exception.expectMessage("Container doesn't exist.");
containerManager.updateContainer(
createSingleNodePipeline("non_exist_container"),
"non_exist_container", newData);
}
}

View File

@ -32,6 +32,8 @@ import org.junit.Test;
import org.junit.rules.Timeout;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
* Tests ozone containers.
@ -177,6 +179,27 @@ public class TestOzoneContainer {
Assert.assertNotNull(response);
Assert.assertEquals(ContainerProtos.Result.SUCCESS, response.getResult());
Assert.assertTrue(request.getTraceID().equals(response.getTraceID()));
//Update an existing container
Map<String, String> containerUpdate = new HashMap<String, String>();
containerUpdate.put("container_updated_key", "container_updated_value");
ContainerProtos.ContainerCommandRequestProto updateRequest1 =
ContainerTestHelper.getUpdateContainerRequest(
containerName, containerUpdate);
ContainerProtos.ContainerCommandResponseProto updateResponse1 =
client.sendCommand(updateRequest1);
Assert.assertNotNull(updateResponse1);
Assert.assertEquals(ContainerProtos.Result.SUCCESS,
response.getResult());
//Update an non-existing container
ContainerProtos.ContainerCommandRequestProto updateRequest2 =
ContainerTestHelper.getUpdateContainerRequest(
"non_exist_container", containerUpdate);
ContainerProtos.ContainerCommandResponseProto updateResponse2 =
client.sendCommand(updateRequest2);
Assert.assertEquals(ContainerProtos.Result.CONTAINER_NOT_FOUND,
updateResponse2.getResult());
} finally {
if (client != null) {
client.close();