/* * Licensed to Crate under one or more contributor license agreements. * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. Crate licenses this file * to you under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may * obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * However, if you have executed another commercial license agreement * with Crate these terms will supersede the license and you may use the * software solely pursuant to the terms of the relevant commercial * agreement. */ package io.crate.operation.collect.stats; import io.crate.breaker.SizeEstimator; import io.crate.core.collections.BlockingEvictingQueue; import io.crate.operation.reference.sys.job.ContextLog; import io.crate.operation.reference.sys.job.JobContext; import io.crate.operation.reference.sys.job.JobContextLog; import io.crate.test.integration.CrateUnitTest; import org.elasticsearch.common.breaker.CircuitBreaker; import org.elasticsearch.common.unit.TimeValue; import org.junit.After; import org.junit.Before; import org.junit.Test; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.*; import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class RamAccountingQueueSinkTest extends CrateUnitTest { private static final NoopLogEstimator NOOP_ESTIMATOR = new NoopLogEstimator(); private ScheduledExecutorService scheduler; private QueueSink logSink; private static class NoopLog implements ContextLog { NoopLog() { } @Override public long ended() { return 0; } } private static class NoopLogEstimator extends SizeEstimator<NoopLog> { @Override public long estimateSize(@Nullable NoopLog value) { return 0L; } } @Before public void createScheduler() { scheduler = Executors.newSingleThreadScheduledExecutor(); } @After public void terminateScheduler() throws InterruptedException { if (logSink != null) { logSink.close(); } terminate(scheduler); } public static CircuitBreaker breaker() { CircuitBreaker circuitBreaker = mock(CircuitBreaker.class); // mocked CircuitBreaker has unlimited memory (⌐■_■) when(circuitBreaker.getLimit()).thenReturn(Long.MAX_VALUE); return circuitBreaker; } @Test public void testFixedSizeRamAccountingQueueSink() throws Exception { BlockingEvictingQueue<NoopLog> q = new BlockingEvictingQueue<>(15_000); RamAccountingQueue<NoopLog> ramAccountingQueue = new RamAccountingQueue<>(q, breaker(), NOOP_ESTIMATOR); logSink = new QueueSink<>(ramAccountingQueue, ramAccountingQueue::close); int THREADS = 50; final CountDownLatch latch = new CountDownLatch(THREADS); List<Thread> threads = new ArrayList<>(20); for (int i = 0; i < THREADS; i++) { Thread t = new Thread(() -> { for (int j = 0; j < 1000; j++) { logSink.add(new NoopLog()); } latch.countDown(); }); t.start(); threads.add(t); } latch.await(); assertThat(ramAccountingQueue.size(), is(15_000)); for (Thread thread : threads) { thread.join(); } } @Test public void testRemoveExpiredLogs() { ConcurrentLinkedQueue<JobContextLog> q = new ConcurrentLinkedQueue<>(); ScheduledFuture<?> task = new TimeExpiring(1_000_000L, 1_000_000L).registerTruncateTask(q, scheduler, TimeValue.timeValueSeconds(1L)); q.add(new JobContextLog(new JobContext(UUID.fromString("067e6162-3b6f-4ae2-a171-2470b63dff01"), "select 1", 1L), null, 2000L)); q.add(new JobContextLog(new JobContext(UUID.fromString("067e6162-3b6f-4ae2-a171-2470b63dff02"), "select 1", 1L), null, 4000L)); q.add(new JobContextLog(new JobContext(UUID.fromString("067e6162-3b6f-4ae2-a171-2470b63dff03"), "select 1", 1L), null, 7000L)); TimeExpiring.instance().removeExpiredLogs(q, 10_000L, 5_000L); assertThat(q.size(), is(1)); assertThat(q.iterator().next().id(), is(UUID.fromString("067e6162-3b6f-4ae2-a171-2470b63dff03"))); task.cancel(true); } @Test public void testTimedRamAccountingQueueSink() throws Exception { ConcurrentLinkedQueue<NoopLog> q = new ConcurrentLinkedQueue<>(); RamAccountingQueue<NoopLog> ramAccountingQueue = new RamAccountingQueue<>(q, breaker(), NOOP_ESTIMATOR); TimeValue timeValue = TimeValue.timeValueSeconds(1L); TimeExpiring timeExiring = new TimeExpiring(1000L, 1000L); ScheduledFuture<?> task = timeExiring.registerTruncateTask(q, scheduler, timeValue); logSink = new QueueSink<>(ramAccountingQueue, () -> { task.cancel(false); ramAccountingQueue.close(); }); for (int j = 0; j < 100; j++) { logSink.add(new NoopLog()); } assertThat(ramAccountingQueue.size(), is(100)); Thread.sleep(2000L); assertThat(ramAccountingQueue.size(), is(0)); } }