Skip to content

Commit 58adc18

Browse files
authored
BugFix: call listener.onFailure on failure to pin the timestamp (#16248)
Signed-off-by: Sachin Kale <[email protected]>
1 parent d7b0116 commit 58adc18

File tree

2 files changed

+131
-21
lines changed

2 files changed

+131
-21
lines changed

server/src/internalClusterTest/java/org/opensearch/remotestore/RemoteStorePinnedTimestampsIT.java

Lines changed: 119 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,40 +11,59 @@
1111
import org.opensearch.action.LatchedActionListener;
1212
import org.opensearch.action.admin.cluster.node.stats.NodeStats;
1313
import org.opensearch.action.admin.cluster.node.stats.NodesStatsResponse;
14+
import org.opensearch.action.admin.cluster.repositories.get.GetRepositoriesRequest;
15+
import org.opensearch.action.admin.cluster.repositories.get.GetRepositoriesResponse;
16+
import org.opensearch.cluster.metadata.RepositoryMetadata;
1417
import org.opensearch.common.collect.Tuple;
1518
import org.opensearch.common.settings.Settings;
1619
import org.opensearch.common.unit.TimeValue;
1720
import org.opensearch.core.action.ActionListener;
1821
import org.opensearch.indices.RemoteStoreSettings;
1922
import org.opensearch.node.remotestore.RemoteStorePinnedTimestampService;
23+
import org.opensearch.repositories.fs.ReloadableFsRepository;
2024
import org.opensearch.test.OpenSearchIntegTestCase;
2125

2226
import java.util.List;
27+
import java.util.Locale;
2328
import java.util.Map;
2429
import java.util.Optional;
2530
import java.util.Set;
2631
import java.util.concurrent.CountDownLatch;
32+
import java.util.concurrent.ExecutionException;
2733

2834
import static org.opensearch.action.admin.cluster.node.stats.NodesStatsRequest.Metric.REMOTE_STORE;
35+
import static org.opensearch.node.remotestore.RemoteStoreNodeAttribute.REMOTE_STORE_REPOSITORY_TYPE_ATTRIBUTE_KEY_FORMAT;
36+
import static org.opensearch.repositories.fs.ReloadableFsRepository.REPOSITORIES_SLOWDOWN_SETTING;
2937

3038
@OpenSearchIntegTestCase.ClusterScope(scope = OpenSearchIntegTestCase.Scope.TEST, numDataNodes = 0)
3139
public class RemoteStorePinnedTimestampsIT extends RemoteStoreBaseIntegTestCase {
3240
static final String INDEX_NAME = "remote-store-test-idx-1";
3341

3442
@Override
3543
protected Settings nodeSettings(int nodeOrdinal) {
44+
String segmentRepoTypeAttributeKey = String.format(
45+
Locale.getDefault(),
46+
"node.attr." + REMOTE_STORE_REPOSITORY_TYPE_ATTRIBUTE_KEY_FORMAT,
47+
REPOSITORY_NAME
48+
);
49+
3650
return Settings.builder()
3751
.put(super.nodeSettings(nodeOrdinal))
52+
.put(segmentRepoTypeAttributeKey, ReloadableFsRepository.TYPE)
3853
.put(RemoteStoreSettings.CLUSTER_REMOTE_STORE_PINNED_TIMESTAMP_ENABLED.getKey(), true)
3954
.build();
4055
}
4156

4257
ActionListener<Void> noOpActionListener = new ActionListener<>() {
4358
@Override
44-
public void onResponse(Void unused) {}
59+
public void onResponse(Void unused) {
60+
// do nothing
61+
}
4562

4663
@Override
47-
public void onFailure(Exception e) {}
64+
public void onFailure(Exception e) {
65+
fail();
66+
}
4867
};
4968

5069
public void testTimestampPinUnpin() throws Exception {
@@ -57,15 +76,8 @@ public void testTimestampPinUnpin() throws Exception {
5776
);
5877

5978
Tuple<Long, Set<Long>> pinnedTimestampWithFetchTimestamp = RemoteStorePinnedTimestampService.getPinnedTimestamps();
60-
long lastFetchTimestamp = pinnedTimestampWithFetchTimestamp.v1();
61-
assertEquals(-1L, lastFetchTimestamp);
6279
assertEquals(Set.of(), pinnedTimestampWithFetchTimestamp.v2());
6380

64-
assertThrows(
65-
IllegalArgumentException.class,
66-
() -> remoteStorePinnedTimestampService.pinTimestamp(1234L, "ss1", noOpActionListener)
67-
);
68-
6981
long timestamp1 = System.currentTimeMillis() + 30000L;
7082
long timestamp2 = System.currentTimeMillis() + 60000L;
7183
long timestamp3 = System.currentTimeMillis() + 900000L;
@@ -197,6 +209,104 @@ public void onFailure(Exception e) {
197209
remoteStorePinnedTimestampService.rescheduleAsyncUpdatePinnedTimestampTask(TimeValue.timeValueMinutes(3));
198210
}
199211

212+
public void testPinExceptionsOlderTimestamp() throws InterruptedException {
213+
prepareCluster(1, 1, INDEX_NAME, 0, 2);
214+
ensureGreen(INDEX_NAME);
215+
216+
RemoteStorePinnedTimestampService remoteStorePinnedTimestampService = internalCluster().getInstance(
217+
RemoteStorePinnedTimestampService.class,
218+
primaryNodeName(INDEX_NAME)
219+
);
220+
221+
CountDownLatch latch = new CountDownLatch(1);
222+
remoteStorePinnedTimestampService.pinTimestamp(1234L, "ss1", new LatchedActionListener<>(new ActionListener<>() {
223+
@Override
224+
public void onResponse(Void unused) {
225+
// We expect onFailure to be called
226+
fail();
227+
}
228+
229+
@Override
230+
public void onFailure(Exception e) {
231+
assertTrue(e instanceof IllegalArgumentException);
232+
}
233+
}, latch));
234+
235+
latch.await();
236+
}
237+
238+
public void testPinExceptionsRemoteStoreCallTakeTime() throws InterruptedException, ExecutionException {
239+
prepareCluster(1, 1, INDEX_NAME, 0, 2);
240+
ensureGreen(INDEX_NAME);
241+
242+
RemoteStorePinnedTimestampService remoteStorePinnedTimestampService = internalCluster().getInstance(
243+
RemoteStorePinnedTimestampService.class,
244+
primaryNodeName(INDEX_NAME)
245+
);
246+
247+
CountDownLatch latch = new CountDownLatch(1);
248+
slowDownRepo(REPOSITORY_NAME, 10);
249+
RemoteStoreSettings.setPinnedTimestampsLookbackInterval(TimeValue.timeValueSeconds(1));
250+
long timestampToBePinned = System.currentTimeMillis() + 600000;
251+
remoteStorePinnedTimestampService.pinTimestamp(timestampToBePinned, "ss1", new LatchedActionListener<>(new ActionListener<>() {
252+
@Override
253+
public void onResponse(Void unused) {
254+
// We expect onFailure to be called
255+
fail();
256+
}
257+
258+
@Override
259+
public void onFailure(Exception e) {
260+
logger.error(e.getMessage());
261+
assertTrue(e instanceof RuntimeException);
262+
assertTrue(e.getMessage().contains("Timestamp pinning took"));
263+
264+
// Check if the timestamp was unpinned
265+
remoteStorePinnedTimestampService.forceSyncPinnedTimestamps();
266+
assertFalse(RemoteStorePinnedTimestampService.getPinnedTimestamps().v2().contains(timestampToBePinned));
267+
}
268+
}, latch));
269+
270+
latch.await();
271+
}
272+
273+
protected void slowDownRepo(String repoName, int value) throws ExecutionException, InterruptedException {
274+
GetRepositoriesRequest gr = new GetRepositoriesRequest(new String[] { repoName });
275+
GetRepositoriesResponse res = client().admin().cluster().getRepositories(gr).get();
276+
RepositoryMetadata rmd = res.repositories().get(0);
277+
Settings.Builder settings = Settings.builder()
278+
.put("location", rmd.settings().get("location"))
279+
.put(REPOSITORIES_SLOWDOWN_SETTING.getKey(), value);
280+
createRepository(repoName, rmd.type(), settings);
281+
}
282+
283+
public void testUnpinException() throws InterruptedException {
284+
prepareCluster(1, 1, INDEX_NAME, 0, 2);
285+
ensureGreen(INDEX_NAME);
286+
287+
RemoteStorePinnedTimestampService remoteStorePinnedTimestampService = internalCluster().getInstance(
288+
RemoteStorePinnedTimestampService.class,
289+
primaryNodeName(INDEX_NAME)
290+
);
291+
292+
CountDownLatch latch = new CountDownLatch(1);
293+
remoteStorePinnedTimestampService.unpinTimestamp(1234L, "dummy-entity", new LatchedActionListener<>(new ActionListener<>() {
294+
@Override
295+
public void onResponse(Void unused) {
296+
// We expect onFailure to be called
297+
fail();
298+
}
299+
300+
@Override
301+
public void onFailure(Exception e) {
302+
logger.error(e.getMessage());
303+
assertTrue(e instanceof IllegalArgumentException);
304+
}
305+
}, latch));
306+
307+
latch.await();
308+
}
309+
200310
public void testLastSuccessfulFetchOfPinnedTimestampsPresentInNodeStats() throws Exception {
201311
logger.info("Starting up cluster manager");
202312
logger.info("cluster.remote_store.pinned_timestamps.enabled set to true");

server/src/main/java/org/opensearch/node/remotestore/RemoteStorePinnedTimestampService.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -130,16 +130,16 @@ public static Map<String, Set<Long>> fetchPinnedTimestamps(Settings settings, Re
130130
* @throws IllegalArgumentException If the timestamp is less than the current time minus one second
131131
*/
132132
public void pinTimestamp(long timestamp, String pinningEntity, ActionListener<Void> listener) {
133-
// If a caller uses current system time to pin the timestamp, following check will almost always fail.
134-
// So, we allow pinning timestamp in the past upto some buffer
135-
long lookbackIntervalInMills = RemoteStoreSettings.getPinnedTimestampsLookbackInterval().millis();
136-
if (timestamp < (System.currentTimeMillis() - lookbackIntervalInMills)) {
137-
throw new IllegalArgumentException(
138-
"Timestamp to be pinned is less than current timestamp - value of cluster.remote_store.pinned_timestamps.lookback_interval"
139-
);
140-
}
141-
long startTime = System.nanoTime();
142133
try {
134+
// If a caller uses current system time to pin the timestamp, following check will almost always fail.
135+
// So, we allow pinning timestamp in the past upto some buffer
136+
long lookbackIntervalInMills = RemoteStoreSettings.getPinnedTimestampsLookbackInterval().millis();
137+
if (timestamp < (System.currentTimeMillis() - lookbackIntervalInMills)) {
138+
throw new IllegalArgumentException(
139+
"Timestamp to be pinned is less than current timestamp - value of cluster.remote_store.pinned_timestamps.lookback_interval"
140+
);
141+
}
142+
long startTime = System.nanoTime();
143143
logger.debug("Pinning timestamp = {} against entity = {}", timestamp, pinningEntity);
144144
blobContainer.writeBlob(getBlobName(timestamp, pinningEntity), new ByteArrayInputStream(new byte[0]), 0, true);
145145
long elapsedTime = System.nanoTime() - startTime;
@@ -155,7 +155,7 @@ public void pinTimestamp(long timestamp, String pinningEntity, ActionListener<Vo
155155
} else {
156156
listener.onResponse(null);
157157
}
158-
} catch (IOException e) {
158+
} catch (Exception e) {
159159
listener.onFailure(e);
160160
}
161161
}
@@ -198,7 +198,7 @@ public void cloneTimestamp(long timestamp, String existingPinningEntity, String
198198
logger.error(errorMessage);
199199
listener.onFailure(new IllegalArgumentException(errorMessage));
200200
}
201-
} catch (IOException e) {
201+
} catch (Exception e) {
202202
listener.onFailure(e);
203203
}
204204
}
@@ -249,7 +249,7 @@ public void unpinTimestamp(long timestamp, String pinningEntity, ActionListener<
249249
logger.error(errorMessage);
250250
listener.onFailure(new IllegalArgumentException(errorMessage));
251251
}
252-
} catch (IOException e) {
252+
} catch (Exception e) {
253253
listener.onFailure(e);
254254
}
255255
}

0 commit comments

Comments
 (0)