HDDS-133:Change format of .container files to Yaml. Contributed by Bharat Viswanadham
This commit is contained in:
parent
772c95395b
commit
143dd560bf
|
@ -52,6 +52,12 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.yaml</groupId>
|
||||||
|
<artifactId>snakeyaml</artifactId>
|
||||||
|
<version>1.8</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.dropwizard.metrics</groupId>
|
<groupId>io.dropwizard.metrics</groupId>
|
||||||
<artifactId>metrics-core</artifactId>
|
<artifactId>metrics-core</artifactId>
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
package org.apache.hadoop.ozone.container.common.impl;
|
package org.apache.hadoop.ozone.container.common.impl;
|
||||||
|
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines layout versions for the Chunks.
|
* Defines layout versions for the Chunks.
|
||||||
*/
|
*/
|
||||||
|
@ -42,6 +44,22 @@ public final class ChunkLayOutVersion {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return ChunkLayOutVersion object for the chunkVersion.
|
||||||
|
* @param chunkVersion
|
||||||
|
* @return ChunkLayOutVersion
|
||||||
|
*/
|
||||||
|
public static ChunkLayOutVersion getChunkLayOutVersion(int chunkVersion) {
|
||||||
|
Preconditions.checkArgument((chunkVersion <= ChunkLayOutVersion
|
||||||
|
.getLatestVersion().getVersion()));
|
||||||
|
for(ChunkLayOutVersion chunkLayOutVersion : CHUNK_LAYOUT_VERSION_INFOS) {
|
||||||
|
if(chunkLayOutVersion.getVersion() == chunkVersion) {
|
||||||
|
return chunkLayOutVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all versions.
|
* Returns all versions.
|
||||||
*
|
*
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class ContainerData {
|
||||||
private final long containerId;
|
private final long containerId;
|
||||||
|
|
||||||
// Layout version of the container data
|
// Layout version of the container data
|
||||||
private final ChunkLayOutVersion layOutVersion;
|
private final int layOutVersion;
|
||||||
|
|
||||||
// Metadata of the container will be a key value pair.
|
// Metadata of the container will be a key value pair.
|
||||||
// This can hold information like volume name, owner etc.,
|
// This can hold information like volume name, owner etc.,
|
||||||
|
@ -67,7 +67,27 @@ public class ContainerData {
|
||||||
public ContainerData(ContainerType type, long containerId) {
|
public ContainerData(ContainerType type, long containerId) {
|
||||||
this.containerType = type;
|
this.containerType = type;
|
||||||
this.containerId = containerId;
|
this.containerId = containerId;
|
||||||
this.layOutVersion = ChunkLayOutVersion.getLatestVersion();
|
this.layOutVersion = ChunkLayOutVersion.getLatestVersion().getVersion();
|
||||||
|
this.metadata = new TreeMap<>();
|
||||||
|
this.state = ContainerLifeCycleState.OPEN;
|
||||||
|
this.readCount = new AtomicLong(0L);
|
||||||
|
this.readBytes = new AtomicLong(0L);
|
||||||
|
this.writeCount = new AtomicLong(0L);
|
||||||
|
this.writeBytes = new AtomicLong(0L);
|
||||||
|
this.bytesUsed = new AtomicLong(0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ContainerData Object, which holds metadata of the container.
|
||||||
|
* @param type - ContainerType
|
||||||
|
* @param containerId - ContainerId
|
||||||
|
* @param layOutVersion - Container layOutVersion
|
||||||
|
*/
|
||||||
|
public ContainerData(ContainerType type, long containerId, int
|
||||||
|
layOutVersion) {
|
||||||
|
this.containerType = type;
|
||||||
|
this.containerId = containerId;
|
||||||
|
this.layOutVersion = layOutVersion;
|
||||||
this.metadata = new TreeMap<>();
|
this.metadata = new TreeMap<>();
|
||||||
this.state = ContainerLifeCycleState.OPEN;
|
this.state = ContainerLifeCycleState.OPEN;
|
||||||
this.readCount = new AtomicLong(0L);
|
this.readCount = new AtomicLong(0L);
|
||||||
|
@ -113,8 +133,8 @@ public class ContainerData {
|
||||||
* Returns the layOutVersion of the actual container data format.
|
* Returns the layOutVersion of the actual container data format.
|
||||||
* @return layOutVersion
|
* @return layOutVersion
|
||||||
*/
|
*/
|
||||||
public ChunkLayOutVersion getLayOutVersion() {
|
public int getLayOutVersion() {
|
||||||
return layOutVersion;
|
return ChunkLayOutVersion.getChunkLayOutVersion(layOutVersion).getVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -52,12 +52,23 @@ public class KeyValueContainerData extends ContainerData {
|
||||||
this.numPendingDeletionBlocks = 0;
|
this.numPendingDeletionBlocks = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs KeyValueContainerData object.
|
||||||
|
* @param type - containerType
|
||||||
|
* @param id - ContainerId
|
||||||
|
* @param layOutVersion
|
||||||
|
*/
|
||||||
|
public KeyValueContainerData(ContainerProtos.ContainerType type, long id,
|
||||||
|
int layOutVersion) {
|
||||||
|
super(type, id, layOutVersion);
|
||||||
|
this.numPendingDeletionBlocks = 0;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Returns path.
|
* Returns path.
|
||||||
*
|
*
|
||||||
* @return - path
|
* @return - path
|
||||||
*/
|
*/
|
||||||
public String getDBPath() {
|
public String getDbPath() {
|
||||||
return dbPath;
|
return dbPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +77,7 @@ public class KeyValueContainerData extends ContainerData {
|
||||||
*
|
*
|
||||||
* @param path - String.
|
* @param path - String.
|
||||||
*/
|
*/
|
||||||
public void setDBPath(String path) {
|
public void setDbPath(String path) {
|
||||||
this.dbPath = path;
|
this.dbPath = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +85,7 @@ public class KeyValueContainerData extends ContainerData {
|
||||||
* Get container file path.
|
* Get container file path.
|
||||||
* @return - Physical path where container file and checksum is stored.
|
* @return - Physical path where container file and checksum is stored.
|
||||||
*/
|
*/
|
||||||
public String getContainerPath() {
|
public String getContainerFilePath() {
|
||||||
return containerFilePath;
|
return containerFilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +93,7 @@ public class KeyValueContainerData extends ContainerData {
|
||||||
* Set container Path.
|
* Set container Path.
|
||||||
* @param containerPath - File path.
|
* @param containerPath - File path.
|
||||||
*/
|
*/
|
||||||
public void setContainerPath(String containerPath) {
|
public void setContainerFilePath(String containerPath) {
|
||||||
this.containerFilePath = containerPath;
|
this.containerFilePath = containerPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,274 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.hadoop.ozone.container.common.impl;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos;
|
||||||
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
|
||||||
|
|
||||||
|
import java.beans.IntrospectionException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.yaml.snakeyaml.constructor.AbstractConstruct;
|
||||||
|
import org.yaml.snakeyaml.constructor.Constructor;
|
||||||
|
import org.yaml.snakeyaml.introspector.BeanAccess;
|
||||||
|
import org.yaml.snakeyaml.introspector.Property;
|
||||||
|
import org.yaml.snakeyaml.introspector.PropertyUtils;
|
||||||
|
import org.yaml.snakeyaml.nodes.MappingNode;
|
||||||
|
import org.yaml.snakeyaml.nodes.Node;
|
||||||
|
import org.yaml.snakeyaml.nodes.ScalarNode;
|
||||||
|
import org.yaml.snakeyaml.nodes.Tag;
|
||||||
|
import org.yaml.snakeyaml.representer.Representer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for creating and reading .container files.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class KeyValueYaml {
|
||||||
|
|
||||||
|
private KeyValueYaml() {
|
||||||
|
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Creates a .container file in yaml format.
|
||||||
|
*
|
||||||
|
* @param containerFile
|
||||||
|
* @param containerData
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static void createContainerFile(File containerFile, ContainerData
|
||||||
|
containerData) throws IOException {
|
||||||
|
|
||||||
|
Preconditions.checkNotNull(containerFile, "yamlFile cannot be null");
|
||||||
|
Preconditions.checkNotNull(containerData, "containerData cannot be null");
|
||||||
|
|
||||||
|
PropertyUtils propertyUtils = new PropertyUtils();
|
||||||
|
propertyUtils.setBeanAccess(BeanAccess.FIELD);
|
||||||
|
propertyUtils.setAllowReadOnlyProperties(true);
|
||||||
|
|
||||||
|
Representer representer = new KeyValueContainerDataRepresenter();
|
||||||
|
representer.setPropertyUtils(propertyUtils);
|
||||||
|
representer.addClassTag(org.apache.hadoop.ozone.container.common.impl
|
||||||
|
.KeyValueContainerData.class, new Tag("KeyValueContainerData"));
|
||||||
|
|
||||||
|
Constructor keyValueDataConstructor = new KeyValueDataConstructor();
|
||||||
|
|
||||||
|
Yaml yaml = new Yaml(keyValueDataConstructor, representer);
|
||||||
|
|
||||||
|
Writer writer = new OutputStreamWriter(new FileOutputStream(containerFile),
|
||||||
|
"UTF-8");
|
||||||
|
yaml.dump(containerData, writer);
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the yaml file, and return containerData.
|
||||||
|
*
|
||||||
|
* @param containerFile
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public static KeyValueContainerData readContainerFile(File containerFile)
|
||||||
|
throws IOException {
|
||||||
|
Preconditions.checkNotNull(containerFile, "containerFile cannot be null");
|
||||||
|
|
||||||
|
InputStream input = null;
|
||||||
|
KeyValueContainerData keyValueContainerData;
|
||||||
|
try {
|
||||||
|
PropertyUtils propertyUtils = new PropertyUtils();
|
||||||
|
propertyUtils.setBeanAccess(BeanAccess.FIELD);
|
||||||
|
propertyUtils.setAllowReadOnlyProperties(true);
|
||||||
|
|
||||||
|
Representer representer = new KeyValueContainerDataRepresenter();
|
||||||
|
representer.setPropertyUtils(propertyUtils);
|
||||||
|
representer.addClassTag(org.apache.hadoop.ozone.container.common.impl
|
||||||
|
.KeyValueContainerData.class, new Tag("KeyValueContainerData"));
|
||||||
|
|
||||||
|
Constructor keyValueDataConstructor = new KeyValueDataConstructor();
|
||||||
|
|
||||||
|
Yaml yaml = new Yaml(keyValueDataConstructor, representer);
|
||||||
|
yaml.setBeanAccess(BeanAccess.FIELD);
|
||||||
|
|
||||||
|
input = new FileInputStream(containerFile);
|
||||||
|
keyValueContainerData = (KeyValueContainerData)
|
||||||
|
yaml.load(input);
|
||||||
|
} finally {
|
||||||
|
if (input!= null) {
|
||||||
|
input.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keyValueContainerData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representer class to define which fields need to be stored in yaml file.
|
||||||
|
*/
|
||||||
|
private static class KeyValueContainerDataRepresenter extends Representer {
|
||||||
|
@Override
|
||||||
|
protected Set<Property> getProperties(Class<? extends Object> type)
|
||||||
|
throws IntrospectionException {
|
||||||
|
Set<Property> set = super.getProperties(type);
|
||||||
|
Set<Property> filtered = new TreeSet<Property>();
|
||||||
|
if (type.equals(KeyValueContainerData.class)) {
|
||||||
|
// filter properties
|
||||||
|
for (Property prop : set) {
|
||||||
|
String name = prop.getName();
|
||||||
|
// When a new field needs to be added, it needs to be added here.
|
||||||
|
if (name.equals("containerType") || name.equals("containerId") ||
|
||||||
|
name.equals("layOutVersion") || name.equals("state") ||
|
||||||
|
name.equals("metadata") || name.equals("dbPath") ||
|
||||||
|
name.equals("containerFilePath") || name.equals(
|
||||||
|
"containerDBType")) {
|
||||||
|
filtered.add(prop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor class for KeyValueData, which will be used by Yaml.
|
||||||
|
*/
|
||||||
|
private static class KeyValueDataConstructor extends Constructor {
|
||||||
|
KeyValueDataConstructor() {
|
||||||
|
//Adding our own specific constructors for tags.
|
||||||
|
this.yamlConstructors.put(new Tag("KeyValueContainerData"),
|
||||||
|
new ConstructKeyValueContainerData());
|
||||||
|
this.yamlConstructors.put(Tag.INT, new ConstructLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ConstructKeyValueContainerData extends AbstractConstruct {
|
||||||
|
public Object construct(Node node) {
|
||||||
|
MappingNode mnode = (MappingNode) node;
|
||||||
|
Map<Object, Object> nodes = constructMapping(mnode);
|
||||||
|
String type = (String) nodes.get("containerType");
|
||||||
|
|
||||||
|
ContainerProtos.ContainerType containerType = ContainerProtos
|
||||||
|
.ContainerType.KeyValueContainer;
|
||||||
|
if (type.equals("KeyValueContainer")) {
|
||||||
|
containerType = ContainerProtos.ContainerType.KeyValueContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Needed this, as TAG.INT type is by default converted to Long.
|
||||||
|
long layOutVersion = (long) nodes.get("layOutVersion");
|
||||||
|
int lv = (int) layOutVersion;
|
||||||
|
|
||||||
|
//When a new field is added, it needs to be added here.
|
||||||
|
KeyValueContainerData kvData = new KeyValueContainerData(containerType,
|
||||||
|
(long) nodes.get("containerId"), lv);
|
||||||
|
kvData.setContainerDBType((String)nodes.get("containerDBType"));
|
||||||
|
kvData.setDbPath((String) nodes.get("dbPath"));
|
||||||
|
kvData.setContainerFilePath((String) nodes.get("containerFilePath"));
|
||||||
|
Map<String, String> meta = (Map) nodes.get("metadata");
|
||||||
|
meta.forEach((key, val) -> {
|
||||||
|
try {
|
||||||
|
kvData.addMetadata(key, val);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalStateException("Unexpected " +
|
||||||
|
"Key Value Pair " + "(" + key + "," + val +")in the metadata " +
|
||||||
|
"for containerId " + (long) nodes.get("containerId"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
String state = (String) nodes.get("state");
|
||||||
|
switch (state) {
|
||||||
|
case "OPEN":
|
||||||
|
kvData.setState(ContainerProtos.ContainerLifeCycleState.OPEN);
|
||||||
|
break;
|
||||||
|
case "CLOSING":
|
||||||
|
kvData.setState(ContainerProtos.ContainerLifeCycleState.CLOSING);
|
||||||
|
break;
|
||||||
|
case "CLOSED":
|
||||||
|
kvData.setState(ContainerProtos.ContainerLifeCycleState.CLOSED);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unexpected " +
|
||||||
|
"ContainerLifeCycleState " + state + " for the containerId " +
|
||||||
|
(long) nodes.get("containerId"));
|
||||||
|
}
|
||||||
|
return kvData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Below code is taken from snake yaml, as snakeyaml tries to fit the
|
||||||
|
// number if it fits in integer, otherwise returns long. So, slightly
|
||||||
|
// modified the code to return long in all cases.
|
||||||
|
private class ConstructLong extends AbstractConstruct {
|
||||||
|
public Object construct(Node node) {
|
||||||
|
String value = constructScalar((ScalarNode) node).toString()
|
||||||
|
.replaceAll("_", "");
|
||||||
|
int sign = +1;
|
||||||
|
char first = value.charAt(0);
|
||||||
|
if (first == '-') {
|
||||||
|
sign = -1;
|
||||||
|
value = value.substring(1);
|
||||||
|
} else if (first == '+') {
|
||||||
|
value = value.substring(1);
|
||||||
|
}
|
||||||
|
int base = 10;
|
||||||
|
if ("0".equals(value)) {
|
||||||
|
return Long.valueOf(0);
|
||||||
|
} else if (value.startsWith("0b")) {
|
||||||
|
value = value.substring(2);
|
||||||
|
base = 2;
|
||||||
|
} else if (value.startsWith("0x")) {
|
||||||
|
value = value.substring(2);
|
||||||
|
base = 16;
|
||||||
|
} else if (value.startsWith("0")) {
|
||||||
|
value = value.substring(1);
|
||||||
|
base = 8;
|
||||||
|
} else if (value.indexOf(':') != -1) {
|
||||||
|
String[] digits = value.split(":");
|
||||||
|
int bes = 1;
|
||||||
|
int val = 0;
|
||||||
|
for (int i = 0, j = digits.length; i < j; i++) {
|
||||||
|
val += (Long.parseLong(digits[(j - i) - 1]) * bes);
|
||||||
|
bes *= 60;
|
||||||
|
}
|
||||||
|
return createNumber(sign, String.valueOf(val), 10);
|
||||||
|
} else {
|
||||||
|
return createNumber(sign, value, 10);
|
||||||
|
}
|
||||||
|
return createNumber(sign, value, base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Number createNumber(int sign, String number, int radix) {
|
||||||
|
Number result;
|
||||||
|
if (sign < 0) {
|
||||||
|
number = "-" + number;
|
||||||
|
}
|
||||||
|
result = Long.valueOf(number, radix);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -38,8 +38,6 @@ public class TestKeyValueContainerData {
|
||||||
long containerId = 1L;
|
long containerId = 1L;
|
||||||
ContainerProtos.ContainerType containerType = ContainerProtos
|
ContainerProtos.ContainerType containerType = ContainerProtos
|
||||||
.ContainerType.KeyValueContainer;
|
.ContainerType.KeyValueContainer;
|
||||||
String path = "/tmp";
|
|
||||||
String containerDBType = "RocksDB";
|
|
||||||
int layOutVersion = 1;
|
int layOutVersion = 1;
|
||||||
ContainerProtos.ContainerLifeCycleState state = ContainerProtos
|
ContainerProtos.ContainerLifeCycleState state = ContainerProtos
|
||||||
.ContainerLifeCycleState.OPEN;
|
.ContainerLifeCycleState.OPEN;
|
||||||
|
@ -57,10 +55,9 @@ public class TestKeyValueContainerData {
|
||||||
|
|
||||||
KeyValueContainerData kvData = KeyValueContainerData.getFromProtoBuf(
|
KeyValueContainerData kvData = KeyValueContainerData.getFromProtoBuf(
|
||||||
containerData);
|
containerData);
|
||||||
|
|
||||||
assertEquals(containerType, kvData.getContainerType());
|
assertEquals(containerType, kvData.getContainerType());
|
||||||
assertEquals(containerId, kvData.getContainerId());
|
assertEquals(containerId, kvData.getContainerId());
|
||||||
assertEquals(layOutVersion, kvData.getLayOutVersion().getVersion());
|
assertEquals(layOutVersion, kvData.getLayOutVersion());
|
||||||
assertEquals(state, kvData.getState());
|
assertEquals(state, kvData.getState());
|
||||||
assertEquals(2, kvData.getMetadata().size());
|
assertEquals(2, kvData.getMetadata().size());
|
||||||
assertEquals("ozone", kvData.getMetadata().get("VOLUME"));
|
assertEquals("ozone", kvData.getMetadata().get("VOLUME"));
|
||||||
|
@ -75,11 +72,9 @@ public class TestKeyValueContainerData {
|
||||||
.ContainerType.KeyValueContainer;
|
.ContainerType.KeyValueContainer;
|
||||||
String path = "/tmp";
|
String path = "/tmp";
|
||||||
String containerDBType = "RocksDB";
|
String containerDBType = "RocksDB";
|
||||||
int layOutVersion = 1;
|
|
||||||
ContainerProtos.ContainerLifeCycleState state = ContainerProtos
|
ContainerProtos.ContainerLifeCycleState state = ContainerProtos
|
||||||
.ContainerLifeCycleState.CLOSED;
|
.ContainerLifeCycleState.CLOSED;
|
||||||
AtomicLong val = new AtomicLong(0);
|
AtomicLong val = new AtomicLong(0);
|
||||||
AtomicLong updatedVal = new AtomicLong(100);
|
|
||||||
|
|
||||||
KeyValueContainerData kvData = new KeyValueContainerData(containerType,
|
KeyValueContainerData kvData = new KeyValueContainerData(containerType,
|
||||||
containerId);
|
containerId);
|
||||||
|
@ -97,8 +92,8 @@ public class TestKeyValueContainerData {
|
||||||
|
|
||||||
kvData.setState(state);
|
kvData.setState(state);
|
||||||
kvData.setContainerDBType(containerDBType);
|
kvData.setContainerDBType(containerDBType);
|
||||||
kvData.setContainerPath(path);
|
kvData.setContainerFilePath(path);
|
||||||
kvData.setDBPath(path);
|
kvData.setDbPath(path);
|
||||||
kvData.incrReadBytes(10);
|
kvData.incrReadBytes(10);
|
||||||
kvData.incrWriteBytes(10);
|
kvData.incrWriteBytes(10);
|
||||||
kvData.incrReadCount();
|
kvData.incrReadCount();
|
||||||
|
@ -106,8 +101,8 @@ public class TestKeyValueContainerData {
|
||||||
|
|
||||||
assertEquals(state, kvData.getState());
|
assertEquals(state, kvData.getState());
|
||||||
assertEquals(containerDBType, kvData.getContainerDBType());
|
assertEquals(containerDBType, kvData.getContainerDBType());
|
||||||
assertEquals(path, kvData.getContainerPath());
|
assertEquals(path, kvData.getContainerFilePath());
|
||||||
assertEquals(path, kvData.getDBPath());
|
assertEquals(path, kvData.getDbPath());
|
||||||
|
|
||||||
assertEquals(10, kvData.getReadBytes());
|
assertEquals(10, kvData.getReadBytes());
|
||||||
assertEquals(10, kvData.getWriteBytes());
|
assertEquals(10, kvData.getWriteBytes());
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.hadoop.ozone.container.common.impl;
|
||||||
|
|
||||||
|
import org.apache.hadoop.fs.FileSystemTestHelper;
|
||||||
|
import org.apache.hadoop.fs.FileUtil;
|
||||||
|
import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos;
|
||||||
|
import org.apache.hadoop.test.GenericTestUtils;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class tests create/read .container files.
|
||||||
|
*/
|
||||||
|
public class TestKeyValueYaml {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateContainerFile() throws IOException {
|
||||||
|
String path = new FileSystemTestHelper().getTestRootDir();
|
||||||
|
String containerPath = "1.container";
|
||||||
|
|
||||||
|
File filePath = new File(new FileSystemTestHelper().getTestRootDir());
|
||||||
|
filePath.mkdirs();
|
||||||
|
|
||||||
|
KeyValueContainerData keyValueContainerData = new KeyValueContainerData(
|
||||||
|
ContainerProtos.ContainerType.KeyValueContainer, Long.MAX_VALUE);
|
||||||
|
keyValueContainerData.setContainerDBType("RocksDB");
|
||||||
|
keyValueContainerData.setDbPath(path);
|
||||||
|
keyValueContainerData.setContainerFilePath(path);
|
||||||
|
|
||||||
|
File containerFile = new File(filePath, containerPath);
|
||||||
|
|
||||||
|
// Create .container file with ContainerData
|
||||||
|
KeyValueYaml.createContainerFile(containerFile, keyValueContainerData);
|
||||||
|
|
||||||
|
//Check .container file exists or not.
|
||||||
|
assertTrue(containerFile.exists());
|
||||||
|
|
||||||
|
// Read from .container file, and verify data.
|
||||||
|
KeyValueContainerData kvData = KeyValueYaml.readContainerFile(
|
||||||
|
containerFile);
|
||||||
|
assertEquals(Long.MAX_VALUE, kvData.getContainerId());
|
||||||
|
assertEquals(ContainerProtos.ContainerType.KeyValueContainer, kvData
|
||||||
|
.getContainerType());
|
||||||
|
assertEquals("RocksDB", kvData.getContainerDBType());
|
||||||
|
assertEquals(path, kvData.getContainerFilePath());
|
||||||
|
assertEquals(path, kvData.getDbPath());
|
||||||
|
assertEquals(ContainerProtos.ContainerLifeCycleState.OPEN, kvData
|
||||||
|
.getState());
|
||||||
|
assertEquals(1, kvData.getLayOutVersion());
|
||||||
|
assertEquals(0, kvData.getMetadata().size());
|
||||||
|
|
||||||
|
// Update ContainerData.
|
||||||
|
kvData.addMetadata("VOLUME", "hdfs");
|
||||||
|
kvData.addMetadata("OWNER", "ozone");
|
||||||
|
kvData.setState(ContainerProtos.ContainerLifeCycleState.CLOSED);
|
||||||
|
|
||||||
|
|
||||||
|
// Update .container file with new ContainerData.
|
||||||
|
containerFile = new File(filePath, containerPath);
|
||||||
|
KeyValueYaml.createContainerFile(containerFile, kvData);
|
||||||
|
|
||||||
|
// Reading newly updated data from .container file
|
||||||
|
kvData = KeyValueYaml.readContainerFile(containerFile);
|
||||||
|
|
||||||
|
// verify data.
|
||||||
|
assertEquals(Long.MAX_VALUE, kvData.getContainerId());
|
||||||
|
assertEquals(ContainerProtos.ContainerType.KeyValueContainer, kvData
|
||||||
|
.getContainerType());
|
||||||
|
assertEquals("RocksDB", kvData.getContainerDBType());
|
||||||
|
assertEquals(path, kvData.getContainerFilePath());
|
||||||
|
assertEquals(path, kvData.getDbPath());
|
||||||
|
assertEquals(ContainerProtos.ContainerLifeCycleState.CLOSED, kvData
|
||||||
|
.getState());
|
||||||
|
assertEquals(1, kvData.getLayOutVersion());
|
||||||
|
assertEquals(2, kvData.getMetadata().size());
|
||||||
|
assertEquals("hdfs", kvData.getMetadata().get("VOLUME"));
|
||||||
|
assertEquals("ozone", kvData.getMetadata().get("OWNER"));
|
||||||
|
|
||||||
|
FileUtil.fullyDelete(filePath);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIncorrectContainerFile() throws IOException{
|
||||||
|
try {
|
||||||
|
String path = "incorrect.container";
|
||||||
|
//Get file from resources folder
|
||||||
|
ClassLoader classLoader = getClass().getClassLoader();
|
||||||
|
File file = new File(classLoader.getResource(path).getFile());
|
||||||
|
KeyValueContainerData kvData = KeyValueYaml.readContainerFile(file);
|
||||||
|
fail("testIncorrectContainerFile failed");
|
||||||
|
} catch (IllegalStateException ex) {
|
||||||
|
GenericTestUtils.assertExceptionContains("Unexpected " +
|
||||||
|
"ContainerLifeCycleState", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCheckBackWardCompatabilityOfContainerFile() throws
|
||||||
|
IOException {
|
||||||
|
// This test is for if we upgrade, and then .container files added by new
|
||||||
|
// server will have new fields added to .container file, after a while we
|
||||||
|
// decided to rollback. Then older ozone can read .container files
|
||||||
|
// created or not.
|
||||||
|
|
||||||
|
try {
|
||||||
|
String path = "additionalfields.container";
|
||||||
|
//Get file from resources folder
|
||||||
|
ClassLoader classLoader = getClass().getClassLoader();
|
||||||
|
File file = new File(classLoader.getResource(path).getFile());
|
||||||
|
KeyValueContainerData kvData = KeyValueYaml.readContainerFile(file);
|
||||||
|
|
||||||
|
//Checking the Container file data is consistent or not
|
||||||
|
assertEquals(ContainerProtos.ContainerLifeCycleState.CLOSED, kvData
|
||||||
|
.getState());
|
||||||
|
assertEquals("RocksDB", kvData.getContainerDBType());
|
||||||
|
assertEquals(ContainerProtos.ContainerType.KeyValueContainer, kvData
|
||||||
|
.getContainerType());
|
||||||
|
assertEquals(9223372036854775807L, kvData.getContainerId());
|
||||||
|
assertEquals("/hdds/current/aed-fg4-hji-jkl/containerdir0/1", kvData
|
||||||
|
.getDbPath());
|
||||||
|
assertEquals("/hdds/current/aed-fg4-hji-jkl/containerdir0/1", kvData
|
||||||
|
.getContainerFilePath());
|
||||||
|
assertEquals(1, kvData.getLayOutVersion());
|
||||||
|
assertEquals(2, kvData.getMetadata().size());
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
fail("testCheckBackWardCompatabilityOfContainerFile failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
!<KeyValueContainerData>
|
||||||
|
containerDBType: RocksDB
|
||||||
|
containerFilePath: /hdds/current/aed-fg4-hji-jkl/containerdir0/1
|
||||||
|
containerId: 9223372036854775807
|
||||||
|
containerType: KeyValueContainer
|
||||||
|
dbPath: /hdds/current/aed-fg4-hji-jkl/containerdir0/1
|
||||||
|
layOutVersion: 1
|
||||||
|
metadata: {OWNER: ozone, VOLUME: hdfs}
|
||||||
|
state: CLOSED
|
|
@ -0,0 +1,10 @@
|
||||||
|
!<KeyValueContainerData>
|
||||||
|
containerDBType: RocksDB
|
||||||
|
containerFilePath: /hdds/current/aed-fg4-hji-jkl/containerdir0/1
|
||||||
|
containerId: 9223372036854775807
|
||||||
|
containerType: KeyValueContainer
|
||||||
|
dbPath: /hdds/current/aed-fg4-hji-jkl/containerdir0/1
|
||||||
|
layOutVersion: 1
|
||||||
|
metadata: {OWNER: ozone, VOLUME: hdfs}
|
||||||
|
state: INVALID
|
||||||
|
aclEnabled: true
|
|
@ -102,6 +102,8 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<exclude>src/main/resources/webapps/static/nvd3-1.8.5.min.css.map</exclude>
|
<exclude>src/main/resources/webapps/static/nvd3-1.8.5.min.css.map</exclude>
|
||||||
<exclude>src/main/resources/webapps/static/nvd3-1.8.5.min.js</exclude>
|
<exclude>src/main/resources/webapps/static/nvd3-1.8.5.min.js</exclude>
|
||||||
<exclude>src/main/resources/webapps/static/nvd3-1.8.5.min.js.map</exclude>
|
<exclude>src/main/resources/webapps/static/nvd3-1.8.5.min.js.map</exclude>
|
||||||
|
<exclude>src/test/resources/incorrect.container</exclude>
|
||||||
|
<exclude>src/test/resources/additionalfields.container</exclude>
|
||||||
</excludes>
|
</excludes>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
Loading…
Reference in New Issue