88
99package org .opensearch .remotestore ;
1010
11+ import org .opensearch .action .LatchedActionListener ;
1112import org .opensearch .common .collect .Tuple ;
1213import org .opensearch .common .settings .Settings ;
1314import org .opensearch .common .unit .TimeValue ;
1718import org .opensearch .test .OpenSearchIntegTestCase ;
1819
1920import java .util .Set ;
21+ import java .util .concurrent .CountDownLatch ;
2022
2123@ OpenSearchIntegTestCase .ClusterScope (scope = OpenSearchIntegTestCase .Scope .TEST , numDataNodes = 0 )
2224public class RemoteStorePinnedTimestampsIT extends RemoteStoreBaseIntegTestCase {
@@ -75,10 +77,25 @@ public void testTimestampPinUnpin() throws Exception {
7577
7678 remoteStorePinnedTimestampService .rescheduleAsyncUpdatePinnedTimestampTask (TimeValue .timeValueMinutes (3 ));
7779
78- // This should be a no-op as pinning entity is different
79- remoteStorePinnedTimestampService .unpinTimestamp (timestamp1 , "no-snapshot" , noOpActionListener );
8080 // Unpinning already pinned entity
8181 remoteStorePinnedTimestampService .unpinTimestamp (timestamp2 , "ss3" , noOpActionListener );
82+
83+ // This should fail as timestamp is not pinned by pinning entity
84+ CountDownLatch latch = new CountDownLatch (1 );
85+ remoteStorePinnedTimestampService .unpinTimestamp (timestamp1 , "no-snapshot" , new LatchedActionListener <>(new ActionListener <Void >() {
86+ @ Override
87+ public void onResponse (Void unused ) {
88+ // onResponse should not get called.
89+ fail ();
90+ }
91+
92+ @ Override
93+ public void onFailure (Exception e ) {
94+ assertTrue (e instanceof IllegalArgumentException );
95+ }
96+ }, latch ));
97+ latch .await ();
98+
8299 // Adding different entity to already pinned timestamp
83100 remoteStorePinnedTimestampService .pinTimestamp (timestamp3 , "ss5" , noOpActionListener );
84101
@@ -93,4 +110,74 @@ public void testTimestampPinUnpin() throws Exception {
93110
94111 remoteStorePinnedTimestampService .rescheduleAsyncUpdatePinnedTimestampTask (TimeValue .timeValueMinutes (3 ));
95112 }
113+
114+ public void testPinnedTimestampClone () throws Exception {
115+ prepareCluster (1 , 1 , INDEX_NAME , 0 , 2 );
116+ ensureGreen (INDEX_NAME );
117+
118+ RemoteStorePinnedTimestampService remoteStorePinnedTimestampService = internalCluster ().getInstance (
119+ RemoteStorePinnedTimestampService .class ,
120+ primaryNodeName (INDEX_NAME )
121+ );
122+
123+ long timestamp1 = System .currentTimeMillis () + 30000L ;
124+ long timestamp2 = System .currentTimeMillis () + 60000L ;
125+ long timestamp3 = System .currentTimeMillis () + 900000L ;
126+ remoteStorePinnedTimestampService .pinTimestamp (timestamp1 , "ss2" , noOpActionListener );
127+ remoteStorePinnedTimestampService .pinTimestamp (timestamp2 , "ss3" , noOpActionListener );
128+ remoteStorePinnedTimestampService .pinTimestamp (timestamp3 , "ss4" , noOpActionListener );
129+
130+ // Clone timestamp1
131+ remoteStorePinnedTimestampService .cloneTimestamp (timestamp1 , "ss2" , "ss2-2" , noOpActionListener );
132+
133+ // With clone, set of pinned timestamp will not change
134+ remoteStorePinnedTimestampService .rescheduleAsyncUpdatePinnedTimestampTask (TimeValue .timeValueSeconds (1 ));
135+ assertBusy (
136+ () -> assertEquals (Set .of (timestamp1 , timestamp2 , timestamp3 ), RemoteStorePinnedTimestampService .getPinnedTimestamps ().v2 ())
137+ );
138+ remoteStorePinnedTimestampService .rescheduleAsyncUpdatePinnedTimestampTask (TimeValue .timeValueMinutes (3 ));
139+
140+ // Clone timestamp1 but provide invalid existing entity
141+ CountDownLatch latch = new CountDownLatch (1 );
142+ remoteStorePinnedTimestampService .cloneTimestamp (
143+ timestamp1 ,
144+ "ss3" ,
145+ "ss2-3" ,
146+ new LatchedActionListener <>(new ActionListener <Void >() {
147+ @ Override
148+ public void onResponse (Void unused ) {
149+ // onResponse should not get called.
150+ fail ();
151+ }
152+
153+ @ Override
154+ public void onFailure (Exception e ) {
155+ assertTrue (e instanceof IllegalArgumentException );
156+ }
157+ }, latch )
158+ );
159+ latch .await ();
160+
161+ remoteStorePinnedTimestampService .rescheduleAsyncUpdatePinnedTimestampTask (TimeValue .timeValueSeconds (1 ));
162+ assertBusy (
163+ () -> assertEquals (Set .of (timestamp1 , timestamp2 , timestamp3 ), RemoteStorePinnedTimestampService .getPinnedTimestamps ().v2 ())
164+ );
165+ remoteStorePinnedTimestampService .rescheduleAsyncUpdatePinnedTimestampTask (TimeValue .timeValueMinutes (3 ));
166+
167+ // Now we have timestamp1 pinned by 2 entities, unpin 1, this should not change set of pinned timestamps
168+ remoteStorePinnedTimestampService .unpinTimestamp (timestamp1 , "ss2" , noOpActionListener );
169+
170+ remoteStorePinnedTimestampService .rescheduleAsyncUpdatePinnedTimestampTask (TimeValue .timeValueSeconds (1 ));
171+ assertBusy (
172+ () -> assertEquals (Set .of (timestamp1 , timestamp2 , timestamp3 ), RemoteStorePinnedTimestampService .getPinnedTimestamps ().v2 ())
173+ );
174+ remoteStorePinnedTimestampService .rescheduleAsyncUpdatePinnedTimestampTask (TimeValue .timeValueMinutes (3 ));
175+
176+ // Now unpin second entity as well, set of pinned timestamp should be reduced by 1
177+ remoteStorePinnedTimestampService .unpinTimestamp (timestamp1 , "ss2-2" , noOpActionListener );
178+
179+ remoteStorePinnedTimestampService .rescheduleAsyncUpdatePinnedTimestampTask (TimeValue .timeValueSeconds (1 ));
180+ assertBusy (() -> assertEquals (Set .of (timestamp2 , timestamp3 ), RemoteStorePinnedTimestampService .getPinnedTimestamps ().v2 ()));
181+ remoteStorePinnedTimestampService .rescheduleAsyncUpdatePinnedTimestampTask (TimeValue .timeValueMinutes (3 ));
182+ }
96183}
0 commit comments