1
1
package com .linkedin .venice .endToEnd ;
2
2
3
+ import static com .linkedin .venice .ConfigKeys .CLIENT_SYSTEM_STORE_REPOSITORY_REFRESH_INTERVAL_SECONDS ;
3
4
import static com .linkedin .venice .ConfigKeys .CONTROLLER_DEFERRED_VERSION_SWAP_SERVICE_ENABLED ;
4
5
import static com .linkedin .venice .ConfigKeys .CONTROLLER_DEFERRED_VERSION_SWAP_SLEEP_MS ;
6
+ import static com .linkedin .venice .ConfigKeys .DATA_BASE_PATH ;
7
+ import static com .linkedin .venice .ConfigKeys .LOCAL_REGION_NAME ;
5
8
import static com .linkedin .venice .utils .IntegrationTestPushUtils .createStoreForJob ;
6
9
import static com .linkedin .venice .utils .TestWriteUtils .NAME_RECORD_V3_SCHEMA ;
7
10
import static com .linkedin .venice .utils .TestWriteUtils .getTempDataDirectory ;
8
11
import static com .linkedin .venice .vpj .VenicePushJobConstants .TARGETED_REGION_PUSH_WITH_DEFERRED_SWAP ;
12
+ import static org .testng .Assert .assertNotNull ;
13
+ import static org .testng .Assert .assertNull ;
9
14
15
+ import com .linkedin .davinci .client .DaVinciClient ;
16
+ import com .linkedin .davinci .client .DaVinciConfig ;
10
17
import com .linkedin .venice .controllerapi .ControllerClient ;
11
18
import com .linkedin .venice .controllerapi .UpdateStoreQueryParams ;
19
+ import com .linkedin .venice .integration .utils .DaVinciTestContext ;
12
20
import com .linkedin .venice .integration .utils .ServiceFactory ;
21
+ import com .linkedin .venice .integration .utils .VeniceClusterWrapper ;
22
+ import com .linkedin .venice .integration .utils .VeniceMultiClusterWrapper ;
13
23
import com .linkedin .venice .integration .utils .VeniceMultiRegionClusterCreateOptions ;
14
24
import com .linkedin .venice .integration .utils .VeniceTwoLayerMultiRegionMultiClusterWrapper ;
15
25
import com .linkedin .venice .meta .StoreInfo ;
19
29
import com .linkedin .venice .utils .TestUtils ;
20
30
import com .linkedin .venice .utils .TestWriteUtils ;
21
31
import com .linkedin .venice .utils .Utils ;
32
+ import com .linkedin .venice .utils .VeniceProperties ;
22
33
import java .io .File ;
23
34
import java .io .IOException ;
35
+ import java .util .List ;
24
36
import java .util .Map ;
25
37
import java .util .Properties ;
26
38
import java .util .concurrent .TimeUnit ;
27
39
import java .util .stream .IntStream ;
40
+ import org .apache .logging .log4j .LogManager ;
41
+ import org .apache .logging .log4j .Logger ;
28
42
import org .testng .Assert ;
29
43
import org .testng .annotations .AfterClass ;
30
44
import org .testng .annotations .BeforeClass ;
@@ -40,6 +54,9 @@ public class TestDeferredVersionSwap {
40
54
private static final String [] CLUSTER_NAMES =
41
55
IntStream .range (0 , NUMBER_OF_CLUSTERS ).mapToObj (i -> "venice-cluster" + i ).toArray (String []::new );
42
56
57
+ private static final int TEST_TIMEOUT = 120_000 ;
58
+ private static final Logger LOGGER = LogManager .getLogger (TestDeferredVersionSwap .class );
59
+
43
60
@ BeforeClass
44
61
public void setUp () {
45
62
Properties controllerProps = new Properties ();
@@ -68,7 +85,7 @@ public void cleanUp() {
68
85
Utils .closeQuietlyWithErrorLogged (multiRegionMultiClusterWrapper );
69
86
}
70
87
71
- @ Test
88
+ @ Test ( timeOut = TEST_TIMEOUT )
72
89
public void testDeferredVersionSwap () throws IOException {
73
90
File inputDir = getTempDataDirectory ();
74
91
TestWriteUtils .writeSimpleAvroFileWithStringToV3Schema (inputDir , 100 , 100 );
@@ -131,4 +148,140 @@ public void testDeferredVersionSwap() throws IOException {
131
148
}
132
149
}
133
150
151
+ @ Test (timeOut = TEST_TIMEOUT * 2 )
152
+ public void testDvcDelayedIngestionWithTargetRegion () throws Exception {
153
+ // Setup job properties
154
+ UpdateStoreQueryParams storeParms = new UpdateStoreQueryParams ().setUnusedSchemaDeletionEnabled (true );
155
+ storeParms .setTargetRegionSwapWaitTime (1 );
156
+ storeParms .setTargetRegionSwap (TARGET_REGION );
157
+ String parentControllerURLs = multiRegionMultiClusterWrapper .getControllerConnectString ();
158
+ String keySchemaStr = "\" int\" " ;
159
+ String valueSchemaStr = "\" int\" " ;
160
+
161
+ // Create store + start a normal push
162
+ int keyCount = 100 ;
163
+ File inputDir = getTempDataDirectory ();
164
+ TestWriteUtils .writeSimpleAvroFileWithIntToIntSchema (inputDir , keyCount );
165
+ String inputDirPath = "file://" + inputDir .getAbsolutePath ();
166
+ String storeName = Utils .getUniqueString ("testDvcDelayedIngestionWithTargetRegion" );
167
+ Properties props =
168
+ IntegrationTestPushUtils .defaultVPJProps (multiRegionMultiClusterWrapper , inputDirPath , storeName );
169
+ try (ControllerClient parentControllerClient = new ControllerClient (CLUSTER_NAMES [0 ], parentControllerURLs )) {
170
+ createStoreForJob (CLUSTER_NAMES [0 ], keySchemaStr , valueSchemaStr , props , storeParms ).close ();
171
+ LOGGER .info ("DvcDeferredVersionSwap starting normal push job" );
172
+ TestWriteUtils .runPushJob ("Test push job" , props );
173
+ TestUtils .waitForNonDeterministicPushCompletion (
174
+ Version .composeKafkaTopic (storeName , 1 ),
175
+ parentControllerClient ,
176
+ 30 ,
177
+ TimeUnit .SECONDS );
178
+
179
+ // Version should only be swapped in all regions
180
+ TestUtils .waitForNonDeterministicAssertion (1 , TimeUnit .MINUTES , () -> {
181
+ Map <String , Integer > coloVersions =
182
+ parentControllerClient .getStore (storeName ).getStore ().getColoToCurrentVersions ();
183
+
184
+ coloVersions .forEach ((colo , version ) -> {
185
+ Assert .assertEquals ((int ) version , 1 );
186
+ });
187
+ });
188
+ }
189
+
190
+ // Create dvc client in target region
191
+ List <VeniceMultiClusterWrapper > childDatacenters = multiRegionMultiClusterWrapper .getChildRegions ();
192
+ VeniceClusterWrapper cluster1 = childDatacenters .get (0 ).getClusters ().get (CLUSTER_NAMES [0 ]);
193
+ VeniceProperties backendConfig = DaVinciTestContext .getDaVinciPropertyBuilder (cluster1 .getZk ().getAddress ())
194
+ .put (DATA_BASE_PATH , Utils .getTempDataDirectory ().getAbsolutePath ())
195
+ .put (LOCAL_REGION_NAME , TARGET_REGION )
196
+ .put (CLIENT_SYSTEM_STORE_REPOSITORY_REFRESH_INTERVAL_SECONDS , 1 )
197
+ .build ();
198
+ DaVinciClient <Object , Object > client1 =
199
+ ServiceFactory .getGenericAvroDaVinciClient (storeName , cluster1 , new DaVinciConfig (), backendConfig );
200
+ client1 .subscribeAll ().get ();
201
+
202
+ // Check that v1 is ingested
203
+ for (int i = 1 ; i <= keyCount ; i ++) {
204
+ assertNotNull (client1 .get (i ).get ());
205
+ }
206
+
207
+ // Do another push with target region enabled
208
+ int keyCount2 = 200 ;
209
+ File inputDir2 = getTempDataDirectory ();
210
+ String inputDirPath2 = "file://" + inputDir2 .getAbsolutePath ();
211
+ TestWriteUtils .writeSimpleAvroFileWithIntToIntSchema (inputDir2 , keyCount2 );
212
+ Properties props2 =
213
+ IntegrationTestPushUtils .defaultVPJProps (multiRegionMultiClusterWrapper , inputDirPath2 , storeName );
214
+ try (ControllerClient parentControllerClient = new ControllerClient (CLUSTER_NAMES [0 ], parentControllerURLs )) {
215
+ props2 .put (TARGETED_REGION_PUSH_WITH_DEFERRED_SWAP , true );
216
+ LOGGER .info ("DvcDeferredVersionSwap starting target region push job" );
217
+ TestWriteUtils .runPushJob ("Test push job" , props2 );
218
+ TestUtils .waitForNonDeterministicPushCompletion (
219
+ Version .composeKafkaTopic (storeName , 2 ),
220
+ parentControllerClient ,
221
+ 30 ,
222
+ TimeUnit .SECONDS );
223
+
224
+ // Version should only be swapped in the target region
225
+ TestUtils .waitForNonDeterministicAssertion (1 , TimeUnit .MINUTES , () -> {
226
+ Map <String , Integer > coloVersions =
227
+ parentControllerClient .getStore (storeName ).getStore ().getColoToCurrentVersions ();
228
+
229
+ coloVersions .forEach ((colo , version ) -> {
230
+ if (colo .equals (TARGET_REGION )) {
231
+ Assert .assertEquals ((int ) version , 2 );
232
+ } else {
233
+ Assert .assertEquals ((int ) version , 1 );
234
+ }
235
+ });
236
+ });
237
+
238
+ // Data should be automatically ingested in target region for dvc
239
+ TestUtils .waitForNonDeterministicAssertion (30 , TimeUnit .SECONDS , () -> {
240
+ for (int i = 101 ; i <= keyCount2 ; i ++) {
241
+ assertNotNull (client1 .get (i ).get ());
242
+ }
243
+ });
244
+
245
+ // Close dvc client in target region
246
+ client1 .close ();
247
+
248
+ // Create dvc client in non target region
249
+ VeniceClusterWrapper cluster2 = childDatacenters .get (1 ).getClusters ().get (CLUSTER_NAMES [0 ]);
250
+ VeniceProperties backendConfig2 = DaVinciTestContext .getDaVinciPropertyBuilder (cluster2 .getZk ().getAddress ())
251
+ .put (DATA_BASE_PATH , Utils .getTempDataDirectory ().getAbsolutePath ())
252
+ .put (LOCAL_REGION_NAME , "dc-1" )
253
+ .put (CLIENT_SYSTEM_STORE_REPOSITORY_REFRESH_INTERVAL_SECONDS , 1 )
254
+ .build ();
255
+ DaVinciClient <Object , Object > client2 =
256
+ ServiceFactory .getGenericAvroDaVinciClient (storeName , cluster2 , new DaVinciConfig (), backendConfig2 );
257
+ client2 .subscribeAll ().get ();
258
+
259
+ // Check that v2 is not ingested
260
+ TestUtils .waitForNonDeterministicAssertion (30 , TimeUnit .SECONDS , () -> {
261
+ for (int i = 101 ; i <= keyCount2 ; i ++) {
262
+ assertNull (client2 .get (i ).get ());
263
+ }
264
+ });
265
+
266
+ // Version should be swapped in all regions
267
+ LOGGER .info ("DvcDeferredVersionSwap check that target region push is complete" );
268
+ TestUtils .waitForNonDeterministicAssertion (1 , TimeUnit .MINUTES , () -> {
269
+ Map <String , Integer > coloVersions =
270
+ parentControllerClient .getStore (storeName ).getStore ().getColoToCurrentVersions ();
271
+
272
+ coloVersions .forEach ((colo , version ) -> {
273
+ Assert .assertEquals ((int ) version , 2 );
274
+ });
275
+ });
276
+
277
+ // Check that v2 is ingested in dvc non target region
278
+ TestUtils .waitForNonDeterministicAssertion (30 , TimeUnit .SECONDS , () -> {
279
+ for (int i = 101 ; i <= keyCount2 ; i ++) {
280
+ assertNotNull (client2 .get (i ).get ());
281
+ }
282
+ });
283
+
284
+ client2 .close ();
285
+ }
286
+ }
134
287
}
0 commit comments