-
Notifications
You must be signed in to change notification settings - Fork 587
HDDS-11205. Implement a search feature for users to locate keys pending Deletion within the OM Deleted Keys Insights section #6969
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
Merged
Merged
Changes from 6 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
b858f85
HDDS-11205. Implement a search feature for users to locate keys pendi…
ArafatKhan2198 f9a96c5
Fixed a bug and improved the tests
ArafatKhan2198 26223d0
Refactored some code
ArafatKhan2198 abb9d65
Improved the java doc
ArafatKhan2198 abca3c9
Fixed checkstyle issues
ArafatKhan2198 2af1de1
Fixed a dead store variable
ArafatKhan2198 ab9765a
Refactored key search logic to OMDBInsightEndpoint and enhanced with…
ArafatKhan2198 53d8126
Fixed checkstyle issues
ArafatKhan2198 28c4536
Made sure all the Insight endpoints utilise one method for extracting…
ArafatKhan2198 1df317d
Made final review changes
ArafatKhan2198 5d9d3c2
Fixed failing test
ArafatKhan2198 9ec2c32
Fixed java doc error
ArafatKhan2198 384ce67
Merge branch 'master' into HDDS-11205
ArafatKhan2198 28b0b00
Fixed possible java doc comment
ArafatKhan2198 16b2c36
Fixed final java doc problem
ArafatKhan2198 da82a51
Fixed checkstyle issue
ArafatKhan2198 86c9f46
Final review refactoring
ArafatKhan2198 2338c5e
Fixed checkstyle issues
ArafatKhan2198 f688dac
Removed unnecessary blank check
ArafatKhan2198 96a7f79
Reverted back the blank check
ArafatKhan2198 005850a
Done with the null check
ArafatKhan2198 510b307
Fixed the checkstyle and changed the status code
ArafatKhan2198 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -20,12 +20,11 @@ | |||||||||||||||||
|
|
||||||||||||||||||
| import org.apache.hadoop.hdds.scm.server.OzoneStorageContainerManager; | ||||||||||||||||||
| import org.apache.hadoop.hdds.utils.db.Table; | ||||||||||||||||||
| import org.apache.hadoop.hdds.utils.db.TableIterator; | ||||||||||||||||||
| import org.apache.hadoop.ozone.om.helpers.OmBucketInfo; | ||||||||||||||||||
| import org.apache.hadoop.ozone.om.helpers.OmDirectoryInfo; | ||||||||||||||||||
| import org.apache.hadoop.ozone.om.helpers.OmKeyInfo; | ||||||||||||||||||
| import org.apache.hadoop.ozone.om.helpers.BucketLayout; | ||||||||||||||||||
| import org.apache.hadoop.ozone.recon.ReconUtils; | ||||||||||||||||||
| import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo; | ||||||||||||||||||
| import org.apache.hadoop.ozone.recon.api.handlers.BucketHandler; | ||||||||||||||||||
| import org.apache.hadoop.ozone.recon.api.types.KeyEntityInfo; | ||||||||||||||||||
| import org.apache.hadoop.ozone.recon.api.types.KeyInsightInfoResponse; | ||||||||||||||||||
|
|
@@ -50,20 +49,27 @@ | |||||||||||||||||
| import java.util.ArrayList; | ||||||||||||||||||
|
|
||||||||||||||||||
| import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.ReconConstants.DEFAULT_START_PREFIX; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.ReconConstants.RECON_OPEN_KEY_DEFAULT_SEARCH_LIMIT; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.ReconConstants.RECON_OPEN_KEY_SEARCH_DEFAULT_PREV_KEY; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.ReconConstants.RECON_OM_INSIGHTS_DEFAULT_START_PREFIX; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.ReconConstants.RECON_OM_INSIGHTS_DEFAULT_SEARCH_LIMIT; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.ReconConstants.RECON_OM_INSIGHTS_DEFAULT_SEARCH_PREV_KEY; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.ReconResponseUtils.noMatchedKeysResponse; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.ReconResponseUtils.createBadRequestResponse; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.ReconResponseUtils.createInternalServerErrorResponse; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.ReconUtils.constructObjectPathWithPrefix; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.ReconUtils.retrieveKeysFromTable; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.ReconUtils.gatherSubPaths; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.ReconUtils.validateNames; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.api.handlers.BucketHandler.getBucketHandler; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.api.handlers.EntityHandler.normalizePath; | ||||||||||||||||||
| import static org.apache.hadoop.ozone.recon.api.handlers.EntityHandler.parseRequestPath; | ||||||||||||||||||
|
|
||||||||||||||||||
| /** | ||||||||||||||||||
| * REST endpoint for search implementation in OM DB Insight. | ||||||||||||||||||
| * | ||||||||||||||||||
| * This class provides endpoints for searching keys in the Ozone Manager database. | ||||||||||||||||||
| * It supports searching for both open and deleted keys across File System Optimized (FSO) | ||||||||||||||||||
| * and Object Store (non-FSO) bucket layouts. The results include matching keys and their | ||||||||||||||||||
| * data sizes. | ||||||||||||||||||
| */ | ||||||||||||||||||
| @Path("/keys") | ||||||||||||||||||
| @Produces(MediaType.APPLICATION_JSON) | ||||||||||||||||||
|
|
@@ -88,14 +94,14 @@ public OMDBInsightSearchEndpoint(OzoneStorageContainerManager reconSCM, | |||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| /** | ||||||||||||||||||
| * Performs a search for open keys in the Ozone Manager (OM) database using a specified search prefix. | ||||||||||||||||||
| * Performs a search for open keys in the Ozone Manager OpenKey and OpenFile table using a specified search prefix. | ||||||||||||||||||
| * This endpoint searches across both File System Optimized (FSO) and Object Store (non-FSO) layouts, | ||||||||||||||||||
| * compiling a list of keys that match the given prefix along with their data sizes. | ||||||||||||||||||
| * <p> | ||||||||||||||||||
| * | ||||||||||||||||||
| * The search prefix must start from the bucket level ('/volumeName/bucketName/') or any specific directory | ||||||||||||||||||
| * or key level (e.g., '/volA/bucketA/dir1' for everything under 'dir1' inside 'bucketA' of 'volA'). | ||||||||||||||||||
| * The search operation matches the prefix against the start of keys' names within the OM DB. | ||||||||||||||||||
| * <p> | ||||||||||||||||||
| * | ||||||||||||||||||
| * Example Usage: | ||||||||||||||||||
| * 1. A startPrefix of "/volA/bucketA/" retrieves every key under bucket 'bucketA' in volume 'volA'. | ||||||||||||||||||
| * 2. Specifying "/volA/bucketA/dir1" focuses the search within 'dir1' inside 'bucketA' of 'volA'. | ||||||||||||||||||
|
|
@@ -110,25 +116,17 @@ public OMDBInsightSearchEndpoint(OzoneStorageContainerManager reconSCM, | |||||||||||||||||
| @GET | ||||||||||||||||||
| @Path("/open/search") | ||||||||||||||||||
| public Response searchOpenKeys( | ||||||||||||||||||
| @DefaultValue(DEFAULT_START_PREFIX) @QueryParam("startPrefix") | ||||||||||||||||||
| @DefaultValue(RECON_OM_INSIGHTS_DEFAULT_START_PREFIX) @QueryParam("startPrefix") | ||||||||||||||||||
| String startPrefix, | ||||||||||||||||||
| @DefaultValue(RECON_OPEN_KEY_DEFAULT_SEARCH_LIMIT) @QueryParam("limit") | ||||||||||||||||||
| @DefaultValue(RECON_OM_INSIGHTS_DEFAULT_SEARCH_LIMIT) @QueryParam("limit") | ||||||||||||||||||
| int limit, | ||||||||||||||||||
| @DefaultValue(RECON_OPEN_KEY_SEARCH_DEFAULT_PREV_KEY) @QueryParam("prevKey") String prevKey) throws IOException { | ||||||||||||||||||
| @DefaultValue(RECON_OM_INSIGHTS_DEFAULT_SEARCH_PREV_KEY) @QueryParam("prevKey") | ||||||||||||||||||
| String prevKey) throws IOException { | ||||||||||||||||||
|
|
||||||||||||||||||
| try { | ||||||||||||||||||
| // Ensure startPrefix is not null or empty and starts with '/' | ||||||||||||||||||
| if (startPrefix == null || startPrefix.length() == 0) { | ||||||||||||||||||
| return createBadRequestResponse( | ||||||||||||||||||
| "Invalid startPrefix: Path must be at the bucket level or deeper."); | ||||||||||||||||||
| } | ||||||||||||||||||
| startPrefix = startPrefix.startsWith("/") ? startPrefix : "/" + startPrefix; | ||||||||||||||||||
|
|
||||||||||||||||||
| // Split the path to ensure it's at least at the bucket level | ||||||||||||||||||
| String[] pathComponents = startPrefix.split("/"); | ||||||||||||||||||
| if (pathComponents.length < 3 || pathComponents[2].isEmpty()) { | ||||||||||||||||||
| return createBadRequestResponse( | ||||||||||||||||||
| "Invalid startPrefix: Path must be at the bucket level or deeper."); | ||||||||||||||||||
| // Validate the request parameters | ||||||||||||||||||
| if (!validateStartPrefixAndLimit(startPrefix)) { | ||||||||||||||||||
| return createBadRequestResponse("Invalid startPrefix: Path must be at the bucket level or deeper."); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| // Ensure the limit is non-negative | ||||||||||||||||||
|
|
@@ -221,7 +219,7 @@ public Map<String, OmKeyInfo> searchOpenKeysInFSO(String startPrefix, | |||||||||||||||||
| subPaths.add(startPrefixObjectPath); | ||||||||||||||||||
|
|
||||||||||||||||||
| // Recursively gather all subpaths | ||||||||||||||||||
| ReconUtils.gatherSubPaths(parentId, subPaths, Long.parseLong(names[0]), Long.parseLong(names[1]), | ||||||||||||||||||
| gatherSubPaths(parentId, subPaths, Long.parseLong(names[0]), Long.parseLong(names[1]), | ||||||||||||||||||
| reconNamespaceSummaryManager); | ||||||||||||||||||
|
|
||||||||||||||||||
| // Iterate over the subpaths and retrieve the open files | ||||||||||||||||||
|
|
@@ -325,46 +323,93 @@ public String convertToObjectPath(String prevKeyPrefix) throws IOException { | |||||||||||||||||
| return prevKeyPrefix; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| /** | ||||||||||||||||||
| * Common method to retrieve keys from a table based on a search prefix and a limit. | ||||||||||||||||||
| * Performs a search for deleted keys in the Ozone Manager DeletedTable using a specified search prefix. | ||||||||||||||||||
| * In the DeletedTable both the fso and non-fso keys are stored in a similar format, this endpoint compiles | ||||||||||||||||||
| * a list of keys that match the given prefix along with their data sizes. | ||||||||||||||||||
| * | ||||||||||||||||||
| * @param table The table to retrieve keys from. | ||||||||||||||||||
| * @param startPrefix The search prefix to match keys against. | ||||||||||||||||||
| * @param limit The maximum number of keys to retrieve. | ||||||||||||||||||
| * The search prefix must start from the bucket level ('/volumeName/bucketName/') or any specific directory | ||||||||||||||||||
| * or key level (e.g., '/volA/bucketA/dir1' for everything under 'dir1' inside 'bucketA' of 'volA'). | ||||||||||||||||||
| * The search operation matches the prefix against the start of keys' names within the OM DB DeletedTable. | ||||||||||||||||||
| * | ||||||||||||||||||
| * Example Usage: | ||||||||||||||||||
| * 1. A startPrefix of "/volA/bucketA/" retrieves every key under bucket 'bucketA' in volume 'volA'. | ||||||||||||||||||
| * 2. Specifying "/volA/bucketA/dir1" focuses the search within 'dir1' inside 'bucketA' of 'volA'. | ||||||||||||||||||
| * | ||||||||||||||||||
| * @param startPrefix The prefix for searching keys, starting from the bucket level or any specific path. | ||||||||||||||||||
| * @param limit Limits the number of returned keys. | ||||||||||||||||||
| * @param prevKey The key to start after for the next set of records. | ||||||||||||||||||
| * @return A map of keys and their corresponding OmKeyInfo objects. | ||||||||||||||||||
| * @throws IOException If there are problems accessing the table. | ||||||||||||||||||
| * @return A KeyInsightInfoResponse, containing matching keys and their data sizes. | ||||||||||||||||||
| * @throws IOException On failure to access the OM database or process the operation. | ||||||||||||||||||
| */ | ||||||||||||||||||
| private Map<String, OmKeyInfo> retrieveKeysFromTable( | ||||||||||||||||||
| Table<String, OmKeyInfo> table, String startPrefix, int limit, String prevKey) | ||||||||||||||||||
| throws IOException { | ||||||||||||||||||
| Map<String, OmKeyInfo> matchedKeys = new LinkedHashMap<>(); | ||||||||||||||||||
| try (TableIterator<String, ? extends Table.KeyValue<String, OmKeyInfo>> keyIter = table.iterator()) { | ||||||||||||||||||
| // If a previous key is provided, seek to the previous key and skip it. | ||||||||||||||||||
| if (!prevKey.isEmpty()) { | ||||||||||||||||||
| keyIter.seek(prevKey); | ||||||||||||||||||
| if (keyIter.hasNext()) { | ||||||||||||||||||
| // Skip the previous key | ||||||||||||||||||
| keyIter.next(); | ||||||||||||||||||
| } | ||||||||||||||||||
| } else { | ||||||||||||||||||
| // If no previous key is provided, start from the search prefix. | ||||||||||||||||||
| keyIter.seek(startPrefix); | ||||||||||||||||||
| @GET | ||||||||||||||||||
| @Path("/deletePending/search") | ||||||||||||||||||
sumitagrawl marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||
| public Response searchDeletedKeys( | ||||||||||||||||||
|
||||||||||||||||||
| @GET | |
| @Path("/open/search") | |
| public Response searchOpenKeys( | |
| @DefaultValue(DEFAULT_START_PREFIX) @QueryParam("startPrefix") | |
| String startPrefix, | |
| @DefaultValue(RECON_OPEN_KEY_DEFAULT_SEARCH_LIMIT) @QueryParam("limit") | |
| int limit, | |
| @DefaultValue(RECON_OPEN_KEY_SEARCH_DEFAULT_PREV_KEY) @QueryParam("prevKey") String prevKey) throws IOException { |
Can we extract them? Do you think it would make sense?
ArafatKhan2198 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
ArafatKhan2198 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.