Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HDDS-3947: Sort DNs for client when the key is a file for #getFileStatus #listStatus APIs #1385

Merged
merged 5 commits into from
Sep 18, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1030,6 +1030,7 @@ public OzoneFileStatus getOzoneFileStatus(String volumeName,
.setBucketName(bucketName)
.setKeyName(keyName)
.setRefreshPipeline(true)
.setSortDatanodesInPipeline(topologyAwareReadEnabled)
.build();
return ozoneManagerClient.getFileStatus(keyArgs);
}
Expand Down Expand Up @@ -1112,6 +1113,7 @@ public List<OzoneFileStatus> listStatus(String volumeName, String bucketName,
.setBucketName(bucketName)
.setKeyName(keyName)
.setRefreshPipeline(true)
.setSortDatanodesInPipeline(topologyAwareReadEnabled)
.build();
return ozoneManagerClient
.listStatus(keyArgs, recursive, startKey, numEntries);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,7 @@ public OzoneFileStatus getFileStatus(OmKeyArgs args) throws IOException {
.setVolumeName(args.getVolumeName())
.setBucketName(args.getBucketName())
.setKeyName(args.getKeyName())
.setSortDatanodes(args.getSortDatanodes())
.build();
GetFileStatusRequest req =
GetFileStatusRequest.newBuilder()
Expand Down Expand Up @@ -1390,6 +1391,7 @@ public List<OzoneFileStatus> listStatus(OmKeyArgs args, boolean recursive,
.setVolumeName(args.getVolumeName())
.setBucketName(args.getBucketName())
.setKeyName(args.getKeyName())
.setSortDatanodes(args.getSortDatanodes())
.build();
ListStatusRequest listStatusRequest =
ListStatusRequest.newBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,8 @@ public static void cleanup() throws Exception {
@After
public void cleanupTest() throws IOException {
List<OzoneFileStatus> fileStatuses = keyManager
.listStatus(createBuilder().setKeyName("").build(), true, "", 100000);
.listStatus(createBuilder().setKeyName("").build(), true, "", 100000,
null);
for (OzoneFileStatus fileStatus : fileStatuses) {
if (fileStatus.isFile()) {
keyManager.deleteKey(
Expand Down Expand Up @@ -833,17 +834,17 @@ public void testListStatusWithTableCache() throws Exception {
OmKeyArgs rootDirArgs = createKeyArgs("");
// Get entries in both TableCache and DB
List<OzoneFileStatus> fileStatuses =
keyManager.listStatus(rootDirArgs, true, "", 1000);
keyManager.listStatus(rootDirArgs, true, "", 1000, null);
Assert.assertEquals(100, fileStatuses.size());

// Get entries with startKey=prefixKeyInDB
fileStatuses =
keyManager.listStatus(rootDirArgs, true, prefixKeyInDB, 1000);
keyManager.listStatus(rootDirArgs, true, prefixKeyInDB, 1000, null);
Assert.assertEquals(50, fileStatuses.size());

// Get entries with startKey=prefixKeyInCache
fileStatuses =
keyManager.listStatus(rootDirArgs, true, prefixKeyInCache, 1000);
keyManager.listStatus(rootDirArgs, true, prefixKeyInCache, 1000, null);
Assert.assertEquals(100, fileStatuses.size());

// Clean up cache by marking those keys in cache as deleted
Expand Down Expand Up @@ -875,12 +876,12 @@ public void testListStatusWithTableCacheRecursive() throws Exception {
OmKeyArgs rootDirArgs = createKeyArgs("");
// Test listStatus with recursive=false, should only have dirs under root
List<OzoneFileStatus> fileStatuses =
keyManager.listStatus(rootDirArgs, false, "", 1000);
keyManager.listStatus(rootDirArgs, false, "", 1000, null);
Assert.assertEquals(2, fileStatuses.size());

// Test listStatus with recursive=true, should have dirs under root and
fileStatuses =
keyManager.listStatus(rootDirArgs, true, "", 1000);
keyManager.listStatus(rootDirArgs, true, "", 1000, null);
Assert.assertEquals(3, fileStatuses.size());

// Add a total of 10 key entries to DB and TableCache under dir1
Expand All @@ -904,12 +905,12 @@ public void testListStatusWithTableCacheRecursive() throws Exception {

// Test non-recursive, should return the dir under root
fileStatuses =
keyManager.listStatus(rootDirArgs, false, "", 1000);
keyManager.listStatus(rootDirArgs, false, "", 1000, null);
Assert.assertEquals(2, fileStatuses.size());

// Test recursive, should return the dir and the keys in it
fileStatuses =
keyManager.listStatus(rootDirArgs, true, "", 1000);
keyManager.listStatus(rootDirArgs, true, "", 1000, null);
Assert.assertEquals(10 + 3, fileStatuses.size());

// Clean up
Expand Down Expand Up @@ -954,12 +955,12 @@ public void testListStatusWithDeletedEntriesInCache() throws Exception {

OmKeyArgs rootDirArgs = createKeyArgs("");
List<OzoneFileStatus> fileStatuses =
keyManager.listStatus(rootDirArgs, true, "", 1000);
keyManager.listStatus(rootDirArgs, true, "", 1000, null);
// Should only get entries that are not marked as deleted.
Assert.assertEquals(50, fileStatuses.size());
// Test startKey
fileStatuses =
keyManager.listStatus(rootDirArgs, true, prefixKey, 1000);
keyManager.listStatus(rootDirArgs, true, prefixKey, 1000, null);
// Should only get entries that are not marked as deleted.
Assert.assertEquals(50, fileStatuses.size());
// Verify result
Expand Down Expand Up @@ -991,7 +992,7 @@ public void testListStatusWithDeletedEntriesInCache() throws Exception {
existKeySet.removeAll(deletedKeySet);

fileStatuses = keyManager.listStatus(
rootDirArgs, true, "", 1000);
rootDirArgs, true, "", 1000, null);
// Should only get entries that are not marked as deleted.
Assert.assertEquals(50 / 2, fileStatuses.size());

Expand All @@ -1010,7 +1011,7 @@ public void testListStatusWithDeletedEntriesInCache() throws Exception {
expectedKeys.clear();
do {
fileStatuses = keyManager.listStatus(
rootDirArgs, true, startKey, batchSize);
rootDirArgs, true, startKey, batchSize, null);
// Note fileStatuses will never be empty since we are using the last
// keyName as the startKey of next batch,
// the startKey itself will show up in the next batch of results.
Expand Down Expand Up @@ -1058,31 +1059,31 @@ public void testListStatus() throws IOException {

OmKeyArgs rootDirArgs = createKeyArgs("");
List<OzoneFileStatus> fileStatuses =
keyManager.listStatus(rootDirArgs, true, "", 100);
keyManager.listStatus(rootDirArgs, true, "", 100, null);
// verify the number of status returned is same as number of entries
Assert.assertEquals(numEntries, fileStatuses.size());

fileStatuses = keyManager.listStatus(rootDirArgs, false, "", 100);
fileStatuses = keyManager.listStatus(rootDirArgs, false, "", 100, null);
// the number of immediate children of root is 1
Assert.assertEquals(1, fileStatuses.size());

// if startKey is the first descendant of the root then listStatus should
// return all the entries.
String startKey = children.iterator().next();
fileStatuses = keyManager.listStatus(rootDirArgs, true,
startKey.substring(0, startKey.length() - 1), 100);
startKey.substring(0, startKey.length() - 1), 100, null);
Assert.assertEquals(numEntries, fileStatuses.size());

for (String directory : directorySet) {
// verify status list received for each directory with recursive flag set
// to false
OmKeyArgs dirArgs = createKeyArgs(directory);
fileStatuses = keyManager.listStatus(dirArgs, false, "", 100);
fileStatuses = keyManager.listStatus(dirArgs, false, "", 100, null);
verifyFileStatus(directory, fileStatuses, directorySet, fileSet, false);

// verify status list received for each directory with recursive flag set
// to true
fileStatuses = keyManager.listStatus(dirArgs, true, "", 100);
fileStatuses = keyManager.listStatus(dirArgs, true, "", 100, null);
verifyFileStatus(directory, fileStatuses, directorySet, fileSet, true);

// verify list status call with using the startKey parameter and
Expand All @@ -1096,7 +1097,7 @@ public void testListStatus() throws IOException {
tempFileStatus != null ?
tempFileStatus.get(tempFileStatus.size() - 1).getKeyInfo()
.getKeyName() : null,
2);
2, null);
tmpStatusSet.addAll(tempFileStatus);
} while (tempFileStatus.size() == 2);
verifyFileStatus(directory, new ArrayList<>(tmpStatusSet), directorySet,
Expand All @@ -1114,7 +1115,7 @@ public void testListStatus() throws IOException {
tempFileStatus.get(tempFileStatus.size() - 1).getKeyInfo()
.getKeyName() :
null,
2);
2, null);
tmpStatusSet.addAll(tempFileStatus);
} while (tempFileStatus.size() == 2);
verifyFileStatus(directory, new ArrayList<>(tmpStatusSet), directorySet,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1732,17 +1732,36 @@ private void validateOzoneObj(OzoneObj obj) throws OMException {
* @param args Key args
* @throws OMException if file does not exist
* if bucket does not exist
* if volume does not exist
* @throws IOException if there is error in the db
* invalid arguments
*/
public OzoneFileStatus getFileStatus(OmKeyArgs args) throws IOException {
Preconditions.checkNotNull(args, "Key args can not be null");
return getFileStatus(args, null);
}

/**
* OzoneFS api to get file status for an entry.
*
* @param args Key args
* @param clientAddress a hint to key manager, order the datanode in returned
* pipeline by distance between client and datanode.
* @throws OMException if file does not exist
* if bucket does not exist
* if volume does not exist
* @throws IOException if there is error in the db
* invalid arguments
*/
public OzoneFileStatus getFileStatus(OmKeyArgs args, String clientAddress)
throws IOException {
Preconditions.checkNotNull(args, "Key args can not be null");
String volumeName = args.getVolumeName();
String bucketName = args.getBucketName();
String keyName = args.getKeyName();

return getOzoneFileStatus(volumeName, bucketName, keyName,
args.getRefreshPipeline(), false, null);
args.getRefreshPipeline(), args.getSortDatanodes(), clientAddress);
}

private OzoneFileStatus getOzoneFileStatus(String volumeName,
Expand Down Expand Up @@ -1783,7 +1802,9 @@ private OzoneFileStatus getOzoneFileStatus(String volumeName,

// if the key is a file then do refresh pipeline info in OM by asking SCM
if (fileKeyInfo != null) {
refreshPipeline(fileKeyInfo);
if (refreshPipeline) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think refreshPipeline condition was removed intentionally in HDDS-3658 and should not be restored. (This is also causing failure of TestKeyManagerUnit.testLookupFileWithDnFailure unit test.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @adoroszlai again for the review help.

Yes, you are correct. Test passed locally without the if (refreshPipeline) condition.

Point-1) That means, the caller should callrefreshPipeline(OmKeyInfo value) method without the refreshPipeline condition.

Point-2) Also, I'm planning to move the refreshPipeline call outside BUCKET_LOCK and will be moving to here. Now, its a duplicate call added as part of HDDS-3658.

Does these two changes make sense to you?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, both points make sense. Thanks for noticing the duplicate call.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, Done!

refreshPipeline(fileKeyInfo);
}
if (sortDatanodes) {
sortDatanodeInPipeline(fileKeyInfo, clientAddress);
}
Expand Down Expand Up @@ -2011,7 +2032,8 @@ private void listStatusFindKeyInTableCache(
* @return list of file status
*/
public List<OzoneFileStatus> listStatus(OmKeyArgs args, boolean recursive,
String startKey, long numEntries) throws IOException {
String startKey, long numEntries, String clientAddress)
throws IOException {
Preconditions.checkNotNull(args, "Key args can not be null");

List<OzoneFileStatus> fileStatusList = new ArrayList<>();
Expand Down Expand Up @@ -2144,10 +2166,14 @@ public List<OzoneFileStatus> listStatus(OmKeyArgs args, boolean recursive,
metadataManager.getLock().releaseReadLock(BUCKET_LOCK, volumeName,
bucketName);
}
if (args.getRefreshPipeline()) {
for(OzoneFileStatus fileStatus : fileStatusList){

for (OzoneFileStatus fileStatus : fileStatusList) {
if (args.getRefreshPipeline()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ChenSammi Was this instance of getRefreshPipeline condition retained in HDDS-3658 intentionally?

refreshPipeline(fileStatus.getKeyInfo());
}
if (args.getSortDatanodes()) {
sortDatanodeInPipeline(fileStatus.getKeyInfo(), clientAddress);
}
}
return fileStatusList;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2797,7 +2797,7 @@ public OzoneFileStatus getFileStatus(OmKeyArgs args) throws IOException {

try {
metrics.incNumGetFileStatus();
return keyManager.getFileStatus(args);
return keyManager.getFileStatus(args, getClientAddress());
} catch (IOException ex) {
metrics.incNumGetFileStatusFails();
auditSuccess = false;
Expand Down Expand Up @@ -2921,7 +2921,8 @@ public List<OzoneFileStatus> listStatus(OmKeyArgs args, boolean recursive,

try {
metrics.incNumListStatus();
return keyManager.listStatus(args, recursive, startKey, numEntries);
return keyManager.listStatus(args, recursive, startKey, numEntries,
getClientAddress());
} catch (Exception ex) {
metrics.incNumListStatusFails();
auditSuccess = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,28 @@
* Ozone Manager FileSystem interface.
*/
public interface OzoneManagerFS extends IOzoneAcl {

/**
* Get file status for a file or a directory.
*
* @param args the args of the key provided by client.
* @return file status.
* @throws IOException if file or bucket or volume does not exist
*/
OzoneFileStatus getFileStatus(OmKeyArgs args) throws IOException;

/**
* Get file status for a file or a directory.
*
* @param args the args of the key provided by client.
* @param clientAddress a hint to key manager, order the datanode in returned
* pipeline by distance between client and datanode.
* @return file status.
* @throws IOException if file or bucket or volume does not exist
*/
OzoneFileStatus getFileStatus(OmKeyArgs args, String clientAddress)
throws IOException;

void createDirectory(OmKeyArgs args) throws IOException;

OpenKeySession createFile(OmKeyArgs args, boolean isOverWrite,
Expand All @@ -49,6 +69,21 @@ OpenKeySession createFile(OmKeyArgs args, boolean isOverWrite,
*/
OmKeyInfo lookupFile(OmKeyArgs args, String clientAddress) throws IOException;

/**
* List the status for a file or a directory and its contents.
*
* @param keyArgs the args of the key provided by client.
* @param recursive For a directory if true all the descendants of a
* particular directory are listed
* @param startKey Key from which listing needs to start. If startKey
* exists its status is included in the final list.
* @param numEntries Number of entries to list from the start key
* @param clientAddress a hint to key manager, order the datanode in returned
* pipeline by distance between client and datanode.
* @return list of file status
* @throws IOException if file or bucket or volume does not exist
*/
List<OzoneFileStatus> listStatus(OmKeyArgs keyArgs, boolean recursive,
String startKey, long numEntries) throws IOException;
String startKey, long numEntries, String clientAddress)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my comment on the previous PR:

Should we also keep the two original methods?

I meant both getFileStatus and listStatus. Sorry if it was unclear.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I will make the changes in my next commit.

Copy link
Contributor Author

@rakeshadr rakeshadr Sep 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adoroszlai , Sorry for re-opening the discussion on this comment. On a second thought listStatus is only used in one place in the source code and there won't be any other caller for listStatus() without ClientAddress. So, how about deleting the original method and can add it later if there is any need ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

listStatus is only used in one place in the source code

It is also used by several tests, which all pass null as address.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, addressed in my new commit

throws IOException;
}