use of com.linkedin.d2.balancer.clients.DegraderTrackerClientImpl in project rest.li by linkedin.
the class SimpleLoadBalancerStateTest method testRefreshWithConcurrentGetTC.
// This test is to verify a fix for a specific bug, where the d2 client receives a zookeeper
// update and concurrent getTrackerClient requests. In that case, all but the first concurrent
// requests got a null tracker client because the degraderLoadBalancerState was not fully initialized
// (hashring was empty), and this continued until the first request had atomically swamped a
// fully initialized state for other requests to use. This test failed on pre-fix code, it now
// succeeds.
@Test(groups = { "small", "back-end" })
public void testRefreshWithConcurrentGetTC() throws URISyntaxException, InterruptedException {
reset();
LinkedList<String> strategyList = new LinkedList<>();
URI uri = URI.create("http://cluster-1/test");
final List<String> schemes = new ArrayList<>();
schemes.add("http");
strategyList.add("degraderV3");
// set up state
_state.listenToService("service-1", new NullStateListenerCallback());
_state.listenToCluster("cluster-1", new NullStateListenerCallback());
assertNull(_state.getStrategy("service-1", "http"));
// Use the _clusterRegistry.put to populate the _state.clusterProperties, used by
// _state.refreshServiceStrategies
_clusterRegistry.put("cluster-1", new ClusterProperties("cluster-1"));
_serviceRegistry.put("service-1", new ServiceProperties("service-1", "cluster-1", "/test", strategyList, Collections.<String, Object>emptyMap(), Collections.<String, Object>emptyMap(), Collections.<String, String>emptyMap(), schemes, Collections.<URI>emptySet()));
LoadBalancerStrategy strategy = _state.getStrategy("service-1", "http");
assertNotNull(strategy, "got null strategy in setup");
// test serial to make sure things are working before concurrent test
TransportClient resultTC = _state.getClient("service-1", "http");
assertNotNull(resultTC, "got null tracker client in non-concurrent env");
ExecutorService myExecutor = Executors.newCachedThreadPool();
ArrayList<TcCallable> cArray = new ArrayList<>();
List<TrackerClient> clients = new ArrayList<>();
Map<Integer, PartitionData> partitionDataMap = new HashMap<>(2);
partitionDataMap.put(DefaultPartitionAccessor.DEFAULT_PARTITION_ID, new PartitionData(1d));
clients.add(new DegraderTrackerClientImpl(uri, partitionDataMap, new DegraderLoadBalancerTest.TestLoadBalancerClient(uri), SystemClock.instance(), null));
for (int i = 0; i < 20; i++) {
cArray.add(i, new TcCallable(clients, _state));
}
Runnable refreshTask = new Runnable() {
@Override
public void run() {
while (true) {
List<String> myStrategyList = new LinkedList<>();
myStrategyList.add("degraderV3");
_state.refreshServiceStrategies(new ServiceProperties("service-1", "cluster-1", "/test", myStrategyList, Collections.<String, Object>emptyMap(), Collections.<String, Object>emptyMap(), Collections.<String, String>emptyMap(), schemes, Collections.<URI>emptySet()));
if (Thread.interrupted()) {
return;
}
}
}
};
myExecutor.execute(refreshTask);
Integer badResults = 0;
ArrayList<Future<Integer>> myList = new ArrayList<>();
for (int i = 0; i < cArray.size(); i++) {
@SuppressWarnings("unchecked") Callable<Integer> c = (Callable) cArray.get(i);
myList.add(i, myExecutor.submit(c));
}
try {
for (int i = 0; i < cArray.size(); i++) {
badResults += myList.get(i).get();
}
} catch (ExecutionException e) {
Assert.assertFalse(true, "got ExecutionException");
} finally {
try {
// call shutdownNow() to send an interrupt to the refreshTask
myExecutor.shutdownNow();
boolean status = myExecutor.awaitTermination(5, TimeUnit.SECONDS);
if (status == false) {
Assert.assertFalse(true, "failed to shutdown threads correctly");
}
} catch (InterruptedException ie) {
// this thread was interrupted
myExecutor.shutdownNow();
}
}
Assert.assertTrue(badResults == 0, "getTrackerClients returned null");
}
use of com.linkedin.d2.balancer.clients.DegraderTrackerClientImpl in project rest.li by linkedin.
the class LoadBalancerStrategyTestRunnerBuilder method buildDegraderStrategy.
private LoadBalancerStrategyTestRunner buildDegraderStrategy() {
if (_serviceProperties == null) {
setDegraderStrategies(new HashMap<>(), new HashMap<>());
}
_strategy = new DegraderLoadBalancerStrategyFactoryV3().newLoadBalancer(_serviceProperties);
_transportClients = _uris.stream().map(uri -> new MockTransportClient(_clockedExecutor, _latencyManager, _errorCountManager, uri, INTERVAL_IN_MILLIS, _currentErrorCountMap, _lastRequestCountMap, _callCountMap, _latencySumMap)).collect(Collectors.toList());
Map<URI, TrackerClient> trackerClientMap = _transportClients.stream().map(transportClient -> {
// If partition map is not specified, by default we only support one partition
Map<Integer, PartitionData> partitionDataMap = _partitionDataMap.getOrDefault(transportClient.getUri(), DEFAULT_PARTITION_DATA_MAP);
return new DegraderTrackerClientImpl(transportClient.getUri(), partitionDataMap, transportClient, _clockedExecutor, DegraderConfigFactory.toDegraderConfig(_serviceProperties.getDegraderProperties()));
}).collect(Collectors.toMap(TrackerClient::getUri, trackerClient -> trackerClient));
return buildInternal(trackerClientMap);
}
use of com.linkedin.d2.balancer.clients.DegraderTrackerClientImpl in project rest.li by linkedin.
the class TestBackupRequestsClient method createAlwaysBackupClientWithHosts.
private BackupRequestsClient createAlwaysBackupClientWithHosts(List<String> uris, Deque<URI> hostsReceivingRequestList, int responseDelayNano, int backupDelayNano, boolean isD2Async) throws IOException {
Map<URI, Map<Integer, PartitionData>> partitionDescriptions = new HashMap<>();
uris.forEach(uri -> partitionDescriptions.put(URI.create(uri), Collections.singletonMap(0, new PartitionData(1))));
StaticLoadBalancerState LbState = new StaticLoadBalancerState() {
@Override
public TrackerClient getClient(String serviceName, URI uri) {
return new DegraderTrackerClientImpl(uri, partitionDescriptions.get(uri), null, SystemClock.instance(), null) {
@Override
public void restRequest(RestRequest request, RequestContext requestContext, Map<String, String> wireAttrs, TransportCallback<RestResponse> callback) {
// whenever a trackerClient is used to make request, record down it's hostname
hostsReceivingRequestList.add(uri);
// delay response to allow backup request to happen
_executor.schedule(() -> callback.onResponse(TransportResponseImpl.success(new RestResponseBuilder().build())), responseDelayNano, TimeUnit.NANOSECONDS);
}
@Override
public void streamRequest(StreamRequest request, RequestContext requestContext, Map<String, String> wireAttrs, TransportCallback<StreamResponse> callback) {
// whenever a trackerClient is used to make request, record down it's hostname
hostsReceivingRequestList.add(uri);
if (null != requestContext.getLocalAttr(R2Constants.BACKUP_REQUEST_BUFFERED_BODY)) {
callback.onResponse(TransportResponseImpl.success(new StreamResponseBuilder().setHeader(BUFFERED_HEADER, String.valueOf(requestContext.getLocalAttr(R2Constants.BACKUP_REQUEST_BUFFERED_BODY) != null)).build(EntityStreams.emptyStream())));
return;
}
request.getEntityStream().setReader(new DrainReader() {
public void onDone() {
// delay response to allow backup request to happen
_executor.schedule(() -> callback.onResponse(TransportResponseImpl.success(new StreamResponseBuilder().setHeader(BUFFERED_HEADER, String.valueOf(requestContext.getLocalAttr(R2Constants.BACKUP_REQUEST_BUFFERED_BODY) != null)).build(EntityStreams.emptyStream()))), responseDelayNano, TimeUnit.NANOSECONDS);
}
});
}
};
}
};
LbState.TEST_URIS_PARTITIONDESCRIPTIONS.putAll(partitionDescriptions);
LbState.TEST_SERVICE_BACKUP_REQUEST_PROPERTIES.add(createBackupRequestsConfiguration(5, "get"));
LbState.refreshDefaultProperties();
LoadBalancer loadBalancer = new SimpleLoadBalancer(LbState, _executor);
DynamicClient dynamicClient = new DynamicClient(loadBalancer, null);
return new BackupRequestsClient(dynamicClient, loadBalancer, _executor, null, 10, TimeUnit.SECONDS, isD2Async) {
@Override
Optional<TrackingBackupRequestsStrategy> getStrategyAfterUpdate(final String serviceName, final String operation) {
// constantly enable backup request after backupDelayNano time.
BackupRequestsStrategy alwaysBackup = new TestTrackingBackupRequestsStrategy.MockBackupRequestsStrategy(() -> Optional.of((long) backupDelayNano), () -> true);
return Optional.of(new TrackingBackupRequestsStrategy(alwaysBackup));
}
};
}
use of com.linkedin.d2.balancer.clients.DegraderTrackerClientImpl in project rest.li by linkedin.
the class LoadBalancerTestState method getClient.
@Override
public TrackerClient getClient(String clusterName, URI uri) {
Map<Integer, PartitionData> partitionDataMap = new HashMap<>(2);
partitionDataMap.put(DefaultPartitionAccessor.DEFAULT_PARTITION_ID, new PartitionData(1));
return (getClient) ? new DegraderTrackerClientImpl(uri, partitionDataMap, new TestClient(), SystemClock.instance(), null) : null;
}
use of com.linkedin.d2.balancer.clients.DegraderTrackerClientImpl in project rest.li by linkedin.
the class DegraderTrackerClientTest method testClientStreamRequest.
@Test(groups = { "small", "back-end" })
public void testClientStreamRequest() throws URISyntaxException {
URI uri = URI.create("http://test.qa.com:1234/foo");
double weight = 3d;
TestClient wrappedClient = new TestClient(true);
Clock clock = new SettableClock();
Map<Integer, PartitionData> partitionDataMap = createDefaultPartitionData(3d);
DegraderTrackerClient client = new DegraderTrackerClientImpl(uri, partitionDataMap, wrappedClient, clock, null);
Assert.assertEquals(client.getUri(), uri);
Double clientWeight = client.getPartitionWeight(DefaultPartitionAccessor.DEFAULT_PARTITION_ID);
Assert.assertEquals(clientWeight, weight);
Assert.assertEquals(client.getTransportClient(), wrappedClient);
StreamRequest streamRequest = new StreamRequestBuilder(uri).build(EntityStreams.emptyStream());
Map<String, String> restWireAttrs = new HashMap<>();
TestTransportCallback<StreamResponse> restCallback = new TestTransportCallback<>();
client.streamRequest(streamRequest, new RequestContext(), restWireAttrs, restCallback);
Assert.assertFalse(restCallback.response.hasError());
Assert.assertSame(wrappedClient.streamRequest, streamRequest);
Assert.assertEquals(wrappedClient.restWireAttrs, restWireAttrs);
}
Aggregations