-
Notifications
You must be signed in to change notification settings - Fork 474
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-10634. Recon - listKeys API for listing keys with optional filters #6658
Conversation
…Legacy bucket keys with filters.
@sodonnel @sumitagrawl @ArafatKhan2198 @dombizita kindly review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@devmadhuu Thanks for working, have few comments
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/types/ListKeysResponse.java
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Outdated
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Outdated
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Outdated
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Outdated
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this @devmadhuu Few comments for now Ill send in the next comments after some time.
if (StringUtils.isEmpty(dateString)) { | ||
return Instant.now().toEpochMilli(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also Validate dateFormat and timeZone parameters to ensure they are not null.?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this code flow, caller is passing dateFormat and timezone, so they cannot be null, however I have added null check as this method can be called by other callers as well.
* @param dateString | ||
* @param dateFormat | ||
* @param timeZone | ||
* @return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- @return the epoch milliseconds representation of the date.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Date date = sdf.parse(dateString); | ||
return date.getTime(); // Convert to epoch milliseconds | ||
} catch (ParseException parseException) { | ||
log.error("Date parse exception for date: {} in format: {} -> {}", dateString, dateFormat, parseException); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also log the exception details in the general Exception catch block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok done.
public Response validateNames(String resName) | ||
throws IllegalArgumentException { | ||
if (resName.length() < OzoneConsts.OZONE_MIN_BUCKET_NAME_LENGTH || | ||
resName.length() > OzoneConsts.OZONE_MAX_BUCKET_NAME_LENGTH) { | ||
throw new IllegalArgumentException( | ||
"Bucket or Volume name length should be between " + | ||
OzoneConsts.OZONE_MIN_BUCKET_NAME_LENGTH + " and " + | ||
OzoneConsts.OZONE_MAX_BUCKET_NAME_LENGTH); | ||
} | ||
|
||
if (resName.charAt(0) == '.' || resName.charAt(0) == '-' || | ||
resName.charAt(resName.length() - 1) == '.' || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we move some the methods mentioned in this class to ReconUtils?
Like the validateNames here, which could be utilised by other endpoints as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok sure.
* @param startPrefix The search prefix that was used. | ||
* @return The response indicating that no keys matched the search prefix. | ||
*/ | ||
private Response noMatchedKeysResponse(String startPrefix) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an effective way to generate response messages. Can we create a new class named ResponseUtil
and move these methods to it? This will help reduce the amount of code in the current class and make these utility methods available for other endpoints as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
.filter(keySizeFilter) | ||
.collect(Collectors.toList()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The anyMatch
method can beused instead of collecting the filtered entries to a list and checking its size. This makes the code more efficient as the stream will short-circuit on the first match.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed, anyMatch just matches any one element in stream and terminate. We need apply filters on all elements. So this may not suit our usecase.
return matchedKeys; | ||
} | ||
|
||
private boolean applyFilters(Table.KeyValue<String, OmKeyInfo> entry, ParamInfo paramInfo) throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are already propagating the throws IOException
upwards do we require the try and catch block to handle the IOException?
We could further simplify the code in the method by removing them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we need for defining the predicate definition, else compiler gives error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some more comments @devmadhuu
* { | ||
* "status": "OK", | ||
* "path": "/volume1/obs-bucket", | ||
* "replicatedDataSize": 62914560, | ||
* "unReplicatedDataSize": 62914560, | ||
* "lastKey": "/volume1/obs-bucket/key6", | ||
* "keys": [ | ||
* { | ||
* "key": "/volume1/obs-bucket/key1", | ||
* "path": "volume1/obs-bucket/key1", | ||
* "size": 10485760, | ||
* "replicatedSize": 10485760, | ||
* "replicationInfo": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the structure of the JSON response remains consistent across different bucket types, there is no need to show multiple example responses for each bucket type. Instead, we can show one example response and clarify that this structure applies to all bucket types (OBS, Legacy, and FSO).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to keep OBS and FSO, as output values different in path, so that it is evident from javadoc comment. I have removed for LEGACY buckets.
* @param ids The IDs to construct the object path with. | ||
* @return The constructed object path. | ||
*/ | ||
private String constructObjectPathWithPrefix(long... ids) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this can also be placed inside ReconUtils
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok
@@ -300,5 +300,4 @@ public OmDirectoryInfo getDirInfo(String[] names) throws IOException { | |||
.getDirectoryTable().getSkipCache(dirKey); | |||
return dirInfo; | |||
} | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please Remove this unwanted change, from the file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra line space was not needed. So removed.
@@ -785,10 +1103,284 @@ public void testGetDirectorySizeInfo() throws Exception { | |||
assertEquals(18L, keyInsightInfoResp.getUnreplicatedDataSize()); | |||
} | |||
|
|||
@Test | |||
public void testListKeysFSOBucket() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The existing test cases cover the following main scenarios which is great!
- Listing keys at different levels (bucket, directory) for FSO and OBS buckets.
- Verifying the number of keys returned, paths, keys, replication types, and last keys.
- Testing pagination with different limits and across multiple pages.
- Filtering keys based on replication type, creation date, and key size.
- Handling edge cases like empty results and last page with an empty last key.
Can we write a few more methods that test out these simple scenarios as well.
Empty Buckets: Verify the behaviour when the bucket is empty.
Non-existent Paths: Test with paths that do not exist to ensure the API handles such cases gracefully.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@devmadhuu few more comments, please check
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Outdated
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Outdated
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Outdated
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Outdated
Show resolved
Hide resolved
… with FSEnabled flag.
… with FSEnabled flag.
… with FSEnabled flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@devmadhuu Given few comments
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Outdated
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Outdated
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Outdated
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Outdated
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Outdated
Show resolved
Hide resolved
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/OMDBInsightEndpoint.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the changes @devmadhuu
The patch looks good!
LGTM +1
This PR adds a new API in Recon for listing keys for OBS buckets, Legacy buckets and FSO buckets with filters and recursively in a flat structure for OBS, LEGACY and FSO buckets.
New API:
api/v1/keys/listKeys?startPrefix=/volume1/obs-bucket/&limit=105
Default values of API parameters if not provided:
replicationType
- empty string and filter will not be applied, so list out all keys irrespective of replication type.creationTime
- empty string and filter will not be applied, so list out keys irrespective of age, else list out keys which got created on or after provided creationTimekeySize
- 0 bytes, which means all keys greater than zero bytes will be listed, effectively all.startPrefix
- /prevKey
- ""limit
- 1000Behavior of API:
For OBS bucket - list out
limit
number of keys on the provided path.This API will implement pagination support using
prevKey
andlimit
params.Get List of All Keys:
GET /api/v1/keys/listKeys
API params:
replicationType
- Filter for RATIS or EC replication keyscreationDate
in "MM-dd-yyyy HH:mm:ss" string format.startPrefix
prevKey
limit
keySize
Now lets consider, we have following OBS, LEGACY and FSO bucket key/files namespace tree structure
For OBS Bucket
For LEGACY Bucket
For FSO Bucket
Input Request for OBS bucket:
Output Response:
Input Request for FSO bucket:
Output Response:
Input Request for Legacy bucket:
Output Response:
What is the link to the Apache JIRA
https://issues.apache.org/jira/browse/HDDS-10634
How was this patch tested?
Added Junit test cases and tested various assertions.