use of com.github.ambry.commons.LoggingNotificationSystem in project ambry by linkedin.
the class RestServerTest method startShutdownTest.
/**
* Tests {@link RestServer#start()} and {@link RestServer#shutdown()}.
* @throws Exception
*/
@Test
public void startShutdownTest() throws Exception {
Properties properties = new Properties();
VerifiableProperties verifiableProperties = getVProps(properties);
ClusterMap clusterMap = new MockClusterMap();
NotificationSystem notificationSystem = new LoggingNotificationSystem();
RestServer server = new RestServer(verifiableProperties, clusterMap, notificationSystem, SSL_FACTORY);
server.start();
server.shutdown();
server.awaitShutdown();
}
use of com.github.ambry.commons.LoggingNotificationSystem in project ambry by linkedin.
the class NonBlockingRouterTest method testBadCallbackForUpdateTtl.
/**
* Test that a bad user defined callback will not crash the router or the manager.
* @throws Exception
*/
@Test
public void testBadCallbackForUpdateTtl() throws Exception {
try {
MockServerLayout serverLayout = new MockServerLayout(mockClusterMap);
setRouter(getNonBlockingRouterProperties("DC1"), serverLayout, new LoggingNotificationSystem());
setOperationParams();
String blobId = router.putBlob(putBlobProperties, putUserMetadata, putChannel, new PutBlobOptionsBuilder().build()).get(AWAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
putChannel = new ByteBufferReadableStreamChannel(ByteBuffer.wrap(putContent));
String blobIdCheck = router.putBlob(putBlobProperties, putUserMetadata, putChannel, new PutBlobOptionsBuilder().build()).get(AWAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
testWithErrorCodes(Collections.singletonMap(ServerErrorCode.No_Error, 9), serverLayout, null, expectedError -> {
final CountDownLatch callbackCalled = new CountDownLatch(1);
router.updateBlobTtl(blobId, null, Utils.Infinite_Time, (result, exception) -> {
callbackCalled.countDown();
throw new RuntimeException("Throwing an exception in the user callback");
}, null).get(AWAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertTrue("Callback not called.", callbackCalled.await(10, TimeUnit.MILLISECONDS));
assertEquals("All operations should be finished.", 0, router.getOperationsCount());
assertTrue("Router should not be closed", router.isOpen());
assertTtl(router, Collections.singleton(blobId), Utils.Infinite_Time);
// Test that TtlUpdateManager is still functional
router.updateBlobTtl(blobIdCheck, null, Utils.Infinite_Time).get(AWAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertTtl(router, Collections.singleton(blobIdCheck), Utils.Infinite_Time);
});
} finally {
if (router != null) {
router.close();
}
}
}
use of com.github.ambry.commons.LoggingNotificationSystem in project ambry by linkedin.
the class NonBlockingRouterTest method testWarmUpConnectionFailureHandling.
/**
* Test that Response Handler correctly handles disconnected connections after warming up.
*/
@Test
public void testWarmUpConnectionFailureHandling() throws Exception {
try {
Properties props = getNonBlockingRouterProperties("DC3");
MockServerLayout mockServerLayout = new MockServerLayout(mockClusterMap);
mockSelectorState.set(MockSelectorState.FailConnectionInitiationOnPoll);
setRouter(props, mockServerLayout, new LoggingNotificationSystem());
for (DataNodeId node : mockClusterMap.getDataNodes()) {
assertTrue("Node should be marked as timed out by ResponseHandler.", ((MockDataNodeId) node).isTimedOut());
}
} finally {
if (router != null) {
router.close();
}
mockSelectorState.set(MockSelectorState.Good);
}
}
use of com.github.ambry.commons.LoggingNotificationSystem in project ambry by linkedin.
the class NonBlockingRouterTest method testUndeleteWithNotificationSystem.
/**
* Test undelete notification system when successfully undelete a blob.
* @throws Exception
*/
@Test
public void testUndeleteWithNotificationSystem() throws Exception {
try {
assumeTrue(!includeCloudDc);
final CountDownLatch undeletesDoneLatch = new CountDownLatch(2);
final Set<String> blobsThatAreUndeleted = new HashSet<>();
LoggingNotificationSystem undeleteTrackingNotificationSystem = new LoggingNotificationSystem() {
@Override
public void onBlobUndeleted(String blobId, String serviceId, Account account, Container container) {
blobsThatAreUndeleted.add(blobId);
undeletesDoneLatch.countDown();
}
};
setRouter(getNonBlockingRouterProperties("DC1"), mockServerLayout, undeleteTrackingNotificationSystem);
List<String> blobIds = new ArrayList<>();
for (int i = 0; i < 4; i++) {
setOperationParams();
String blobId = router.putBlob(putBlobProperties, putUserMetadata, putChannel, PutBlobOptions.DEFAULT).get();
ensurePutInAllServers(blobId, mockServerLayout);
blobIds.add(blobId);
}
setOperationParams();
List<ChunkInfo> chunksToStitch = blobIds.stream().map(blobId -> new ChunkInfo(blobId, PUT_CONTENT_SIZE, Utils.Infinite_Time)).collect(Collectors.toList());
String blobId = router.stitchBlob(putBlobProperties, putUserMetadata, chunksToStitch).get();
ensureStitchInAllServers(blobId, mockServerLayout, chunksToStitch, PUT_CONTENT_SIZE);
blobIds.add(blobId);
Set<String> blobsToBeUndeleted = getBlobsInServers(mockServerLayout);
router.getBlob(blobId, new GetBlobOptionsBuilder().build()).get();
router.deleteBlob(blobId, null).get();
for (String chunkBlobId : blobIds) {
ensureDeleteInAllServers(chunkBlobId, mockServerLayout);
}
router.undeleteBlob(blobId, "undelete_server_id").get();
Assert.assertTrue("Undelete should not take longer than " + AWAIT_TIMEOUT_MS, undeletesDoneLatch.await(AWAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
Assert.assertTrue("All blobs in server are deleted", blobsThatAreUndeleted.containsAll(blobsToBeUndeleted));
Assert.assertTrue("Only blobs in server are undeleted", blobsToBeUndeleted.containsAll(blobsThatAreUndeleted));
} finally {
if (router != null) {
router.close();
assertClosed();
}
}
}
use of com.github.ambry.commons.LoggingNotificationSystem in project ambry by linkedin.
the class NonBlockingRouterTest method testSuccessfulPutDataChunkDelete.
/**
* Test that even when a composite blob put succeeds, the slipped put data chunks are deleted.
*/
@Test
public void testSuccessfulPutDataChunkDelete() throws Exception {
try {
// This test is somehow probabilistic. Since it is not possible to devise a mocking to enforce the occurrence of
// slipped puts given we cannot control the order of the hosts requests are sent and not all requests are sent when
// put requests are guaranteed to fail/succeed. So, we are setting the number of chunks and max attempts high enough
// to guarantee that slipped puts would eventually happen and operation would succeed.
maxPutChunkSize = PUT_CONTENT_SIZE / 8;
final int NUM_MAX_ATTEMPTS = 100;
Properties props = getNonBlockingRouterProperties("DC1");
props.setProperty("router.max.slipped.put.attempts", Integer.toString(NUM_MAX_ATTEMPTS));
VerifiableProperties verifiableProperties = new VerifiableProperties((props));
RouterConfig routerConfig = new RouterConfig(verifiableProperties);
MockClusterMap mockClusterMap = new MockClusterMap();
MockTime mockTime = new MockTime();
MockServerLayout mockServerLayout = new MockServerLayout(mockClusterMap);
// Since this test wants to ensure that successfully put data chunks are deleted when the overall put operation
// succeeds but some chunks succeed only after a retry, it uses a notification system to track the deletions.
final CountDownLatch deletesDoneLatch = new CountDownLatch(1);
final Map<String, String> blobsThatAreDeleted = new HashMap<>();
LoggingNotificationSystem deleteTrackingNotificationSystem = new LoggingNotificationSystem() {
@Override
public void onBlobDeleted(String blobId, String serviceId, Account account, Container container) {
blobsThatAreDeleted.put(blobId, serviceId);
deletesDoneLatch.countDown();
}
};
router = new NonBlockingRouter(routerConfig, new NonBlockingRouterMetrics(mockClusterMap, routerConfig), new MockNetworkClientFactory(verifiableProperties, mockSelectorState, MAX_PORTS_PLAIN_TEXT, MAX_PORTS_SSL, CHECKOUT_TIMEOUT_MS, mockServerLayout, mockTime), deleteTrackingNotificationSystem, mockClusterMap, kms, cryptoService, cryptoJobHandler, accountService, mockTime, MockClusterMap.DEFAULT_PARTITION_CLASS);
setOperationParams();
// In each DC, set up the servers such that one node always succeeds and the other nodes return an unknown_error and
// no_error alternately. This will make it with a very high probability that there will at least be a time that a
// put will succeed on a node but will fail on the other two.
List<DataNodeId> dataNodeIds = mockClusterMap.getDataNodeIds();
List<ServerErrorCode> serverErrorList = new ArrayList<>();
for (int i = 0; i < NUM_MAX_ATTEMPTS; i++) {
serverErrorList.add(ServerErrorCode.Unknown_Error);
serverErrorList.add(ServerErrorCode.No_Error);
}
Set<String> healthyNodeDC = new HashSet<>();
for (DataNodeId dataNodeId : dataNodeIds) {
MockServer server = mockServerLayout.getMockServer(dataNodeId.getHostname(), dataNodeId.getPort());
if (healthyNodeDC.contains(dataNodeId.getDatacenterName())) {
server.setServerErrors(serverErrorList);
} else {
server.resetServerErrors();
}
healthyNodeDC.add(dataNodeId.getDatacenterName());
}
// Submit the put operation and wait for it to succeed.
String blobId = router.putBlob(putBlobProperties, putUserMetadata, putChannel, new PutBlobOptionsBuilder().build()).get();
// Now, wait until at least one delete happens within AWAIT_TIMEOUT_MS.
Assert.assertTrue("Some blobs should have been deleted within " + AWAIT_TIMEOUT_MS, deletesDoneLatch.await(AWAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
// Wait for the rest of the deletes to finish.
long waitStart = SystemTime.getInstance().milliseconds();
while (router.getBackgroundOperationsCount() != 0 && SystemTime.getInstance().milliseconds() < waitStart + AWAIT_TIMEOUT_MS) {
Thread.sleep(1000);
}
for (Map.Entry<String, String> blobIdAndServiceId : blobsThatAreDeleted.entrySet()) {
Assert.assertNotSame("We should not be deleting the valid blob by mistake", blobId, blobIdAndServiceId.getKey());
Assert.assertEquals("Unexpected service ID for deleted blob", BackgroundDeleteRequest.SERVICE_ID_PREFIX + putBlobProperties.getServiceId(), blobIdAndServiceId.getValue());
}
} finally {
if (router != null) {
router.close();
assertClosed();
}
}
}
Aggregations