-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Delete PIT changes #3401
Delete PIT changes #3401
Conversation
20520b2
to
0b44292
Compare
❌ Gradle Check failure 20520b22af5cdee3a7d8daad50ef088a501eca5f |
❌ Gradle Check failure 0b442923704bb5e32c317ca97777f9fa677f77f3 |
0b44292
to
9f382e7
Compare
❌ Gradle Check failure 9f382e7e2ec70f681a76f642e8f697c955bbd173 |
9f382e7
to
53ee52c
Compare
✅ Gradle Check success 53ee52c3e77d01232ecd2a021cc83c87e21cea6b |
53ee52c
to
8229655
Compare
❌ Gradle Check failure 8229655db3ae8ccacbf564a691aaa33899f5822d |
Signed-off-by: Bharathwaj G <[email protected]>
8229655
to
25cc2b1
Compare
Regarding the API, #1147 describes |
Since PIT ID is quite large, and we are supporting deletion of list of pit ids, we made this change to support only list of pit ids in body. Similar APIs like clear scroll also forms a similar pattern. ( though it supports passing id as part of params, now its deprecated ) Behavior: Invalid IDs: |
Signed-off-by: Bharathwaj G <[email protected]>
highLevelClient()::deletePit, | ||
highLevelClient()::deletePitAsync | ||
); | ||
assertTrue(deletePitResponse.isSucceeded()); |
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.
let's verify that searchservice map of activeReader
is empty on each node
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.
we can use 'list all pits api' to verify active pits as part of 'list all pits' pr.
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 making this changes Bharat.
I have requested some
- changes in Delete PIT logic
- suggested an optimization for delete PIt contexts to reduce transport calls
Apart from that have a few minor comments.
Some points to ponder over:
- should we rename from delete PIT to clear PIT. that would in keeping with how scroll is named.
- we could avoid using the term reader context in documentation and rest layer as it might only confuse people. That's a transport layer or service layer construct. As a user I will be only worried if PIT is deleted or not. I wouldn't be wanting to know fi contexts are cleared or not. Just if my operation succeeded.
Will review tests after this batch of comments are addressed
"delete_pit":{ | ||
"documentation":{ | ||
"url":"https://opensearch.org/docs/latest/opensearch/rest-api/point_in_time/", | ||
"description":"Deletes one or more point in time contexts." |
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 be worded differently. Maybe something more on the lines of "Deletes all point-in-time whose id is passed"?
Deletes one or more point in time contexts sounds confusing
User wants an api to delete a PIT. Contexts might be confusing.
"delete_all_pits":{ | ||
"documentation":{ | ||
"url":"https://opensearch.org/docs/latest/opensearch/rest-api/point_in_time/", | ||
"description":"Deletes all active point in time contexts." |
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 mention "contexts"?
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.
context is used as part of scroll as well - 'Explicitly clears the search context for a scroll.'
i think just saying point of time will be confusing, we can take a second opinion here.
import org.opensearch.action.ActionType; | ||
|
||
/** | ||
* Action type for deleting PIT reader contexts |
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.
same as above. let's talk about deleting point-in-time's
the fact that PIT contexts are deleted could be an abstraction to the rest and transport layer.
This description seems to hint we can deleted contexts selectively.
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.
let's talk about deleting point-in-time's
I would consider using "point-in-time search" as the noun form to disambiguate from future point-in-times (e.g. point-in-time restore). It also aligns with the _search/point_in_time
resource path.
server/src/main/java/org/opensearch/action/search/DeletePitResponse.java
Outdated
Show resolved
Hide resolved
pitIds = Arrays.asList(in.readStringArray()); | ||
} | ||
|
||
public DeletePitRequest(String... pitIds) { |
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.
why is this required?
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.
public DeletePitRequest(List<String> pitIds)
should suffice right?
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 we use "_all" , this will be needed.
import java.util.List; | ||
|
||
/** | ||
* Transport action for deleting pit reader context - supports deleting list and all pit contexts |
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.
we are deleting a point in time. Let's not say "deleting pit reader context".
Supports deletion of a list of PIT by their Id's or all PITs
import java.util.Set; | ||
import java.util.function.BiFunction; | ||
import java.util.stream.Collectors; | ||
|
||
/** | ||
* Helper class for common search functions | ||
*/ | ||
public class SearchUtils { |
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.
still not sure why deletePitContexts is not present in PITController and why CreatePitController is not just called PitController or PitService catering to all things PIT
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.
Not a big fan of Utils with static method, any reason why we can't have them encapsulated in a service
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.
Made the change to make it a separate service. One challenge with just putting everything in create pit controller is that there are too many dependencies and integ tests fail with inject errors ( sometimes even on the classes which are existing ). So created a new lightweight service file which will have the common methods. Create pit controller will continue to cater create pit specific methods.
@Override | ||
protected void doExecute(Task task, DeletePitRequest request, ActionListener<DeletePitResponse> listener) { | ||
List<String> pitIds = request.getPitIds(); | ||
if (pitIds.size() == 1 && "_all".equals(pitIds.get(0))) { |
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.
what happens if some one passes PIT Id1, PIT Id2, _all i.e. size!=1 but contains _all ?
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.
we will throw exception when '_all' is passed as part of body as its not a valid encoded pit id. Current implementation accepts '_all' as part of params as its in line with other similar impl such as clear scrolls.
listener.onResponse(new DeletePitResponse(false)); | ||
} | ||
}, e -> { | ||
logger.debug("Delete PITs failed ", e); |
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 ERROR level log
server/src/main/java/org/opensearch/action/search/TransportDeletePitAction.java
Show resolved
Hide resolved
re: Behavior:
As an example, take a look at the documentation for the DynamoDB BatchWriteItem API. It clearly defines how partial success is handled and cases where the entire batch will be rejected. We'll want to think through all those same cases here. |
} | ||
|
||
public DeletePitRequest(List<String> pitIds) { | ||
if (pitIds != 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.
Is null really valid input here? I'd consider just letting this fail with an NPE (or throwing an IllegalArgumentException).
} | ||
} | ||
|
||
public void addPitId(String pitId) { |
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.
Do you need to expose this as a public method? I'd consider simplifying this class by:
- remove this method
- make
pitIds
final, and assign it to an empty list in the default constructor case - in
fromXContent
clearpidIds
and then add to it directly instead of calling this method
|
||
public DeletePitRequest(List<String> pitIds) { | ||
if (pitIds != null) { | ||
this.pitIds = pitIds; |
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 make a defensive copy of the list in this case? This is vulnerable to the action-at-a-distance problem if the caller later modifies the list that was passed here.
server/src/main/java/org/opensearch/rest/action/search/RestDeletePitAction.java
Outdated
Show resolved
Hide resolved
❌ Gradle Check failure 2219aebc9219391ad9f38b80a56560b04b8f56a0 |
9a4f707
to
0ffc780
Compare
❌ Gradle Check failure 0ffc780b8e21378b4fe470bc4ea44f8e31c33b77 |
Signed-off-by: Bharathwaj G <[email protected]>
0ffc780
to
e482053
Compare
❌ Gradle Check failure 36dcd86b4348ea030271053abe31388f7418f439 |
❌ Gradle Check failure a569b07903830a8e764d9a40fa61734f79f34d8e |
a569b07
to
f9db591
Compare
❌ Gradle Check failure f9db591aec235045f91c909589e1bf069c83b64d |
Signed-off-by: Bharathwaj G <[email protected]>
f9db591
to
93f8db7
Compare
❌ Gradle Check failure 2e4c56c4118d1d1c902a2bce6cb440b4ccb1fd65 |
2e4c56c
to
758aaac
Compare
❌ Gradle Check failure 758aaaca96d6507390904a8648c31840df1bcae4 |
758aaac
to
2a25a8a
Compare
❌ Gradle Check failure 2a25a8a099c7a42131f6146ab0ebffe8d26abbaa |
Signed-off-by: Bharathwaj G <[email protected]>
2a25a8a
to
d4ecca2
Compare
@@ -223,7 +228,7 @@ public void testSearchWithFirstPhaseKeepAliveExpiry() throws ExecutionException, | |||
// since first phase temporary keep alive is set at 1 second in this test file | |||
// and create pit request keep alive is less than that, keep alive is set to 1 second, (max of 2 keep alives) | |||
// so reader context will clear up after 1 second | |||
Thread.sleep(1000); | |||
Thread.sleep(1200); |
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.
Thread.sleep()
calls make a test flaky. As everything depends on the state of the server at the time tests are running and CPU context switch that is happening, the code that we expect to finish in 1200ms may take more than that. Is there any way to provide listener?
if (!logger.isDebugEnabled()) return; | ||
for (DeletePitInfo deletePitInfo : response.getDeletePitResults()) { | ||
if (!deletePitInfo.isSucceeded()) { | ||
logger.debug(() -> new ParameterizedMessage("Failed to delete PIT ID {}", deletePitInfo.getPitId())); |
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.
Why debug, should this be warn instead?. Lets have a single log line with concatenated ids?
/** | ||
* This will be true if PIT reader contexts are deleted ond also if contexts are not found. | ||
*/ | ||
private final boolean succeeded; |
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.
Rename to successful
@Override | ||
public ActionRequestValidationException validate() { | ||
ActionRequestValidationException validationException = null; | ||
if (pitIds == null || pitIds.isEmpty()) { |
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.
Use collection utility?
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.
collection utils works on arrays , since this is list, keeping the checks same
import java.util.Set; | ||
import java.util.function.BiFunction; | ||
import java.util.stream.Collectors; | ||
|
||
/** | ||
* Helper class for common search functions | ||
*/ | ||
public class SearchUtils { |
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.
Not a big fan of Utils with static method, any reason why we can't have them encapsulated in a service
private void deletePits(ActionListener<DeletePitResponse> listener, DeletePitRequest request) { | ||
Map<String, List<PitSearchContextIdForNode>> nodeToContextsMap = new HashMap<>(); | ||
for (String pitId : request.getPitIds()) { | ||
SearchContextId contextId = SearchContextId.decode(namedWriteableRegistry, pitId); | ||
for (SearchContextIdForNode contextIdForNode : contextId.shards().values()) { | ||
PitSearchContextIdForNode pitSearchContext = new PitSearchContextIdForNode(pitId, contextIdForNode); | ||
List<PitSearchContextIdForNode> contexts = nodeToContextsMap.getOrDefault(contextIdForNode.getNode(), new ArrayList<>()); | ||
contexts.add(pitSearchContext); | ||
nodeToContextsMap.put(contextIdForNode.getNode(), contexts); | ||
} | ||
} | ||
SearchUtils.deletePitContexts(nodeToContextsMap, listener, clusterService.state(), searchTransportService); | ||
} | ||
|
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.
Lets move this to a Service
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.
Made the change to make it a separate service. One challenge with just putting everything in create pit controller is that there are too many dependencies and integ tests fail with inject errors ( sometimes even on the classes which are existing ). So created a new lightweight service file which will have the common methods. Create pit controller will continue to cater create pit specific methods.
5d62ef1
to
17419e8
Compare
Signed-off-by: Bharathwaj G <[email protected]>
17419e8
to
beacfc1
Compare
* Delete PIT changes Signed-off-by: Bharathwaj G <[email protected]>
Description
This PR contains Delete PIT API changes. User can use '_all' to delete all pit contexts, or pass list of pit IDs as part of body to delete PITs.
Create PIT PR : #2745
Request:
Response:
Issues Resolved
#1147
Check List
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.