HDFS-11984. Ozone: Ensures listKey lists all required key fields. Contributed by Yiqun Lin.

This commit is contained in:
Weiwei Yang 2017-08-01 13:47:44 +08:00
parent c49297b5b2
commit 1fd2790344
6 changed files with 110 additions and 26 deletions

View File

@ -51,11 +51,11 @@ import org.apache.hadoop.ozone.web.interfaces.StorageHandler;
import org.apache.hadoop.ozone.web.response.ListVolumes;
import org.apache.hadoop.ozone.web.response.VolumeInfo;
import org.apache.hadoop.ozone.web.response.VolumeOwner;
import org.apache.hadoop.ozone.web.utils.OzoneUtils;
import org.apache.hadoop.ozone.web.response.ListBuckets;
import org.apache.hadoop.ozone.web.response.BucketInfo;
import org.apache.hadoop.ozone.web.response.KeyInfo;
import org.apache.hadoop.ozone.web.response.ListKeys;
import org.apache.hadoop.util.Time;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -433,8 +433,10 @@ public final class DistributedStorageHandler implements StorageHandler {
keyInfo.setVersion(0);
keyInfo.setKeyName(ksmKeyInfo.getKeyName());
keyInfo.setSize(ksmKeyInfo.getDataSize());
keyInfo.setCreatedOn(Time.formatTime(ksmKeyInfo.getCreationTime()));
keyInfo.setModifiedOn(Time.formatTime(ksmKeyInfo.getModificationTime()));
keyInfo.setCreatedOn(
OzoneUtils.formatTime(ksmKeyInfo.getCreationTime()));
keyInfo.setModifiedOn(
OzoneUtils.formatTime(ksmKeyInfo.getModificationTime()));
return keyInfo;
}
@ -474,6 +476,10 @@ public final class DistributedStorageHandler implements StorageHandler {
tempInfo.setVersion(0);
tempInfo.setKeyName(info.getKeyName());
tempInfo.setSize(info.getDataSize());
tempInfo.setCreatedOn(
OzoneUtils.formatTime(info.getCreationTime()));
tempInfo.setModifiedOn(
OzoneUtils.formatTime(info.getModificationTime()));
result.addKey(tempInfo);
}

View File

@ -28,6 +28,7 @@ import org.apache.hadoop.ozone.web.exceptions.ErrorTable;
import org.apache.hadoop.ozone.web.exceptions.OzoneException;
import org.apache.hadoop.ozone.web.handlers.UserArgs;
import org.apache.hadoop.ozone.web.headers.Header;
import org.apache.hadoop.util.Time;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Request;
@ -58,6 +59,21 @@ public final class OzoneUtils {
// Never constructed
}
/**
* Date format that used in ozone. Here the format is thread safe to use.
*/
private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT =
new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
SimpleDateFormat format = new SimpleDateFormat(
OzoneConsts.OZONE_DATE_FORMAT, Locale.US);
format.setTimeZone(TimeZone.getTimeZone(OzoneConsts.OZONE_TIME_ZONE));
return format;
}
};
/**
* verifies that bucket name / volume name is a valid DNS name.
*
@ -242,12 +258,8 @@ public final class OzoneUtils {
public static synchronized Date parseDate(String dateString, String reqID,
String resource, String hostname)
throws OzoneException {
SimpleDateFormat format =
new SimpleDateFormat(OzoneConsts.OZONE_DATE_FORMAT, Locale.US);
format.setTimeZone(TimeZone.getTimeZone(OzoneConsts.OZONE_TIME_ZONE));
try {
return format.parse(dateString);
return DATE_FORMAT.get().parse(dateString);
} catch (ParseException ex) {
OzoneException exp =
ErrorTable.newError(ErrorTable.BAD_DATE, reqID, resource, hostname);
@ -267,10 +279,7 @@ public final class OzoneUtils {
*/
public static Response getResponse(UserArgs args, int statusCode,
String payload) {
SimpleDateFormat format =
new SimpleDateFormat(OzoneConsts.OZONE_DATE_FORMAT, Locale.US);
format.setTimeZone(TimeZone.getTimeZone(OzoneConsts.OZONE_TIME_ZONE));
String date = format.format(new Date(System.currentTimeMillis()));
String date = DATE_FORMAT.get().format(new Date(Time.now()));
return Response.ok(payload)
.header(Header.OZONE_SERVER_NAME, args.getHostName())
.header(Header.OZONE_REQUEST_ID, args.getRequestID())
@ -288,10 +297,7 @@ public final class OzoneUtils {
*/
public static Response getResponse(UserArgs args, int statusCode,
LengthInputStream stream) {
SimpleDateFormat format =
new SimpleDateFormat(OzoneConsts.OZONE_DATE_FORMAT, Locale.US);
format.setTimeZone(TimeZone.getTimeZone(OzoneConsts.OZONE_TIME_ZONE));
String date = format.format(new Date(System.currentTimeMillis()));
String date = DATE_FORMAT.get().format(new Date(Time.now()));
return Response.ok(stream, MediaType.APPLICATION_OCTET_STREAM)
.header(Header.OZONE_SERVER_NAME, args.getHostName())
.header(Header.OZONE_REQUEST_ID, args.getRequestID())
@ -319,4 +325,21 @@ public final class OzoneUtils {
}
return dirPath;
}
/**
* Convert time in millisecond to a human readable format required in ozone.
* @return a human readable string for the input time
*/
public static String formatTime(long millis) {
return DATE_FORMAT.get().format(millis);
}
/**
* Convert time in ozone date format to millisecond.
* @return time in milliseconds
*/
public static long formatDate(String date) throws ParseException {
Preconditions.checkNotNull(date, "Date string should not be null.");
return DATE_FORMAT.get().parse(date).getTime();
}
}

View File

@ -961,7 +961,7 @@ public class TestKeySpaceManager {
String adminName = "admin" + RandomStringUtils.randomNumeric(5);
String volumeName = "volume" + RandomStringUtils.randomNumeric(5);
String bucketName = "bucket" + RandomStringUtils.randomNumeric(5);
long currentTime = Time.monotonicNow();
long currentTime = Time.now();
VolumeArgs createVolumeArgs = new VolumeArgs(volumeName, userArgs);
createVolumeArgs.setUserName(userName);
@ -982,8 +982,12 @@ public class TestKeySpaceManager {
stream.close();
KeyInfo keyInfo = storageHandler.getKeyInfo(keyArgs);
Assert.assertTrue(Time.formatDate(keyInfo.getCreatedOn()) >= currentTime);
Assert.assertTrue(Time.formatDate(keyInfo.getModifiedOn()) >= currentTime);
// Compare the time in second unit since the date string reparsed to
// millisecond will lose precision.
Assert.assertTrue((OzoneUtils.formatDate(keyInfo.getCreatedOn())
/ 1000) >= (currentTime / 1000));
Assert.assertTrue((OzoneUtils.formatDate(keyInfo.getModifiedOn())
/ 1000) >= (currentTime / 1000));
Assert.assertEquals(keyName, keyInfo.getKeyName());
Assert.assertEquals(4096, keyInfo.getSize());
}

View File

@ -626,7 +626,11 @@ public class TestOzoneShell {
// verify the response output
assertEquals(0, ToolRunner.run(shell, args));
assertTrue(out.toString().contains(keyName));
String output = out.toString();
assertTrue(output.contains(keyName));
assertTrue(output.contains("createdOn") && output.contains("modifiedOn")
&& output.contains(OzoneConsts.OZONE_TIME_ZONE));
// reset stream
out.reset();
@ -665,12 +669,23 @@ public class TestOzoneShell {
List<String> keys = getValueLines("keyName", out.toString());
assertEquals(11, keys.size());
List<String> creationTime = getValueLines("createdOn", out.toString());
List<String> modificationTime = getValueLines("modifiedOn", out.toString());
assertEquals(11, creationTime.size());
assertEquals(11, modificationTime.size());
// sort key names since the return keys isn't in created order
Collections.sort(keyNames);
// return key names should be [test-key0, test-key1,
// test-key10, test-key2, ,..., test-key9]
for (int i = 0; i < keys.size(); i++) {
assertTrue(keys.get(i).contains(keyNames.get(i)));
// verify the creation/modification time of key
assertTrue(creationTime.get(i).contains(OzoneConsts.OZONE_TIME_ZONE));
assertTrue(
modificationTime.get(i).contains(OzoneConsts.OZONE_TIME_ZONE));
}
out.reset();

View File

@ -31,6 +31,7 @@ import org.apache.hadoop.ozone.web.exceptions.OzoneException;
import org.apache.hadoop.ozone.web.utils.OzoneUtils;
import org.apache.hadoop.test.GenericTestUtils;
import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.util.Time;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.junit.AfterClass;
@ -47,11 +48,13 @@ import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.util.List;
import java.util.Random;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class TestKeys {
@ -387,7 +390,8 @@ public class TestKeys {
}
@Test
public void testPutAndListKey() throws OzoneException, IOException {
public void testPutAndListKey()
throws OzoneException, IOException, ParseException {
runTestPutAndListKey(new PutHelper(ozoneRestClient, path));
String delimiter = RandomStringUtils.randomAscii(1);
runTestPutAndListKey(new PutHelper(ozoneRestClient, path,
@ -395,12 +399,13 @@ public class TestKeys {
}
static void runTestPutAndListKey(PutHelper helper)
throws OzoneException, IOException {
throws OzoneException, IOException, ParseException {
final OzoneRestClient client = helper.client;
helper.putKey();
assertNotNull(helper.getBucket());
assertNotNull(helper.getFile());
long currentTime = Time.now();
// add keys [list-key0, list-key1, ..., list-key9]
for (int x = 0; x < 10; x++) {
String newkeyName = "list-key" + x;
@ -414,6 +419,22 @@ public class TestKeys {
Assert.assertEquals(keyList1.size(), 11);
Assert.assertEquals(keyList2.size(), 11);
// Verify the key creation/modification time. Here we compare the time in
// second unit since the date string reparsed to millisecond will
// lose precision.
for (OzoneKey key : keyList1) {
assertTrue((OzoneUtils.formatDate(key.getObjectInfo().getCreatedOn())
/ 1000) >= (currentTime / 1000));
assertTrue((OzoneUtils.formatDate(key.getObjectInfo().getModifiedOn())
/ 1000) >= (currentTime / 1000));
}
for (OzoneKey key : keyList2) {
assertTrue((OzoneUtils.formatDate(key.getObjectInfo().getCreatedOn())
/ 1000) >= (currentTime / 1000));
assertTrue((OzoneUtils.formatDate(key.getObjectInfo().getModifiedOn())
/ 1000) >= (currentTime / 1000));
}
// test maxLength parameter of list keys
keyList1 = helper.getBucket().listKeys("1", null, null);
@ -459,14 +480,17 @@ public class TestKeys {
}
@Test
public void testGetKeyInfo() throws OzoneException, IOException {
public void testGetKeyInfo()
throws OzoneException, IOException, ParseException {
runTestGetKeyInfo(new PutHelper(ozoneRestClient, path));
String delimiter = RandomStringUtils.randomAscii(1);
runTestGetKeyInfo(new PutHelper(ozoneRestClient, path,
getMultiPartKey(delimiter)));
}
static void runTestGetKeyInfo(PutHelper helper) throws OzoneException {
static void runTestGetKeyInfo(PutHelper helper)
throws OzoneException, ParseException {
long currentTime = Time.now();
String keyName = helper.putKey();
assertNotNull(helper.getBucket());
assertNotNull(helper.getFile());
@ -474,5 +498,14 @@ public class TestKeys {
OzoneKey keyInfo = helper.getBucket().getKeyInfo(keyName);
assertNotNull(keyInfo.getObjectInfo());
assertEquals(keyName, keyInfo.getObjectInfo().getKeyName());
// Compare the time in second unit since the date string reparsed to
// millisecond will lose precision.
Assert.assertTrue(
(OzoneUtils.formatDate(keyInfo.getObjectInfo().getCreatedOn())
/ 1000) >= (currentTime / 1000));
Assert.assertTrue(
(OzoneUtils.formatDate(keyInfo.getObjectInfo().getModifiedOn())
/ 1000) >= (currentTime / 1000));
}
}

View File

@ -29,6 +29,7 @@ import org.junit.rules.Timeout;
import java.io.IOException;
import java.net.URISyntaxException;
import java.text.ParseException;
import static org.apache.hadoop.ozone.web.client.TestKeys.*;
@ -91,7 +92,8 @@ public class TestKeysRatis {
}
@Test
public void testPutAndListKey() throws OzoneException, IOException {
public void testPutAndListKey()
throws OzoneException, IOException, ParseException {
runTestPutAndListKey(new PutHelper(ozoneRestClient, path));
String delimiter = RandomStringUtils.randomAlphanumeric(1);
runTestPutAndListKey(new PutHelper(ozoneRestClient, path,
@ -99,7 +101,8 @@ public class TestKeysRatis {
}
@Test
public void testGetKeyInfo() throws OzoneException, IOException {
public void testGetKeyInfo()
throws OzoneException, IOException, ParseException {
runTestGetKeyInfo(new PutHelper(ozoneRestClient, path));
String delimiter = RandomStringUtils.randomAlphanumeric(1);
runTestGetKeyInfo(new PutHelper(ozoneRestClient, path,