Skip to content

Commit a3fdc4d

Browse files
committed
Add dedicated retention lease exceptions
When a retention lease already exists on an add retention lease invocation, or a retention lease is not found on a renew retention lease invocation today we throw an illegal argument exception. This puts a burden on the caller to catch that specific exception and parse the message. This commit relieves the burden from the caller by adding dedicated exception types for these situations.
1 parent ec4f487 commit a3fdc4d

File tree

6 files changed

+149
-3
lines changed

6 files changed

+149
-3
lines changed

server/src/main/java/org/elasticsearch/ElasticsearchException.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -1012,7 +1012,17 @@ private enum ElasticsearchExceptionHandle {
10121012
SNAPSHOT_IN_PROGRESS_EXCEPTION(org.elasticsearch.snapshots.SnapshotInProgressException.class,
10131013
org.elasticsearch.snapshots.SnapshotInProgressException::new, 151, Version.V_6_7_0),
10141014
NO_SUCH_REMOTE_CLUSTER_EXCEPTION(org.elasticsearch.transport.NoSuchRemoteClusterException.class,
1015-
org.elasticsearch.transport.NoSuchRemoteClusterException::new, 152, Version.V_6_7_0);
1015+
org.elasticsearch.transport.NoSuchRemoteClusterException::new, 152, Version.V_6_7_0),
1016+
RETENTION_LEASE_ALREADY_EXISTS_EXCEPTION(
1017+
org.elasticsearch.index.seqno.RetentionLeaseAlreadyExistsException.class,
1018+
org.elasticsearch.index.seqno.RetentionLeaseAlreadyExistsException::new,
1019+
153,
1020+
Version.V_6_7_0),
1021+
RETENTION_LEASE_NOT_FOUND_EXCEPTION(
1022+
org.elasticsearch.index.seqno.RetentionLeaseNotFoundException.class,
1023+
org.elasticsearch.index.seqno.RetentionLeaseNotFoundException::new,
1024+
154,
1025+
Version.V_6_7_0);
10161026

10171027
final Class<? extends ElasticsearchException> exceptionClass;
10181028
final CheckedFunction<StreamInput, ? extends ElasticsearchException, IOException> constructor;

server/src/main/java/org/elasticsearch/index/seqno/ReplicationTracker.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ public RetentionLease addRetentionLease(
237237
synchronized (this) {
238238
assert primaryMode;
239239
if (retentionLeases.contains(id)) {
240-
throw new IllegalArgumentException("retention lease with ID [" + id + "] already exists");
240+
throw new RetentionLeaseAlreadyExistsException(id);
241241
}
242242
retentionLease = new RetentionLease(id, retainingSequenceNumber, currentTimeMillisSupplier.getAsLong(), source);
243243
retentionLeases = new RetentionLeases(
@@ -262,7 +262,7 @@ public RetentionLease addRetentionLease(
262262
public synchronized RetentionLease renewRetentionLease(final String id, final long retainingSequenceNumber, final String source) {
263263
assert primaryMode;
264264
if (retentionLeases.contains(id) == false) {
265-
throw new IllegalArgumentException("retention lease with ID [" + id + "] does not exist");
265+
throw new RetentionLeaseNotFoundException(id);
266266
}
267267
final RetentionLease retentionLease =
268268
new RetentionLease(id, retainingSequenceNumber, currentTimeMillisSupplier.getAsLong(), source);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.index.seqno;
21+
22+
import org.elasticsearch.ResourceAlreadyExistsException;
23+
import org.elasticsearch.common.io.stream.StreamInput;
24+
25+
import java.io.IOException;
26+
import java.util.Objects;
27+
28+
public class RetentionLeaseAlreadyExistsException extends ResourceAlreadyExistsException {
29+
30+
RetentionLeaseAlreadyExistsException(final String id) {
31+
super("retention lease with ID [" + Objects.requireNonNull(id) + "] already exists");
32+
}
33+
34+
public RetentionLeaseAlreadyExistsException(final StreamInput in) throws IOException {
35+
super(in);
36+
}
37+
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.index.seqno;
21+
22+
import org.elasticsearch.ResourceNotFoundException;
23+
import org.elasticsearch.common.io.stream.StreamInput;
24+
25+
import java.io.IOException;
26+
import java.util.Objects;
27+
28+
public class RetentionLeaseNotFoundException extends ResourceNotFoundException {
29+
30+
RetentionLeaseNotFoundException(final String id) {
31+
super("retention lease with ID [" + Objects.requireNonNull(id) + "] not found");
32+
}
33+
34+
public RetentionLeaseNotFoundException(final StreamInput in) throws IOException {
35+
super(in);
36+
}
37+
38+
}

server/src/test/java/org/elasticsearch/ExceptionSerializationTests.java

+4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
import org.elasticsearch.index.Index;
6262
import org.elasticsearch.index.engine.RecoveryEngineException;
6363
import org.elasticsearch.index.query.QueryShardException;
64+
import org.elasticsearch.index.seqno.RetentionLeaseAlreadyExistsException;
65+
import org.elasticsearch.index.seqno.RetentionLeaseNotFoundException;
6466
import org.elasticsearch.index.shard.IllegalIndexShardStateException;
6567
import org.elasticsearch.index.shard.IndexShardState;
6668
import org.elasticsearch.index.shard.ShardId;
@@ -812,6 +814,8 @@ public void testIds() {
812814
ids.put(150, CoordinationStateRejectedException.class);
813815
ids.put(151, SnapshotInProgressException.class);
814816
ids.put(152, NoSuchRemoteClusterException.class);
817+
ids.put(153, RetentionLeaseAlreadyExistsException.class);
818+
ids.put(154, RetentionLeaseNotFoundException.class);
815819

816820
Map<Class<? extends ElasticsearchException>, Integer> reverse = new HashMap<>();
817821
for (Map.Entry<Integer, Class<? extends ElasticsearchException>> entry : ids.entrySet()) {

server/src/test/java/org/elasticsearch/index/seqno/ReplicationTrackerRetentionLeaseTests.java

+56
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@
4141

4242
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
4343
import static org.hamcrest.Matchers.contains;
44+
import static org.hamcrest.Matchers.containsString;
4445
import static org.hamcrest.Matchers.empty;
4546
import static org.hamcrest.Matchers.equalTo;
4647
import static org.hamcrest.Matchers.hasItem;
4748
import static org.hamcrest.Matchers.hasSize;
49+
import static org.hamcrest.Matchers.hasToString;
4850

4951
public class ReplicationTrackerRetentionLeaseTests extends ReplicationTrackerTestCase {
5052

@@ -90,6 +92,60 @@ public void testAddOrRenewRetentionLease() {
9092
}
9193
}
9294

95+
public void testAddDuplicateRetentionLease() {
96+
final AllocationId allocationId = AllocationId.newInitializing();
97+
long primaryTerm = randomLongBetween(1, Long.MAX_VALUE);
98+
final ReplicationTracker replicationTracker = new ReplicationTracker(
99+
new ShardId("test", "_na", 0),
100+
allocationId.getId(),
101+
IndexSettingsModule.newIndexSettings("test", Settings.EMPTY),
102+
primaryTerm,
103+
UNASSIGNED_SEQ_NO,
104+
value -> {},
105+
() -> 0L,
106+
(leases, listener) -> {});
107+
replicationTracker.updateFromMaster(
108+
randomNonNegativeLong(),
109+
Collections.singleton(allocationId.getId()),
110+
routingTable(Collections.emptySet(), allocationId),
111+
Collections.emptySet());
112+
replicationTracker.activatePrimaryMode(SequenceNumbers.NO_OPS_PERFORMED);
113+
final String id = randomAlphaOfLength(8);
114+
final long retainingSequenceNumber = randomNonNegativeLong();
115+
final String source = randomAlphaOfLength(8);
116+
replicationTracker.addRetentionLease(id, retainingSequenceNumber, source, ActionListener.wrap(() -> {}));
117+
final long nextRetaininSequenceNumber = randomLongBetween(retainingSequenceNumber, Long.MAX_VALUE);
118+
final RetentionLeaseAlreadyExistsException e = expectThrows(
119+
RetentionLeaseAlreadyExistsException.class,
120+
() -> replicationTracker.addRetentionLease(id, nextRetaininSequenceNumber, source, ActionListener.wrap(() -> {})));
121+
assertThat(e, hasToString(containsString("retention lease with ID [" + id + "] already exists")));
122+
}
123+
124+
public void testRenewNotFoundRetentionLease() {
125+
final AllocationId allocationId = AllocationId.newInitializing();
126+
long primaryTerm = randomLongBetween(1, Long.MAX_VALUE);
127+
final ReplicationTracker replicationTracker = new ReplicationTracker(
128+
new ShardId("test", "_na", 0),
129+
allocationId.getId(),
130+
IndexSettingsModule.newIndexSettings("test", Settings.EMPTY),
131+
primaryTerm,
132+
UNASSIGNED_SEQ_NO,
133+
value -> {},
134+
() -> 0L,
135+
(leases, listener) -> {});
136+
replicationTracker.updateFromMaster(
137+
randomNonNegativeLong(),
138+
Collections.singleton(allocationId.getId()),
139+
routingTable(Collections.emptySet(), allocationId),
140+
Collections.emptySet());
141+
replicationTracker.activatePrimaryMode(SequenceNumbers.NO_OPS_PERFORMED);
142+
final String id = randomAlphaOfLength(8);
143+
final RetentionLeaseNotFoundException e = expectThrows(
144+
RetentionLeaseNotFoundException.class,
145+
() -> replicationTracker.renewRetentionLease(id, randomNonNegativeLong(), randomAlphaOfLength(8)));
146+
assertThat(e, hasToString(containsString("retention lease with [" + id + "] not found")));
147+
}
148+
93149
public void testAddRetentionLeaseCausesRetentionLeaseSync() {
94150
final AllocationId allocationId = AllocationId.newInitializing();
95151
final Map<String, Long> retainingSequenceNumbers = new HashMap<>();

0 commit comments

Comments
 (0)